Leavitt/pkg/core/state.go

164 lines
3.8 KiB
Go

/*
Copyright © 2022 Sameer Rahmani <lxsameer@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package core
import (
"regexp"
"strings"
"sync"
git "github.com/go-git/go-git/v5"
log "github.com/sirupsen/logrus"
)
type State struct {
Version int
ProjectRoot string
Repo *git.Repository
// A mapping of file extensions to the language
// e.g '.h' -> 'C/C++'
EnabledLangs map[string]*Lang
BlockTypePattern *regexp.Regexp
EndBlockTypePattern *regexp.Regexp
TagPattern *regexp.Regexp
FirstLineContent *regexp.Regexp
WaitGroup sync.WaitGroup
ErrChannel chan error
NumberOfWorkers int
}
func CreateState(projectRoot string, debug bool) (*State, error) {
state := State{}
var err error
if debug {
log.SetLevel(log.TraceLevel)
} else {
log.SetLevel(log.InfoLevel)
}
state.ProjectRoot = strings.TrimSpace(projectRoot)
log.Debugf("Found project at '%s'", state.ProjectRoot)
state.Repo, err = git.PlainOpen(state.ProjectRoot)
if err != nil {
return nil, err
}
// TODO: Read the pattern from the global or project wide config file
// using viper
state.BlockTypePattern = regexp.MustCompile(`^(?P<type>[A-Z]+):`)
state.EndBlockTypePattern = regexp.MustCompile(`/(?P<end>[A-Z]+)$`)
state.TagPattern = regexp.MustCompile(`\[([^]]+)\]`)
state.FirstLineContent = regexp.MustCompile(`[A-Z]+:\s+(?:\[[^]]+\])*\s?(?P<text>.*)`)
state.EnabledLangs = ExtsToLang
state.ErrChannel = make(chan error, 10)
state.NumberOfWorkers = 2
return &state, nil
}
func (s *State) LogErrors() {
for err := range s.ErrChannel {
log.Error(err)
}
}
func (s *State) CheckErr(e error) {
if e != nil {
s.ErrChannel <- e
}
}
func (s *State) GetLangForExt(ext string) *Lang {
// If the extension is the filename itself.
// like: LICENSE
key := ext
if strings.Contains(key, ".") {
// dotless extension
key = ext[1:]
}
lang, exists := s.EnabledLangs[key]
if exists {
return lang
}
return nil
}
// TODO: Maybe move these functions under a different data structure
func (s *State) getCommentType(comment string) *string {
match := s.BlockTypePattern.FindAllStringSubmatch(comment, -1)
if len(match) > 0 {
if len(match[0]) == 2 {
// Return the group of regex which is the tag group
return &match[0][1]
} else {
log.Fatal("bad regex for the block type")
}
}
return nil
}
func (s *State) getTags(comment string) []string {
match := s.TagPattern.FindAllStringSubmatch(comment, -1)
var tags []string
if len(match) > 0 {
for _, tag := range match {
tags = append(tags, tag[1])
}
return tags
}
return nil
}
func (s *State) detectClosingBlock(comment *string) (*string, bool) {
match := s.EndBlockTypePattern.FindAllStringSubmatch(*comment, -1)
if len(match) > 0 {
if len(match[0]) == 2 {
// Return the group of regex which is the type group
return &match[0][1], true
}
}
return nil, false
}
func (s *State) TrimTypeAndTags(comment *string) *string {
match := s.FirstLineContent.FindAllStringSubmatch(*comment, -1)
if len(match) > 0 {
if len(match[0]) == 2 {
// Return the group of regex which is the text group
return &match[0][1]
} else {
log.Fatal("bad regex for the first line content")
}
}
return nil
}
// /TODO