github.com/developest/gtm-core@v1.0.4-0.20220111132249-cc80a3372c3f/project/index.go (about) 1 // Copyright 2016 Michael Schenk. All rights reserved. 2 // Use of this source code is governed by a MIT-style 3 // license that can be found in the LICENSE file. 4 5 package project 6 7 import ( 8 "encoding/json" 9 "io/ioutil" 10 "os" 11 "os/user" 12 "path/filepath" 13 "sort" 14 "time" 15 ) 16 17 // Index contains list of projects and their locations 18 type Index struct { 19 Projects map[string]time.Time 20 } 21 22 // NewIndex initializes Index 23 func NewIndex() (Index, error) { 24 i := Index{Projects: map[string]time.Time{}} 25 26 err := i.load() 27 if err != nil { 28 //TODO: do we need to save here? 29 err := i.save() 30 if err != nil { 31 return i, err 32 } 33 } 34 35 return i, nil 36 } 37 38 // Get finds projects by tags or all projects or the project in the current directory 39 func (i *Index) Get(tags []string, all bool, cwd ...string) ([]string, error) { 40 switch { 41 case all: 42 err := i.clean() 43 return i.projects(), err 44 case len(tags) > 0: 45 if err := i.clean(); err != nil { 46 return []string{}, err 47 } 48 var projectsWithTags []string 49 for _, p := range i.projects() { 50 found, err := i.hasTags(p, tags) 51 if err != nil { 52 return []string{}, nil 53 } 54 if found { 55 projectsWithTags = append(projectsWithTags, p) 56 } 57 } 58 sort.Strings(projectsWithTags) 59 return projectsWithTags, nil 60 default: 61 curProjPath, _, err := Paths(cwd...) 62 if err != nil { 63 return []string{}, err 64 } 65 if _, ok := i.Projects[curProjPath]; !ok { 66 i.add(curProjPath) 67 if err := i.save(); err != nil { 68 return []string{}, err 69 } 70 } 71 return []string{curProjPath}, nil 72 } 73 } 74 75 func (i *Index) add(p string) { 76 i.Projects[p] = time.Now() 77 } 78 79 func (i *Index) remove(p string) { 80 delete(i.Projects, p) 81 } 82 83 func (i *Index) projects() []string { 84 var keys []string 85 for k := range i.Projects { 86 keys = append(keys, k) 87 } 88 sort.Strings(keys) 89 return keys 90 } 91 92 func (i *Index) path() (string, error) { 93 u, err := user.Current() 94 if err != nil { 95 return "", err 96 } 97 return filepath.Join(u.HomeDir, ".config", "gtm", "project.json"), nil 98 } 99 100 func (i *Index) load() error { 101 p, err := i.path() 102 if err != nil { 103 return err 104 } 105 106 raw, err := ioutil.ReadFile(p) 107 if err != nil { 108 return err 109 } 110 111 return json.Unmarshal(raw, &i.Projects) 112 } 113 114 func (i *Index) save() error { 115 bytes, err := json.Marshal(i.Projects) 116 if err != nil { 117 return err 118 } 119 120 p, err := i.path() 121 if err != nil { 122 return err 123 } 124 125 if _, err := os.Stat(filepath.Dir(p)); os.IsNotExist(err) { 126 if err := os.MkdirAll(filepath.Dir(p), 0700); err != nil { 127 return err 128 } 129 } 130 131 return ioutil.WriteFile(p, bytes, 0644) 132 } 133 134 func (i *Index) hasTags(projectPath string, tagsToFind []string) (bool, error) { 135 tags, err := LoadTags(filepath.Join(projectPath, ".gtm")) 136 if err != nil { 137 return false, err 138 } 139 for _, t1 := range tags { 140 for _, t2 := range tagsToFind { 141 if t1 == t2 { 142 return true, nil 143 } 144 } 145 } 146 return false, nil 147 } 148 149 func (i *Index) removeNotFound(projectPath string) { 150 if _, _, err := Paths(projectPath); err != nil { 151 i.remove(projectPath) 152 return 153 } 154 } 155 156 func (i *Index) clean() error { 157 for _, p := range i.projects() { 158 i.removeNotFound(p) 159 } 160 err := i.save() 161 return err 162 }