github.com/kilpkonn/gtm-enhanced@v1.3.5/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) ([]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  		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()
    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, ".git-time-metric", "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  }