diff --git a/clone/clone_test.go b/clone/clone_test.go index 0ba4786..bf51b23 100644 --- a/clone/clone_test.go +++ b/clone/clone_test.go @@ -61,12 +61,12 @@ func TestCloneCommand_MultipleProjects(t *testing.T) { if len(db.Repositories) != 4 { t.Fatal("helloworld and fibonacci were not registered.") } - var hwRepo = db.Repositories[1] - if message := validate(hwRepo, "helloworld", "../testdata/hoge/helloworld"); message != "" { + var hwRepo = db.FindRepository("helloworld") + if message := validate(*hwRepo, "helloworld", "../testdata/hoge/helloworld"); message != "" { t.Error(message) } - var fiboRepo = db.Repositories[0] - if message := validate(fiboRepo, "fibonacci", "../testdata/hoge/fibonacci"); message != "" { + var fiboRepo = db.FindRepository("fibonacci") + if message := validate(*fiboRepo, "fibonacci", "../testdata/hoge/fibonacci"); message != "" { t.Error(message) } if !db.HasGroup("not-exist-group") || len(db.Groups) != 3 { @@ -92,8 +92,8 @@ func TestCloneCommand_Run(t *testing.T) { if len(db.Repositories) != 3 { t.Fatal("helloworld was not registered.") } - var repo = db.Repositories[0] - if message := validate(repo, "helloworld", "./helloworld"); message != "" { + var repo = db.FindRepository("helloworld") + if message := validate(*repo, "helloworld", "./helloworld"); message != "" { t.Error(message) } if db.ContainsCount("no-group") != 1 || !db.HasRelation("no-group", "helloworld") { @@ -115,8 +115,8 @@ func TestCloneCommand_SpecifyingId(t *testing.T) { if len(db.Repositories) != 3 { t.Fatal("newid was not registered.") } - var repo = db.Repositories[0] - if message := validate(repo, "newid", "../testdata/newid"); message != "" { + var repo = db.FindRepository("newid") + if message := validate(*repo, "newid", "../testdata/newid"); message != "" { t.Error(message) } }) diff --git a/common/config.go b/common/config.go index 12b7b7b..929f6c7 100644 --- a/common/config.go +++ b/common/config.go @@ -19,6 +19,7 @@ const ( RrhAutoDeleteGroup = "RRH_AUTO_DELETE_GROUP" RrhAutoCreateGroup = "RRH_AUTO_CREATE_GROUP" RrhTimeFormat = "RRH_TIME_FORMAT" + RrhSortOnUpdating = "RRH_SORT_ON_UPDATING" ) const ( @@ -45,6 +46,7 @@ type Config struct { DefaultGroupName string `json:"rrh_default_group_name"` TimeFormat string `json:"rrh_time_format"` OnError string `json:"rrh_on_error"` + SortOnUpdating string `json:"rrh_sort_on_updating"` } func trueOrFalse(value string) (string, error) { @@ -78,6 +80,12 @@ func (config *Config) Update(label string, value string) error { config.AutoCreateGroup = flag } return err + case RrhSortOnUpdating: + var flag, err = trueOrFalse(value) + if err == nil { + config.SortOnUpdating = flag + } + return err case RrhHome: config.Home = value return nil @@ -118,6 +126,8 @@ func (config *Config) GetString(label string) (value string, readFrom string) { return config.getStringFromEnv(RrhAutoDeleteGroup, config.AutoDeleteGroup) case RrhAutoCreateGroup: return config.getStringFromEnv(RrhAutoCreateGroup, config.AutoCreateGroup) + case RrhSortOnUpdating: + return config.getStringFromEnv(RrhSortOnUpdating, config.SortOnUpdating) case RrhHome: return config.getStringFromEnv(RrhHome, config.Home) case RrhConfigPath: @@ -164,6 +174,8 @@ func (config *Config) findDefaultValue(label string) (value string, readFrom str return "false", Default case RrhAutoCreateGroup: return "false", Default + case RrhSortOnUpdating: + return "false", Default default: return "", NotFound } diff --git a/common/config_cmd.go b/common/config_cmd.go index 91ae1c0..b85ce2a 100644 --- a/common/config_cmd.go +++ b/common/config_cmd.go @@ -145,6 +145,7 @@ func (clc *configListCommand) Run(args []string) int { fmt.Println(config.formatVariableAndValue(RrhTimeFormat)) fmt.Println(config.formatVariableAndValue(RrhAutoCreateGroup)) fmt.Println(config.formatVariableAndValue(RrhAutoDeleteGroup)) + fmt.Println(config.formatVariableAndValue(RrhSortOnUpdating)) return 0 } diff --git a/common/config_test.go b/common/config_test.go index 92f99ed..1586177 100644 --- a/common/config_test.go +++ b/common/config_test.go @@ -92,6 +92,7 @@ func ExampleConfigCommand_Run() { // RRH_TIME_FORMAT: relative (default) // RRH_AUTO_CREATE_GROUP: true (config_file) // RRH_AUTO_DELETE_GROUP: false (config_file) + // RRH_SORT_ON_UPDATING: true (config_file) } func Example_configListCommand_Run() { os.Setenv(RrhConfigPath, "../testdata/config.json") @@ -107,6 +108,7 @@ func Example_configListCommand_Run() { // RRH_TIME_FORMAT: relative (default) // RRH_AUTO_CREATE_GROUP: true (config_file) // RRH_AUTO_DELETE_GROUP: false (config_file) + // RRH_SORT_ON_UPDATING: true (config_file) } func TestOpenConfigBrokenJson(t *testing.T) { diff --git a/common/database.go b/common/database.go index c1e1f22..8dc7893 100644 --- a/common/database.go +++ b/common/database.go @@ -137,6 +137,24 @@ func (db *Database) FindGroup(groupID string) *Group { return nil } +func sortIfNeeded(db *Database) { + if db.Config.GetValue(RrhSortOnUpdating) != "true" { + return + } + sort.Slice(db.Repositories, func(i, j int) bool { + return db.Repositories[i].ID < db.Repositories[j].ID + }) + sort.Slice(db.Groups, func(i, j int) bool { + return db.Groups[i].Name < db.Groups[j].Name + }) + sort.Slice(db.Relations, func(i, j int) bool { + if db.Relations[i].GroupName == db.Relations[j].GroupName { + return db.Relations[i].RepositoryID < db.Relations[j].RepositoryID + } + return db.Relations[i].GroupName < db.Relations[j].GroupName + }) +} + /* CreateRepository returns the repository by creating the given parameters and store it to database. */ @@ -146,9 +164,7 @@ func (db *Database) CreateRepository(repoID string, path string, remotes []Remot } var repo = Repository{repoID, path, remotes} db.Repositories = append(db.Repositories, repo) - sort.Slice(db.Repositories, func(i, j int) bool { - return db.Repositories[i].ID < db.Repositories[j].ID - }) + sortIfNeeded(db) return &repo, nil } @@ -162,10 +178,7 @@ func (db *Database) CreateGroup(groupID string, description string) (*Group, err } var group = Group{groupID, description} db.Groups = append(db.Groups, group) - - sort.Slice(db.Groups, func(i, j int) bool { - return db.Groups[i].Name < db.Groups[j].Name - }) + sortIfNeeded(db) return &group, nil } @@ -184,9 +197,7 @@ func (db *Database) UpdateGroup(groupID string, newGroupID string, newDescriptio db.Groups[i].Description = newDescription } } - sort.Slice(db.Groups, func(i, j int) bool { - return db.Groups[i].Name < db.Groups[j].Name - }) + sortIfNeeded(db) return true } @@ -201,9 +212,7 @@ func (db *Database) Relate(groupID string, repoID string) error { return nil } db.Relations = append(db.Relations, Relation{repoID, groupID}) - sort.Slice(db.Relations, func(i, j int) bool { - return db.Relations[i].GroupName < db.Relations[j].GroupName - }) + sortIfNeeded(db) return nil } @@ -329,7 +338,7 @@ func (db *Database) DeleteRepository(repoID string) error { return nil } -func (db *Database) deleteGroup(groupID string) error { +func deleteGroup(db *Database, groupID string) error { var groups = []Group{} for _, group := range db.Groups { if group.Name != groupID { @@ -353,7 +362,7 @@ func (db *Database) DeleteGroup(groupID string) error { if groups[groupID] != 0 { return fmt.Errorf("%s: group has %d relatins", groupID, groups[groupID]) } - return db.deleteGroup(groupID) + return deleteGroup(db, groupID) } /* @@ -365,7 +374,7 @@ func (db *Database) ForceDeleteGroup(groupID string) error { return fmt.Errorf("%s: group not found", groupID) } db.UnrelateFromGroup(groupID) - return db.deleteGroup(groupID) + return deleteGroup(db, groupID) } func databasePath(config *Config) string { diff --git a/common/database_test.go b/common/database_test.go index 3ca78e0..3dd1027 100644 --- a/common/database_test.go +++ b/common/database_test.go @@ -7,6 +7,7 @@ import ( func openDatabase() *Database { os.Setenv(RrhDatabasePath, "../testdata/database.json") + os.Setenv(RrhConfigPath, "../testdata/config.json") var config = OpenConfig() var db, _ = Open(config) return db @@ -45,6 +46,9 @@ func TestOpenNullDatabase(t *testing.T) { if len(db.Groups) != 0 { t.Error("null db have no group entries") } + if len(db.Relations) != 0 { + t.Error("null db have no group entries") + } } func TestStore(t *testing.T) { @@ -72,7 +76,10 @@ func TestStore(t *testing.T) { if !db2.HasRepository("repo2") { t.Error("repo2 not found!") } - os.Remove("./testdata/tmp.json") + if !db2.HasRelation("group1", "repo1") { + t.Error("group1 does not relate with repo1") + } + } func TestPrune(t *testing.T) { @@ -90,6 +97,9 @@ func TestPrune(t *testing.T) { if db.HasRepository("repo2") { t.Error("repo2 was not pruned") } + if !db.HasRelation("group1", "repo1") { + t.Error("relation is removed?") + } } func TestDeleteGroup(t *testing.T) { @@ -131,7 +141,6 @@ func TestDeleteRepository(t *testing.T) { } func TestUnrelate(t *testing.T) { - t.Skip("db.Unrelate never failed.") var db = openDatabase() db.CreateRepository("somerepo", "unknown", []Remote{}) @@ -141,6 +150,10 @@ func TestUnrelate(t *testing.T) { db.Unrelate("group2", "Rrh") db.Unrelate("no-group", "rrh") + + if !db.HasRelation("group2", "somerepo") { + t.Error("group2 does not relate with somerepo") + } } func TestCreateRepository(t *testing.T) { diff --git a/remove/remove_cmd.go b/remove/remove_cmd.go index e6e3de3..555f450 100644 --- a/remove/remove_cmd.go +++ b/remove/remove_cmd.go @@ -60,7 +60,7 @@ func (rm *RemoveCommand) Run(args []string) int { } } if result == 0 { - if config.GetValue(common.RrhAutoDeleteGroup) == "yes" { + if config.GetValue(common.RrhAutoDeleteGroup) == "true" { db.Prune() } db.StoreAndClose() diff --git a/remove/remove_test.go b/remove/remove_test.go index f163e1e..18ebdf9 100644 --- a/remove/remove_test.go +++ b/remove/remove_test.go @@ -44,9 +44,9 @@ func TestRemoveRepository(t *testing.T) { if err := rm.executeRemoveRepository(db, "unknown-repo"); err == nil { t.Error("unknown-repo: found") } - var _ = rm.executeRemoveRepository(db, "repo1") - if len(db.Repositories) != 1 { - t.Error("repo1 did not remove?") + var err = rm.executeRemoveRepository(db, "repo1") + if err != nil || len(db.Repositories) != 1 { + t.Errorf("repo1 did not remove?: %s", err.Error()) } if len(db.Groups) != 2 { t.Error("the number of groups changed") diff --git a/status/status.go b/status/status.go index ca3ac1f..44c1311 100644 --- a/status/status.go +++ b/status/status.go @@ -57,7 +57,7 @@ func isTarget(options *statusOptions, ref *plumbing.Reference) bool { return refName.String() == "HEAD" || options.isRemoteTarget(refName) || options.isBranchTarget(refName) } -func (status *StatusCommand) findLocalBranches(name repo, r *git.Repository, options *statusOptions) ([]StatusResult, error) { +func (status *StatusCommand) findLocalBranches(name repo, r *git.Repository) ([]StatusResult, error) { var results = []StatusResult{} var iter, err2 = r.References() if err2 != nil { @@ -65,7 +65,7 @@ func (status *StatusCommand) findLocalBranches(name repo, r *git.Repository, opt } iter.ForEach(func(ref *plumbing.Reference) error { - if isTarget(options, ref) { + if isTarget(status.Options, ref) { var result, err = status.lastCommitOnLocalBranch(name, r, ref) if err != nil { return err @@ -82,7 +82,7 @@ func (status *StatusCommand) findLocalBranches(name repo, r *git.Repository, opt return results, nil } -func (status *StatusCommand) findTime(path string, repoID string, db *common.Database) time.Time { +func (status *StatusCommand) findTime(db *common.Database, path string, repoID string) time.Time { var repo = db.FindRepository(repoID) var absPath = common.ToAbsolutePath(repo.Path, db.Config) var target = filepath.Join(absPath, path) @@ -102,7 +102,7 @@ func (status *StatusCommand) findTime(path string, repoID string, db *common.Dat } func (status *StatusCommand) flagChecker(db *common.Database, rname string, key string, lastModified *time.Time) *time.Time { - var time = status.findTime(key, rname, db) + var time = status.findTime(db, key, rname) if lastModified == nil || time.After(*lastModified) { return &time } @@ -141,7 +141,7 @@ func (status *StatusCommand) findWorktree(name repo, r *git.Repository, db *comm return &StatusResult{name.gname, name.rname, "WORKTREE", lastModified, status.generateMessage(staging, changesNotAdded)}, nil } -func (status *StatusCommand) executeStatusOnRepository(db *common.Database, name repo, options *statusOptions) ([]StatusResult, error) { +func (status *StatusCommand) executeStatusOnRepository(db *common.Database, name repo) ([]StatusResult, error) { var r, err = status.openRepository(db, name.rname) if err != nil { return nil, fmt.Errorf("%s: %s", name.rname, err.Error()) @@ -151,7 +151,7 @@ func (status *StatusCommand) executeStatusOnRepository(db *common.Database, name if err2 != nil { return nil, err2 } - var localBranches, err3 = status.findLocalBranches(name, r, options) + var localBranches, err3 = status.findLocalBranches(name, r) if err3 != nil { return nil, err3 } @@ -161,36 +161,33 @@ func (status *StatusCommand) executeStatusOnRepository(db *common.Database, name return results, nil } -func (status *StatusCommand) executeStatus(db *common.Database, name string, options *statusOptions) ([]StatusResult, []error) { +func (status *StatusCommand) executeStatus(db *common.Database, name string) ([]StatusResult, []error) { if db.HasRepository(name) { - var results, err = status.executeStatusOnRepository(db, repo{"unknown-group", name}, options) + var results, err = status.executeStatusOnRepository(db, repo{"unknown-group", name}) if err != nil { return results, []error{err} } return results, nil } else if db.HasGroup(name) { - return status.executeStatusOnGroup(db, name, options) + return status.executeStatusOnGroup(db, name) } return nil, []error{fmt.Errorf("%s: group and repository not found", name)} } -func (status *StatusCommand) executeStatusOnGroup(db *common.Database, groupName string, options *statusOptions) ([]StatusResult, []error) { +func (status *StatusCommand) executeStatusOnGroup(db *common.Database, groupName string) ([]StatusResult, []error) { var group = db.FindGroup(groupName) if group == nil { return nil, []error{fmt.Errorf("%s: group not found", groupName)} } var errors = []error{} var results = []StatusResult{} - for _, relation := range db.Relations { - if relation.GroupName == groupName { - var sr, err = status.executeStatusOnRepository(db, repo{groupName, relation.RepositoryID}, options) - if err != nil { - errors = append(errors, err) - } else { - results = append(results, sr...) - } + for _, repoID := range db.FindRelationsOfGroup(groupName) { + var sr, err = status.executeStatusOnRepository(db, repo{groupName, repoID}) + if err != nil { + errors = append(errors, err) + } else { + results = append(results, sr...) } } - return results, errors } diff --git a/status/status_cmd.go b/status/status_cmd.go index f8d8e96..a4140dd 100644 --- a/status/status_cmd.go +++ b/status/status_cmd.go @@ -13,6 +13,7 @@ import ( StatusCommand represents a command. */ type StatusCommand struct { + Options *statusOptions } type statusOptions struct { @@ -34,7 +35,7 @@ func (options *statusOptions) isBranchTarget(name plumbing.ReferenceName) bool { StatusCommandFactory returns an instance of the StatusCommand. */ func StatusCommandFactory() (cli.Command, error) { - return &StatusCommand{}, nil + return &StatusCommand{&statusOptions{false, false, false, []string{}}}, nil } /* @@ -92,16 +93,16 @@ func (status *StatusCommand) printResult(results []StatusResult, config *common. } } -func (status *StatusCommand) runStatus(db *common.Database, arg string, options *statusOptions) int { +func (status *StatusCommand) runStatus(db *common.Database, arg string) int { var errorFlag = 0 - var result, err = status.executeStatus(db, arg, options) + var result, err = status.executeStatus(db, arg) if len(err) != 0 { for _, item := range err { fmt.Println(item.Error()) errorFlag = 1 } } else { - if options.csv { + if status.Options.csv { status.printResultInCsv(result, db.Config) } else { status.printResult(result, db.Config) @@ -127,7 +128,7 @@ func (status *StatusCommand) Run(args []string) int { } var errorFlag = 0 for _, arg := range options.args { - errorFlag += status.runStatus(db, arg, options) + errorFlag += status.runStatus(db, arg) } return errorFlag @@ -150,6 +151,7 @@ func (status *StatusCommand) parse(args []string, config *common.Config) (*statu if len(options.args) == 0 { options.args = []string{config.GetValue(common.RrhDefaultGroupName)} } + status.Options = &options return &options, nil } diff --git a/testdata/config.json b/testdata/config.json index 1e9b4ee..3044fcc 100644 --- a/testdata/config.json +++ b/testdata/config.json @@ -1 +1,5 @@ -{"rrh_home":"","rrh_auto_delete_group":"false","rrh_auto_create_group":"true","rrh_config_path":"","rrh_database_path":"","rrh_default_group_name":"","rrh_time_format":"","rrh_on_error":""} \ No newline at end of file +{ + "rrh_auto_delete_group": "false", + "rrh_auto_create_group": "true", + "rrh_sort_on_updating": "true" +}