/* Copyright © 2022 Sameer Rahmani 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 . */ 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[A-Z]+):`) state.EndBlockTypePattern = regexp.MustCompile(`/(?P[A-Z]+)$`) state.TagPattern = regexp.MustCompile(`\[([^]]+)\]`) state.FirstLineContent = regexp.MustCompile(`[A-Z]+:\s+(?:\[[^]]+\])*\s?(?P.*)`) 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