<commit_before>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

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

	"github.com/mvdan/fdroidcl"
)

var cmdShow = &Command{
	UsageLine: "show <appid...>",
	Short:     "Show detailed info about an app",
}

func init() {
	cmdShow.Run = runShow
}

func runShow(args []string) {
	apps := findApps(args)
	for i, app := range apps {
		if i > 0 {
			fmt.Printf("\n--\n\n")
		}
		printAppDetailed(*app)
	}
}

func appsMap(apps []fdroidcl.App) map[string]*fdroidcl.App {
	m := make(map[string]*fdroidcl.App, len(apps))
	for i := range apps {
		app := &apps[i]
		m[app.ID] = app
	}
	return m
}

func findApps(ids []string) []*fdroidcl.App {
	apps := appsMap(mustLoadIndexes())
	result := make([]*fdroidcl.App, len(ids))
	for i, id := range ids {
		app, e := apps[id]
		if !e {
			log.Fatalf("Could not find app with ID '%s'", id)
		}
		result[i] = app
	}
	return result
}

func printAppDetailed(app fdroidcl.App) {
	p := func(title string, format string, args ...interface{}) {
		if format == "" {
			fmt.Println(title)
		} else {
			fmt.Printf("%s %s\n", title, fmt.Sprintf(format, args...))
		}
	}
	p("Package          :", "%s", app.ID)
	p("Name             :", "%s", app.Name)
	p("Summary          :", "%s", app.Summary)
	cur := app.CurApk()
	if cur != nil {
		p("Current Version  :", "%s (%d)", cur.VName, cur.VCode)
	} else {
		p("Current Version  :", "(no version available)")
	}
	p("Upstream Version :", "%s (%d)", app.CVName, app.CVCode)
	p("License          :", "%s", app.License)
	if app.Categs != nil {
		p("Categories       :", "%s", strings.Join(app.Categs, ", "))
	}
	if app.Website != "" {
		p("Website          :", "%s", app.Website)
	}
	if app.Source != "" {
		p("Source           :", "%s", app.Source)
	}
	if app.Tracker != "" {
		p("Tracker          :", "%s", app.Tracker)
	}
	if app.Changelog != "" {
		p("Changelog        :", "%s", app.Changelog)
	}
	if app.Donate != "" {
		p("Donate           :", "%s", app.Donate)
	}
	if app.Bitcoin != "" {
		p("Bitcoin          :", "bitcoin:%s", app.Bitcoin)
	}
	if app.Litecoin != "" {
		p("Litecoin         :", "litecoin:%s", app.Litecoin)
	}
	if app.FlattrID != "" {
		p("Flattr           :", "https://flattr.com/thing/%s", app.FlattrID)
	}
	fmt.Println()
	p("Description :", "")
	fmt.Println()
	app.TextDesc(os.Stdout)
	fmt.Println()
	p("Available Versions :", "")
	for _, apk := range app.Apks {
		fmt.Println()
		p("    Name   :", "%s (%d)", apk.VName, apk.VCode)
		p("    Size   :", "%d", apk.Size)
		p("    MinSdk :", "%d", apk.MinSdk)
		if apk.MaxSdk > 0 {
			p("    MaxSdk :", "%d", apk.MaxSdk)
		}
		if apk.ABIs != nil {
			p("    ABIs   :", "%s", strings.Join(apk.ABIs, ", "))
		}
	}
}
<commit_msg>show: require args<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

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

	"github.com/mvdan/fdroidcl"
)

var cmdShow = &Command{
	UsageLine: "show <appid...>",
	Short:     "Show detailed info about an app",
}

func init() {
	cmdShow.Run = runShow
}

func runShow(args []string) {
	if len(args) < 1 {
		log.Fatalf("No package names given")
	}
	apps := findApps(args)
	for i, app := range apps {
		if i > 0 {
			fmt.Printf("\n--\n\n")
		}
		printAppDetailed(*app)
	}
}

func appsMap(apps []fdroidcl.App) map[string]*fdroidcl.App {
	m := make(map[string]*fdroidcl.App, len(apps))
	for i := range apps {
		app := &apps[i]
		m[app.ID] = app
	}
	return m
}

func findApps(ids []string) []*fdroidcl.App {
	apps := appsMap(mustLoadIndexes())
	result := make([]*fdroidcl.App, len(ids))
	for i, id := range ids {
		app, e := apps[id]
		if !e {
			log.Fatalf("Could not find app with ID '%s'", id)
		}
		result[i] = app
	}
	return result
}

func printAppDetailed(app fdroidcl.App) {
	p := func(title string, format string, args ...interface{}) {
		if format == "" {
			fmt.Println(title)
		} else {
			fmt.Printf("%s %s\n", title, fmt.Sprintf(format, args...))
		}
	}
	p("Package          :", "%s", app.ID)
	p("Name             :", "%s", app.Name)
	p("Summary          :", "%s", app.Summary)
	cur := app.CurApk()
	if cur != nil {
		p("Current Version  :", "%s (%d)", cur.VName, cur.VCode)
	} else {
		p("Current Version  :", "(no version available)")
	}
	p("Upstream Version :", "%s (%d)", app.CVName, app.CVCode)
	p("License          :", "%s", app.License)
	if app.Categs != nil {
		p("Categories       :", "%s", strings.Join(app.Categs, ", "))
	}
	if app.Website != "" {
		p("Website          :", "%s", app.Website)
	}
	if app.Source != "" {
		p("Source           :", "%s", app.Source)
	}
	if app.Tracker != "" {
		p("Tracker          :", "%s", app.Tracker)
	}
	if app.Changelog != "" {
		p("Changelog        :", "%s", app.Changelog)
	}
	if app.Donate != "" {
		p("Donate           :", "%s", app.Donate)
	}
	if app.Bitcoin != "" {
		p("Bitcoin          :", "bitcoin:%s", app.Bitcoin)
	}
	if app.Litecoin != "" {
		p("Litecoin         :", "litecoin:%s", app.Litecoin)
	}
	if app.FlattrID != "" {
		p("Flattr           :", "https://flattr.com/thing/%s", app.FlattrID)
	}
	fmt.Println()
	p("Description :", "")
	fmt.Println()
	app.TextDesc(os.Stdout)
	fmt.Println()
	p("Available Versions :", "")
	for _, apk := range app.Apks {
		fmt.Println()
		p("    Name   :", "%s (%d)", apk.VName, apk.VCode)
		p("    Size   :", "%d", apk.Size)
		p("    MinSdk :", "%d", apk.MinSdk)
		if apk.MaxSdk > 0 {
			p("    MaxSdk :", "%d", apk.MaxSdk)
		}
		if apk.ABIs != nil {
			p("    ABIs   :", "%s", strings.Join(apk.ABIs, ", "))
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"net/http"

	"github.com/gorilla/mux"
	garagepi "github.com/robdimsdale/garage-pi"
)

var (
	port = flag.String("port", "9999", "Port for server to bind to.")

	webcamHost = flag.String("webcamHost", "localhost", "Host of webcam image.")
	webcamPort = flag.String("webcamPort", "8080", "Port of webcam image.")
)

func main() {
	flag.Parse()

	loggingOn := true
	l := garagepi.NewLoggerImpl(loggingOn)

	osHelper := garagepi.NewOsHelperImpl(l, "../assets")
	httpHelper := garagepi.NewHttpHelperImpl()

	rtr := mux.NewRouter()

	e := garagepi.NewExecutor(
		l,
		httpHelper,
		osHelper,
		*webcamHost,
		*webcamPort)

	staticFileSystem, err := garagepi.GetStaticFileSystem()
	if err != nil {
		panic(err)
	}
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(staticFileSystem)))

	rtr.HandleFunc("/", e.HomepageHandler).Methods("GET")
	rtr.HandleFunc("/webcam", e.WebcamHandler).Methods("GET")
	rtr.HandleFunc("/toggle", e.ToggleDoorHandler).Methods("POST")

	http.Handle("/", rtr)
	l.Log("Listening on port " + *port + "...")
	http.ListenAndServe(":"+*port, nil)
}
<commit_msg>Fix package import in main.go<commit_after>package main

import (
	"flag"
	"net/http"

	"github.com/gorilla/mux"
	"github.com/robdimsdale/garagepi"
)

var (
	port = flag.String("port", "9999", "Port for server to bind to.")

	webcamHost = flag.String("webcamHost", "localhost", "Host of webcam image.")
	webcamPort = flag.String("webcamPort", "8080", "Port of webcam image.")
)

func main() {
	flag.Parse()

	loggingOn := true
	l := garagepi.NewLoggerImpl(loggingOn)

	osHelper := garagepi.NewOsHelperImpl(l, "../assets")
	httpHelper := garagepi.NewHttpHelperImpl()

	rtr := mux.NewRouter()

	e := garagepi.NewExecutor(
		l,
		httpHelper,
		osHelper,
		*webcamHost,
		*webcamPort)

	staticFileSystem, err := osHelper.GetStaticFileSystem()
	if err != nil {
		panic(err)
	}
	http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(staticFileSystem)))

	rtr.HandleFunc("/", e.HomepageHandler).Methods("GET")
	rtr.HandleFunc("/webcam", e.WebcamHandler).Methods("GET")
	rtr.HandleFunc("/toggle", e.ToggleDoorHandler).Methods("POST")

	http.Handle("/", rtr)
	l.Log("Listening on port " + *port + "...")
	http.ListenAndServe(":"+*port, nil)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"runtime"
	"strings"
	"time"

	tun "github.com/glycerine/sshego"
	"github.com/skratchdot/open-golang/open"
)

const ProgramName = "gosshtun"

func main() {

	myflags := flag.NewFlagSet(ProgramName, flag.ExitOnError)
	cfg := tun.NewSshegoConfig()
	cfg.DefineFlags(myflags)
	err := myflags.Parse(os.Args[1:])
	err = cfg.ValidateConfig()
	if err != nil {
		log.Fatalf("%s command line flag error: '%s'", ProgramName, err)
	}
	//p("cfg = %#v", cfg)
	h, err := tun.NewKnownHosts(cfg.ClientKnownHostsPath, tun.KHJson)
	panicOn(err)
	cfg.KnownHosts = h

	if cfg.WriteConfigOut != "" {
		var o io.WriteCloser
		if cfg.WriteConfigOut == "-" {
			o = os.Stdout
		} else {
			o, err = os.Create(cfg.WriteConfigOut)
			if err != nil {
				panic(err)
			}
		}
		err = cfg.SaveConfig(o)
		if err != nil {
			panic(err)
		}
	}

	if cfg.AddUser != "" {
		addUserAndExit(cfg)
	}

	if cfg.DelUser != "" {
		delUserAndExit(cfg)
	}

	passphrase := ""
	totpUrl := ""

	_, err = cfg.SSHConnect(h, cfg.Username, cfg.PrivateKeyPath,
		cfg.SSHdServer.Host, cfg.SSHdServer.Port, passphrase, totpUrl)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(0)
	}
	if err != nil {
		panic(err)
	}
	if !cfg.WriteConfigOnly {
		select {}
	}
}

func panicOn(err error) {
	if err != nil {
		panic(err)
	}
}

func addUserAndExit(cfg *tun.SshegoConfig) {

	err := cfg.NewHostDb()
	panicOn(err)

	mylogin := cfg.AddUser

	if cfg.HostDb.UserExists(mylogin) {
		fmt.Fprintf(os.Stderr, "\nerror: user '%s' already exists. If you want to replace them, use -deluser first.\n", mylogin)
		os.Exit(1)
	}
	var ok bool
	ok, err = cfg.HostDb.ValidLogin(mylogin)
	if !ok {
		fmt.Printf("\n%s\n", err)
		os.Exit(1)
	}

	reader := bufio.NewReader(os.Stdin)

	var myemail string
	fmt.Printf("\nEnter the email address for '%s' (for backups/recovery): ",
		mylogin)
	myemail, err = reader.ReadString('\n')
	panicOn(err)
	myemail = strings.Trim(myemail, "\n\r")
	ok, err = cfg.HostDb.ValidEmail(myemail)
	if !ok {
		fmt.Printf("\n%s\n", err)
		os.Exit(1)
	}

	fmt.Printf("\n'%s' should be a valid email, but may be fake if you insist.\n\nIf this email is real, we can backup the passphrase you will create in the next step. This convenience feature is optional, but strongly recommended.  The RSA key and One-time-password secret will not be sent by email, but their locations on disk will be noted for ease of retreival.\n\nDo you want to backup the passphase to email '%s'? [y/n]:", myemail, myemail)
	yn, err := reader.ReadString('\n')
	panicOn(err)
	yn = strings.ToLower(strings.Trim(yn, "\n\r"))
	sendEmail := false
	if yn == "y" || yn == "yes" {
		sendEmail = true
		fmt.Printf("\n\n Very good. Upon completion, your passphrase "+
			"will backed up to '%s'\n\n", myemail)
	} else {
		fmt.Printf("\n\n As you wish. No email will be sent.\n\n")
	}

	var fullname string
	fmt.Printf("\nCorresponding to '%s'/'%s', enter the first and last name (e.g. 'John Q. Smith'). This helps identify the account during maintenance. First and last name:\n", mylogin, myemail)
	fullname, err = reader.ReadString('\n')
	panicOn(err)
	fullname = strings.Trim(fullname, "\n\r")

	var pw string
	if !cfg.SkipPassphrase {
		pw, err = tun.PromptForPassword(cfg.AddUser)
		if err != nil {
			fmt.Printf("\n%v\n", err)
			os.Exit(1)
		}
		fmt.Printf("\n account: '%s', passphrase: '%s'\n", cfg.AddUser, pw)
	}
	if !cfg.SkipRSA {
		fmt.Printf("\n generating a strong RSA key, this may take a 5-10 seconds... \n")
	}
	user := tun.NewUser()
	user.MyLogin = mylogin
	user.MyEmail = myemail
	user.MyFullname = fullname
	user.ClearPw = pw
	user.Issuer = "gosshtun"

	var toptPath, qrPath, rsaPath string

	var prt tun.TcpPort
	prt.Port = cfg.SshegoSystemMutexPort

	limitMsec := 5000
	err = prt.Lock(limitMsec)
	if err == tun.ErrCouldNotAquirePort {
		// already running...
		p("we see gosshtun is already running and has the xport open")
		toptPath, qrPath, rsaPath, err = cfg.TcpClientUserAdd(user)
	} else {
		p("we got xport, so while holding it, modify the database directly")
		// we must do it ourselves; other process is not
		// up and we now hold the port (listening on it) as a lock.
		toptPath, qrPath, rsaPath, err = cfg.HostDb.AddUser(
			mylogin, myemail, pw, "gosshtun", fullname)
		prt.Unlock()
	}
	if err != nil {
		es := err.Error()
		if strings.HasPrefix(es,
			"bad email: give a full email address.") {
			fmt.Printf("\n%s\n", es)
			os.Exit(1)
		}
	}
	panicOn(err)

	hostname, _ := os.Hostname()
	var plain bytes.Buffer
	var html bytes.Buffer
	both := io.MultiWriter(&plain, &html)
	ip := tun.GetExternalIP()
	userEnv := os.Getenv("USER")

	fmt.Fprintf(&html, "")
	fmt.Fprintf(both, "%s:\n\n", fullname)
	fmt.Fprintf(&html, "
")

	fmt.Fprintf(both, "## ===============================================\n")
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## \n")
	fmt.Fprintf(&html, "
")
	authDetail := "tri-factor"
	if cfg.SkipPassphrase || cfg.SkipRSA || cfg.SkipTOTP {
		authDetail = ""
	}
	authList := cfg.GenAuthString()
	fmt.Fprintf(both, "##  %s auth details:\n", authDetail)
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## \n")
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "##    %s\n", authList)
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## \n")
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## ==  run: gosshtun -adduser %s\n",
		cfg.AddUser)
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## ==  run on host:  %s (%s)\n", hostname, ip)
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## ==  run by user:  %s\n", userEnv)
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## ==  at UTC time:  %s\n", time.Now().UTC())
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## ===============================================\n")
	fmt.Fprintf(&html, "
")

	fmt.Fprintf(&plain, "\nyour login:\n%s\n\n", mylogin)
	fmt.Fprintf(&html, "\n
your login:
\n%s
\n\n", mylogin)

	fmt.Fprintf(&plain, "your email:\n%s\n\n", myemail)
	fmt.Fprintf(&html, "\n
your email:
\n%s
\n\n", myemail)

	fmt.Fprintf(&plain, "your fullname:\n%s\n\n", fullname)
	fmt.Fprintf(&html, "\n
your fullname:
\n%s
\n\n", fullname)

	if !cfg.SkipPassphrase {
		fmt.Fprintf(&plain, "Passphrase:\n%v\n\n", pw)
		fmt.Fprintf(&html, "
Passphrase:\n
\n%v\n\n", pw)
		fmt.Fprintf(&html, "

")
	}
	if !cfg.SkipTOTP {
		fmt.Fprintf(&plain, "GoogleAuthenticator (time-based-one-time-password; RFC6238) secret location (on host %s):\n%s\n\n", hostname, toptPath)
		fmt.Fprintf(&html, "GoogleAuthenticator (time-based-one-time-password; RFC6238) secret location (on host %s):\n
\n%s

\n", hostname, toptPath)

		qrUrl := fmt.Sprintf("file://%s", qrPath)

		fmt.Printf("\n checking if we should open the QR-code automajically...\n")
		if runtime.GOOS == "darwin" { // "windows", "linux"
			fmt.Printf("...runtime.GOOS='%s'; try to open the QR-code\n",
				runtime.GOOS)
			open.Start(qrUrl)
		}

		fmt.Fprintf(&plain, "GoogleAuthenticator QR-code url (on host %s):\n%s\n\n", hostname, qrPath)
		fmt.Fprintf(&html, "GoogleAuthenticator QR-code url (on host %s):\n
%s
\n\n", hostname, qrUrl, qrUrl)
		fmt.Fprintf(&html, "
")
	}
	if !cfg.SkipRSA {
		fmt.Fprintf(&plain, "Your new RSA Private key is here (on host %s):\n%s\n\n", hostname, rsaPath)
		fmt.Fprintf(&html, "Your new RSA Private key is here (on host %s):\n
%s\n\n
", hostname, rsaPath)

		fmt.Fprintf(&plain, "Your new RSA Public key is here (on host %s):\n%s\n\n", hostname, rsaPath+".pub")
		fmt.Fprintf(&html, "Your new RSA Public key is here (on host %s):\n
%s
\n\n", hostname, rsaPath+".pub")
	}
	fmt.Fprintf(&html, "")

	os.Stdout.Write(plain.Bytes())

	if sendEmail {
		if cfg.MailCfg.Domain == "" ||
			cfg.MailCfg.PublicApiKey == "" ||
			cfg.MailCfg.SecretApiKey == "" {
			fmt.Printf("\n\n alert! -- mailgun not configured; not sending backup email.\n\n")
		} else {
			subject := fmt.Sprintf("gosshtun passphrase backup "+
				"- from %s@%s (%s)", userEnv, hostname, ip)
			senderEmail := fmt.Sprintf("%s@%s", userEnv, hostname)

			pl := string(plain.Bytes())
			ht := string(html.Bytes())

			id, err := cfg.MailCfg.SendEmail(senderEmail,
				subject,
				pl,
				ht,
				myemail)
			if err != nil {
				fmt.Printf("\n mailCfg.SendEmail() failed: %s\n", err)
			} else {
				fmt.Printf("\n backup email sent; id: '%s'\n", id)
			}
		}
	}

	os.Exit(0)
}

func delUserAndExit(cfg *tun.SshegoConfig) {

	fmt.Printf("\ndeleting user '%s'...\n", cfg.DelUser)

	user := tun.NewUser()
	user.MyLogin = cfg.DelUser

	var prt tun.TcpPort
	prt.Port = cfg.SshegoSystemMutexPort

	limitMsec := 5000
	err := prt.Lock(limitMsec)
	if err == tun.ErrCouldNotAquirePort {
		// already running...
		p("we see gosshtun is already running and has the xport open")
		err = cfg.TcpClientUserDel(user)
		if err != nil {
			fmt.Printf("\n error: %s\n", err)
			os.Exit(1)
		}
	} else {
		p("we got xport, so while holding it, modify the database directly")
		// we must do it ourselves; other process is not
		// up and we now hold the port (listening on it) as a lock.

		err := cfg.NewHostDb()
		if err != nil {
			fmt.Printf("\n%s\n", err)
			os.Exit(1)
		}
		err = cfg.HostDb.DelUser(cfg.DelUser)
		if err != nil {
			fmt.Printf("\n%s\n", err)
			os.Exit(1)
		}
		prt.Unlock()
	}
	fmt.Printf("\n deleted user '%s'\n", cfg.DelUser)
	os.Exit(0)
}
<commit_msg>atg. better input trimming of whitespace<commit_after>package main

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"runtime"
	"strings"
	"time"

	tun "github.com/glycerine/sshego"
	"github.com/skratchdot/open-golang/open"
)

const ProgramName = "gosshtun"

func main() {

	myflags := flag.NewFlagSet(ProgramName, flag.ExitOnError)
	cfg := tun.NewSshegoConfig()
	cfg.DefineFlags(myflags)
	err := myflags.Parse(os.Args[1:])
	err = cfg.ValidateConfig()
	if err != nil {
		log.Fatalf("%s command line flag error: '%s'", ProgramName, err)
	}
	//p("cfg = %#v", cfg)
	h, err := tun.NewKnownHosts(cfg.ClientKnownHostsPath, tun.KHJson)
	panicOn(err)
	cfg.KnownHosts = h

	if cfg.WriteConfigOut != "" {
		var o io.WriteCloser
		if cfg.WriteConfigOut == "-" {
			o = os.Stdout
		} else {
			o, err = os.Create(cfg.WriteConfigOut)
			if err != nil {
				panic(err)
			}
		}
		err = cfg.SaveConfig(o)
		if err != nil {
			panic(err)
		}
	}

	if cfg.AddUser != "" {
		addUserAndExit(cfg)
	}

	if cfg.DelUser != "" {
		delUserAndExit(cfg)
	}

	passphrase := ""
	totpUrl := ""

	_, err = cfg.SSHConnect(h, cfg.Username, cfg.PrivateKeyPath,
		cfg.SSHdServer.Host, cfg.SSHdServer.Port, passphrase, totpUrl)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(0)
	}
	if err != nil {
		panic(err)
	}
	if !cfg.WriteConfigOnly {
		select {}
	}
}

func panicOn(err error) {
	if err != nil {
		panic(err)
	}
}

func addUserAndExit(cfg *tun.SshegoConfig) {

	err := cfg.NewHostDb()
	panicOn(err)

	mylogin := cfg.AddUser

	if cfg.HostDb.UserExists(mylogin) {
		fmt.Fprintf(os.Stderr, "\nerror: user '%s' already exists. If you want to replace them, use -deluser first.\n", mylogin)
		os.Exit(1)
	}
	var ok bool
	ok, err = cfg.HostDb.ValidLogin(mylogin)
	if !ok {
		fmt.Printf("\n%s\n", err)
		os.Exit(1)
	}

	reader := bufio.NewReader(os.Stdin)

	var myemail string
	fmt.Printf("\nEnter the email address for '%s' (for backups/recovery): ",
		mylogin)
	myemail, err = reader.ReadString('\n')
	panicOn(err)
	myemail = strings.Trim(myemail, "\n\r\t ")
	ok, err = cfg.HostDb.ValidEmail(myemail)
	if !ok {
		fmt.Printf("\n%s\n", err)
		os.Exit(1)
	}

	fmt.Printf("\n'%s' should be a valid email, but may be fake if you insist.\n\nIf this email is real, we can backup the passphrase you will create in the next step. This convenience feature is optional, but strongly recommended.  The RSA key and One-time-password secret will not be sent by email, but their locations on disk will be noted for ease of retreival.\n\nDo you want to backup the passphase to email '%s'? [y/n]:", myemail, myemail)
	yn, err := reader.ReadString('\n')
	panicOn(err)
	yn = strings.ToLower(strings.Trim(yn, "\n\r\t "))
	sendEmail := false
	if yn == "y" || yn == "yes" {
		sendEmail = true
		fmt.Printf("\n\n Very good. Upon completion, your passphrase "+
			"will backed up to '%s'\n\n", myemail)
	} else {
		fmt.Printf("\n\n As you wish. No email will be sent.\n\n")
	}

	var fullname string
	fmt.Printf("\nCorresponding to '%s'/'%s', enter the first and last name (e.g. 'John Q. Smith'). This helps identify the account during maintenance. First and last name:\n", mylogin, myemail)
	fullname, err = reader.ReadString('\n')
	panicOn(err)
	fullname = strings.Trim(fullname, "\n\r\t ")

	var pw string
	if !cfg.SkipPassphrase {
		pw, err = tun.PromptForPassword(cfg.AddUser)
		if err != nil {
			fmt.Printf("\n%v\n", err)
			os.Exit(1)
		}
		fmt.Printf("\n account: '%s', passphrase: '%s'\n", cfg.AddUser, pw)
	}
	if !cfg.SkipRSA {
		fmt.Printf("\n generating a strong RSA key, this may take a 5-10 seconds... \n")
	}
	user := tun.NewUser()
	user.MyLogin = mylogin
	user.MyEmail = myemail
	user.MyFullname = fullname
	user.ClearPw = pw
	user.Issuer = "gosshtun"

	var toptPath, qrPath, rsaPath string

	var prt tun.TcpPort
	prt.Port = cfg.SshegoSystemMutexPort

	limitMsec := 5000
	err = prt.Lock(limitMsec)
	if err == tun.ErrCouldNotAquirePort {
		// already running...
		p("we see gosshtun is already running and has the xport open")
		toptPath, qrPath, rsaPath, err = cfg.TcpClientUserAdd(user)
	} else {
		p("we got xport, so while holding it, modify the database directly")
		// we must do it ourselves; other process is not
		// up and we now hold the port (listening on it) as a lock.
		toptPath, qrPath, rsaPath, err = cfg.HostDb.AddUser(
			mylogin, myemail, pw, "gosshtun", fullname)
		prt.Unlock()
	}
	if err != nil {
		es := err.Error()
		if strings.HasPrefix(es,
			"bad email: give a full email address.") {
			fmt.Printf("\n%s\n", es)
			os.Exit(1)
		}
	}
	panicOn(err)

	hostname, _ := os.Hostname()
	var plain bytes.Buffer
	var html bytes.Buffer
	both := io.MultiWriter(&plain, &html)
	ip := tun.GetExternalIP()
	userEnv := os.Getenv("USER")

	fmt.Fprintf(&html, "")
	fmt.Fprintf(both, "%s:\n\n", fullname)
	fmt.Fprintf(&html, "
")

	fmt.Fprintf(both, "## ===============================================\n")
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## \n")
	fmt.Fprintf(&html, "
")
	authDetail := "tri-factor"
	if cfg.SkipPassphrase || cfg.SkipRSA || cfg.SkipTOTP {
		authDetail = ""
	}
	authList := cfg.GenAuthString()
	fmt.Fprintf(both, "##  %s auth details:\n", authDetail)
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## \n")
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "##    %s\n", authList)
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## \n")
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## ==  run: gosshtun -adduser %s\n",
		cfg.AddUser)
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## ==  run on host:  %s (%s)\n", hostname, ip)
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## ==  run by user:  %s\n", userEnv)
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## ==  at UTC time:  %s\n", time.Now().UTC())
	fmt.Fprintf(&html, "
")
	fmt.Fprintf(both, "## ===============================================\n")
	fmt.Fprintf(&html, "
")

	fmt.Fprintf(&plain, "\nyour login:\n%s\n\n", mylogin)
	fmt.Fprintf(&html, "\n
your login:
\n%s
\n\n", mylogin)

	fmt.Fprintf(&plain, "your email:\n%s\n\n", myemail)
	fmt.Fprintf(&html, "\n
your email:
\n%s
\n\n", myemail)

	fmt.Fprintf(&plain, "your fullname:\n%s\n\n", fullname)
	fmt.Fprintf(&html, "\n
your fullname:
\n%s
\n\n", fullname)

	if !cfg.SkipPassphrase {
		fmt.Fprintf(&plain, "Passphrase:\n%v\n\n", pw)
		fmt.Fprintf(&html, "
Passphrase:\n
\n%v\n\n", pw)
		fmt.Fprintf(&html, "

")
	}
	if !cfg.SkipTOTP {
		fmt.Fprintf(&plain, "GoogleAuthenticator (time-based-one-time-password; RFC6238) secret location (on host %s):\n%s\n\n", hostname, toptPath)
		fmt.Fprintf(&html, "GoogleAuthenticator (time-based-one-time-password; RFC6238) secret location (on host %s):\n
\n%s

\n", hostname, toptPath)

		qrUrl := fmt.Sprintf("file://%s", qrPath)

		fmt.Printf("\n checking if we should open the QR-code automajically...\n")
		if runtime.GOOS == "darwin" { // "windows", "linux"
			fmt.Printf("...runtime.GOOS='%s'; try to open the QR-code\n",
				runtime.GOOS)
			open.Start(qrUrl)
		}

		fmt.Fprintf(&plain, "GoogleAuthenticator QR-code url (on host %s):\n%s\n\n", hostname, qrPath)
		fmt.Fprintf(&html, "GoogleAuthenticator QR-code url (on host %s):\n
%s
\n\n", hostname, qrUrl, qrUrl)
		fmt.Fprintf(&html, "
")
	}
	if !cfg.SkipRSA {
		fmt.Fprintf(&plain, "Your new RSA Private key is here (on host %s):\n%s\n\n", hostname, rsaPath)
		fmt.Fprintf(&html, "Your new RSA Private key is here (on host %s):\n
%s\n\n
", hostname, rsaPath)

		fmt.Fprintf(&plain, "Your new RSA Public key is here (on host %s):\n%s\n\n", hostname, rsaPath+".pub")
		fmt.Fprintf(&html, "Your new RSA Public key is here (on host %s):\n
%s
\n\n", hostname, rsaPath+".pub")
	}
	fmt.Fprintf(&html, "")

	os.Stdout.Write(plain.Bytes())

	if sendEmail {
		if cfg.MailCfg.Domain == "" ||
			cfg.MailCfg.PublicApiKey == "" ||
			cfg.MailCfg.SecretApiKey == "" {
			fmt.Printf("\n\n alert! -- mailgun not configured; not sending backup email.\n\n")
		} else {
			subject := fmt.Sprintf("gosshtun passphrase backup "+
				"- from %s@%s (%s)", userEnv, hostname, ip)
			senderEmail := fmt.Sprintf("%s@%s", userEnv, hostname)

			pl := string(plain.Bytes())
			ht := string(html.Bytes())

			id, err := cfg.MailCfg.SendEmail(senderEmail,
				subject,
				pl,
				ht,
				myemail)
			if err != nil {
				fmt.Printf("\n mailCfg.SendEmail() failed: %s\n", err)
			} else {
				fmt.Printf("\n backup email sent; id: '%s'\n", id)
			}
		}
	}

	os.Exit(0)
}

func delUserAndExit(cfg *tun.SshegoConfig) {

	fmt.Printf("\ndeleting user '%s'...\n", cfg.DelUser)

	user := tun.NewUser()
	user.MyLogin = cfg.DelUser

	var prt tun.TcpPort
	prt.Port = cfg.SshegoSystemMutexPort

	limitMsec := 5000
	err := prt.Lock(limitMsec)
	if err == tun.ErrCouldNotAquirePort {
		// already running...
		p("we see gosshtun is already running and has the xport open")
		err = cfg.TcpClientUserDel(user)
		if err != nil {
			fmt.Printf("\n error: %s\n", err)
			os.Exit(1)
		}
	} else {
		p("we got xport, so while holding it, modify the database directly")
		// we must do it ourselves; other process is not
		// up and we now hold the port (listening on it) as a lock.

		err := cfg.NewHostDb()
		if err != nil {
			fmt.Printf("\n%s\n", err)
			os.Exit(1)
		}
		err = cfg.HostDb.DelUser(cfg.DelUser)
		if err != nil {
			fmt.Printf("\n%s\n", err)
			os.Exit(1)
		}
		prt.Unlock()
	}
	fmt.Printf("\n deleted user '%s'\n", cfg.DelUser)
	os.Exit(0)
}
<|endoftext|>


<commit_before>package main

import (
	"io"
	"log"
	"os"
	"os/exec"
	"time"
)

func main() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	display := exec.Command("display")
	//get stdout
	stdoutd, err := display.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}

	core := exec.Command("core")
	stdoutc, err := core.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}

	chronicle := exec.Command("chronicle")
	stdoutcr, err := chronicle.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}

	//map containing the commands and their pth as keys
	cmdm := make(map[string]*exec.Cmd)
	//start the commands and puththem in the map
	err = display.Start()
	if err != nil {
		log.Fatalf("Start error %+v\n", err)
	}
	//this is gross but it needs some tiem to connect...
	time.Sleep(1 * time.Second)
	//copy stdout of child process to stdout
	go io.Copy(os.Stdout, stdoutd)
	cmdm[display.Path] = display
	err = core.Start()
	if err != nil {
		display.Process.Kill()
		log.Fatalf("%+v\n", err)
	}
	go io.Copy(os.Stdout, stdoutc)
	cmdm[core.Path] = core
	err = chronicle.Start()
	if err != nil {
		core.Process.Kill()
		display.Process.Kill()
		log.Fatalf("%+v\n", err)
	}
	go io.Copy(os.Stdout, stdoutcr)

	cmdm[chronicle.Path] = chronicle
	//all running we wait for deaths
	//upon a death we remove the dead command fomr the map
	//and kill the others to clean up
	deadchan := make(chan string)
	wait2(display, deadchan)
	wait2(core, deadchan)
	wait2(chronicle, deadchan)
	dead := <-deadchan
	delete(cmdm, dead)
	for _, c := range cmdm {
		c.Process.Kill()
	}

}

func wait2(cmd *exec.Cmd, ch chan string) {
	go func() {
		err := cmd.Wait()
		if err != nil {
			log.Printf("Process %s ended with  error %v\n", cmd.Path, err)
		}
		ch <- cmd.Path
	}()
}
func wait(cmd exec.Cmd) chan struct{} {
	ch := make(chan struct{})
	go func() {
		err := cmd.Wait()
		if err != nil {
			log.Println(err)
		}
		ch <- struct{}{}
	}()
	return ch
}
<commit_msg>gross yuky hack<commit_after>package main

import (
	"io"
	"log"
	"os"
	"os/exec"
	"time"
)

func main() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)

	//display
	display := exec.Command("display")
	//get stdout
	stdoutd, err := display.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	//go io.Copy(os.Stdout, stdoutd)

	//core
	core := exec.Command("core")
	stdoutc, err := core.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	//go io.Copy(os.Stdout, stdoutc)

	//chronicle
	chronicle := exec.Command("chronicle")
	stdoutcr, err := chronicle.StdoutPipe()
	if err != nil {
		log.Fatal(err)
	}
	//go io.Copy(os.Stdout, stdoutcr)

	//Write combined stdout of the comands
	go io.Copy(os.Stdout, io.MultiReader(stdoutd, stdoutc, stdoutcr))

	//map containing the commands and their pth as keys
	cmdm := make(map[string]*exec.Cmd)

	//start the commands and puththem in the map
	err = display.Start()
	if err != nil {
		log.Fatalf("Start error %+v\n", err)
	}
	cmdm[display.Path] = display
	//this is gross and wrong but it needs some time to connect...
	time.Sleep(1 * time.Second)

	err = core.Start()
	if err != nil {
		display.Process.Kill()
		log.Fatalf("%+v\n", err)
	}
	cmdm[core.Path] = core
	//this is gross and wrong but it needs some time to connect...
	time.Sleep(1 * time.Second)

	err = chronicle.Start()
	if err != nil {
		core.Process.Kill()
		display.Process.Kill()
		log.Fatalf("%+v\n", err)
	}
	cmdm[chronicle.Path] = chronicle
	//this is gross and wrong but it needs some time to connect...
	time.Sleep(1 * time.Second)

	//all running we wait for deaths
	//upon a death we remove the dead command fomr the map
	//and kill the others to clean up
	deadchan := make(chan string)
	wait2(display, deadchan)
	wait2(core, deadchan)
	wait2(chronicle, deadchan)
	dead := <-deadchan
	delete(cmdm, dead)
	for _, c := range cmdm {
		c.Process.Kill()
	}

}

func wait2(cmd *exec.Cmd, ch chan string) {
	go func() {
		err := cmd.Wait()
		if err != nil {
			log.Printf("Process %s ended with  error %v\n", cmd.Path, err)
		}
		ch <- cmd.Path
	}()
}
func wait(cmd exec.Cmd) chan struct{} {
	ch := make(chan struct{})
	go func() {
		err := cmd.Wait()
		if err != nil {
			log.Println(err)
		}
		ch <- struct{}{}
	}()
	return ch
}
<|endoftext|>


<commit_before>// 擷取盤中即時資訊與大盤、上櫃、寶島指數.
//
/*

Install:

	go install github.com/toomore/gogrs/cmd/realtime

Usage:

	realtime [flags]

The flags are:

	-twse
		上市股票代碼，可使用 ',' 分隔多組代碼，例：2618,2329
	-otc
		上櫃股票代碼，可使用 ',' 分隔多組代碼，例：8446,2719
	-index
		顯示大盤、上櫃、寶島指數（default: false）

範例

	/realtime -twse=2618,2329 -otc=8446,2719 -index=true

回傳內容

	2015/04/29 23:43:13 櫃買指數(o00) $144.72(-1.15) 1271/23250 [2015-04-29 13:33:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 發行量加權股價指數(t00) $9853.83(-80.99) 5742/113762 [2015-04-29 13:33:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 寶島股價指數(FRMSA) $11416.04(-93.58) 0/0 [2015-04-29 13:33:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 華研(8446) $124.00(1.00) 6/293 [2015-04-29 14:30:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 長榮航(2618) $24.20(-0.55) 666/15618 [2015-04-29 14:30:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 燦星旅(2719) $24.15(0.25) 6/83 [2015-04-29 14:30:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 華泰(2329) $15.95(0.50) 648/19995 [2015-04-29 14:30:00 +0800 CST] [20150429 23:43:13]

*/
package main

import (
	"flag"
	"fmt"
	"log"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/toomore/gogrs/realtime"
	"github.com/toomore/gogrs/tradingdays"
	"github.com/toomore/gogrs/utils"
)

var cacheTime time.Time

// TaipeiNow show Taipei Now time.
func TaipeiNow() time.Time {
	if cacheTime.Year() == 1 {
		d := time.Now().UTC()
		days := d.Day()
		for {
			if tradingdays.IsOpen(d.Year(), d.Month(), days) {
				break
			}
			days--
		}
		if d.Before(time.Date(d.Year(), d.Month(), days, 1, 0, 0, 0, time.FixedZone("UTC", 0))) {
			if d.Hour() == 0 && d.Minute() <= 59 {
				days--
			}
		}
		cacheTime = time.Date(d.Year(), d.Month(), days, 0, 0, 0, 0, utils.TaipeiTimeZone)
	}
	return cacheTime
}

func prettyprint(data realtime.Data) string {
	return fmt.Sprintf("%s(%s) $%.2f(%.2f) %.0f/%.0f [%s] [%s %s]",
		data.Info.Name, data.Info.No,
		data.Price, data.Price-data.Open, data.Volume, data.VolumeAcc,
		data.TradeTime, data.SysInfo["sysDate"], data.SysInfo["sysTime"])
}

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}

var twseNo = flag.String("twse", "", "上市股票代碼，可使用 ',' 分隔多組代碼，例：2618,2329")
var otcNo = flag.String("otc", "", "上櫃股票代碼，可使用 ',' 分隔多組代碼，例：8446,2719")
var index = flag.Bool("index", false, "顯示大盤、上櫃、寶島指數（default: false）")

func main() {
	flag.Parse()
	queue := []*realtime.StockRealTime{}
	if *twseNo != "" {
		for _, no := range strings.Split(*twseNo, ",") {
			queue = append(queue, realtime.NewTWSE(no, TaipeiNow()))
		}
	}
	if *otcNo != "" {
		for _, no := range strings.Split(*otcNo, ",") {
			queue = append(queue, realtime.NewOTC(no, TaipeiNow()))
		}
	}
	if *index {
		queue = append(queue, []*realtime.StockRealTime{realtime.NewWeight(TaipeiNow()),
			realtime.NewOTCI(TaipeiNow()), realtime.NewFRMSA(TaipeiNow())}...)
	}
	result := make(chan string)
	var wg sync.WaitGroup
	wg.Add(len(queue))
	for _, r := range queue {
		go func(r *realtime.StockRealTime) {
			data, _ := r.Get()
			result <- prettyprint(data)
		}(r)
	}
	go func() {
		for v := range result {
			wg.Done()
			log.Println(v)
		}
	}()
	wg.Wait()
	if len(queue) == 0 {
		flag.PrintDefaults()
	}
}
<commit_msg>Fixed chan num.<commit_after>// 擷取盤中即時資訊與大盤、上櫃、寶島指數.
//
/*

Install:

	go install github.com/toomore/gogrs/cmd/realtime

Usage:

	realtime [flags]

The flags are:

	-twse
		上市股票代碼，可使用 ',' 分隔多組代碼，例：2618,2329
	-otc
		上櫃股票代碼，可使用 ',' 分隔多組代碼，例：8446,2719
	-index
		顯示大盤、上櫃、寶島指數（default: false）

範例

	/realtime -twse=2618,2329 -otc=8446,2719 -index=true

回傳內容

	2015/04/29 23:43:13 櫃買指數(o00) $144.72(-1.15) 1271/23250 [2015-04-29 13:33:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 發行量加權股價指數(t00) $9853.83(-80.99) 5742/113762 [2015-04-29 13:33:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 寶島股價指數(FRMSA) $11416.04(-93.58) 0/0 [2015-04-29 13:33:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 華研(8446) $124.00(1.00) 6/293 [2015-04-29 14:30:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 長榮航(2618) $24.20(-0.55) 666/15618 [2015-04-29 14:30:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 燦星旅(2719) $24.15(0.25) 6/83 [2015-04-29 14:30:00 +0800 CST] [20150429 23:43:13]
	2015/04/29 23:43:13 華泰(2329) $15.95(0.50) 648/19995 [2015-04-29 14:30:00 +0800 CST] [20150429 23:43:13]

*/
package main

import (
	"flag"
	"fmt"
	"log"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/toomore/gogrs/realtime"
	"github.com/toomore/gogrs/tradingdays"
	"github.com/toomore/gogrs/utils"
)

var cacheTime time.Time

// TaipeiNow show Taipei Now time.
func TaipeiNow() time.Time {
	if cacheTime.Year() == 1 {
		d := time.Now().UTC()
		days := d.Day()
		for {
			if tradingdays.IsOpen(d.Year(), d.Month(), days) {
				break
			}
			days--
		}
		if d.Before(time.Date(d.Year(), d.Month(), days, 1, 0, 0, 0, time.FixedZone("UTC", 0))) {
			if d.Hour() == 0 && d.Minute() <= 59 {
				days--
			}
		}
		cacheTime = time.Date(d.Year(), d.Month(), days, 0, 0, 0, 0, utils.TaipeiTimeZone)
	}
	return cacheTime
}

func prettyprint(data realtime.Data) string {
	return fmt.Sprintf("%s(%s) $%.2f(%.2f) %.0f/%.0f [%s] [%s %s]",
		data.Info.Name, data.Info.No,
		data.Price, data.Price-data.Open, data.Volume, data.VolumeAcc,
		data.TradeTime, data.SysInfo["sysDate"], data.SysInfo["sysTime"])
}

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}

var twseNo = flag.String("twse", "", "上市股票代碼，可使用 ',' 分隔多組代碼，例：2618,2329")
var otcNo = flag.String("otc", "", "上櫃股票代碼，可使用 ',' 分隔多組代碼，例：8446,2719")
var index = flag.Bool("index", false, "顯示大盤、上櫃、寶島指數（default: false）")

func main() {
	flag.Parse()
	queue := []*realtime.StockRealTime{}
	if *twseNo != "" {
		for _, no := range strings.Split(*twseNo, ",") {
			queue = append(queue, realtime.NewTWSE(no, TaipeiNow()))
		}
	}
	if *otcNo != "" {
		for _, no := range strings.Split(*otcNo, ",") {
			queue = append(queue, realtime.NewOTC(no, TaipeiNow()))
		}
	}
	if *index {
		queue = append(queue, []*realtime.StockRealTime{realtime.NewWeight(TaipeiNow()),
			realtime.NewOTCI(TaipeiNow()), realtime.NewFRMSA(TaipeiNow())}...)
	}
	result := make(chan string, runtime.NumCPU())
	var wg sync.WaitGroup
	wg.Add(len(queue))
	for _, r := range queue {
		go func(r *realtime.StockRealTime) {
			runtime.Gosched()
			data, _ := r.Get()
			result <- prettyprint(data)
		}(r)
	}
	go func() {
		for v := range result {
			wg.Done()
			log.Println(v)
		}
	}()
	wg.Wait()
	if len(queue) == 0 {
		flag.PrintDefaults()
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 The Reposeed Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"text/template"

	"github.com/okkur/reposeed/cmd/reposeed/config"
	templates "github.com/okkur/reposeed/cmd/reposeed/templates"
	yaml "gopkg.in/yaml.v2"
)

const SupportedConfigVersion = "v1"

func parseConfig(path string) config.Config {
	var conf config.Config

	filename, _ := filepath.Abs(path)
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	err = yaml.Unmarshal(file, &conf)
	if err != nil {
		panic(err)
	}
	return conf
}

func generateFile(config config.Config, fileContent []byte, newPath string, overwrite bool) error {

	// Create a temporary file based on fileContent
	tmpfile, err := ioutil.TempFile("", "template")
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove(tmpfile.Name())
	if _, err := tmpfile.Write(fileContent); err != nil {
		log.Fatal(err)
	}
	if _, e := os.Stat(newPath); os.IsNotExist(e) {
		os.MkdirAll(filepath.Dir(newPath), os.ModePerm)
	}

	if !overwrite {
		if _, e := os.Stat(newPath); !os.IsNotExist(e) {
			return fmt.Errorf("file %s not overwritten", newPath)
		}
	}

	file, err := os.Create(newPath)
	defer file.Close()
	if err != nil {
		return fmt.Errorf("unable to create file: %s", err)
	}

	temp, err := template.ParseFiles(tmpfile.Name())
	if err != nil {
		return fmt.Errorf("unable to parse file: %s", err)
	}

	err = temp.Execute(file, config)
	if err != nil {
		return fmt.Errorf("unable to parse template: %s", err)
	}
	if err := tmpfile.Close(); err != nil {
		log.Fatal(err)
	}

	return nil
}

func main() {
	var outputDir, conf string
	var overwrite bool
	flag.StringVar(&outputDir, "output", "", "Output directory")
	flag.StringVar(&conf, "conf", ".seed-config.yaml", "Config file")
	flag.BoolVar(&overwrite, "overwrite", false, "Force overwrite files")

	flag.Parse()
	box := templates.GetTemplates()

	// Commands
	if os.Args[1] == "init" {
		seedString := box.String("seed-config.example.yaml")
		file, _ := os.Create(os.Args[2] + "/.seed-config.yaml")
		defer file.Close()
		file.WriteString(seedString)
		os.Exit(1)
	}

	config := parseConfig(conf)
	templatesName := box.List()
	bl := make(map[string]bool)
	bl["seed-config.example.yaml"] = true
	configVersion := config.Reposeed.ConfigVersion

	if configVersion == SupportedConfigVersion {
		for _, templateName := range templatesName {
			file, _ := box.Open(templateName)
			fileStat, _ := file.Stat()
			fileContent := box.Bytes(templateName)
			if bl[fileStat.Name()] {
				log.Println(filepath.SkipDir)
			}

			if !fileStat.IsDir() {
				if !bl[fileStat.Name()] {
					err := generateFile(config, fileContent, templateName, overwrite)
					if err != nil {
						log.Println(err)
					}
				}
			}
		}
	} else {
		log.Fatalf("Invalid config version. Currently supported versions: v1")
	}
}
<commit_msg>Delete extra if<commit_after>/*
Copyright 2017 The Reposeed Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"text/template"

	"github.com/okkur/reposeed/cmd/reposeed/config"
	templates "github.com/okkur/reposeed/cmd/reposeed/templates"
	yaml "gopkg.in/yaml.v2"
)

const SupportedConfigVersion = "v1"

func parseConfig(path string) config.Config {
	var conf config.Config

	filename, _ := filepath.Abs(path)
	file, err := ioutil.ReadFile(filename)
	if err != nil {
		panic(err)
	}
	err = yaml.Unmarshal(file, &conf)
	if err != nil {
		panic(err)
	}
	return conf
}

func generateFile(config config.Config, fileContent []byte, newPath string, overwrite bool) error {

	// Create a temporary file based on fileContent
	tmpfile, err := ioutil.TempFile("", "template")
	if err != nil {
		log.Fatal(err)
	}
	defer os.Remove(tmpfile.Name())
	if _, err := tmpfile.Write(fileContent); err != nil {
		log.Fatal(err)
	}
	if _, e := os.Stat(newPath); os.IsNotExist(e) {
		os.MkdirAll(filepath.Dir(newPath), os.ModePerm)
	}

	if !overwrite {
		if _, e := os.Stat(newPath); !os.IsNotExist(e) {
			return fmt.Errorf("file %s not overwritten", newPath)
		}
	}

	file, err := os.Create(newPath)
	defer file.Close()
	if err != nil {
		return fmt.Errorf("unable to create file: %s", err)
	}

	temp, err := template.ParseFiles(tmpfile.Name())
	if err != nil {
		return fmt.Errorf("unable to parse file: %s", err)
	}

	err = temp.Execute(file, config)
	if err != nil {
		return fmt.Errorf("unable to parse template: %s", err)
	}
	if err := tmpfile.Close(); err != nil {
		log.Fatal(err)
	}

	return nil
}

func main() {
	var outputDir, conf string
	var overwrite bool
	flag.StringVar(&outputDir, "output", "", "Output directory")
	flag.StringVar(&conf, "conf", ".seed-config.yaml", "Config file")
	flag.BoolVar(&overwrite, "overwrite", false, "Force overwrite files")

	flag.Parse()
	box := templates.GetTemplates()

	// Commands
	if os.Args[1] == "init" {
		seedString := box.String("seed-config.example.yaml")
		file, _ := os.Create(os.Args[2] + "/.seed-config.yaml")
		defer file.Close()
		file.WriteString(seedString)
		os.Exit(1)
	}

	config := parseConfig(conf)
	templatesName := box.List()
	bl := make(map[string]bool)
	bl["seed-config.example.yaml"] = true
	configVersion := config.Reposeed.ConfigVersion

	if configVersion == SupportedConfigVersion {
		for _, templateName := range templatesName {
			file, _ := box.Open(templateName)
			fileStat, _ := file.Stat()
			fileContent := box.Bytes(templateName)
			if bl[fileStat.Name()] {
				log.Println(filepath.SkipDir)
				continue
			}

			if fileStat.IsDir() {
				continue
			}

			err := generateFile(config, fileContent, templateName, overwrite)
			if err != nil {
				log.Println(err)
			}
		}
	} else {
		log.Fatalf("Invalid config version. Currently supported versions: v1")
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Tigera, Inc. All rights reserved.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ifacemonitor_test

import (
	"strings"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/projectcalico/felix/go/felix/ifacemonitor"
	"github.com/projectcalico/felix/go/felix/set"
	"github.com/vishvananda/netlink"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

type linkModel struct {
	index int
	state string
	addrs set.Set
}

type netlinkTest struct {
	linkUpdates chan netlink.LinkUpdate
	addrUpdates chan netlink.AddrUpdate

	nextIndex int
	links     map[string]linkModel
}

func (nl *netlinkTest) addLink(name string) {
	if nl.links == nil {
		nl.links = map[string]linkModel{}
		nl.nextIndex = 10
	}
	nl.links[name] = linkModel{
		index: nl.nextIndex,
		state: "down",
		addrs: set.New(),
	}
	nl.nextIndex++
	nl.signalLink(name)
}

func (nl *netlinkTest) changeLinkState(name string, state string) {
	link := nl.links[name]
	link.state = state
	nl.links[name] = link
	nl.signalLink(name)
}

func (nl *netlinkTest) delLink(name string) {
	delete(nl.links, name)
	nl.signalLink(name)
}

func (nl *netlinkTest) signalLink(name string) {
	// Values for a link that does not exist...
	index := 0
	var rawFlags uint32 = 0
	var msgType uint16 = syscall.RTM_DELLINK

	// If the link does exist, overwrite appropriately.
	link, prs := nl.links[name]
	if prs {
		msgType = syscall.RTM_NEWLINK
		index = link.index
		if link.state == "up" {
			rawFlags = syscall.IFF_RUNNING
		}
	}

	// Build the update.
	update := netlink.LinkUpdate{
		Header: syscall.NlMsghdr{
			Type: msgType,
		},
		Link: &netlink.Dummy{
			LinkAttrs: netlink.LinkAttrs{
				Name:     name,
				Index:    index,
				RawFlags: rawFlags,
			},
		},
	}

	// Send it.
	log.Info("Test code signaling a link update")
	nl.linkUpdates <- update
}

func (nl *netlinkTest) addAddr(name string, addr string) {
	link := nl.links[name]
	link.addrs.Add(addr)
	nl.links[name] = link
	nl.signalAddr(name, addr, true)
}

func (nl *netlinkTest) delAddr(name string, addr string) {
	link := nl.links[name]
	link.addrs.Discard(addr)
	nl.links[name] = link
	nl.signalAddr(name, addr, false)
}

func (nl *netlinkTest) signalAddr(name string, addr string, exists bool) {
	// Build the update.
	net, err := netlink.ParseIPNet(addr)
	if err != nil {
		panic("Address parsing failed")
	}
	update := netlink.AddrUpdate{
		LinkIndex:   nl.links[name].index,
		NewAddr:     exists,
		LinkAddress: *net,
	}

	// Send it.
	log.Info("Test code signaling an addr update")
	nl.addrUpdates <- update
}

func (nl *netlinkTest) Subscribe(
	linkUpdates chan netlink.LinkUpdate,
	addrUpdates chan netlink.AddrUpdate,
) error {
	nl.linkUpdates = linkUpdates
	nl.addrUpdates = addrUpdates
	return nil
}

func (nl *netlinkTest) LinkList() ([]netlink.Link, error) {
	links := []netlink.Link{}
	for name, link := range nl.links {
		var rawFlags uint32 = 0
		if link.state == "up" {
			rawFlags = syscall.IFF_RUNNING
		}
		links = append(links, &netlink.Dummy{
			LinkAttrs: netlink.LinkAttrs{
				Name:     name,
				Index:    link.index,
				RawFlags: rawFlags,
			},
		})
	}
	return links, nil
}

func (nl *netlinkTest) AddrList(link netlink.Link, family int) ([]netlink.Addr, error) {
	name := link.Attrs().Name
	model, prs := nl.links[name]
	addrs := []netlink.Addr{}
	if prs {
		model.addrs.Iter(func(item interface{}) error {
			addr := item.(string)
			net, err := netlink.ParseIPNet(addr)
			if err != nil {
				panic("Address parsing failed")
			}
			if strings.ContainsRune(addr, ':') {
				if family == netlink.FAMILY_V6 {
					addrs = append(addrs, netlink.Addr{
						IPNet: net,
					})
				}
			} else {
				if family == netlink.FAMILY_V4 {
					addrs = append(addrs, netlink.Addr{
						IPNet: net,
					})
				}
			}
			return nil
		})
	}
	return addrs, nil
}

var linkC = make(chan string, 1)

func linkStateCallback(ifaceName string, ifaceState ifacemonitor.State) {
	log.Info("linkStateCallback: ifaceName=", ifaceName)
	log.Info("linkStateCallback: ifaceState=", ifaceState)
	linkC <- ifaceName
}

func expectLinkStateCb(ifaceName string) {
	cbIface := <-linkC
	Expect(cbIface).To(Equal(ifaceName))
}

var addrC = make(chan string, 1)

func addrStateCallback(ifaceName string, addrs set.Set) {
	log.Info("addrStateCallback: ifaceName=", ifaceName)
	log.Info("addrStateCallback: addrs=", addrs)
	addrC <- ifaceName
}

func expectAddrStateCb(ifaceName string) {
	cbIface := <-addrC
	Expect(cbIface).To(Equal(ifaceName))
}

var _ = Describe("ifacemonitor", func() {
	It("New", func() {
		nl := &netlinkTest{}
		resyncC := make(chan time.Time)
		im := ifacemonitor.NewWithStubs(nl, resyncC)
		im.Callback = linkStateCallback
		im.AddrCallback = addrStateCallback
		go im.MonitorInterfaces()
		time.Sleep(10 * time.Millisecond)
		nl.addLink("eth0")
		nl.addAddr("eth0", "10.0.240.10/24")
		nl.changeLinkState("eth0", "up")
		expectLinkStateCb("eth0")
		expectAddrStateCb("eth0")
		nl.addAddr("eth0", "172.19.34.1/27")
		expectAddrStateCb("eth0")
		nl.delAddr("eth0", "172.19.34.1/27")
		expectAddrStateCb("eth0")
		nl.addAddr("eth0", "172.19.34.1/27")
		expectAddrStateCb("eth0")
		nl.delAddr("eth0", "8.8.8.8/32")
		nl.changeLinkState("eth0", "down")
		expectAddrStateCb("eth0")
		expectLinkStateCb("eth0")
		nl.changeLinkState("eth0", "up")
		expectLinkStateCb("eth0")
		expectAddrStateCb("eth0")
		// Allow a resync.
		resyncC <- time.Time{}
		nl.delLink("eth0")
		expectLinkStateCb("eth0")
		expectAddrStateCb("eth0")
		// Allow a resync.
		resyncC <- time.Time{}
	})
})
<commit_msg>Add comments to explain ifacemonitor testing<commit_after>// Copyright (c) 2017 Tigera, Inc. All rights reserved.

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ifacemonitor_test

import (
	"strings"
	"syscall"
	"time"

	log "github.com/Sirupsen/logrus"
	"github.com/projectcalico/felix/go/felix/ifacemonitor"
	"github.com/projectcalico/felix/go/felix/set"
	"github.com/vishvananda/netlink"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

type linkModel struct {
	index int
	state string
	addrs set.Set
}

type netlinkTest struct {
	linkUpdates chan netlink.LinkUpdate
	addrUpdates chan netlink.AddrUpdate

	nextIndex int
	links     map[string]linkModel
}

func (nl *netlinkTest) addLink(name string) {
	if nl.links == nil {
		nl.links = map[string]linkModel{}
		nl.nextIndex = 10
	}
	nl.links[name] = linkModel{
		index: nl.nextIndex,
		state: "down",
		addrs: set.New(),
	}
	nl.nextIndex++
	nl.signalLink(name)
}

func (nl *netlinkTest) changeLinkState(name string, state string) {
	link := nl.links[name]
	link.state = state
	nl.links[name] = link
	nl.signalLink(name)
}

func (nl *netlinkTest) delLink(name string) {
	delete(nl.links, name)
	nl.signalLink(name)
}

func (nl *netlinkTest) signalLink(name string) {
	// Values for a link that does not exist...
	index := 0
	var rawFlags uint32 = 0
	var msgType uint16 = syscall.RTM_DELLINK

	// If the link does exist, overwrite appropriately.
	link, prs := nl.links[name]
	if prs {
		msgType = syscall.RTM_NEWLINK
		index = link.index
		if link.state == "up" {
			rawFlags = syscall.IFF_RUNNING
		}
	}

	// Build the update.
	update := netlink.LinkUpdate{
		Header: syscall.NlMsghdr{
			Type: msgType,
		},
		Link: &netlink.Dummy{
			LinkAttrs: netlink.LinkAttrs{
				Name:     name,
				Index:    index,
				RawFlags: rawFlags,
			},
		},
	}

	// Send it.
	log.Info("Test code signaling a link update")
	nl.linkUpdates <- update
}

func (nl *netlinkTest) addAddr(name string, addr string) {
	link := nl.links[name]
	link.addrs.Add(addr)
	nl.links[name] = link
	nl.signalAddr(name, addr, true)
}

func (nl *netlinkTest) delAddr(name string, addr string) {
	link := nl.links[name]
	link.addrs.Discard(addr)
	nl.links[name] = link
	nl.signalAddr(name, addr, false)
}

func (nl *netlinkTest) signalAddr(name string, addr string, exists bool) {
	// Build the update.
	net, err := netlink.ParseIPNet(addr)
	if err != nil {
		panic("Address parsing failed")
	}
	update := netlink.AddrUpdate{
		LinkIndex:   nl.links[name].index,
		NewAddr:     exists,
		LinkAddress: *net,
	}

	// Send it.
	log.Info("Test code signaling an addr update")
	nl.addrUpdates <- update
}

func (nl *netlinkTest) Subscribe(
	linkUpdates chan netlink.LinkUpdate,
	addrUpdates chan netlink.AddrUpdate,
) error {
	nl.linkUpdates = linkUpdates
	nl.addrUpdates = addrUpdates
	return nil
}

func (nl *netlinkTest) LinkList() ([]netlink.Link, error) {
	links := []netlink.Link{}
	for name, link := range nl.links {
		var rawFlags uint32 = 0
		if link.state == "up" {
			rawFlags = syscall.IFF_RUNNING
		}
		links = append(links, &netlink.Dummy{
			LinkAttrs: netlink.LinkAttrs{
				Name:     name,
				Index:    link.index,
				RawFlags: rawFlags,
			},
		})
	}
	return links, nil
}

func (nl *netlinkTest) AddrList(link netlink.Link, family int) ([]netlink.Addr, error) {
	name := link.Attrs().Name
	model, prs := nl.links[name]
	addrs := []netlink.Addr{}
	if prs {
		model.addrs.Iter(func(item interface{}) error {
			addr := item.(string)
			net, err := netlink.ParseIPNet(addr)
			if err != nil {
				panic("Address parsing failed")
			}
			if strings.ContainsRune(addr, ':') {
				if family == netlink.FAMILY_V6 {
					addrs = append(addrs, netlink.Addr{
						IPNet: net,
					})
				}
			} else {
				if family == netlink.FAMILY_V4 {
					addrs = append(addrs, netlink.Addr{
						IPNet: net,
					})
				}
			}
			return nil
		})
	}
	return addrs, nil
}

var linkC = make(chan string, 1)

func linkStateCallback(ifaceName string, ifaceState ifacemonitor.State) {
	log.Info("linkStateCallback: ifaceName=", ifaceName)
	log.Info("linkStateCallback: ifaceState=", ifaceState)
	linkC <- ifaceName
}

func expectLinkStateCb(ifaceName string) {
	cbIface := <-linkC
	Expect(cbIface).To(Equal(ifaceName))
}

var addrC = make(chan string, 1)

func addrStateCallback(ifaceName string, addrs set.Set) {
	log.Info("addrStateCallback: ifaceName=", ifaceName)
	log.Info("addrStateCallback: addrs=", addrs)
	addrC <- ifaceName
}

func expectAddrStateCb(ifaceName string) {
	cbIface := <-addrC
	Expect(cbIface).To(Equal(ifaceName))
}

var _ = Describe("ifacemonitor", func() {
	It("New", func() {

		// Make an Interface Monitor that uses a test netlink
		// stub implementation and resync trigger channel -
		// both controlled by this code.
		nl := &netlinkTest{}
		resyncC := make(chan time.Time)
		im := ifacemonitor.NewWithStubs(nl, resyncC)

		// Register this test code's callbacks, which (a) log;
		// and (b) send to a 1-buffered channel, so that the
		// test code _must_ explicitly indicate when it
		// expects those callbacks to have occurred.
		im.Callback = linkStateCallback
		im.AddrCallback = addrStateCallback

		// Start the monitor running, and give it time for its
		// initial resync (which will be a no-op) before we
		// start adding link state.
		go im.MonitorInterfaces()
		time.Sleep(10 * time.Millisecond)

		// Add a link and an address.  No callbacks expected
		// because the link is not up yet.
		nl.addLink("eth0")
		nl.addAddr("eth0", "10.0.240.10/24")

		// Set the link up, and expect callbacks.
		nl.changeLinkState("eth0", "up")
		expectLinkStateCb("eth0")
		expectAddrStateCb("eth0")

		// Add an address.
		nl.addAddr("eth0", "172.19.34.1/27")
		expectAddrStateCb("eth0")

		// Delete that address.
		nl.delAddr("eth0", "172.19.34.1/27")
		expectAddrStateCb("eth0")

		// Add address again.
		nl.addAddr("eth0", "172.19.34.1/27")
		expectAddrStateCb("eth0")

		// Delete an address that wasn't actually there - no callback.
		nl.delAddr("eth0", "8.8.8.8/32")

		// Set link down.
		nl.changeLinkState("eth0", "down")
		expectAddrStateCb("eth0")
		expectLinkStateCb("eth0")

		// Set link up again.
		nl.changeLinkState("eth0", "up")
		expectLinkStateCb("eth0")
		expectAddrStateCb("eth0")

		// Trigger a resync, then immediately delete the link.
		// What happens is that the test code deletes its
		// state for eth0 before the monitor's resync() calls
		// LinkList, and so the monitor reports "Spotted
		// interface removal on resync" and makes link and
		// address callbacks accordingly.
		resyncC <- time.Time{}
		nl.delLink("eth0")
		expectLinkStateCb("eth0")
		expectAddrStateCb("eth0")

		// Trigger another resync.  Nothing is expected.  We
		// ensure that the resync processing completes, before
		// exiting from this test, by sending a further resync
		// trigger.  (This would block if the interface
		// monitor's main loop was not yet ready to read it.)
		resyncC <- time.Time{}
		resyncC <- time.Time{}
	})
})
<|endoftext|>


<commit_before>package golisp

import "testing"

var testdata = []struct {
	expression []string
	result     []string
}{
	{[]string{"(+ 2 3)"}, []string{"5"}},
	{[]string{"(+ 1 6)"}, []string{"7"}},
	{[]string{"(oddp (+ 1 6))"}, []string{"t"}},
	{[]string{"(* 3 (+ 1 6))"}, []string{"21"}},
	{[]string{"(/ (* 2 11) (+ 1 6))"}, []string{"22/7"}},
	{[]string{"23"}, []string{"23"}},
	{[]string{"t"}, []string{"t"}},
	{[]string{"nil"}, []string{"nil"}},
	{[]string{"(equal (+ 7 5) (* 2 8))"}, []string{"nil"}},
	{[]string{"(/ (+ 6 8) 2.0)"}, []string{"7.0"}},
	{[]string{"(defun average (x y) (/ (+ x y) 2.0))", "(average 6 8)"}, []string{"nil", "7.0"}},
	{[]string{"(defun square (n) (* n n))", "(square 2)"}, []string{"nil", "4"}},
	{[]string{"(defun total-cost (quantity price handling-charge) (+ (* quantity price) handling-charge))", "(total-cost 2 3 4)"}, []string{"nil", "10"}},
	{[]string{"pi"}, []string{"3.14159"}},
	{[]string{"(equal 'kirk 'spock)"}, []string{"nil"}},
	{[]string{"(list 'james t 'kirk)"}, []string{"(james t kirk)"}},
	{[]string{"(defun riddle (x y) (list 'why 'is 'a x 'like 'a y))", "(riddle 'raven 'writing-desk)"}, []string{"nil", "(why is a raven like a writing-desk)"}},
	{[]string{"(first (list 1 2 3))"}, []string{"1"}},
	{[]string{"(first '(we hold these truths))"}, []string{"we"}},
	{[]string{"'(+ 1 2)"}, []string{"(+ 1 2)"}},
	{[]string{"(oddp (+ 1 2))"}, []string{"t"}},
	{[]string{"(list 'a 'b 'c)"}, []string{"(a b c)"}},
	{[]string{"(cons 'a '(b c))"}, []string{"(a b c)"}},
	{[]string{"(+ 10 (- 5 2))"}, []string{"13"}},
}

var baddata = []struct {
	expression []string
	fail       []bool
	message    []string
}{
	{[]string{"(1 2 3)"}, []bool{true}, []string{""}},
	{[]string{"(defun average (x y) (/ (+ x y) 2.0))", "(average 6 8 7)"}, []bool{false, true}, []string{"", ""}},
	{[]string{"(equal kirk spock)"}, []bool{true}, []string{""}},
	{[]string{"(list kirk 1 2)"}, []bool{true}, []string{""}},
	{[]string{"(first (we hold these truths))"}, []bool{true}, []string{"Error! 'we' undefined function"}},
	{[]string{"(first 1 2 3 4)"}, []bool{true}, []string{""}},
	{[]string{"(oddp '(+ 1 2))"}, []bool{false}, []string{"Error! Wrong type input to oddp"}},
	{[]string{"(cons 'a (b c))"}, []bool{false}, []string{"Error! 'b' undefined function"}},
	{[]string{"(cons a (b c))"}, []bool{false}, []string{""}},
	{[]string{"(+ 10 '(- 5 2))"}, []bool{false}, []string{"Error! Wrong type input to +"}},
	{[]string{"(- 10 '(- 5 2))"}, []bool{false}, []string{"Error! Wrong type input to -"}},
}

func TestGolispBad(t *testing.T) {
	for _, test := range baddata {
		i := Init()
		for j := range test.expression {
			e := Parse(test.expression[j])
			p, err := i.Eval(e.(Primitive))
			if test.fail[j] && err == nil {
				t.Errorf("Executing %v has not failed and it should have done: %v -> %v", e.str(), p, p.str())
			}
			if err != nil && test.message[j] != "" {
				if test.message[j] != err.Error() {
					t.Errorf("Error messages don't match %v vs %v", test.message[j], err.Error())
				}
			}
		}
	}
}

func TestGolisp(t *testing.T) {
	for _, test := range testdata {
		i := Init()
		for j := range test.expression {
			e := Parse(test.expression[j])
			r, err := i.Eval(e.(Primitive))
			if err != nil {
				t.Errorf("Executing %v has failed for %v", e.str(), err)
			} else if r.str() != test.result[j] {
				t.Errorf("%v did not lead to %v, it lead to %v", test.expression[j], test.result[j], r.str())
			}
		}
	}
}
<commit_msg>Added test for number 29 and 30. This closes #52.<commit_after>package golisp

import "testing"

var testdata = []struct {
	expression []string
	result     []string
}{
	{[]string{"(+ 2 3)"}, []string{"5"}},
	{[]string{"(+ 1 6)"}, []string{"7"}},
	{[]string{"(oddp (+ 1 6))"}, []string{"t"}},
	{[]string{"(* 3 (+ 1 6))"}, []string{"21"}},
	{[]string{"(/ (* 2 11) (+ 1 6))"}, []string{"22/7"}},
	{[]string{"23"}, []string{"23"}},
	{[]string{"t"}, []string{"t"}},
	{[]string{"nil"}, []string{"nil"}},
	{[]string{"(equal (+ 7 5) (* 2 8))"}, []string{"nil"}},
	{[]string{"(/ (+ 6 8) 2.0)"}, []string{"7.0"}},
	{[]string{"(defun average (x y) (/ (+ x y) 2.0))", "(average 6 8)"}, []string{"nil", "7.0"}},
	{[]string{"(defun square (n) (* n n))", "(square 2)"}, []string{"nil", "4"}},
	{[]string{"(defun total-cost (quantity price handling-charge) (+ (* quantity price) handling-charge))", "(total-cost 2 3 4)"}, []string{"nil", "10"}},
	{[]string{"pi"}, []string{"3.14159"}},
	{[]string{"(equal 'kirk 'spock)"}, []string{"nil"}},
	{[]string{"(list 'james t 'kirk)"}, []string{"(james t kirk)"}},
	{[]string{"(defun riddle (x y) (list 'why 'is 'a x 'like 'a y))", "(riddle 'raven 'writing-desk)"}, []string{"nil", "(why is a raven like a writing-desk)"}},
	{[]string{"(first (list 1 2 3))"}, []string{"1"}},
	{[]string{"(first '(we hold these truths))"}, []string{"we"}},
	{[]string{"'(+ 1 2)"}, []string{"(+ 1 2)"}},
	{[]string{"(oddp (+ 1 2))"}, []string{"t"}},
	{[]string{"(list 'a 'b 'c)"}, []string{"(a b c)"}},
	{[]string{"(cons 'a '(b c))"}, []string{"(a b c)"}},
	{[]string{"(+ 10 (- 5 2))"}, []string{"13"}},
	{[]string{"(list 'buy '(* 27 34) 'bagels)"}, []string{"(buy (* 27 34) bagels)"}},
	{[]string{"(list 'buy (* 27 34) 'bagels)"}, []string{"(buy 918 bagels)"}},
}

var baddata = []struct {
	expression []string
	fail       []bool
	message    []string
}{
	{[]string{"(1 2 3)"}, []bool{true}, []string{""}},
	{[]string{"(defun average (x y) (/ (+ x y) 2.0))", "(average 6 8 7)"}, []bool{false, true}, []string{"", ""}},
	{[]string{"(equal kirk spock)"}, []bool{true}, []string{""}},
	{[]string{"(list kirk 1 2)"}, []bool{true}, []string{""}},
	{[]string{"(first (we hold these truths))"}, []bool{true}, []string{"Error! 'we' undefined function"}},
	{[]string{"(first 1 2 3 4)"}, []bool{true}, []string{""}},
	{[]string{"(oddp '(+ 1 2))"}, []bool{false}, []string{"Error! Wrong type input to oddp"}},
	{[]string{"(cons 'a (b c))"}, []bool{false}, []string{"Error! 'b' undefined function"}},
	{[]string{"(cons a (b c))"}, []bool{false}, []string{""}},
	{[]string{"(+ 10 '(- 5 2))"}, []bool{false}, []string{"Error! Wrong type input to +"}},
	{[]string{"(- 10 '(- 5 2))"}, []bool{false}, []string{"Error! Wrong type input to -"}},
}

func TestGolispBad(t *testing.T) {
	for _, test := range baddata {
		i := Init()
		for j := range test.expression {
			e := Parse(test.expression[j])
			p, err := i.Eval(e.(Primitive))
			if test.fail[j] && err == nil {
				t.Errorf("Executing %v has not failed and it should have done: %v -> %v", e.str(), p, p.str())
			}
			if err != nil && test.message[j] != "" {
				if test.message[j] != err.Error() {
					t.Errorf("Error messages don't match %v vs %v", test.message[j], err.Error())
				}
			}
		}
	}
}

func TestGolisp(t *testing.T) {
	for _, test := range testdata {
		i := Init()
		for j := range test.expression {
			e := Parse(test.expression[j])
			r, err := i.Eval(e.(Primitive))
			if err != nil {
				t.Errorf("Executing %v has failed for %v", e.str(), err)
			} else if r.str() != test.result[j] {
				t.Errorf("%v did not lead to %v, it lead to %v", test.expression[j], test.result[j], r.str())
			}
		}
	}
}
<|endoftext|>


<commit_before>package misspell

import (
	"testing"
)

func TestFalsePositives(t *testing.T) {
	cases := []string{
		"implementor", // alt spelling, see https://github.com/client9/misspell/issues/46
		"searchtypes",
		" witness",
		"returndata",
		"UNDERSTOOD",
		"textinterface",
		" committed ",
		"committed",
		"Bengali",
		"Portuguese",
		"scientists",
		"causally",
		"embarrassing",
		"setuptools", // python package
		"committing",
		"guises",
		"disguise",
		"begging",
		"cmo",
		"cmos",
		"borked",
		"hadn't",
		"Iceweasel",
		"summarised",
		"autorenew",
		"travelling",
		"republished",
		"fallthru",
		"pruning",
		"deb.VersionDontCare",
		"authtag",
		"intrepid",
		"usefully",
		"there",
		"definite",
		"earliest",
		"Japanese",
		"international",
		"excellent",
		"gracefully",
		"carefully",
		"class",
		"include",
		"process",
		"address",
		"attempt",
		"large",
		"although",
		"specific",
		"taste",
		"against",
		"successfully",
		"unsuccessfully",
		"occurred",
		"agree",
		"controlled",
		"publisher",
		"strategy",
		"geoposition",
		"paginated",
		"happened",
		"relative",
		"computing",
		"language",
		"manual",
		"token",
		"into",
		"nothing",
		"datatool",
		"propose",
		"learnt",
		"tolerant",
		"whitehat",
		"monotonic",
		"comprised",
		"indemnity",
		"flattened",
		"interrupted",
		"inotify",
		"occasional",
		"forging",
		"ampersand",
		"decomposition",
		"commit",
		"programmer", // "grammer"
		//		"requestsinserted",
		"seeked",      // technical word
		"bodyreader",  // variable name
		"cantPrepare", // variable name
		"dontPrepare", // variable name
	}
	r := New()
	r.Debug = true
	for casenum, tt := range cases {
		got, _ := r.Replace(tt)
		if got != tt {
			t.Errorf("%d: %q got converted to %q", casenum, tt, got)
		}
	}
}
<commit_msg>add test case for Issue #51<commit_after>package misspell

import (
	"testing"
)

func TestFalsePositives(t *testing.T) {
	cases := []string{
		"Malcom_McLean",
		"implementor", // alt spelling, see https://github.com/client9/misspell/issues/46
		"searchtypes",
		" witness",
		"returndata",
		"UNDERSTOOD",
		"textinterface",
		" committed ",
		"committed",
		"Bengali",
		"Portuguese",
		"scientists",
		"causally",
		"embarrassing",
		"setuptools", // python package
		"committing",
		"guises",
		"disguise",
		"begging",
		"cmo",
		"cmos",
		"borked",
		"hadn't",
		"Iceweasel",
		"summarised",
		"autorenew",
		"travelling",
		"republished",
		"fallthru",
		"pruning",
		"deb.VersionDontCare",
		"authtag",
		"intrepid",
		"usefully",
		"there",
		"definite",
		"earliest",
		"Japanese",
		"international",
		"excellent",
		"gracefully",
		"carefully",
		"class",
		"include",
		"process",
		"address",
		"attempt",
		"large",
		"although",
		"specific",
		"taste",
		"against",
		"successfully",
		"unsuccessfully",
		"occurred",
		"agree",
		"controlled",
		"publisher",
		"strategy",
		"geoposition",
		"paginated",
		"happened",
		"relative",
		"computing",
		"language",
		"manual",
		"token",
		"into",
		"nothing",
		"datatool",
		"propose",
		"learnt",
		"tolerant",
		"whitehat",
		"monotonic",
		"comprised",
		"indemnity",
		"flattened",
		"interrupted",
		"inotify",
		"occasional",
		"forging",
		"ampersand",
		"decomposition",
		"commit",
		"programmer", // "grammer"
		//		"requestsinserted",
		"seeked",      // technical word
		"bodyreader",  // variable name
		"cantPrepare", // variable name
		"dontPrepare", // variable name
	}
	r := New()
	r.Debug = true
	for casenum, tt := range cases {
		got, _ := r.Replace(tt)
		if got != tt {
			t.Errorf("%d: %q got converted to %q", casenum, tt, got)
		}
	}
}
<|endoftext|>


<commit_before>// +build linux freebsd

package container

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/chrootarchive"
	"github.com/docker/docker/pkg/symlink"
	"github.com/docker/docker/pkg/system"
	"github.com/docker/docker/utils"
	"github.com/docker/docker/volume"
	containertypes "github.com/docker/engine-api/types/container"
	"github.com/opencontainers/runc/libcontainer/label"
)

// DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container
const DefaultSHMSize int64 = 67108864

// Container holds the fields specific to unixen implementations.
// See CommonContainer for standard fields common to all containers.
type Container struct {
	CommonContainer

	// Fields below here are platform specific.
	AppArmorProfile string
	HostnamePath    string
	HostsPath       string
	ShmPath         string
	ResolvConfPath  string
	SeccompProfile  string
	NoNewPrivileges bool
}

// ExitStatus provides exit reasons for a container.
type ExitStatus struct {
	// The exit code with which the container exited.
	ExitCode int

	// Whether the container encountered an OOM.
	OOMKilled bool
}

// CreateDaemonEnvironment returns the list of all environment variables given the list of
// environment variables related to links.
// Sets PATH, HOSTNAME and if container.Config.Tty is set: TERM.
// The defaults set here do not override the values in container.Config.Env
func (container *Container) CreateDaemonEnvironment(linkedEnv []string) []string {
	// Setup environment
	env := []string{
		"PATH=" + system.DefaultPathEnv,
		"HOSTNAME=" + container.Config.Hostname,
	}
	if container.Config.Tty {
		env = append(env, "TERM=xterm")
	}
	env = append(env, linkedEnv...)
	// because the env on the container can override certain default values
	// we need to replace the 'env' keys where they match and append anything
	// else.
	env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env)
	return env
}

// TrySetNetworkMount attempts to set the network mounts given a provided destination and
// the path to use for it; return true if the given destination was a network mount file
func (container *Container) TrySetNetworkMount(destination string, path string) bool {
	if destination == "/etc/resolv.conf" {
		container.ResolvConfPath = path
		return true
	}
	if destination == "/etc/hostname" {
		container.HostnamePath = path
		return true
	}
	if destination == "/etc/hosts" {
		container.HostsPath = path
		return true
	}

	return false
}

// BuildHostnameFile writes the container's hostname file.
func (container *Container) BuildHostnameFile() error {
	hostnamePath, err := container.GetRootResourcePath("hostname")
	if err != nil {
		return err
	}
	container.HostnamePath = hostnamePath
	return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
}

// appendNetworkMounts appends any network mounts to the array of mount points passed in
func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
	for _, mnt := range container.NetworkMounts() {
		dest, err := container.GetResourcePath(mnt.Destination)
		if err != nil {
			return nil, err
		}
		volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest})
	}
	return volumeMounts, nil
}

// NetworkMounts returns the list of network mounts.
func (container *Container) NetworkMounts() []Mount {
	var mounts []Mount
	shared := container.HostConfig.NetworkMode.IsContainer()
	if container.ResolvConfPath != "" {
		if _, err := os.Stat(container.ResolvConfPath); err != nil {
			logrus.Warnf("ResolvConfPath set to %q, but can't stat this filename (err = %v); skipping", container.ResolvConfPath, err)
		} else {
			label.Relabel(container.ResolvConfPath, container.MountLabel, shared)
			writable := !container.HostConfig.ReadonlyRootfs
			if m, exists := container.MountPoints["/etc/resolv.conf"]; exists {
				writable = m.RW
			}
			mounts = append(mounts, Mount{
				Source:      container.ResolvConfPath,
				Destination: "/etc/resolv.conf",
				Writable:    writable,
				Propagation: volume.DefaultPropagationMode,
			})
		}
	}
	if container.HostnamePath != "" {
		if _, err := os.Stat(container.HostnamePath); err != nil {
			logrus.Warnf("HostnamePath set to %q, but can't stat this filename (err = %v); skipping", container.HostnamePath, err)
		} else {
			label.Relabel(container.HostnamePath, container.MountLabel, shared)
			writable := !container.HostConfig.ReadonlyRootfs
			if m, exists := container.MountPoints["/etc/hostname"]; exists {
				writable = m.RW
			}
			mounts = append(mounts, Mount{
				Source:      container.HostnamePath,
				Destination: "/etc/hostname",
				Writable:    writable,
				Propagation: volume.DefaultPropagationMode,
			})
		}
	}
	if container.HostsPath != "" {
		if _, err := os.Stat(container.HostsPath); err != nil {
			logrus.Warnf("HostsPath set to %q, but can't stat this filename (err = %v); skipping", container.HostsPath, err)
		} else {
			label.Relabel(container.HostsPath, container.MountLabel, shared)
			writable := !container.HostConfig.ReadonlyRootfs
			if m, exists := container.MountPoints["/etc/hosts"]; exists {
				writable = m.RW
			}
			mounts = append(mounts, Mount{
				Source:      container.HostsPath,
				Destination: "/etc/hosts",
				Writable:    writable,
				Propagation: volume.DefaultPropagationMode,
			})
		}
	}
	return mounts
}

// CopyImagePathContent copies files in destination to the volume.
func (container *Container) CopyImagePathContent(v volume.Volume, destination string) error {
	rootfs, err := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, destination), container.BaseFS)
	if err != nil {
		return err
	}

	if _, err = ioutil.ReadDir(rootfs); err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}

	path, err := v.Mount()
	if err != nil {
		return err
	}
	defer v.Unmount()
	return copyExistingContents(rootfs, path)
}

// ShmResourcePath returns path to shm
func (container *Container) ShmResourcePath() (string, error) {
	return container.GetRootResourcePath("shm")
}

// HasMountFor checks if path is a mountpoint
func (container *Container) HasMountFor(path string) bool {
	_, exists := container.MountPoints[path]
	return exists
}

// UnmountIpcMounts uses the provided unmount function to unmount shm and mqueue if they were mounted
func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
	if container.HostConfig.IpcMode.IsContainer() || container.HostConfig.IpcMode.IsHost() {
		return
	}

	var warnings []string

	if !container.HasMountFor("/dev/shm") {
		shmPath, err := container.ShmResourcePath()
		if err != nil {
			logrus.Error(err)
			warnings = append(warnings, err.Error())
		} else if shmPath != "" {
			if err := unmount(shmPath); err != nil {
				warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", shmPath, err))
			}

		}
	}

	if len(warnings) > 0 {
		logrus.Warnf("failed to cleanup ipc mounts:\n%v", strings.Join(warnings, "\n"))
	}
}

// IpcMounts returns the list of IPC mounts
func (container *Container) IpcMounts() []Mount {
	var mounts []Mount

	if !container.HasMountFor("/dev/shm") {
		label.SetFileLabel(container.ShmPath, container.MountLabel)
		mounts = append(mounts, Mount{
			Source:      container.ShmPath,
			Destination: "/dev/shm",
			Writable:    true,
			Propagation: volume.DefaultPropagationMode,
		})
	}

	return mounts
}

// UpdateContainer updates configuration of a container.
func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfig) error {
	container.Lock()
	defer container.Unlock()

	// update resources of container
	resources := hostConfig.Resources
	cResources := &container.HostConfig.Resources
	if resources.BlkioWeight != 0 {
		cResources.BlkioWeight = resources.BlkioWeight
	}
	if resources.CPUShares != 0 {
		cResources.CPUShares = resources.CPUShares
	}
	if resources.CPUPeriod != 0 {
		cResources.CPUPeriod = resources.CPUPeriod
	}
	if resources.CPUQuota != 0 {
		cResources.CPUQuota = resources.CPUQuota
	}
	if resources.CpusetCpus != "" {
		cResources.CpusetCpus = resources.CpusetCpus
	}
	if resources.CpusetMems != "" {
		cResources.CpusetMems = resources.CpusetMems
	}
	if resources.Memory != 0 {
		cResources.Memory = resources.Memory
	}
	if resources.MemorySwap != 0 {
		cResources.MemorySwap = resources.MemorySwap
	}
	if resources.MemoryReservation != 0 {
		cResources.MemoryReservation = resources.MemoryReservation
	}
	if resources.KernelMemory != 0 {
		cResources.KernelMemory = resources.KernelMemory
	}

	// update HostConfig of container
	if hostConfig.RestartPolicy.Name != "" {
		container.HostConfig.RestartPolicy = hostConfig.RestartPolicy
	}

	if err := container.ToDisk(); err != nil {
		logrus.Errorf("Error saving updated container: %v", err)
		return err
	}

	return nil
}

func detachMounted(path string) error {
	return syscall.Unmount(path, syscall.MNT_DETACH)
}

// UnmountVolumes unmounts all volumes
func (container *Container) UnmountVolumes(forceSyscall bool, volumeEventLog func(name, action string, attributes map[string]string)) error {
	var (
		volumeMounts []volume.MountPoint
		err          error
	)

	for _, mntPoint := range container.MountPoints {
		dest, err := container.GetResourcePath(mntPoint.Destination)
		if err != nil {
			return err
		}

		volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest, Volume: mntPoint.Volume})
	}

	// Append any network mounts to the list (this is a no-op on Windows)
	if volumeMounts, err = appendNetworkMounts(container, volumeMounts); err != nil {
		return err
	}

	for _, volumeMount := range volumeMounts {
		if forceSyscall {
			if err := detachMounted(volumeMount.Destination); err != nil {
				logrus.Warnf("%s unmountVolumes: Failed to do lazy umount %v", container.ID, err)
			}
		}

		if volumeMount.Volume != nil {
			if err := volumeMount.Volume.Unmount(); err != nil {
				return err
			}

			attributes := map[string]string{
				"driver":    volumeMount.Volume.DriverName(),
				"container": container.ID,
			}
			volumeEventLog(volumeMount.Volume.Name(), "unmount", attributes)
		}
	}

	return nil
}

// copyExistingContents copies from the source to the destination and
// ensures the ownership is appropriately set.
func copyExistingContents(source, destination string) error {
	volList, err := ioutil.ReadDir(source)
	if err != nil {
		return err
	}
	if len(volList) > 0 {
		srcList, err := ioutil.ReadDir(destination)
		if err != nil {
			return err
		}
		if len(srcList) == 0 {
			// If the source volume is empty, copies files from the root into the volume
			if err := chrootarchive.CopyWithTar(source, destination); err != nil {
				return err
			}
		}
	}
	return copyOwnership(source, destination)
}

// copyOwnership copies the permissions and uid:gid of the source file
// to the destination file
func copyOwnership(source, destination string) error {
	stat, err := system.Stat(source)
	if err != nil {
		return err
	}

	if err := os.Chown(destination, int(stat.UID()), int(stat.GID())); err != nil {
		return err
	}

	return os.Chmod(destination, os.FileMode(stat.Mode()))
}

// TmpfsMounts returns the list of tmpfs mounts
func (container *Container) TmpfsMounts() []Mount {
	var mounts []Mount
	for dest, data := range container.HostConfig.Tmpfs {
		mounts = append(mounts, Mount{
			Source:      "tmpfs",
			Destination: dest,
			Data:        data,
		})
	}
	return mounts
}

// cleanResourcePath cleans a resource path and prepares to combine with mnt path
func cleanResourcePath(path string) string {
	return filepath.Join(string(os.PathSeparator), path)
}

// canMountFS determines if the file system for the container
// can be mounted locally. A no-op on non-Windows platforms
func (container *Container) canMountFS() bool {
	return true
}
<commit_msg>Don't throw error on clenaup ipc mounts if it does not exists<commit_after>// +build linux freebsd

package container

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/pkg/chrootarchive"
	"github.com/docker/docker/pkg/symlink"
	"github.com/docker/docker/pkg/system"
	"github.com/docker/docker/utils"
	"github.com/docker/docker/volume"
	containertypes "github.com/docker/engine-api/types/container"
	"github.com/opencontainers/runc/libcontainer/label"
)

// DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container
const DefaultSHMSize int64 = 67108864

// Container holds the fields specific to unixen implementations.
// See CommonContainer for standard fields common to all containers.
type Container struct {
	CommonContainer

	// Fields below here are platform specific.
	AppArmorProfile string
	HostnamePath    string
	HostsPath       string
	ShmPath         string
	ResolvConfPath  string
	SeccompProfile  string
	NoNewPrivileges bool
}

// ExitStatus provides exit reasons for a container.
type ExitStatus struct {
	// The exit code with which the container exited.
	ExitCode int

	// Whether the container encountered an OOM.
	OOMKilled bool
}

// CreateDaemonEnvironment returns the list of all environment variables given the list of
// environment variables related to links.
// Sets PATH, HOSTNAME and if container.Config.Tty is set: TERM.
// The defaults set here do not override the values in container.Config.Env
func (container *Container) CreateDaemonEnvironment(linkedEnv []string) []string {
	// Setup environment
	env := []string{
		"PATH=" + system.DefaultPathEnv,
		"HOSTNAME=" + container.Config.Hostname,
	}
	if container.Config.Tty {
		env = append(env, "TERM=xterm")
	}
	env = append(env, linkedEnv...)
	// because the env on the container can override certain default values
	// we need to replace the 'env' keys where they match and append anything
	// else.
	env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env)
	return env
}

// TrySetNetworkMount attempts to set the network mounts given a provided destination and
// the path to use for it; return true if the given destination was a network mount file
func (container *Container) TrySetNetworkMount(destination string, path string) bool {
	if destination == "/etc/resolv.conf" {
		container.ResolvConfPath = path
		return true
	}
	if destination == "/etc/hostname" {
		container.HostnamePath = path
		return true
	}
	if destination == "/etc/hosts" {
		container.HostsPath = path
		return true
	}

	return false
}

// BuildHostnameFile writes the container's hostname file.
func (container *Container) BuildHostnameFile() error {
	hostnamePath, err := container.GetRootResourcePath("hostname")
	if err != nil {
		return err
	}
	container.HostnamePath = hostnamePath
	return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
}

// appendNetworkMounts appends any network mounts to the array of mount points passed in
func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
	for _, mnt := range container.NetworkMounts() {
		dest, err := container.GetResourcePath(mnt.Destination)
		if err != nil {
			return nil, err
		}
		volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest})
	}
	return volumeMounts, nil
}

// NetworkMounts returns the list of network mounts.
func (container *Container) NetworkMounts() []Mount {
	var mounts []Mount
	shared := container.HostConfig.NetworkMode.IsContainer()
	if container.ResolvConfPath != "" {
		if _, err := os.Stat(container.ResolvConfPath); err != nil {
			logrus.Warnf("ResolvConfPath set to %q, but can't stat this filename (err = %v); skipping", container.ResolvConfPath, err)
		} else {
			label.Relabel(container.ResolvConfPath, container.MountLabel, shared)
			writable := !container.HostConfig.ReadonlyRootfs
			if m, exists := container.MountPoints["/etc/resolv.conf"]; exists {
				writable = m.RW
			}
			mounts = append(mounts, Mount{
				Source:      container.ResolvConfPath,
				Destination: "/etc/resolv.conf",
				Writable:    writable,
				Propagation: volume.DefaultPropagationMode,
			})
		}
	}
	if container.HostnamePath != "" {
		if _, err := os.Stat(container.HostnamePath); err != nil {
			logrus.Warnf("HostnamePath set to %q, but can't stat this filename (err = %v); skipping", container.HostnamePath, err)
		} else {
			label.Relabel(container.HostnamePath, container.MountLabel, shared)
			writable := !container.HostConfig.ReadonlyRootfs
			if m, exists := container.MountPoints["/etc/hostname"]; exists {
				writable = m.RW
			}
			mounts = append(mounts, Mount{
				Source:      container.HostnamePath,
				Destination: "/etc/hostname",
				Writable:    writable,
				Propagation: volume.DefaultPropagationMode,
			})
		}
	}
	if container.HostsPath != "" {
		if _, err := os.Stat(container.HostsPath); err != nil {
			logrus.Warnf("HostsPath set to %q, but can't stat this filename (err = %v); skipping", container.HostsPath, err)
		} else {
			label.Relabel(container.HostsPath, container.MountLabel, shared)
			writable := !container.HostConfig.ReadonlyRootfs
			if m, exists := container.MountPoints["/etc/hosts"]; exists {
				writable = m.RW
			}
			mounts = append(mounts, Mount{
				Source:      container.HostsPath,
				Destination: "/etc/hosts",
				Writable:    writable,
				Propagation: volume.DefaultPropagationMode,
			})
		}
	}
	return mounts
}

// CopyImagePathContent copies files in destination to the volume.
func (container *Container) CopyImagePathContent(v volume.Volume, destination string) error {
	rootfs, err := symlink.FollowSymlinkInScope(filepath.Join(container.BaseFS, destination), container.BaseFS)
	if err != nil {
		return err
	}

	if _, err = ioutil.ReadDir(rootfs); err != nil {
		if os.IsNotExist(err) {
			return nil
		}
		return err
	}

	path, err := v.Mount()
	if err != nil {
		return err
	}
	defer v.Unmount()
	return copyExistingContents(rootfs, path)
}

// ShmResourcePath returns path to shm
func (container *Container) ShmResourcePath() (string, error) {
	return container.GetRootResourcePath("shm")
}

// HasMountFor checks if path is a mountpoint
func (container *Container) HasMountFor(path string) bool {
	_, exists := container.MountPoints[path]
	return exists
}

// UnmountIpcMounts uses the provided unmount function to unmount shm and mqueue if they were mounted
func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
	if container.HostConfig.IpcMode.IsContainer() || container.HostConfig.IpcMode.IsHost() {
		return
	}

	var warnings []string

	if !container.HasMountFor("/dev/shm") {
		shmPath, err := container.ShmResourcePath()
		if err != nil {
			logrus.Error(err)
			warnings = append(warnings, err.Error())
		} else if shmPath != "" {
			if err := unmount(shmPath); err != nil && !os.IsNotExist(err) {
				warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", shmPath, err))
			}

		}
	}

	if len(warnings) > 0 {
		logrus.Warnf("failed to cleanup ipc mounts:\n%v", strings.Join(warnings, "\n"))
	}
}

// IpcMounts returns the list of IPC mounts
func (container *Container) IpcMounts() []Mount {
	var mounts []Mount

	if !container.HasMountFor("/dev/shm") {
		label.SetFileLabel(container.ShmPath, container.MountLabel)
		mounts = append(mounts, Mount{
			Source:      container.ShmPath,
			Destination: "/dev/shm",
			Writable:    true,
			Propagation: volume.DefaultPropagationMode,
		})
	}

	return mounts
}

// UpdateContainer updates configuration of a container.
func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfig) error {
	container.Lock()
	defer container.Unlock()

	// update resources of container
	resources := hostConfig.Resources
	cResources := &container.HostConfig.Resources
	if resources.BlkioWeight != 0 {
		cResources.BlkioWeight = resources.BlkioWeight
	}
	if resources.CPUShares != 0 {
		cResources.CPUShares = resources.CPUShares
	}
	if resources.CPUPeriod != 0 {
		cResources.CPUPeriod = resources.CPUPeriod
	}
	if resources.CPUQuota != 0 {
		cResources.CPUQuota = resources.CPUQuota
	}
	if resources.CpusetCpus != "" {
		cResources.CpusetCpus = resources.CpusetCpus
	}
	if resources.CpusetMems != "" {
		cResources.CpusetMems = resources.CpusetMems
	}
	if resources.Memory != 0 {
		cResources.Memory = resources.Memory
	}
	if resources.MemorySwap != 0 {
		cResources.MemorySwap = resources.MemorySwap
	}
	if resources.MemoryReservation != 0 {
		cResources.MemoryReservation = resources.MemoryReservation
	}
	if resources.KernelMemory != 0 {
		cResources.KernelMemory = resources.KernelMemory
	}

	// update HostConfig of container
	if hostConfig.RestartPolicy.Name != "" {
		container.HostConfig.RestartPolicy = hostConfig.RestartPolicy
	}

	if err := container.ToDisk(); err != nil {
		logrus.Errorf("Error saving updated container: %v", err)
		return err
	}

	return nil
}

func detachMounted(path string) error {
	return syscall.Unmount(path, syscall.MNT_DETACH)
}

// UnmountVolumes unmounts all volumes
func (container *Container) UnmountVolumes(forceSyscall bool, volumeEventLog func(name, action string, attributes map[string]string)) error {
	var (
		volumeMounts []volume.MountPoint
		err          error
	)

	for _, mntPoint := range container.MountPoints {
		dest, err := container.GetResourcePath(mntPoint.Destination)
		if err != nil {
			return err
		}

		volumeMounts = append(volumeMounts, volume.MountPoint{Destination: dest, Volume: mntPoint.Volume})
	}

	// Append any network mounts to the list (this is a no-op on Windows)
	if volumeMounts, err = appendNetworkMounts(container, volumeMounts); err != nil {
		return err
	}

	for _, volumeMount := range volumeMounts {
		if forceSyscall {
			if err := detachMounted(volumeMount.Destination); err != nil {
				logrus.Warnf("%s unmountVolumes: Failed to do lazy umount %v", container.ID, err)
			}
		}

		if volumeMount.Volume != nil {
			if err := volumeMount.Volume.Unmount(); err != nil {
				return err
			}

			attributes := map[string]string{
				"driver":    volumeMount.Volume.DriverName(),
				"container": container.ID,
			}
			volumeEventLog(volumeMount.Volume.Name(), "unmount", attributes)
		}
	}

	return nil
}

// copyExistingContents copies from the source to the destination and
// ensures the ownership is appropriately set.
func copyExistingContents(source, destination string) error {
	volList, err := ioutil.ReadDir(source)
	if err != nil {
		return err
	}
	if len(volList) > 0 {
		srcList, err := ioutil.ReadDir(destination)
		if err != nil {
			return err
		}
		if len(srcList) == 0 {
			// If the source volume is empty, copies files from the root into the volume
			if err := chrootarchive.CopyWithTar(source, destination); err != nil {
				return err
			}
		}
	}
	return copyOwnership(source, destination)
}

// copyOwnership copies the permissions and uid:gid of the source file
// to the destination file
func copyOwnership(source, destination string) error {
	stat, err := system.Stat(source)
	if err != nil {
		return err
	}

	if err := os.Chown(destination, int(stat.UID()), int(stat.GID())); err != nil {
		return err
	}

	return os.Chmod(destination, os.FileMode(stat.Mode()))
}

// TmpfsMounts returns the list of tmpfs mounts
func (container *Container) TmpfsMounts() []Mount {
	var mounts []Mount
	for dest, data := range container.HostConfig.Tmpfs {
		mounts = append(mounts, Mount{
			Source:      "tmpfs",
			Destination: dest,
			Data:        data,
		})
	}
	return mounts
}

// cleanResourcePath cleans a resource path and prepares to combine with mnt path
func cleanResourcePath(path string) string {
	return filepath.Join(string(os.PathSeparator), path)
}

// canMountFS determines if the file system for the container
// can be mounted locally. A no-op on non-Windows platforms
func (container *Container) canMountFS() bool {
	return true
}
<|endoftext|>