github.com/creichlin/pentaconta@v0.1.1-0.20170602155716-6b53e3be0bdb/main.go (about)

     1  package main
     2  
     3  import (
     4  	"encoding/json"
     5  	"flag"
     6  	"fmt"
     7  	"github.com/ghodss/yaml"
     8  	"gitlab.com/creichlin/pentaconta/declaration"
     9  	"gitlab.com/creichlin/pentaconta/evaluation"
    10  	"gitlab.com/creichlin/pentaconta/logger"
    11  	"gitlab.com/creichlin/pentaconta/services"
    12  	"io/ioutil"
    13  	"log"
    14  	"os"
    15  	"path/filepath"
    16  	"strings"
    17  	"time"
    18  )
    19  
    20  func main() {
    21  	configName, help := readConfigParams()
    22  	if help {
    23  		printHelp()
    24  		return
    25  	}
    26  	location, err := probeLocation(configName)
    27  
    28  	if err != nil {
    29  		log.Fatal(err)
    30  	}
    31  
    32  	data, err := readData(location)
    33  	if err != nil {
    34  		log.Fatal(err)
    35  	}
    36  
    37  	runWithDeclaration(data, time.Hour*24*356*100)
    38  }
    39  
    40  func runWithDeclaration(data interface{}, duration time.Duration) {
    41  	dec, err := declaration.Parse(data)
    42  	if err != nil {
    43  		log.Fatal(err)
    44  	}
    45  
    46  	var logs logger.Logger
    47  	var eval *evaluation.Collector
    48  	if dec.Stats != nil {
    49  		eval = evaluation.EvaluationCollector()
    50  		logs = logger.NewSplitLogger(
    51  			logger.NewStdoutLogger(),
    52  			eval,
    53  		)
    54  	} else {
    55  		logs = logger.NewStdoutLogger()
    56  	}
    57  
    58  	services := &services.Services{
    59  		Logs:        logs,
    60  		Executors:   map[string]*services.Executor{},
    61  		FSListeners: map[string]*services.FSListener{},
    62  	}
    63  
    64  	createAndStartExecutors(services, dec)
    65  	createAndStartFsTriggers(services, dec)
    66  
    67  	startTime := time.Now()
    68  
    69  	for time.Now().Before(startTime.Add(duration)) {
    70  		time.Sleep(time.Second * 1)
    71  
    72  		if eval != nil {
    73  			stats := eval.Status(dec.Stats.Seconds)
    74  			bin, err := json.MarshalIndent(stats, "", "  ")
    75  			if err != nil {
    76  				panic(err)
    77  			}
    78  			err = ioutil.WriteFile(dec.Stats.File, bin, 0644)
    79  			if err != nil {
    80  				panic(err)
    81  			}
    82  		}
    83  	}
    84  }
    85  
    86  func createAndStartFsTriggers(svs *services.Services, data *declaration.Root) {
    87  	for name, fsTrigger := range data.FSTriggers {
    88  		fsListener, err := services.NewFSListener(name, fsTrigger, svs)
    89  		if err != nil {
    90  			panic(err)
    91  		}
    92  		svs.FSListeners[name] = fsListener
    93  		go func() {
    94  			err := fsListener.Start()
    95  			log.Fatal(err)
    96  		}()
    97  	}
    98  }
    99  
   100  func createAndStartExecutors(svs *services.Services, data *declaration.Root) {
   101  	for name, service := range data.Services {
   102  		executor, err := services.NewExecutor(name, service, svs.Logs)
   103  		if err != nil {
   104  			panic(err)
   105  		}
   106  
   107  		svs.Executors[name] = executor
   108  		go executor.Start()
   109  	}
   110  }
   111  
   112  func readConfigParams() (string, bool) {
   113  	var configName string
   114  	var help bool
   115  	executable := filepath.Base(os.Args[0])
   116  	flags := flag.NewFlagSet("pentacota", flag.ContinueOnError)
   117  	flags.StringVar(&configName, "config", executable, "name of config file to use, no .yaml or .json extension.")
   118  	flags.BoolVar(&help, "help", false, "Print help text and exit")
   119  	flags.Parse(os.Args[1:])
   120  	return configName, help
   121  }
   122  
   123  func printHelp() {
   124  	fmt.Println("pentaconta help")
   125  	fmt.Println(declaration.Doc())
   126  }
   127  
   128  func readData(file string) (interface{}, error) {
   129  	binData, err := ioutil.ReadFile(file)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	data := interface{}(nil)
   135  
   136  	if strings.HasSuffix(file, ".json") {
   137  		err = json.Unmarshal(binData, &data)
   138  		if err != nil {
   139  			return nil, err
   140  		}
   141  		return data, nil
   142  	} else if strings.HasSuffix(file, ".yaml") {
   143  		err = yaml.Unmarshal(binData, &data)
   144  		if err != nil {
   145  			return nil, err
   146  		}
   147  		return data, nil
   148  	}
   149  	panic("Returned path must have .json or .yaml extension")
   150  }
   151  
   152  func probeLocation(path string) (string, error) {
   153  	locations := []string{}
   154  	if filepath.IsAbs(path) {
   155  		locations = append(locations, path+".json")
   156  		locations = append(locations, path+".yaml")
   157  	} else {
   158  		wd, err := os.Getwd()
   159  		if err == nil {
   160  			abspath := filepath.Join(wd, path)
   161  			locations = append(locations, abspath+".json")
   162  			locations = append(locations, abspath+".yaml")
   163  		}
   164  		abspath := filepath.Join("/etc", path)
   165  		locations = append(locations, abspath+".json")
   166  		locations = append(locations, abspath+".yaml")
   167  	}
   168  
   169  	for _, location := range locations {
   170  		_, err := ioutil.ReadFile(location)
   171  		if err == nil {
   172  			return location, nil
   173  		}
   174  	}
   175  
   176  	return "", fmt.Errorf("Could not find config file in locations %v", locations)
   177  }