about summary refs log blame commit diff stats
path: root/apps/ex1.mu
blob: f6d67001522e5430076ecb215a47eaa77d062ba6 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13












                                                                        
# First example: return the answer to the Ultimate Question of Life, the
# Universe, and Everything.
#
# To run:
#   $ ./translate_mu apps/ex1.mu
#   $ ./a.elf
# Expected result:
#   $ echo $?
#   42

fn main -> result/ebx: int {
  result <- copy 0x2a  # Mu requires hexadecimal
}
f0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
package main

import (
	"fmt"
	"html/template"
	"log"
	"os"
	"os/signal"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/spf13/pflag"
	"github.com/spf13/viper"
)

// command line flags
var (
	flagVersion *bool = pflag.BoolP("version", "v", false, "Display version information, then exit")
	flagHelp    *bool = pflag.BoolP("help", "h", false, "")
)

// config object
var confObj = &configuration{}

// signals to close the log file
var closelog = make(chan bool, 1)

// templates
var tmpls *template.Template

func init() {
	checkFlags()
	titleScreen()
	initConfig()
	initLogging()
	tmpls = initTemplates()
	watchForInterrupt()
}

func checkFlags() {
	pflag.Parse()
	if *flagVersion {
		titleScreen()
		os.Exit(0)
	}
	if *flagHelp {
		fmt.Printf("\nplaceholder\n")
		fmt.Printf("will add info later\n")
		os.Exit(0)
	}
}

func initConfig() {

	viper.SetConfigName("getwtxt")
	viper.AddConfigPath(".")
	viper.AddConfigPath("/usr/local/getwtxt")
	viper.AddConfigPath("/etc")
	viper.AddConfigPath("/usr/local/etc")

	log.Printf("Loading configuration ...\n")
	if err := viper.ReadInConfig(); err != nil {
		log.Printf("Error reading config file: %v\n", err)
		log.Printf("Using defaults ...\n")
	}

	// separate thread to watch for config file changes.
	// will log event then run rebindConfig()
	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		log.Printf("Config file change detected. Reloading...\n")
		rebindConfig()
	})

	viper.SetDefault("port", 9001)
	viper.SetDefault("logfile", "getwtxt.log")
	viper.SetDefault("stdoutLogging", false)

	confObj.port = viper.GetInt("port")
	confObj.logfile = viper.GetString("logfile")
	confObj.stdoutLogging = viper.GetBool("stdoutLogging")
	confObj.version = getwtxt
	confObj.Instance.Name = viper.GetString("instance.name")
	confObj.Instance.URL = viper.GetString("instance.url")
	confObj.Instance.Owner = viper.GetString("instance.owner")
	confObj.Instance.Mail = viper.GetString("instance.mail")
	confObj.Instance.Desc = viper.GetString("instance.description")
}

func initLogging() {

	// only open a log file if it's necessary
	if confObj.stdoutLogging {
		log.SetOutput(os.Stdout)

	} else {

		logfile, err := os.OpenFile(confObj.logfile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600)
		if err != nil {
			log.Printf("Could not open log file: %v\n", err)
		}

		// Listen for the signal to close the log file
		// in a separate thread. Passing it as an argument
		// to prevent race conditions when the config is
		// reloaded.
		go func(logfile *os.File) {
			<-closelog
			log.Printf("Closing log file ...\n")
			err = logfile.Close()
			if err != nil {
				log.Printf("Couldn't close log file: %v\n", err)
			}
		}(logfile)

		log.SetOutput(logfile)
	}
}

func rebindConfig() {

	// signal to close the log file then wait
	if !confObj.stdoutLogging {
		closelog <- true
	}

	// reassign values to the config object
	confObj.port = viper.GetInt("port")
	confObj.logfile = viper.GetString("logfile")
	confObj.stdoutLogging = viper.GetBool("stdoutLogging")
	confObj.Instance.Name = viper.GetString("instance.name")
	confObj.Instance.URL = viper.GetString("instance.url")
	confObj.Instance.Owner = viper.GetString("instance.owner")
	confObj.Instance.Mail = viper.GetString("instance.mail")
	confObj.Instance.Desc = viper.GetString("instance.description")

	// reinitialize logging
	initLogging()
}

// Parse the HTML templates
func initTemplates() *template.Template {
	return template.Must(template.ParseFiles("assets/tmpl/index.html"))
}

// Watch for SIGINT aka ^C
// Close the log file then exit
func watchForInterrupt() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)

	go func() {
		for sigint := range c {
			log.Printf("\n\nCaught %v. Cleaning up ...\n", sigint)

			if !confObj.stdoutLogging {
				// signal to close the log file
				closelog <- true
				time.Sleep(20 * time.Millisecond)
			}

			close(closelog)
			os.Exit(0)
		}
	}()
}

func titleScreen() {
	fmt.Printf(`
	
            _            _        _
  __ _  ___| |___      _| |___  _| |_
 / _  |/ _ \ __\ \ /\ / / __\ \/ / __|
| (_| |  __/ |_ \ V  V /| |_ >  <| |_
 \__, |\___|\__| \_/\_/  \__/_/\_\\__|
 |___/
             version ` + getwtxt + `
      github.com/gbmor/getwtxt
                GPL v3	
			 
`)
}