Skip to content

Commit

Permalink
refactor a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
mikemackintosh committed Feb 19, 2023
1 parent 4171ee7 commit d2f9707
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 77 deletions.
56 changes: 42 additions & 14 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,21 @@ import (
"errors"
"flag"
"fmt"
"io"
"log"
"ninetails/config"
"ninetails/version"
"os"
"strings"
"sync"
"time"
)

var (
/* */
flagWithFilename bool
flagWithLinenum bool
flagWithFollow bool
flagVersion bool

/* */
Expand All @@ -26,28 +30,30 @@ func init() {
flag.BoolVar(&flagWithFilename, "H", false, "Display filename")
flag.BoolVar(&flagWithLinenum, "n", false, "Display linenum")
flag.BoolVar(&flagVersion, "v", false, "Display version")
flag.BoolVar(&flagWithFollow, "F", false, "Follow changes in the file")
flag.StringVar(&flagConfig, "c", ".ninetail.yml", "Configuration file")
}

func main() {
// Parse the config
flag.Parse()

// Show the version info only if it's requested
if flagVersion {
fmt.Printf("%s - %s\n", version.Version, version.CommitHash)
os.Exit(0)
}

// Parse he configuration
if err := config.Parse(flagConfig); err != nil {
log.Fatal(err)
}

// make a channel
messages := make(chan string)

var wg = &sync.WaitGroup{}

go printChannelData(messages)
// Start the channel watcher
go watcher(messages)

// Check if the config was provided from stdin. To do so, we need
// to see if stdin was provided via a pipe, before we start blocking
Expand All @@ -57,6 +63,7 @@ func main() {
panic(err)
}

// If there is stdin, read it
if fi.Mode()&os.ModeNamedPipe != 0 {
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
Expand All @@ -66,6 +73,8 @@ func main() {
}
}

// Otherwise, look for files passed as arguments
var wg = &sync.WaitGroup{}
var args = flag.Args()
if len(args) > 0 {
for _, f := range args {
Expand All @@ -77,6 +86,7 @@ func main() {
wg.Wait()
}

// readFile
func readFile(wg *sync.WaitGroup, f string, c chan string) {
defer wg.Done()

Expand All @@ -90,31 +100,48 @@ func readFile(wg *sync.WaitGroup, f string, c chan string) {
}
defer file.Close()

scanner := bufio.NewScanner(file)
scanner := bufio.NewReader(file)
var i = 0
for scanner.Scan() {
line := scanner.Text()

var formattedLine = ""
for {
line, err := scanner.ReadString('\n')
line = strings.Replace(line, "\n", "", -1)
if err != nil {
if err == io.EOF {
if !flagWithFollow {
break
}
time.Sleep(time.Millisecond * 100)
} else {
fmt.Println(err)
}
}

var formattedLine = "%s"
// If the user requested to show the filename, prep the string
if flagWithFilename {
if flagWithLinenum {
// Only show line numbers when we are not following
if flagWithLinenum && !flagWithFollow {
i = i + 1
formattedLine = fmt.Sprintf("%s:%d | "+formattedLine, f, i)
} else {
formattedLine = fmt.Sprintf("%s | "+formattedLine, f)
}
}

c <- fmt.Sprintf(formattedLine+"%s", line)
}
// If we are following the file, strings reader will be empty
// skip it only if we are following, otherwise we want to print

if err := scanner.Err(); err != nil {
log.Fatal(err)
if line == "" && flagWithFollow {
continue
}

c <- fmt.Sprintf(formattedLine, line)
}
}

func printChannelData(c chan string) {
// watcher will watch the channel and call the formatter when
// the data is received.
func watcher(c chan string) {
for {
v, ok := <-c
if ok {
Expand All @@ -126,6 +153,7 @@ func printChannelData(c chan string) {
}
}

// formatLines will call the config replacer
func formatLines(line string) {
if v, ok := config.Replace(line); ok {
fmt.Println(v)
Expand Down
66 changes: 3 additions & 63 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -1,75 +1,15 @@
package config

import (
"fmt"
"log"
"os"
"regexp"
"strings"

"gopkg.in/yaml.v3"
)

// Config is an instance of a configuration
var Config = &Configuration{}

type Mappings []*Mapping
type Mapping struct {
Search string `yaml:"search"`
Color *string `yaml:"color"`
Format *string `yaml:"format"`

re *regexp.Regexp
}

func (m *Mapping) Replace(s string) (string, bool) {
if m.Color != nil {
if c, ok := Config.Colors[*m.Color]; ok {
return fmt.Sprintf("\033[%s%s\033[0m", c, s), true
}
}

if m.Format != nil {
var format = *m.Format
for k, v := range Config.Colors {
format = strings.Replace(format, "\\"+k, "\033["+v, -1)
}
v := m.re.ReplaceAllString(s, format+"\033[0m")
return v, true
}

return "", false
}

type Color string
type Configuration struct {
Mappings Mappings `yaml:"tails"`
Colors map[string]string `yaml:"colors,omitempty"`
}

func Parse(f string) error {
file, err := os.ReadFile(f)
if err != nil {
return err
}

var config Configuration
if err = yaml.Unmarshal(file, &config); err != nil {
return err
}

for _, m := range config.Mappings {
r, err := regexp.Compile(m.Search)
if err != nil {
log.Printf("Skipping invalid configuration for: %s", m.Search)
continue
}
m.re = r
}

Config = &config
return nil
}

// Replace is a helper method for looking through mappings for
// the given payload.
func Replace(s string) (string, bool) {
var matched bool
for _, m := range Config.Mappings {
Expand Down
39 changes: 39 additions & 0 deletions config/mapping.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package config

import (
"fmt"
"regexp"
"strings"
)

// Mappings is a slice of Mapping pointers
type Mappings []*Mapping

// Mapping is a struct of match instructions
type Mapping struct {
Search string `yaml:"search"`
Color *string `yaml:"color"`
Format *string `yaml:"format"`

re *regexp.Regexp
}

// Replace will replace the string with the formatted string
func (m *Mapping) Replace(s string) (string, bool) {
if m.Color != nil {
if c, ok := Config.Colors[*m.Color]; ok {
return fmt.Sprintf("\033[%s%s\033[0m", c, s), true
}
}

if m.Format != nil {
var format = *m.Format
for k, v := range Config.Colors {
format = strings.Replace(format, "\\"+k, "\033["+v, -1)
}
v := m.re.ReplaceAllString(s, format+"\033[0m")
return v, true
}

return "", false
}
34 changes: 34 additions & 0 deletions config/parse.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package config

import (
"log"
"os"
"regexp"

"gopkg.in/yaml.v3"
)

// Parse will parse the configuration.
func Parse(f string) error {
file, err := os.ReadFile(f)
if err != nil {
return err
}

var config Configuration
if err = yaml.Unmarshal(file, &config); err != nil {
return err
}

for _, m := range config.Mappings {
r, err := regexp.Compile(m.Search)
if err != nil {
log.Printf("Skipping invalid configuration for: %s", m.Search)
continue
}
m.re = r
}

Config = &config
return nil
}

0 comments on commit d2f9707

Please sign in to comment.