Initial commit.
This commit is contained in:
136
internal/parser/parser.go
Normal file
136
internal/parser/parser.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"go.dev.pztrn.name/hosts-translator/internal/configuration"
|
||||
"go.dev.pztrn.name/hosts-translator/internal/models"
|
||||
)
|
||||
|
||||
var ErrParserError = errors.New("hosts parser")
|
||||
|
||||
// Parser is a controlling structure for hosts file (both parsed and unparsed data).
|
||||
type Parser struct {
|
||||
parsedHosts []models.Host
|
||||
}
|
||||
|
||||
// NewParser creates new hosts file parsing controlling structure.
|
||||
func NewParser() *Parser {
|
||||
p := &Parser{}
|
||||
p.initialize()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// Returns file data as bytes.
|
||||
func (p *Parser) getFileData() ([]string, error) {
|
||||
// Before everything we should normalize file path.
|
||||
filePath := configuration.HostsFilePath
|
||||
|
||||
// Replace possible "~" in the beginning as file reading function unable
|
||||
// to expand it. Also we should check only beginning because tilde is actually
|
||||
// a very valid directory or file name.
|
||||
if strings.HasPrefix(filePath, "~") {
|
||||
homeDir, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filePath = strings.Replace(filePath, "~", homeDir, 1)
|
||||
}
|
||||
|
||||
// Get absolute file path.
|
||||
absolutePath, err := filepath.Abs(filePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Println("Reading file data from", absolutePath)
|
||||
|
||||
// Read file data.
|
||||
rawData, err := os.ReadFile(absolutePath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := strings.Split(string(rawData), "\n")
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// GetParsedData returns parsed data slice.
|
||||
func (p *Parser) GetParsedData() []models.Host {
|
||||
return p.parsedHosts
|
||||
}
|
||||
|
||||
// Initializes internal state of parser as well as CLI flags.
|
||||
func (p *Parser) initialize() {
|
||||
p.parsedHosts = make([]models.Host, 0)
|
||||
}
|
||||
|
||||
// Parse parses hosts file into internal representation.
|
||||
func (p *Parser) Parse() error {
|
||||
log.Println("Starting hosts file parsing. File located at", configuration.HostsFilePath)
|
||||
|
||||
data, err := p.getFileData()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, line := range data {
|
||||
// We should skip commented lines.
|
||||
if strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
|
||||
// Every line is a two-or-more-not-empty-strings. First string is always
|
||||
// an IP address.
|
||||
// Also there are a non-zero possibility that line will contain tabs, so as
|
||||
// very first action we should replace them with spaces.
|
||||
if strings.Contains(line, "\t") {
|
||||
line = strings.Replace(line, "\t", " ", -1)
|
||||
}
|
||||
|
||||
lineSplitted := strings.Split(line, " ")
|
||||
|
||||
// As one IP address can be bound to multiple domains we should take care
|
||||
// of that situation by creating multiple Host structures.
|
||||
var address string
|
||||
|
||||
for _, lineData := range lineSplitted {
|
||||
// Also there might be a case when address placed first in line but
|
||||
// line itself has spaces in the beginning.
|
||||
if address == "" && lineData != "" {
|
||||
address = lineData
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if lineData == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
domainToAdd := lineData
|
||||
|
||||
if configuration.DomainPostfix != "" && !strings.HasSuffix(domainToAdd, configuration.DomainPostfix) {
|
||||
domainToAdd += "." + configuration.DomainPostfix
|
||||
}
|
||||
|
||||
p.parsedHosts = append(p.parsedHosts, models.Host{
|
||||
Domain: domainToAdd,
|
||||
Address: address,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("Got", len(p.parsedHosts), "domains from hosts file")
|
||||
|
||||
// ToDo: hide under CLI parameter like '-debug'?
|
||||
// log.Printf("%+v\n", p.parsedHosts)
|
||||
|
||||
return nil
|
||||
}
|
Reference in New Issue
Block a user