<commit_before>package cmds

import "os"
import "io"
import "path"
import "errors"
import "strings"
import "net/http"
import "io/ioutil"

import "xogeny/gimpact/utils"

import "github.com/wsxiaoys/terminal/color"
import "github.com/pierrre/archivefile/zip"
import "github.com/opesun/copyrecur"

/* Define a struct listing all command line options for 'install' */
type InstallCommand struct {
	Verbose bool `short:"v" login:"verbose" description:"Turn on verbose output"`
}

func ParseVersion(libver string, index utils.Index) (libname utils.LibraryName,
	ver utils.VersionString, err error) {
	parts := strings.Split(libver, "#");

	libname = utils.LibraryName(parts[0]);

	lib, ok := index[libname];
	if (!ok) {
		err = utils.MissingLibraryError{Name:libname};
		return;
	}

	if (len(parts)==1) {
		version, lerr := lib.Latest();
		if (lerr!=nil) { err = lerr; return; }
		ver = version.Version;
	} else if (len(parts)==2) {
		ver = utils.VersionString(parts[1]);
	} else if (len(parts)>2) {
		err = errors.New("Invalid version specification: "+libver+
			" (must be libraryName#version)");
		return;
	}
	return;
}

func (x *InstallCommand) Execute(args []string) error {
	/* Check to make sure we have something to install */
	if (len(args)==0) {
		return errors.New("No libraries requested for installation");
	}

	/* Build the index */
	index := buildIndex();

	/* Create an empty set of libraries */
	todo := utils.Libraries{};

	/* Loop over all the libraries to be installed */
	for _, arg := range(args) {
		/* Determine the version number requested */
		var libname utils.LibraryName;
		var ver utils.VersionString;

		// TODO: Put all this in a function
		parts := strings.Split(arg, "#");

		libname = utils.LibraryName(parts[0]);

		lib, ok := index[libname];
		if (!ok) {
			return utils.MissingLibraryError{Name:libname};
		}

		if (len(parts)==1) {
			version, err := lib.Latest();
			if (err!=nil) { return err; }
			ver = version.Version;
		} else if (len(parts)==2) {
			ver = utils.VersionString(parts[1]);
		} else if (len(parts)>2) {
			return errors.New("Invalid version specification: "+arg+
				" (must be libraryName#version)");
		}

		/* Get Version objects for this library and all its dependencies */
		deps, err := index.Dependencies(libname, ver);
		if (err!=nil) { return err; }

		/* Merge them with the master list of libraries we are going to install */
		err = todo.Merge(deps);
		if (err!=nil) { return err; }
	}

	/* Loop over all the libraries we have identified for installation and install them */
	for ln, lv := range(todo) {
		if (x.Verbose) {
			color.Println("@!Installing @{c}"+string(ln)+", version "+string(lv.Version));
		}
		ierr := Install(lv, index, ".", x.Verbose);
		if (ierr!=nil) { color.Println("@{r}Error: "+ierr.Error()) };
	}

	return nil;
}

func Install(ver utils.Version,	index utils.Index, target string, verbose bool) error {
	// TODO: Keep a cache

	/* Download the Zipball to a temporary file */
	if (verbose) { color.Println("  @{y}Downloading source from: @{!y}"+string(ver.Zipball)); }
	/*   Do a GET request */
	resp, err := http.Get(ver.Zipball);
	if (err!=nil) { return err; }
	defer resp.Body.Close(); // Make sure this gets closed
	/*   Open a temporary file to direct the download into */
	tzf, err := ioutil.TempFile("", "gimpact");
	defer func() {
		tzf.Close(); // Make sure we close this file and...
		os.Remove(tzf.Name()); // ...delete it.
	}();
	/*   Copy the bytes to temporary file */
	zsize, err := io.Copy(tzf, resp.Body);
	if (err!=nil) { return err; }
	resp.Body.Close();

	/* Create a temporary directory to extract into */
	tdir, err := ioutil.TempDir("", "gimpact");
	defer func() {
		os.RemoveAll(string(tdir)); // Make sure this gets removed in case of a panic
	}()
	if (err!=nil) { return err; }

	/* Extract the zip file into our temporary directory */
	var adir string = "";
	err = zip.Unarchive(tzf, zsize, string(tdir), func(x string) {
		if (adir=="") { adir = strings.Split(x, "/")[0]; }
	})
	if (err!=nil) { return err; }

	/* Figure out where the Modelica code is in our temporary directory */
	keep := path.Join(string(tdir), adir, ver.Path);

	/* Figure out whether we are dealing with a package stored as a file or diretory */
	f, err := os.Open(keep);
	defer f.Close();
	if (err!=nil) { return err; }
	fi, err := f.Stat();
	if (err!=nil) { return err; }
	f.Close();

	/* Copy the Modelica code to our target installation directory */
	if (fi.IsDir()) {
		if (verbose) {
			color.Println("  @{y}Copying  @{!y}"+ver.Path+
				"@{y} to @{!y}"+path.Join(target, fi.Name()));
		}
		copyrecur.CopyDir(keep, path.Join(target, fi.Name()));
	} else {
		if (verbose) {
			color.Println("  @{y}Copying  @{!y}"+ver.Path+
				"@{y} to @{!y}"+path.Join(target, fi.Name()));
		}
		copyrecur.CopyFile(keep, path.Join(target, fi.Name()));
	}

	/* Close and clean up temporary stuff */
	tzf.Close();
	os.Remove(tzf.Name());
	os.RemoveAll(string(tdir));

	return nil;
}
<commit_msg>Moved version parsing into a function<commit_after>package cmds

import "os"
import "io"
import "path"
import "errors"
import "strings"
import "net/http"
import "io/ioutil"

import "xogeny/gimpact/utils"

import "github.com/wsxiaoys/terminal/color"
import "github.com/pierrre/archivefile/zip"
import "github.com/opesun/copyrecur"

/* Define a struct listing all command line options for 'install' */
type InstallCommand struct {
	Verbose bool `short:"v" login:"verbose" description:"Turn on verbose output"`
}

func ParseVersion(libver string, index utils.Index) (libname utils.LibraryName,
	ver utils.VersionString, err error) {
	parts := strings.Split(libver, "#");

	libname = utils.LibraryName(parts[0]);

	lib, ok := index[libname];
	if (!ok) {
		err = utils.MissingLibraryError{Name:libname};
		return;
	}

	if (len(parts)==1) {
		version, lerr := lib.Latest();
		if (lerr!=nil) { err = lerr; return; }
		ver = version.Version;
	} else if (len(parts)==2) {
		ver = utils.VersionString(parts[1]);
	} else if (len(parts)>2) {
		err = errors.New("Invalid version specification: "+libver+
			" (must be libraryName#version)");
		return;
	}
	return;
}

func (x *InstallCommand) Execute(args []string) error {
	/* Check to make sure we have something to install */
	if (len(args)==0) {
		return errors.New("No libraries requested for installation");
	}

	/* Build the index */
	index := buildIndex();

	/* Create an empty set of libraries */
	todo := utils.Libraries{};

	/* Loop over all the libraries to be installed */
	for _, arg := range(args) {
		libname, ver, err := ParseVersion(arg, index);
		if (err!=nil) { return err; }

		/* Get Version objects for this library and all its dependencies */
		deps, err := index.Dependencies(libname, ver);
		if (err!=nil) { return err; }

		/* Merge them with the master list of libraries we are going to install */
		err = todo.Merge(deps);
		if (err!=nil) { return err; }
	}

	/* Loop over all the libraries we have identified for installation and install them */
	for ln, lv := range(todo) {
		if (x.Verbose) {
			color.Println("@!Installing @{c}"+string(ln)+", version "+string(lv.Version));
		}
		ierr := Install(lv, index, ".", x.Verbose);
		if (ierr!=nil) { color.Println("@{r}Error: "+ierr.Error()) };
	}

	return nil;
}

func Install(ver utils.Version,	index utils.Index, target string, verbose bool) error {
	// TODO: Keep a cache

	/* Download the Zipball to a temporary file */
	if (verbose) { color.Println("  @{y}Downloading source from: @{!y}"+string(ver.Zipball)); }
	/*   Do a GET request */
	resp, err := http.Get(ver.Zipball);
	if (err!=nil) { return err; }
	defer resp.Body.Close(); // Make sure this gets closed
	/*   Open a temporary file to direct the download into */
	tzf, err := ioutil.TempFile("", "gimpact");
	defer func() {
		tzf.Close(); // Make sure we close this file and...
		os.Remove(tzf.Name()); // ...delete it.
	}();
	/*   Copy the bytes to temporary file */
	zsize, err := io.Copy(tzf, resp.Body);
	if (err!=nil) { return err; }
	resp.Body.Close();

	/* Create a temporary directory to extract into */
	tdir, err := ioutil.TempDir("", "gimpact");
	defer func() {
		os.RemoveAll(string(tdir)); // Make sure this gets removed in case of a panic
	}()
	if (err!=nil) { return err; }

	/* Extract the zip file into our temporary directory */
	var adir string = "";
	err = zip.Unarchive(tzf, zsize, string(tdir), func(x string) {
		if (adir=="") { adir = strings.Split(x, "/")[0]; }
	})
	if (err!=nil) { return err; }

	/* Figure out where the Modelica code is in our temporary directory */
	keep := path.Join(string(tdir), adir, ver.Path);

	/* Figure out whether we are dealing with a package stored as a file or diretory */
	f, err := os.Open(keep);
	defer f.Close();
	if (err!=nil) { return err; }
	fi, err := f.Stat();
	if (err!=nil) { return err; }
	f.Close();

	/* Copy the Modelica code to our target installation directory */
	if (fi.IsDir()) {
		if (verbose) {
			color.Println("  @{y}Copying  @{!y}"+ver.Path+
				"@{y} to @{!y}"+path.Join(target, fi.Name()));
		}
		copyrecur.CopyDir(keep, path.Join(target, fi.Name()));
	} else {
		if (verbose) {
			color.Println("  @{y}Copying  @{!y}"+ver.Path+
				"@{y} to @{!y}"+path.Join(target, fi.Name()));
		}
		copyrecur.CopyFile(keep, path.Join(target, fi.Name()));
	}

	/* Close and clean up temporary stuff */
	tzf.Close();
	os.Remove(tzf.Name());
	os.RemoveAll(string(tdir));

	return nil;
}
<|endoftext|>


<commit_before>package client

import (
	"encoding/json"
	"fmt"
	"os"
	"time"

	context "golang.org/x/net/context"

	"sync"

	"github.com/ellcrys/util"
	"github.com/ellcrys/cocoon/core/api/api"
	"github.com/ellcrys/cocoon/core/api/api/proto_api"
	"github.com/ellcrys/cocoon/core/common"
	"github.com/ellcrys/cocoon/core/types"
	"github.com/olekukonko/tablewriter"
	"github.com/xeonx/timeago"
)

// MaxBulkObjCount determines the number of bulk objects in commands that perform bulk requests
var MaxBulkObjCount = 25

// CreateCocoon a new cocoon
func CreateCocoon(cocoonPayload *proto_api.ContractRequest) error {

	ss := util.Spinner("Please wait...")
	defer ss()

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
	defer cc()
	cocoonJSON, err := proto_api.NewAPIClient(conn).CreateCocoon(ctx, cocoonPayload)
	if err != nil {
		return err
	}

	var cocoon types.Cocoon
	util.FromJSON(cocoonJSON.Body, &cocoon)

	ss()

	log.Info(`==> New cocoon created`)
	log.Infof(`==> Cocoon ID:  %s`, cocoon.ID)
	log.Infof(`==> Release ID: %s`, cocoon.Releases[0])

	return nil
}

// UpdateCocoon updates a cocoon and optionally creates a new
// release. A new release is created when Release fields are
// set/defined. No release is created if updated release fields match
// existing fields.
func UpdateCocoon(id string, upd *proto_api.ContractRequest) error {

	stopSpinner := util.Spinner("Please wait")

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
	defer cc()
	cl := proto_api.NewAPIClient(conn)
	resp, err := cl.UpdateCocoon(ctx, upd)
	if err != nil {
		if common.CompareErr(err, types.ErrCocoonNotFound) == 0 {
			stopSpinner()
			return fmt.Errorf("Cocoon not found: %s", id)
		}
		stopSpinner()
		return err
	}

	stopSpinner()

	var body map[string]interface{}
	if err = util.FromJSON(resp.Body, &body); err != nil {
		return fmt.Errorf("failed to coerce to map")
	}

	// no new updates was detected or performed.
	if !body["cocoonUpdated"].(bool) && len(body["newReleaseID"].(string)) == 0 {
		log.Info("No change detected. Nothing to do")
		return nil
	}

	log.Info(`==> Update successfully applied`)

	if body["cocoonUpdated"].(bool) {
		log.Infof(`==> Cocoon has been updated`)
	}

	if len(body["newReleaseID"].(string)) != 0 {
		log.Infof(`==> New Release ID: %s`, body["newReleaseID"].(string))
	}

	return nil
}

// GetCocoons fetches one or more cocoons and logs them
func GetCocoons(ids []string) error {

	var cocoons = []types.Cocoon{}
	var err error
	var resp *proto_api.Response

	if len(ids) > MaxBulkObjCount {
		return fmt.Errorf("max number of objects exceeded. Expects a maximum of %d", MaxBulkObjCount)
	}

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	for _, id := range ids {
		stopSpinner := util.Spinner("Please wait")

		ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
		defer cc()
		cl := proto_api.NewAPIClient(conn)
		resp, err = cl.GetCocoon(ctx, &proto_api.GetCocoonRequest{ID: id})
		if err != nil {
			if common.CompareErr(err, types.ErrCocoonNotFound) == 0 {
				stopSpinner()
				err = fmt.Errorf("Cocoon not found: %s", id)
				break
			}
			stopSpinner()
			break
		}

		var cocoon types.Cocoon
		if err = util.FromJSON(resp.Body, &cocoon); err != nil {
			return common.JSONCoerceErr("cocoon", err)
		}

		cocoons = append(cocoons, cocoon)
		stopSpinner()
	}

	bs, _ := json.MarshalIndent(cocoons, "", "   ")
	log.Infof("%s", bs)
	if err != nil {
		return err
	}

	return nil
}

// Deploy creates and sends a deploy request to the server
func deploy(ctx context.Context, cocoonID string, releaseID string) error {

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	client := proto_api.NewAPIClient(conn)
	resp, err := client.Deploy(ctx, &proto_api.DeployRequest{
		CocoonID:  cocoonID,
		ReleaseID: releaseID,
	})
	if err != nil {
		return err
	} else if resp.Status != 200 {
		return fmt.Errorf("%s", resp.Body)
	}

	return nil
}

// ListCocoons fetches and displays running cocoons belonging to
// the logged in user. Set showAll to true to list both running
// and stopped cocoons.
func ListCocoons(showAll, jsonFormatted bool) error {

	var cocoons []types.Cocoon

	stopSpinner := util.Spinner("Please wait")
	defer stopSpinner()

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
	defer cc()
	client := proto_api.NewAPIClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
	defer cancel()

	userSession, err := GetUserSessionToken()
	if err != nil {
		return ErrNoUserSession
	}

	resp, err := client.GetIdentity(ctx, &proto_api.GetIdentityRequest{
		Email: userSession.Email,
	})
	if err != nil {
		stopSpinner()
		return err
	}

	var identity types.Identity
	if err = util.FromJSON(resp.Body, &identity); err != nil {
		stopSpinner()
		return common.JSONCoerceErr("identity", err)
	}

	for _, cid := range identity.Cocoons {

		ctx, cancel = context.WithTimeout(context.Background(), 1*time.Minute)
		defer cancel()
		resp, err = client.GetCocoon(ctx, &proto_api.GetCocoonRequest{
			ID: cid,
		})
		if err != nil {
			stopSpinner()
			return err
		}

		var cocoon types.Cocoon
		if err = util.FromJSON(resp.Body, &cocoon); err != nil {
			stopSpinner()
			return common.JSONCoerceErr("cocoon", err)
		}

		cocoons = append(cocoons, cocoon)
	}

	stopSpinner()

	if jsonFormatted {
		bs, _ := json.MarshalIndent(cocoons, "", "   ")
		log.Info("%s", bs)
		return nil
	}

	tableData := [][]string{}
	for _, cocoon := range cocoons {
		if !showAll && !util.InStringSlice([]string{api.CocoonStatusStarted, api.CocoonStatusBuilding, api.CocoonStatusRunning}, cocoon.Status) {
			continue
		}
		created, _ := time.Parse(time.RFC3339, cocoon.CreatedAt)
		tableData = append(tableData, []string{
			cocoon.ID,
			cocoon.Releases[len(cocoon.Releases)-1],
			common.CapitalizeString(timeago.English.Format(created)),
			common.CapitalizeString(cocoon.Status),
		})
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"COCOON ID", "RELEASE ID (LATEST)", "CREATED", "STATUS"})
	table.SetBorder(false)
	table.SetHeaderLine(false)
	table.AppendBulk(tableData)
	table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
	table.Render()

	return nil
}

// StopCocoon one or more running cocoon codes
func StopCocoon(ids []string) error {

	if len(ids) > MaxBulkObjCount {
		return fmt.Errorf("max number of objects exceeded. Expects a maximum of %d", MaxBulkObjCount)
	}

	var errs []error
	var stopped []string

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	cl := proto_api.NewAPIClient(conn)
	stopSpinner := util.Spinner("Please wait")

	for _, id := range ids {

		ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
		defer cc()
		_, err = cl.StopCocoon(ctx, &proto_api.StopCocoonRequest{ID: id})
		if err != nil {
			stopSpinner()
			return err
		}

		stopped = append(stopped, id)
	}

	stopSpinner()

	for _, id := range stopped {
		log.Info(id)
	}
	for _, err := range errs {
		log.Infof("Err: %s", err.Error())
	}

	return nil
}

// Start starts one or more new or stopped cocoon code.
// If releaseID is set, the release is executed as opposed to
// the latest release being executed
func Start(ids []string, releaseID string) error {

	var errs []error
	var started []string
	var muErr = sync.Mutex{}
	var muStarted = sync.Mutex{}
	var wg = sync.WaitGroup{}

	if len(ids) > MaxBulkObjCount {
		return fmt.Errorf("max number of objects exceeded. Expects a maximum of %d", MaxBulkObjCount)
	}

	stopSpinner := util.Spinner("Please wait")

	for _, id := range ids {
		id := id
		wg.Add(1)
		go func() {
			ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
			defer cc()
			if err := deploy(ctx, id, releaseID); err != nil {
				muErr.Lock()
				errs = append(errs, fmt.Errorf("%s: %s", common.GetShortID(id), common.GetRPCErrDesc(err)))
				muErr.Unlock()
			} else {
				muStarted.Lock()
				started = append(started, id)
				muStarted.Unlock()
			}
			wg.Done()
		}()
	}

	wg.Wait()
	stopSpinner()

	if len(started) > 0 {
		log.Info("==> Successfully deployed the following:")
		for i, id := range started {
			log.Infof("==> %d. %s", i+1, id)
		}
	}

	for _, err := range errs {
		log.Infof(common.GetRPCErrDesc(err))
	}

	return nil
}

// AddSignatories adds one or more valid identities to a cocoon's signatory list.
// All valid identities are included and invalid ones will produce an error log..
func AddSignatories(cocoonID string, ids []string) error {

	if len(ids) > MaxBulkObjCount {
		return fmt.Errorf("max number of objects exceeded. Expects a maximum of %d", MaxBulkObjCount)
	}

	stopSpinner := util.Spinner("Please wait")
	defer stopSpinner()

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
	defer cc()
	cl := proto_api.NewAPIClient(conn)
	resp, err := cl.AddSignatories(ctx, &proto_api.AddSignatoriesRequest{
		CocoonID: cocoonID,
		IDs:      ids,
	})

	stopSpinner()

	if err != nil {
		return err
	}

	var r map[string][]string
	util.FromJSON(resp.Body, &r)

	if len(r["added"]) == 0 {
		log.Info("No new signatory was added")
	} else if len(r["added"]) == 1 {
		log.Info(`==> Successfully added a signatory:`)
	} else {
		log.Info(`==> Successfully added the following signatories:`)
	}

	for i, id := range r["added"] {
		log.Infof(`==> %d. %s`, i+1, id)
	}

	for _, e := range r["errs"] {
		log.Info("Err:", e)
	}

	return nil
}

// RemoveSignatories removes one or more signatories of a cocoon.
func RemoveSignatories(cocoonID string, ids []string) error {

	if len(ids) > MaxBulkObjCount {
		return fmt.Errorf("max number of objects exceeded. Expects a maximum of %d", MaxBulkObjCount)
	}

	stopSpinner := util.Spinner("Please wait")
	defer stopSpinner()

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
	defer cc()

	cl := proto_api.NewAPIClient(conn)
	_, err = cl.RemoveSignatories(ctx, &proto_api.RemoveSignatoriesRequest{
		CocoonID: cocoonID,
		IDs:      ids,
	})

	stopSpinner()

	if err != nil {
		return err
	}

	log.Info("Done.")
	return nil
}

// FirewallAllow adds a firewall rule to allow connection to an outgoing destination
func FirewallAllow(dest, port, protocol string) error {
	return nil
}
<commit_msg>fixed path<commit_after>package client

import (
	"encoding/json"
	"fmt"
	"os"
	"time"

	context "golang.org/x/net/context"

	"sync"

	"github.com/ellcrys/cocoon/core/api/api"
	"github.com/ellcrys/cocoon/core/api/api/proto_api"
	"github.com/ellcrys/cocoon/core/common"
	"github.com/ellcrys/cocoon/core/types"
	"github.com/ellcrys/util"
	"github.com/olekukonko/tablewriter"
	"github.com/xeonx/timeago"
)

// MaxBulkObjCount determines the number of bulk objects in commands that perform bulk requests
var MaxBulkObjCount = 25

// CreateCocoon a new cocoon
func CreateCocoon(cocoonPayload *proto_api.ContractRequest) error {

	ss := util.Spinner("Please wait...")
	defer ss()

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
	defer cc()
	cocoonJSON, err := proto_api.NewAPIClient(conn).CreateCocoon(ctx, cocoonPayload)
	if err != nil {
		return err
	}

	var cocoon types.Cocoon
	util.FromJSON(cocoonJSON.Body, &cocoon)

	ss()

	log.Info(`==> New cocoon created`)
	log.Infof(`==> Cocoon ID:  %s`, cocoon.ID)
	log.Infof(`==> Release ID: %s`, cocoon.Releases[0])

	return nil
}

// UpdateCocoon updates a cocoon and optionally creates a new
// release. A new release is created when Release fields are
// set/defined. No release is created if updated release fields match
// existing fields.
func UpdateCocoon(id string, upd *proto_api.ContractRequest) error {

	stopSpinner := util.Spinner("Please wait")

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
	defer cc()
	cl := proto_api.NewAPIClient(conn)
	resp, err := cl.UpdateCocoon(ctx, upd)
	if err != nil {
		if common.CompareErr(err, types.ErrCocoonNotFound) == 0 {
			stopSpinner()
			return fmt.Errorf("Cocoon not found: %s", id)
		}
		stopSpinner()
		return err
	}

	stopSpinner()

	var body map[string]interface{}
	if err = util.FromJSON(resp.Body, &body); err != nil {
		return fmt.Errorf("failed to coerce to map")
	}

	// no new updates was detected or performed.
	if !body["cocoonUpdated"].(bool) && len(body["newReleaseID"].(string)) == 0 {
		log.Info("No change detected. Nothing to do")
		return nil
	}

	log.Info(`==> Update successfully applied`)

	if body["cocoonUpdated"].(bool) {
		log.Infof(`==> Cocoon has been updated`)
	}

	if len(body["newReleaseID"].(string)) != 0 {
		log.Infof(`==> New Release ID: %s`, body["newReleaseID"].(string))
	}

	return nil
}

// GetCocoons fetches one or more cocoons and logs them
func GetCocoons(ids []string) error {

	var cocoons = []types.Cocoon{}
	var err error
	var resp *proto_api.Response

	if len(ids) > MaxBulkObjCount {
		return fmt.Errorf("max number of objects exceeded. Expects a maximum of %d", MaxBulkObjCount)
	}

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	for _, id := range ids {
		stopSpinner := util.Spinner("Please wait")

		ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
		defer cc()
		cl := proto_api.NewAPIClient(conn)
		resp, err = cl.GetCocoon(ctx, &proto_api.GetCocoonRequest{ID: id})
		if err != nil {
			if common.CompareErr(err, types.ErrCocoonNotFound) == 0 {
				stopSpinner()
				err = fmt.Errorf("Cocoon not found: %s", id)
				break
			}
			stopSpinner()
			break
		}

		var cocoon types.Cocoon
		if err = util.FromJSON(resp.Body, &cocoon); err != nil {
			return common.JSONCoerceErr("cocoon", err)
		}

		cocoons = append(cocoons, cocoon)
		stopSpinner()
	}

	bs, _ := json.MarshalIndent(cocoons, "", "   ")
	log.Infof("%s", bs)
	if err != nil {
		return err
	}

	return nil
}

// Deploy creates and sends a deploy request to the server
func deploy(ctx context.Context, cocoonID string, releaseID string) error {

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	client := proto_api.NewAPIClient(conn)
	resp, err := client.Deploy(ctx, &proto_api.DeployRequest{
		CocoonID:  cocoonID,
		ReleaseID: releaseID,
	})
	if err != nil {
		return err
	} else if resp.Status != 200 {
		return fmt.Errorf("%s", resp.Body)
	}

	return nil
}

// ListCocoons fetches and displays running cocoons belonging to
// the logged in user. Set showAll to true to list both running
// and stopped cocoons.
func ListCocoons(showAll, jsonFormatted bool) error {

	var cocoons []types.Cocoon

	stopSpinner := util.Spinner("Please wait")
	defer stopSpinner()

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
	defer cc()
	client := proto_api.NewAPIClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
	defer cancel()

	userSession, err := GetUserSessionToken()
	if err != nil {
		return ErrNoUserSession
	}

	resp, err := client.GetIdentity(ctx, &proto_api.GetIdentityRequest{
		Email: userSession.Email,
	})
	if err != nil {
		stopSpinner()
		return err
	}

	var identity types.Identity
	if err = util.FromJSON(resp.Body, &identity); err != nil {
		stopSpinner()
		return common.JSONCoerceErr("identity", err)
	}

	for _, cid := range identity.Cocoons {

		ctx, cancel = context.WithTimeout(context.Background(), 1*time.Minute)
		defer cancel()
		resp, err = client.GetCocoon(ctx, &proto_api.GetCocoonRequest{
			ID: cid,
		})
		if err != nil {
			stopSpinner()
			return err
		}

		var cocoon types.Cocoon
		if err = util.FromJSON(resp.Body, &cocoon); err != nil {
			stopSpinner()
			return common.JSONCoerceErr("cocoon", err)
		}

		cocoons = append(cocoons, cocoon)
	}

	stopSpinner()

	if jsonFormatted {
		bs, _ := json.MarshalIndent(cocoons, "", "   ")
		log.Info("%s", bs)
		return nil
	}

	tableData := [][]string{}
	for _, cocoon := range cocoons {
		if !showAll && !util.InStringSlice([]string{api.CocoonStatusStarted, api.CocoonStatusBuilding, api.CocoonStatusRunning}, cocoon.Status) {
			continue
		}
		created, _ := time.Parse(time.RFC3339, cocoon.CreatedAt)
		tableData = append(tableData, []string{
			cocoon.ID,
			cocoon.Releases[len(cocoon.Releases)-1],
			common.CapitalizeString(timeago.English.Format(created)),
			common.CapitalizeString(cocoon.Status),
		})
	}

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"COCOON ID", "RELEASE ID (LATEST)", "CREATED", "STATUS"})
	table.SetBorder(false)
	table.SetHeaderLine(false)
	table.AppendBulk(tableData)
	table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
	table.Render()

	return nil
}

// StopCocoon one or more running cocoon codes
func StopCocoon(ids []string) error {

	if len(ids) > MaxBulkObjCount {
		return fmt.Errorf("max number of objects exceeded. Expects a maximum of %d", MaxBulkObjCount)
	}

	var errs []error
	var stopped []string

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	cl := proto_api.NewAPIClient(conn)
	stopSpinner := util.Spinner("Please wait")

	for _, id := range ids {

		ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
		defer cc()
		_, err = cl.StopCocoon(ctx, &proto_api.StopCocoonRequest{ID: id})
		if err != nil {
			stopSpinner()
			return err
		}

		stopped = append(stopped, id)
	}

	stopSpinner()

	for _, id := range stopped {
		log.Info(id)
	}
	for _, err := range errs {
		log.Infof("Err: %s", err.Error())
	}

	return nil
}

// Start starts one or more new or stopped cocoon code.
// If releaseID is set, the release is executed as opposed to
// the latest release being executed
func Start(ids []string, releaseID string) error {

	var errs []error
	var started []string
	var muErr = sync.Mutex{}
	var muStarted = sync.Mutex{}
	var wg = sync.WaitGroup{}

	if len(ids) > MaxBulkObjCount {
		return fmt.Errorf("max number of objects exceeded. Expects a maximum of %d", MaxBulkObjCount)
	}

	stopSpinner := util.Spinner("Please wait")

	for _, id := range ids {
		id := id
		wg.Add(1)
		go func() {
			ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
			defer cc()
			if err := deploy(ctx, id, releaseID); err != nil {
				muErr.Lock()
				errs = append(errs, fmt.Errorf("%s: %s", common.GetShortID(id), common.GetRPCErrDesc(err)))
				muErr.Unlock()
			} else {
				muStarted.Lock()
				started = append(started, id)
				muStarted.Unlock()
			}
			wg.Done()
		}()
	}

	wg.Wait()
	stopSpinner()

	if len(started) > 0 {
		log.Info("==> Successfully deployed the following:")
		for i, id := range started {
			log.Infof("==> %d. %s", i+1, id)
		}
	}

	for _, err := range errs {
		log.Infof(common.GetRPCErrDesc(err))
	}

	return nil
}

// AddSignatories adds one or more valid identities to a cocoon's signatory list.
// All valid identities are included and invalid ones will produce an error log..
func AddSignatories(cocoonID string, ids []string) error {

	if len(ids) > MaxBulkObjCount {
		return fmt.Errorf("max number of objects exceeded. Expects a maximum of %d", MaxBulkObjCount)
	}

	stopSpinner := util.Spinner("Please wait")
	defer stopSpinner()

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
	defer cc()
	cl := proto_api.NewAPIClient(conn)
	resp, err := cl.AddSignatories(ctx, &proto_api.AddSignatoriesRequest{
		CocoonID: cocoonID,
		IDs:      ids,
	})

	stopSpinner()

	if err != nil {
		return err
	}

	var r map[string][]string
	util.FromJSON(resp.Body, &r)

	if len(r["added"]) == 0 {
		log.Info("No new signatory was added")
	} else if len(r["added"]) == 1 {
		log.Info(`==> Successfully added a signatory:`)
	} else {
		log.Info(`==> Successfully added the following signatories:`)
	}

	for i, id := range r["added"] {
		log.Infof(`==> %d. %s`, i+1, id)
	}

	for _, e := range r["errs"] {
		log.Info("Err:", e)
	}

	return nil
}

// RemoveSignatories removes one or more signatories of a cocoon.
func RemoveSignatories(cocoonID string, ids []string) error {

	if len(ids) > MaxBulkObjCount {
		return fmt.Errorf("max number of objects exceeded. Expects a maximum of %d", MaxBulkObjCount)
	}

	stopSpinner := util.Spinner("Please wait")
	defer stopSpinner()

	conn, err := GetAPIConnection()
	if err != nil {
		return fmt.Errorf("unable to connect to the platform")
	}
	defer conn.Close()

	ctx, cc := context.WithTimeout(context.Background(), ContextTimeout)
	defer cc()

	cl := proto_api.NewAPIClient(conn)
	_, err = cl.RemoveSignatories(ctx, &proto_api.RemoveSignatoriesRequest{
		CocoonID: cocoonID,
		IDs:      ids,
	})

	stopSpinner()

	if err != nil {
		return err
	}

	log.Info("Done.")
	return nil
}

// FirewallAllow adds a firewall rule to allow connection to an outgoing destination
func FirewallAllow(dest, port, protocol string) error {
	return nil
}
<|endoftext|>


<commit_before>package p5r

// MatchString return true if the string matches the regex
// Returns false if an error/timeout occurs
func (re *Regexp) MatchString(s string) bool {
	m, err := re.run(true, -1, getRunes(s))
	if err != nil {
		return false
	}
	return m != nil
}

// ReplaceAllString returns a modified string if the replacement worked
// Returns the original string if an error occured
func (re *Regexp) ReplaceAllString(input, replacement string) string {
	output, err := re.Replace(input, replacement, -1, -1)
	if err != nil {
		// Return the original string if something went wrong
		return input
	}
	// Return the string with replacements
	return output
}

func MustCompile(input string) *Regexp {
	return MustCompile2(input, 0)
}
<commit_msg>Add compatability function<commit_after>package p5r

// Compatability functions for the "regexp" package

// MatchString return true if the string matches the regex
// Returns false if an error/timeout occurs
func (re *Regexp) MatchString(s string) bool {
	m, err := re.run(true, -1, getRunes(s))
	if err != nil {
		return false
	}
	return m != nil
}

// ReplaceAllString returns a modified string if the replacement worked
// Returns the original string if an error occured
func (re *Regexp) ReplaceAllString(input, replacement string) string {
	output, err := re.Replace(input, replacement, -1, -1)
	if err != nil {
		// Return the original string if something went wrong
		return input
	}
	// Return the string with replacements
	return output
}

func MustCompile(input string) *Regexp {
	return MustCompile2(input, 0)
}

func Compile(input string) (*Regexp, error) {
	return Compile2(input, 0)
}
<|endoftext|>


<commit_before>package main

import(
	"fmt"
	"./minesweeper"
)

func main() {
	fmt.Println("Minesweeper");

	var playBoard minesweeper.Board;

	minesweeper.PlayGame(&playBoard);
}<commit_msg>Deleted old version og Go Minesweeper<commit_after><|endoftext|>


<commit_before>// gobar
// Copyright (C) 2014 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

package main

import (
	"encoding/xml"
	"errors"
	"fmt"
	"image"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"code.google.com/p/jamslam-freetype-go/freetype/truetype"

	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/ewmh"
	"github.com/BurntSushi/xgbutil/xevent"
	"github.com/BurntSushi/xgbutil/xgraphics"
	"github.com/BurntSushi/xgbutil/xinerama"
	"github.com/BurntSushi/xgbutil/xrect"
	"github.com/BurntSushi/xgbutil/xwindow"

	"github.com/docopt/docopt-go"
)

// fatal is a helper function to call when something terribly wrong
// had happened. Logs given error and terminates application.
func fatal(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

// Position defines bar placement on the screen.
type Position uint8

const (
	BOTTOM Position = iota
	TOP
)

// Font stores font definition along with it's loaded truetype struct.
type Font struct {
	Path string
	Size float64
	Font *truetype.Font
}

// FindFontError is returned when FindFontPath fails to fint any usable fonts.
type FindFontError struct {
	Action string
	Orig   error
}

func (f FindFontError) Error() string {
	return fmt.Sprintf("[fontconfig] Could not %s. Got `%s`", f.Action, f.Orig)
}

// FindFontPath tries hard to find any usable font(s) in the system.
// It does so by parsing fontconfig configuration and looking through
// the specified directories for anything that could possibly by used
// by freetype font parser.
func FindFontPath() (string, error) {
	log.Print("Trying to find usable font")

	fontsConf, err := os.Open("/etc/fonts/fonts.conf")
	if err != nil {
		return "", FindFontError{"open file", err}
	}
	defer fontsConf.Close()

	result := struct {
		Dirs []string `xml:"dir"`
	}{}
	decoder := xml.NewDecoder(fontsConf)
	if err := decoder.Decode(&result); err != nil {
		return "", FindFontError{"decode file", err}
	}

	for _, dir := range result.Dirs {
		files, err := filepath.Glob(fmt.Sprintf("%s/TTF/*.ttf", dir))
		if err == nil && files != nil {
			return files[0], nil
		}
	}
	return "", FindFontError{"find font files", err}
}

// FontError is returned when NewFont fails to create a font.
type FontError struct {
	Path string
	Orig error
}

func (f FontError) Error() string {
	return fmt.Sprintf("Could not open font `%s`. Got `%s`", f.Path, f.Orig)
}

// NewFont opens a font file and parses it with truetype engine.
func NewFont(path string, size float64) (*Font, error) {
	fontReader, err := os.Open(path)
	if err != nil {
		return nil, FontError{path, err}
	}
	defer fontReader.Close()

	font, err := xgraphics.ParseFont(fontReader)
	if err != nil {
		return nil, FontError{path, err}
	}
	return &Font{path, size, font}, nil
}

// Geometry stores bars geometry on the screen (or actually monitor).
type Geometry struct {
	Width  uint16
	Height uint16
	X      uint16
	Y      uint16
}

// NewGeometry parses geometry from textual definition.
// Input should be formatted as <width>x<height>+<x>+<y>.
// A special "M" value is allowed as <width>, to represent 100%.
func NewGeometry(geostr string, head xrect.Rect, position Position) *Geometry {
	geometry := Geometry{}
	var widthS string
	_, err := fmt.Sscanf(
		geostr, "%1sx%d+%d+%d",
		&widthS, &geometry.Height, &geometry.X, &geometry.Y,
	)

	geometry.X += uint16(head.X())

	hwidth := uint16(head.Width())
	hheight := uint16(head.Height())
	if err != nil {
		log.Print("bad geometry, ", geometry, ", using default")
		geometry.Width = hwidth - (geometry.X - uint16(head.X()))
		geometry.Height = 16
	} else {
		width, err := strconv.Atoi(widthS)
		if err != nil {
			if widthS != "M" {
				// Make people feel guilty
				log.Print("wrong geometry width")
			}
			geometry.Width = hwidth - (geometry.X - uint16(head.X()))
		} else {
			geometry.Width = uint16(width)
		}
	}

	if position == BOTTOM {
		geometry.Y = uint16(head.Y()) + hheight - geometry.Height - geometry.Y
	}

	return &geometry
}

// Bar stores and manages all X related stuff and configuration.
type Bar struct {
	X          *xgbutil.XUtil
	Windows    []*xwindow.Window
	Geometries []*Geometry
	Foreground *xgraphics.BGRA
	Background *xgraphics.BGRA
	Colors     []*xgraphics.BGRA
	Fonts      []*Font
}

// NewBar creates X windows for every monitor.
// Also sets proper EWMH information for docked windows.
func NewBar(
	X *xgbutil.XUtil, geometries []*Geometry, position Position,
	fg uint64, bg uint64, fonts []*Font,
) *Bar {
	windows := make([]*xwindow.Window, len(geometries))
	for i, geometry := range geometries {
		win, err := xwindow.Generate(X)
		fatal(err)
		win.Create(
			X.RootWin(),
			int(geometry.X), int(geometry.Y),
			int(geometry.Width), int(geometry.Height),
			0,
		)

		ewmh.WmWindowTypeSet(X, win.Id, []string{"_NET_WM_WINDOW_TYPE_DOCK"})
		ewmh.WmStateSet(X, win.Id, []string{"_NET_WM_STATE_STICKY"})
		ewmh.WmDesktopSet(X, win.Id, 0xFFFFFFFF)
		strutP := ewmh.WmStrutPartial{}
		strut := ewmh.WmStrut{}
		if position == BOTTOM {
			strutP.BottomStartX = uint(geometry.X)
			strutP.BottomEndX = uint(geometry.X + geometry.Height)
			strutP.Bottom = uint(geometry.Height)
			strut.Bottom = uint(geometry.Height)
		} else {
			strutP.TopStartX = uint(geometry.X)
			strutP.TopEndX = uint(geometry.X + geometry.Height)
			strutP.Top = uint(geometry.Height)
			strut.Top = uint(geometry.Height)
		}
		ewmh.WmStrutPartialSet(X, win.Id, &strutP)
		ewmh.WmStrutSet(X, win.Id, &strut)

		windows[i] = win
	}

	return &Bar{
		X:          X,
		Windows:    windows,
		Geometries: geometries,
		Foreground: NewBGRA(fg),
		Background: NewBGRA(bg),
		Fonts:      fonts,
	}
}

// Draw draws TextPieces into X monitors.
func (self *Bar) Draw(text []*TextPiece) {
	imgs := make([]*xgraphics.Image, len(self.Windows))
	for i, geometry := range self.Geometries {
		imgs[i] = xgraphics.New(self.X, image.Rect(
			0, 0, int(geometry.Width), int(geometry.Height),
		))
		imgs[i].For(func(x, y int) xgraphics.BGRA { return *self.Background })
	}

	xsl := make([]int, len(self.Windows))
	xsr := make([]int, len(self.Windows))
	for i := range xsr {
		xsr[i] = int(self.Geometries[i].Width)
	}
	for _, piece := range text {
		if piece.Background == nil {
			piece.Background = self.Background
		}
		if piece.Foreground == nil {
			piece.Foreground = self.Foreground
		}

		font := self.Fonts[piece.Font]
		width, _ := xgraphics.Extents(font.Font, font.Size, piece.Text)

		screens := piece.Screens
		if screens == nil {
			screens = make([]uint, len(imgs))
			for i := range imgs {
				screens[i] = uint(i)
			}
		}

		for _, screen := range screens {
			xs := xsl[screen]
			if piece.Align == RIGHT {
				xs = xsr[screen] - width
			}

			subimg := imgs[screen].SubImage(image.Rect(
				xs, 0, xs+width, int(self.Geometries[screen].Height),
			))
			subimg.For(func(x, y int) xgraphics.BGRA { return *piece.Background })

			new_xs, _, err := subimg.Text(
				xs, 0, piece.Foreground, font.Size, font.Font, piece.Text,
			)
			if err != nil {
				log.Print(err) // TODO: Better logging
			}

			if piece.Align == LEFT {
				xsl[screen] = new_xs
			} else if piece.Align == RIGHT {
				xsr[screen] -= width
			}

			subimg.XPaint(self.Windows[screen].Id)
			subimg.Destroy()
		}
	}

	for i, img := range imgs {
		img.XSurfaceSet(self.Windows[i].Id)
		img.XDraw()
		img.Destroy()

		self.Windows[i].Map()
	}
}

// main gets command line arguments, creates X connection and initializes Bar.
// This is also where X event loop and Stdin reading lies.
func main() {
	cli := `gobar.

Usage:
  gobar [options]
  gobar -h | --help
  gobar --version

Options:
  -h --help              Show this screen.
  --bottom               Place bar at the bottom of the screen.
  --geometry=<GEOMETRY>  Comma separated list of monitor geometries in form of
                         <w>x<h>+<x>+<y>. If not specified, uses Mx16+0+0 for each screen.
                         M is a special case for <w> only, taking all available space.
  --fonts=<FONTS>        Comma seperated list of fonts in form of path:size.
                         Defaults to whatever it can find in fontconfig configuration.
  --fg=<COLOR>           Foreground color (0xAARRGGBB) [default: 0xFFFFFFFF].
  --bg=<COLOR>           Background color (0xAARRGGBB) [default: 0xFF000000].
	`

	arguments, err := docopt.Parse(cli, nil, true, "", false)
	fatal(err)
	fgColor, err := strconv.ParseUint(arguments["--fg"].(string), 0, 32)
	fatal(err)
	bgColor, err := strconv.ParseUint(arguments["--bg"].(string), 0, 32)
	fatal(err)
	bottom := arguments["--bottom"].(bool)
	position := TOP
	if bottom {
		position = BOTTOM
	}

	fontSpecs := []string{}
	if arguments["--fonts"] != nil {
		fontSpecs = strings.Split(arguments["--fonts"].(string), ",")
	}
	fonts := make([]*Font, 0, len(fontSpecs))
	for _, fontSpec := range fontSpecs {
		fontSpecSplit := strings.Split(fontSpec, ":")
		fontPath := fontSpecSplit[0]
		fontSize, _ := strconv.ParseFloat(fontSpecSplit[1], 32)
		font, err := NewFont(fontPath, fontSize)
		if err != nil {
			log.Print(err)
			if len(fonts) > 0 {
				log.Print("Using font at index 0")
				font, err = fonts[0], nil
			} else {
				fontPath, err := FindFontPath()
				if err != nil {
					log.Print(err)
				} else {
					font, err = NewFont(fontPath, fontSize)
				}
			}
		}
		if err != nil {
			log.Print(err)
		} else {
			fonts = append(fonts, font)
		}
	}
	if len(fonts) == 0 {
		fontPath, err := FindFontPath()
		if err != nil {
			fatal(errors.New("No usable fonts found, bailing out"))
		}

		font, err := NewFont(fontPath, 12)
		if err != nil {
			fatal(errors.New("No usable fonts found, bailing out"))
		}
		fonts = append(fonts, font)
	}

	X, err := xgbutil.NewConn()
	fatal(err)
	heads, err := xinerama.PhysicalHeads(X)
	fatal(err)

	geometryStr := arguments["--geometry"]
	var geometrySpec []string
	if geometryStr != nil {
		geometrySpec = strings.Split(geometryStr.(string), ",")
	}
	if len(geometrySpec) < len(heads) {
		for i := len(geometrySpec); i < len(heads); i++ {
			geometrySpec = append(
				geometrySpec, "Mx16+0+0",
			)
		}
	}

	geometries := make([]*Geometry, len(heads))
	for i, head := range heads {
		geometries[i] = NewGeometry(geometrySpec[i], head, position)
	}

	bar := NewBar(X, geometries, position, fgColor, bgColor, fonts)
	parser := NewTextParser()

	stdin := make(chan []*TextPiece, 0)
	go func() {
		defer close(stdin)

		for {
			parsed, err := parser.Scan(os.Stdin)
			if err != nil {
				log.Print(err) //TODO: Better logging
				continue
			}
			stdin <- parsed
		}
	}()

	pingBefore, pingAfter, pingQuit := xevent.MainPing(X)
	for {
		select {
		case <-pingBefore:
			<-pingAfter
		case text := <-stdin:
			bar.Draw(text)
		case <-pingQuit:
			return
		}
	}
}
<commit_msg>wrong color specification is not fatal<commit_after>// gobar
// Copyright (C) 2014 Karol 'Kenji Takahashi' Woźniak
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

package main

import (
	"encoding/xml"
	"errors"
	"fmt"
	"image"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"code.google.com/p/jamslam-freetype-go/freetype/truetype"

	"github.com/BurntSushi/xgbutil"
	"github.com/BurntSushi/xgbutil/ewmh"
	"github.com/BurntSushi/xgbutil/xevent"
	"github.com/BurntSushi/xgbutil/xgraphics"
	"github.com/BurntSushi/xgbutil/xinerama"
	"github.com/BurntSushi/xgbutil/xrect"
	"github.com/BurntSushi/xgbutil/xwindow"

	"github.com/docopt/docopt-go"
)

// fatal is a helper function to call when something terribly wrong
// had happened. Logs given error and terminates application.
func fatal(err error) {
	if err != nil {
		log.Fatal(err)
	}
}

// Position defines bar placement on the screen.
type Position uint8

const (
	BOTTOM Position = iota
	TOP
)

// Font stores font definition along with it's loaded truetype struct.
type Font struct {
	Path string
	Size float64
	Font *truetype.Font
}

// FindFontError is returned when FindFontPath fails to fint any usable fonts.
type FindFontError struct {
	Action string
	Orig   error
}

func (f FindFontError) Error() string {
	return fmt.Sprintf("[fontconfig] Could not %s. Got `%s`", f.Action, f.Orig)
}

// FindFontPath tries hard to find any usable font(s) in the system.
// It does so by parsing fontconfig configuration and looking through
// the specified directories for anything that could possibly by used
// by freetype font parser.
func FindFontPath() (string, error) {
	log.Print("Trying to find usable font")

	fontsConf, err := os.Open("/etc/fonts/fonts.conf")
	if err != nil {
		return "", FindFontError{"open file", err}
	}
	defer fontsConf.Close()

	result := struct {
		Dirs []string `xml:"dir"`
	}{}
	decoder := xml.NewDecoder(fontsConf)
	if err := decoder.Decode(&result); err != nil {
		return "", FindFontError{"decode file", err}
	}

	for _, dir := range result.Dirs {
		files, err := filepath.Glob(fmt.Sprintf("%s/TTF/*.ttf", dir))
		if err == nil && files != nil {
			return files[0], nil
		}
	}
	return "", FindFontError{"find font files", err}
}

// FontError is returned when NewFont fails to create a font.
type FontError struct {
	Path string
	Orig error
}

func (f FontError) Error() string {
	return fmt.Sprintf("Could not open font `%s`. Got `%s`", f.Path, f.Orig)
}

// NewFont opens a font file and parses it with truetype engine.
func NewFont(path string, size float64) (*Font, error) {
	fontReader, err := os.Open(path)
	if err != nil {
		return nil, FontError{path, err}
	}
	defer fontReader.Close()

	font, err := xgraphics.ParseFont(fontReader)
	if err != nil {
		return nil, FontError{path, err}
	}
	return &Font{path, size, font}, nil
}

// Geometry stores bars geometry on the screen (or actually monitor).
type Geometry struct {
	Width  uint16
	Height uint16
	X      uint16
	Y      uint16
}

// NewGeometry parses geometry from textual definition.
// Input should be formatted as <width>x<height>+<x>+<y>.
// A special "M" value is allowed as <width>, to represent 100%.
func NewGeometry(geostr string, head xrect.Rect, position Position) *Geometry {
	geometry := Geometry{}
	var widthS string
	_, err := fmt.Sscanf(
		geostr, "%1sx%d+%d+%d",
		&widthS, &geometry.Height, &geometry.X, &geometry.Y,
	)

	geometry.X += uint16(head.X())

	hwidth := uint16(head.Width())
	hheight := uint16(head.Height())
	if err != nil {
		log.Print("bad geometry, ", geometry, ", using default")
		geometry.Width = hwidth - (geometry.X - uint16(head.X()))
		geometry.Height = 16
	} else {
		width, err := strconv.Atoi(widthS)
		if err != nil {
			if widthS != "M" {
				// Make people feel guilty
				log.Print("wrong geometry width")
			}
			geometry.Width = hwidth - (geometry.X - uint16(head.X()))
		} else {
			geometry.Width = uint16(width)
		}
	}

	if position == BOTTOM {
		geometry.Y = uint16(head.Y()) + hheight - geometry.Height - geometry.Y
	}

	return &geometry
}

// Bar stores and manages all X related stuff and configuration.
type Bar struct {
	X          *xgbutil.XUtil
	Windows    []*xwindow.Window
	Geometries []*Geometry
	Foreground *xgraphics.BGRA
	Background *xgraphics.BGRA
	Colors     []*xgraphics.BGRA
	Fonts      []*Font
}

// NewBar creates X windows for every monitor.
// Also sets proper EWMH information for docked windows.
func NewBar(
	X *xgbutil.XUtil, geometries []*Geometry, position Position,
	fg uint64, bg uint64, fonts []*Font,
) *Bar {
	windows := make([]*xwindow.Window, len(geometries))
	for i, geometry := range geometries {
		win, err := xwindow.Generate(X)
		fatal(err)
		win.Create(
			X.RootWin(),
			int(geometry.X), int(geometry.Y),
			int(geometry.Width), int(geometry.Height),
			0,
		)

		ewmh.WmWindowTypeSet(X, win.Id, []string{"_NET_WM_WINDOW_TYPE_DOCK"})
		ewmh.WmStateSet(X, win.Id, []string{"_NET_WM_STATE_STICKY"})
		ewmh.WmDesktopSet(X, win.Id, 0xFFFFFFFF)
		strutP := ewmh.WmStrutPartial{}
		strut := ewmh.WmStrut{}
		if position == BOTTOM {
			strutP.BottomStartX = uint(geometry.X)
			strutP.BottomEndX = uint(geometry.X + geometry.Height)
			strutP.Bottom = uint(geometry.Height)
			strut.Bottom = uint(geometry.Height)
		} else {
			strutP.TopStartX = uint(geometry.X)
			strutP.TopEndX = uint(geometry.X + geometry.Height)
			strutP.Top = uint(geometry.Height)
			strut.Top = uint(geometry.Height)
		}
		ewmh.WmStrutPartialSet(X, win.Id, &strutP)
		ewmh.WmStrutSet(X, win.Id, &strut)

		windows[i] = win
	}

	return &Bar{
		X:          X,
		Windows:    windows,
		Geometries: geometries,
		Foreground: NewBGRA(fg),
		Background: NewBGRA(bg),
		Fonts:      fonts,
	}
}

// Draw draws TextPieces into X monitors.
func (self *Bar) Draw(text []*TextPiece) {
	imgs := make([]*xgraphics.Image, len(self.Windows))
	for i, geometry := range self.Geometries {
		imgs[i] = xgraphics.New(self.X, image.Rect(
			0, 0, int(geometry.Width), int(geometry.Height),
		))
		imgs[i].For(func(x, y int) xgraphics.BGRA { return *self.Background })
	}

	xsl := make([]int, len(self.Windows))
	xsr := make([]int, len(self.Windows))
	for i := range xsr {
		xsr[i] = int(self.Geometries[i].Width)
	}
	for _, piece := range text {
		if piece.Background == nil {
			piece.Background = self.Background
		}
		if piece.Foreground == nil {
			piece.Foreground = self.Foreground
		}

		font := self.Fonts[piece.Font]
		width, _ := xgraphics.Extents(font.Font, font.Size, piece.Text)

		screens := piece.Screens
		if screens == nil {
			screens = make([]uint, len(imgs))
			for i := range imgs {
				screens[i] = uint(i)
			}
		}

		for _, screen := range screens {
			xs := xsl[screen]
			if piece.Align == RIGHT {
				xs = xsr[screen] - width
			}

			subimg := imgs[screen].SubImage(image.Rect(
				xs, 0, xs+width, int(self.Geometries[screen].Height),
			))
			subimg.For(func(x, y int) xgraphics.BGRA { return *piece.Background })

			new_xs, _, err := subimg.Text(
				xs, 0, piece.Foreground, font.Size, font.Font, piece.Text,
			)
			if err != nil {
				log.Print(err) // TODO: Better logging
			}

			if piece.Align == LEFT {
				xsl[screen] = new_xs
			} else if piece.Align == RIGHT {
				xsr[screen] -= width
			}

			subimg.XPaint(self.Windows[screen].Id)
			subimg.Destroy()
		}
	}

	for i, img := range imgs {
		img.XSurfaceSet(self.Windows[i].Id)
		img.XDraw()
		img.Destroy()

		self.Windows[i].Map()
	}
}

// ParseColor parses color string to integer value.
// If parsing fails, returns fallback instead.
func ParseColor(color string, fallback uint64) uint64 {
	result, err := strconv.ParseUint(color, 0, 32)
	if err != nil {
		log.Printf("Incorrect color `%s`, using default. Got `%s`", color, err)
		return fallback
	}
	return result
}

// main gets command line arguments, creates X connection and initializes Bar.
// This is also where X event loop and Stdin reading lies.
func main() {
	cli := `gobar.

Usage:
  gobar [options]
  gobar -h | --help
  gobar --version

Options:
  -h --help              Show this screen.
  --bottom               Place bar at the bottom of the screen.
  --geometry=<GEOMETRY>  Comma separated list of monitor geometries in form of
                         <w>x<h>+<x>+<y>. If not specified, uses Mx16+0+0 for each screen.
                         M is a special case for <w> only, taking all available space.
  --fonts=<FONTS>        Comma seperated list of fonts in form of path:size.
                         Defaults to whatever it can find in fontconfig configuration.
  --fg=<COLOR>           Foreground color (0xAARRGGBB) [default: 0xFFFFFFFF].
  --bg=<COLOR>           Background color (0xAARRGGBB) [default: 0xFF000000].
	`

	arguments, err := docopt.Parse(cli, nil, true, "", false)
	fatal(err)
	fgColor := ParseColor(arguments["--fg"].(string), 0xFFFFFFFF)
	bgColor := ParseColor(arguments["--bg"].(string), 0xFF000000)
	bottom := arguments["--bottom"].(bool)
	position := TOP
	if bottom {
		position = BOTTOM
	}

	fontSpecs := []string{}
	if arguments["--fonts"] != nil {
		fontSpecs = strings.Split(arguments["--fonts"].(string), ",")
	}
	fonts := make([]*Font, 0, len(fontSpecs))
	for _, fontSpec := range fontSpecs {
		fontSpecSplit := strings.Split(fontSpec, ":")
		fontPath := fontSpecSplit[0]
		fontSize, _ := strconv.ParseFloat(fontSpecSplit[1], 32)
		font, err := NewFont(fontPath, fontSize)
		if err != nil {
			log.Print(err)
			if len(fonts) > 0 {
				log.Print("Using font at index 0")
				font, err = fonts[0], nil
			} else {
				fontPath, err := FindFontPath()
				if err != nil {
					log.Print(err)
				} else {
					font, err = NewFont(fontPath, fontSize)
				}
			}
		}
		if err != nil {
			log.Print(err)
		} else {
			fonts = append(fonts, font)
		}
	}
	if len(fonts) == 0 {
		fontPath, err := FindFontPath()
		if err != nil {
			fatal(errors.New("No usable fonts found, bailing out"))
		}

		font, err := NewFont(fontPath, 12)
		if err != nil {
			fatal(errors.New("No usable fonts found, bailing out"))
		}
		fonts = append(fonts, font)
	}

	X, err := xgbutil.NewConn()
	fatal(err)
	heads, err := xinerama.PhysicalHeads(X)
	fatal(err)

	geometryStr := arguments["--geometry"]
	var geometrySpec []string
	if geometryStr != nil {
		geometrySpec = strings.Split(geometryStr.(string), ",")
	}
	if len(geometrySpec) < len(heads) {
		for i := len(geometrySpec); i < len(heads); i++ {
			geometrySpec = append(
				geometrySpec, "Mx16+0+0",
			)
		}
	}

	geometries := make([]*Geometry, len(heads))
	for i, head := range heads {
		geometries[i] = NewGeometry(geometrySpec[i], head, position)
	}

	bar := NewBar(X, geometries, position, fgColor, bgColor, fonts)
	parser := NewTextParser()

	stdin := make(chan []*TextPiece, 0)
	go func() {
		defer close(stdin)

		for {
			parsed, err := parser.Scan(os.Stdin)
			if err != nil {
				log.Print(err) //TODO: Better logging
				continue
			}
			stdin <- parsed
		}
	}()

	pingBefore, pingAfter, pingQuit := xevent.MainPing(X)
	for {
		select {
		case <-pingBefore:
			<-pingAfter
		case text := <-stdin:
			bar.Draw(text)
		case <-pingQuit:
			return
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
)

func main() {
	// for who.go Who(char, lvl)
	var char = flag.String("char", "", "Character name for update or import. Ex: Rynshana")
	var lvl = flag.Int("lvl", 0, "Character level for update or import. Ex: 50")
	// for who.go WhoChar(char, lvl, class, race, acct)
	var class = flag.String("class", "", "Character class for initial import. Ex: \"Cleric\"")
	var race = flag.String("race", "", "Character race for initial import. Ex: \"Moon Elf\"")
	var acct = flag.String("acct", "", "Character account for initial import. Ex: Krimic")
	// for identify.go Identify(filename)
	var file = flag.String("import", "", "Parse file for identify stats, import to DB. Ex: newstats.txt")
	// for time.go Uptime(curup)
	var time = flag.String("time", "", "Parse uptime for boot tracking. Ex: 58:10:26")
	// for tell.go
	var tell = flag.String("tell", "", "Tell with command and maybe operant. Ex: stat a longsword")

	flag.Parse()

	// only run one command at a time
	switch {
	case *char != "" && 50 >= *lvl && *lvl > 0 && *class != "" && *race != "" && *acct != "":
		WhoChar(*char, *lvl, *class, *race, *acct)
	case *char != "" && 50 >= *lvl && *lvl > 0:
		Who(*char, *lvl)
	case *file != "":
		Identify(*file)
	case *time != "":
		Uptime(*time)
	case *char != "" && *tell != "":
		ReplyTo(*char, *tell)
	}
}
<commit_msg>Fix commenting<commit_after>package main

import (
	"flag"
)

func main() {
	// for who.go Who(char, lvl)
	var char = flag.String("char", "", "Character name for update or import. Ex: Rynshana")
	var lvl = flag.Int("lvl", 0, "Character level for update or import. Ex: 50")
	// for who.go WhoChar(char, lvl, class, race, acct)
	var class = flag.String("class", "", "Character class for initial import. Ex: \"Cleric\"")
	var race = flag.String("race", "", "Character race for initial import. Ex: \"Moon Elf\"")
	var acct = flag.String("acct", "", "Character account for initial import. Ex: Krimic")
	// for identify.go Identify(filename)
	var file = flag.String("import", "", "Parse file for identify stats, import to DB. Ex: newstats.txt")
	// for time.go Uptime(curup)
	var time = flag.String("time", "", "Parse uptime for boot tracking. Ex: 58:10:26")
	// for tell.go ReplyTo(char, tell)
	var tell = flag.String("tell", "", "Tell with command and maybe operant. Ex: \"stat a longsword\"")

	flag.Parse()

	// only run one command at a time
	switch {
	case *char != "" && 50 >= *lvl && *lvl > 0 && *class != "" && *race != "" && *acct != "":
		WhoChar(*char, *lvl, *class, *race, *acct)
	case *char != "" && 50 >= *lvl && *lvl > 0:
		Who(*char, *lvl)
	case *file != "":
		Identify(*file)
	case *time != "":
		Uptime(*time)
	case *char != "" && *tell != "":
		ReplyTo(*char, *tell)
	}
}
<|endoftext|>


<commit_before>package main

import (
	// stdlib
	"encoding/base64"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"text/template"

	// external
	"github.com/VictorLowther/go-git/git"
	auth "github.com/abbot/go-http-auth"
	"github.com/russross/blackfriday"
)

const (
	GOIKIVERSION = "0.2.0"
)

var (
	configFile     string
	displayConfig  bool
	displayVersion bool
	templateFiles  map[string]string
	conf           config
	templates      *template.Template
	validPath      *regexp.Regexp
	validLink      *regexp.Regexp
	tableTag       *regexp.Regexp
	authenticator  *auth.BasicAuth
)

type page struct {
	SiteName    string
	Title       string
	Theme       string
	Author      author
	Body        string
	Description string
	Revisions   []pageRevision
}

type searchPage struct {
	SiteName string
	Title    string
	Theme    string
	Results  []searchResult
}

type historyPage struct {
	SiteName  string
	Title     string
	Theme     string
	Revisions []pageRevision
}

func (p *page) save() error {
	filename := fileName(p.Title)
	datapath := dataPath(conf.DataDir, filename)

	err := os.MkdirAll(filepath.Dir(datapath), 0777)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(datapath, []byte(p.Body), 0600)
	if err != nil {
		return err
	}

	_, err = gitAdd(filename)
	if err != nil {
		return err
	}

	message := p.Description
	if len(message) == 0 {
		message = fmt.Sprintf("Update %s", filename)
	}
	stdout, err := gitCommit(message, p.Author)
	if err != nil {
		return err
	}
	log.Println(stdout)

	return nil
}

func fileName(title string) string {
	return title + "." + conf.FileExtension
}

func dataPath(dir string, file string) string {
	return filepath.Join(dir, file)
}

func loadPage(title string, revision string) (*page, error) {
	filename := fileName(title)
	if len(revision) == 0 {
		revision = "HEAD"
	}
	body, err := gitShow(filename, revision)
	if err != nil {
		return &page{
			Title:    title,
			Theme:    conf.Theme,
			Body:     body.String(),
			SiteName: conf.Name,
		}, fmt.Errorf("Unable to load page content from %s at %s\n", filename, revision)
	}
	return &page{Title: title, Theme: conf.Theme, Body: body.String(), SiteName: conf.Name}, nil
}

func processLinks(content []byte, link *regexp.Regexp) []byte {
	return link.ReplaceAllFunc(content, func(match []byte) []byte {
		return link.ReplaceAll(match, []byte("[$1]($1)"))
	})
}

func processTables(content []byte, table *regexp.Regexp) []byte {
	return table.ReplaceAllFunc(content, func(match []byte) []byte {
		return table.ReplaceAll(match, []byte(`<table class="`+conf.TableClass+`">`))
	})
}

/*
TODO: How to combine the three functions? With use of an interface for the page?
*/

func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
	err := templates.ExecuteTemplate(w, tmpl, p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func renderHistoryTemplate(w http.ResponseWriter, tmpl string, p *historyPage) {
	err := templates.ExecuteTemplate(w, tmpl, p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func renderSearchTemplate(w http.ResponseWriter, tmpl string, p *searchPage) {
	err := templates.ExecuteTemplate(w, tmpl, p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path
		log.Println(path)
		if path == "/" {
			path = "/view/"
		}
		if path[len(path)-1:len(path)] == "/" {
			viewIndex := path + conf.IndexPage
			http.Redirect(w, r, viewIndex, http.StatusFound)
			return
		}
		m := validPath.FindStringSubmatch(path)
		if m == nil {
			http.NotFound(w, r)
			return
		}
		fn(w, r, m[2])
	}
}

func makeAuthHandler(fn func(http.ResponseWriter, *auth.AuthenticatedRequest, string)) auth.AuthenticatedHandlerFunc {
	return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
		path := r.URL.Path
		log.Println(path)
		m := validPath.FindStringSubmatch(path)
		if m == nil {
			http.NotFound(w, &r.Request)
			return
		}
		fn(w, r, m[2])
	}
}

func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
	revision := r.FormValue("revision")
	if revision == "" {
		revision = "HEAD"
	}

	p, err := loadPage(title, revision)
	if err != nil {
		http.Redirect(w, r, "/edit/"+title, http.StatusFound)
		return
	}

	content := []byte(p.Body)
	content = processLinks(content, validLink)
	content = blackfriday.MarkdownCommon(content)
	content = processTables(content, tableTag)
	p.Body = string(content)

	renderTemplate(w, "view", p)
}

func editHandler(w http.ResponseWriter, r *auth.AuthenticatedRequest, title string) {
	revision := r.FormValue("revision")
	if revision == "" {
		revision = "HEAD"
	}

	p, err := loadPage(title, revision)
	if err != nil {
		p = &page{Title: title, Theme: conf.Theme, SiteName: conf.Name}
	}

	renderTemplate(w, "edit", p)
}

func saveHandler(w http.ResponseWriter, r *auth.AuthenticatedRequest, title string) {
	body := r.FormValue("body")
	description := r.FormValue("description")
	user := conf.Auth[r.Username]
	author := author{Name: user.Name, Email: user.Email}
	p := &page{Title: title, Theme: conf.Theme, Body: body, Description: description, Author: author}
	err := p.save()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, &r.Request, "/view/"+title, http.StatusFound)
}

func historyHandler(w http.ResponseWriter, r *http.Request, title string) {
	revisions, _ := gitLog(fileName(title))
	p := &historyPage{Title: title, Theme: conf.Theme, Revisions: revisions, SiteName: conf.Name}
	renderHistoryTemplate(w, "history", p)
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
	search := r.FormValue("search")
	results, err := gitGrep(search)
	if err != nil {
		log.Println("error in search", err)
	}
	p := &searchPage{Title: "Search", Theme: conf.Theme, Results: results, SiteName: conf.Name}
	renderSearchTemplate(w, "search", p)
}

func bundleHandler(w http.ResponseWriter, r *http.Request) {
	p := strings.TrimLeft(r.URL.Path, "/")
	f, ok := _bundle[p]
	if ok {
		w.Write([]byte(f))
	} else {
		http.NotFound(w, r)
	}
}

func defaultConfig() string {
	return _bundle["goiki.toml"]
}

func loadBundle() {
	for file, content := range _bundle {
		c, err := base64.StdEncoding.DecodeString(content)
		if err != nil {
			log.Printf("Error during loadBundle(): %v", err)
		}
		_bundle[file] = string(c)
	}
}

// Initialize the configuration options, templates and URL and link regexes.
func init() {
	flag.StringVar(&configFile, "c", "", "Specify a configuration file (use default config otherwise)")
	flag.BoolVar(&displayConfig, "d", false, "Display default configuration and exit")
	flag.BoolVar(&displayVersion, "v", false, "Display version and exit")

	loadBundle()

	templateFiles = map[string]string{"header": "_header.html", "footer": "_footer.html", "edit": "edit.html",
		"history": "history.html", "search": "search.html", "view": "view.html"}
	validPath = regexp.MustCompile("^/(edit|save|view|history)/([a-zA-Z0-9/_-]+)$")
	validLink = regexp.MustCompile(`\[([^\]]+)]\(\)`)
	tableTag = regexp.MustCompile(`<table>`)
}

func secret(username, realm string) string {
	return conf.Auth[username].Password
}

func serviceAddress(host string, port int) string {
	return fmt.Sprintf("%s:%d", host, port)
}

func main() {
	flag.Parse()

	// Display version and exit (flag -version)
	if displayVersion {
		fmt.Println("Goiki", GOIKIVERSION)
		return
	}

	// Display the default configuration set and exit (flag -default)
	if displayConfig {
		fmt.Println(defaultConfig())
		return
	}

	// Load the configuration. Use the default embedded configuration unless
	// a config file was specified at the command line.
	var err error
	if len(configFile) == 0 {
		conf, err = loadConfig(defaultConfig())
	} else {
		conf, err = loadConfigFromFile(configFile)
	}

	if err != nil {
		fmt.Printf("FATAL: Unable to load configuration: %v\n", err)
		return
	}

	// Load authentication from the config and run the authenticator.
	conf.loadAuth()
	authenticator = auth.NewBasicAuthenticator(serviceAddress(conf.Host, conf.Port), secret)

	// Load the templates. Use the default embedded templates unless a directory
	// of templates is specified in configuration.
	if len(conf.TemplateDir) == 0 {
		templates = template.Must(template.New("goiki").Parse(""))
		for _, file := range templateFiles {
			data, _ := ioutil.ReadFile(filepath.Join("templates", file))
			template.Must(templates.Parse(string(data)))
		}
	} else {
		templateLocations := make([]string, len(templateFiles))
		i := 0
		for _, file := range templateFiles {
			templateLocations[i] = filepath.Join(conf.TemplateDir, file)
			i += 1
		}
		templates = template.Must(template.ParseFiles(templateLocations...))
	}

	// Load the repository.
	if repo, err = git.Open(conf.DataDir); err != nil {
		log.Fatalf("Unable to open the repo at %s. Please check to make sure it exists and is initialized.\n%v", conf.DataDir, err)
	}

	// Static routes
	// If a static directory is provided in the configuration, use that; otherwise
	// use the embedded static content
	if len(conf.StaticDir) > 0 {
		http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(conf.StaticDir))))
	} else {
		http.Handle("/static/", http.FileServer(FS(false)))
	}

	// Unathenticated routes
	http.HandleFunc("/search/", searchHandler)
	http.HandleFunc("/", makeHandler(viewHandler))
	http.HandleFunc("/view/", makeHandler(viewHandler))
	http.HandleFunc("/history/", makeHandler(historyHandler))

	// Authenticated routes
	http.HandleFunc("/edit/", authenticator.Wrap(makeAuthHandler(editHandler)))
	http.HandleFunc("/save/", authenticator.Wrap(makeAuthHandler(saveHandler)))

	address := serviceAddress(conf.Host, conf.Port)

	log.Printf("Listening on %v\n", address)

	l, err := net.Listen("tcp", address)
	if err != nil {
		log.Fatal(err)
	}

	s := &http.Server{}
	s.Serve(l)
	return
}
<commit_msg>Fix use of embedded templates (it now works); alter error messages<commit_after>package main

import (
	// stdlib
	"encoding/base64"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"text/template"

	// external
	"github.com/VictorLowther/go-git/git"
	auth "github.com/abbot/go-http-auth"
	"github.com/russross/blackfriday"
)

const (
	GOIKIVERSION = "0.2.1"
)

var (
	configFile     string
	displayConfig  bool
	displayVersion bool
	templateFiles  map[string]string
	conf           config
	templates      *template.Template
	validPath      *regexp.Regexp
	validLink      *regexp.Regexp
	tableTag       *regexp.Regexp
	authenticator  *auth.BasicAuth
)

type page struct {
	SiteName    string
	Title       string
	Theme       string
	Author      author
	Body        string
	Description string
	Revisions   []pageRevision
}

type searchPage struct {
	SiteName string
	Title    string
	Theme    string
	Results  []searchResult
}

type historyPage struct {
	SiteName  string
	Title     string
	Theme     string
	Revisions []pageRevision
}

func (p *page) save() error {
	filename := fileName(p.Title)
	datapath := dataPath(conf.DataDir, filename)

	err := os.MkdirAll(filepath.Dir(datapath), 0777)
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(datapath, []byte(p.Body), 0600)
	if err != nil {
		return err
	}

	_, err = gitAdd(filename)
	if err != nil {
		return err
	}

	message := p.Description
	if len(message) == 0 {
		message = fmt.Sprintf("Update %s", filename)
	}
	stdout, err := gitCommit(message, p.Author)
	if err != nil {
		return err
	}
	log.Println(stdout)

	return nil
}

func fileName(title string) string {
	return title + "." + conf.FileExtension
}

func dataPath(dir string, file string) string {
	return filepath.Join(dir, file)
}

func loadPage(title string, revision string) (*page, error) {
	filename := fileName(title)
	if len(revision) == 0 {
		revision = "HEAD"
	}
	body, err := gitShow(filename, revision)
	if err != nil {
		return &page{
			Title:    title,
			Theme:    conf.Theme,
			Body:     body.String(),
			SiteName: conf.Name,
		}, fmt.Errorf("Unable to load page content from %s at %s\n", filename, revision)
	}
	return &page{Title: title, Theme: conf.Theme, Body: body.String(), SiteName: conf.Name}, nil
}

func processLinks(content []byte, link *regexp.Regexp) []byte {
	return link.ReplaceAllFunc(content, func(match []byte) []byte {
		return link.ReplaceAll(match, []byte("[$1]($1)"))
	})
}

func processTables(content []byte, table *regexp.Regexp) []byte {
	return table.ReplaceAllFunc(content, func(match []byte) []byte {
		return table.ReplaceAll(match, []byte(`<table class="`+conf.TableClass+`">`))
	})
}

/*
TODO: How to combine the three functions? With use of an interface for the page?
*/

func renderTemplate(w http.ResponseWriter, tmpl string, p *page) {
	err := templates.ExecuteTemplate(w, tmpl, p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func renderHistoryTemplate(w http.ResponseWriter, tmpl string, p *historyPage) {
	err := templates.ExecuteTemplate(w, tmpl, p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func renderSearchTemplate(w http.ResponseWriter, tmpl string, p *searchPage) {
	err := templates.ExecuteTemplate(w, tmpl, p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path
		log.Println(path)
		if path == "/" {
			path = "/view/"
		}
		if path[len(path)-1:len(path)] == "/" {
			viewIndex := path + conf.IndexPage
			http.Redirect(w, r, viewIndex, http.StatusFound)
			return
		}
		m := validPath.FindStringSubmatch(path)
		if m == nil {
			http.NotFound(w, r)
			return
		}
		fn(w, r, m[2])
	}
}

func makeAuthHandler(fn func(http.ResponseWriter, *auth.AuthenticatedRequest, string)) auth.AuthenticatedHandlerFunc {
	return func(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
		path := r.URL.Path
		log.Println(path)
		m := validPath.FindStringSubmatch(path)
		if m == nil {
			http.NotFound(w, &r.Request)
			return
		}
		fn(w, r, m[2])
	}
}

func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
	revision := r.FormValue("revision")
	if revision == "" {
		revision = "HEAD"
	}

	p, err := loadPage(title, revision)
	if err != nil {
		http.Redirect(w, r, "/edit/"+title, http.StatusFound)
		return
	}

	content := []byte(p.Body)
	content = processLinks(content, validLink)
	content = blackfriday.MarkdownCommon(content)
	content = processTables(content, tableTag)
	p.Body = string(content)

	renderTemplate(w, "view", p)
}

func editHandler(w http.ResponseWriter, r *auth.AuthenticatedRequest, title string) {
	revision := r.FormValue("revision")
	if revision == "" {
		revision = "HEAD"
	}

	p, err := loadPage(title, revision)
	if err != nil {
		p = &page{Title: title, Theme: conf.Theme, SiteName: conf.Name}
	}

	renderTemplate(w, "edit", p)
}

func saveHandler(w http.ResponseWriter, r *auth.AuthenticatedRequest, title string) {
	body := r.FormValue("body")
	description := r.FormValue("description")
	user := conf.Auth[r.Username]
	author := author{Name: user.Name, Email: user.Email}
	p := &page{Title: title, Theme: conf.Theme, Body: body, Description: description, Author: author}
	err := p.save()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, &r.Request, "/view/"+title, http.StatusFound)
}

func historyHandler(w http.ResponseWriter, r *http.Request, title string) {
	revisions, _ := gitLog(fileName(title))
	p := &historyPage{Title: title, Theme: conf.Theme, Revisions: revisions, SiteName: conf.Name}
	renderHistoryTemplate(w, "history", p)
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
	search := r.FormValue("search")
	results, err := gitGrep(search)
	if err != nil {
		log.Println("error in search", err)
	}
	p := &searchPage{Title: "Search", Theme: conf.Theme, Results: results, SiteName: conf.Name}
	renderSearchTemplate(w, "search", p)
}

func bundleHandler(w http.ResponseWriter, r *http.Request) {
	p := strings.TrimLeft(r.URL.Path, "/")
	f, ok := _bundle[p]
	if ok {
		w.Write([]byte(f))
	} else {
		http.NotFound(w, r)
	}
}

func defaultConfig() string {
	return _bundle["goiki.toml"]
}

func loadBundle() {
	for file, content := range _bundle {
		c, err := base64.StdEncoding.DecodeString(content)
		if err != nil {
			log.Printf("Error during loadBundle(): %v", err)
		}
		_bundle[file] = string(c)
	}
}

// Initialize the configuration options, templates and URL and link regexes.
func init() {
	flag.StringVar(&configFile, "c", "", "Specify a configuration file (use default config otherwise)")
	flag.BoolVar(&displayConfig, "d", false, "Display default configuration and exit")
	flag.BoolVar(&displayVersion, "v", false, "Display version and exit")

	loadBundle()

	templateFiles = map[string]string{"header": "_header.html", "footer": "_footer.html", "edit": "edit.html",
		"history": "history.html", "search": "search.html", "view": "view.html"}
	validPath = regexp.MustCompile("^/(edit|save|view|history)/([a-zA-Z0-9/_-]+)$")
	validLink = regexp.MustCompile(`\[([^\]]+)]\(\)`)
	tableTag = regexp.MustCompile(`<table>`)
}

func secret(username, realm string) string {
	return conf.Auth[username].Password
}

func serviceAddress(host string, port int) string {
	return fmt.Sprintf("%s:%d", host, port)
}

func main() {
	flag.Parse()

	// Display version and exit (flag -version)
	if displayVersion {
		fmt.Println("Goiki", GOIKIVERSION)
		return
	}

	// Display the default configuration set and exit (flag -default)
	if displayConfig {
		fmt.Println(defaultConfig())
		return
	}

	// Load the configuration. Use the default embedded configuration unless
	// a config file was specified at the command line.
	var err error
	if len(configFile) == 0 {
		conf, err = loadConfig(defaultConfig())
	} else {
		conf, err = loadConfigFromFile(configFile)
	}

	if err != nil {
		fmt.Printf("FATAL: Unable to load configuration: %v\n", err)
		return
	}

	// Load authentication from the config and run the authenticator.
	conf.loadAuth()
	authenticator = auth.NewBasicAuthenticator(serviceAddress(conf.Host, conf.Port), secret)

	// Load the templates. Use the default embedded templates unless a directory
	// of templates is specified in configuration.
	if len(conf.TemplateDir) == 0 {
		templates = template.Must(template.New("bundle").Parse(""))
		for _, file := range templateFiles {
			data := _bundle[filepath.Join("templates", file)]
			template.Must(templates.Parse(string(data)))
		}
	} else {
		templateLocations := make([]string, len(templateFiles))
		i := 0
		for _, file := range templateFiles {
			templateLocations[i] = filepath.Join(conf.TemplateDir, file)
			i += 1
		}
		templates = template.Must(template.ParseFiles(templateLocations...))
	}

	// Load the repository.
	if repo, err = git.Open(conf.DataDir); err != nil {
		log.Fatalf("Unable to open the repo at %v. Please check to make sure it exists and is initialized.\n%v\n", conf.DataDir, err)
	}

	// Static routes
	// If a static directory is provided in the configuration, use that; otherwise
	// use the embedded static content
	if len(conf.StaticDir) > 0 {
		http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir(conf.StaticDir))))
	} else {
		http.Handle("/static/", http.FileServer(FS(false)))
	}

	// Unathenticated routes
	http.HandleFunc("/search/", searchHandler)
	http.HandleFunc("/", makeHandler(viewHandler))
	http.HandleFunc("/view/", makeHandler(viewHandler))
	http.HandleFunc("/history/", makeHandler(historyHandler))

	// Authenticated routes
	http.HandleFunc("/edit/", authenticator.Wrap(makeAuthHandler(editHandler)))
	http.HandleFunc("/save/", authenticator.Wrap(makeAuthHandler(saveHandler)))

	address := serviceAddress(conf.Host, conf.Port)

	log.Printf("Listening on %v\n", address)

	l, err := net.Listen("tcp", address)
	if err != nil {
		log.Fatalf("Unable to start server at %v. Please check the host and port configuration and try again.\n%v\n", address, err)
	}

	s := &http.Server{}
	s.Serve(l)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"os/user"
	"path"
	"reflect"
	"strconv"
	"strings"
)

var (
	homeDir    string
	selfURL127 string // 127.0.0.1:listenAddr
	selfURLLH  string // localhost:listenAddr
)

const (
	dotDir             = ".cow"
	blockedFname       = "auto-blocked"
	directFname        = "auto-direct"
	alwaysBlockedFname = "blocked"
	alwaysDirectFname  = "direct"
	chouFname          = "chou"
	rcFname            = "rc"

	version = "0.3.4"
)

var config struct {
	listenAddr    string
	socksAddr     string
	numProc       int
	sshServer     string
	updateBlocked bool
	updateDirect  bool
	autoRetry     bool
	detectSSLErr  bool
	logFile       string
	alwaysProxy   bool
	printVer      bool

	// For shadowsocks server
	shadowSocks  string
	shadowPasswd string

	// These are for internal use
	dir               string // directory containing config file and blocked site list
	blockedFile       string // contains blocked domains
	directFile        string // contains sites that can be directly accessed
	alwaysDirectFile  string
	alwaysBlockedFile string
	chouFile          string // chou feng, sites which will be temporary blocked
	rcFile            string
}

func printVersion() {
	fmt.Println("cow version", version)
}

func init() {
	u, err := user.Current()
	if err != nil {
		errl.Printf("Can't get user information %v", err)
		os.Exit(1)
	}
	homeDir = u.HomeDir

	flag.StringVar(&config.listenAddr, "listen", "127.0.0.1:7777", "proxy server listen address")
	flag.StringVar(&config.socksAddr, "socks", "127.0.0.1:1080", "socks proxy address")
	flag.IntVar(&config.numProc, "core", 2, "number of cores to use")
	flag.StringVar(&config.sshServer, "sshServer", "", "remote server which will ssh to and provide sock server")
	flag.BoolVar(&config.updateBlocked, "updateBlocked", true, "update blocked site list")
	flag.BoolVar(&config.updateDirect, "updateDirect", true, "update direct site list")
	flag.BoolVar(&config.autoRetry, "autoRetry", false, "automatically retry timeout requests using socks proxy")
	flag.BoolVar(&config.detectSSLErr, "detectSSLErr", true, "detect SSL error based on how soon client closes connection")
	flag.StringVar(&config.logFile, "logFile", "", "write output to file, empty means stdout")
	flag.BoolVar(&config.alwaysProxy, "alwaysProxy", false, "always use parent proxy")
	flag.BoolVar(&config.printVer, "version", false, "print version")

	flag.StringVar(&config.shadowSocks, "shadowSocks", "", "shadowsocks server address")
	flag.StringVar(&config.shadowPasswd, "shadowPasswd", "", "shadowsocks password")

	config.dir = path.Join(homeDir, dotDir)
	config.blockedFile = path.Join(config.dir, blockedFname)
	config.directFile = path.Join(config.dir, directFname)
	config.alwaysBlockedFile = path.Join(config.dir, alwaysBlockedFname)
	config.alwaysDirectFile = path.Join(config.dir, alwaysDirectFname)
	config.chouFile = path.Join(config.dir, chouFname)
	config.rcFile = path.Join(config.dir, rcFname)

	// Make it easy to find config directory on windows
	if isWindows() {
		fmt.Println("Config directory:", config.dir)
	}
}

// Tries to open a file, if file not exist, return both nil for os.File and
// err
func openFile(path string) (f *os.File, err error) {
	if f, err = os.Open(path); err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		errl.Println("Error opening file:", path, err)
		return nil, err
	}
	return
}

func parseBool(v string, msg string) bool {
	switch v {
	case "true":
		return true
	case "false":
		return false
	default:
		fmt.Printf("%s should be true or false\n", msg)
		os.Exit(1)
	}
	return false
}

type configParser struct{}

func (p configParser) ParseListen(val string) {
	config.listenAddr = val
}

func isServerAddrValid(val string) bool {
	if val == "" {
		return true
	}
	_, port := splitHostPort(val)
	if port == "" {
		return false
	}
	return true
}

func (p configParser) ParseSocks(val string) {
	if !isServerAddrValid(val) {
		fmt.Println("socks server must have port specified")
		os.Exit(1)
	}
	config.socksAddr = val
}

func (p configParser) ParseCore(val string) {
	if val == "" {
		return
	}
	var err error
	config.numProc, err = strconv.Atoi(val)
	if err != nil {
		fmt.Printf("Config error: core number %s %v", val, err)
		os.Exit(1)
	}
}

func (p configParser) ParseSshServer(val string) {
	config.sshServer = val
}

func (p configParser) ParseUpdateBlocked(val string) {
	config.updateBlocked = parseBool(val, "updateBlocked")
}

func (p configParser) ParseUpdateDirect(val string) {
	config.updateDirect = parseBool(val, "updateDirect")
}

func (p configParser) ParseAutoRetry(val string) {
	config.autoRetry = parseBool(val, "autoRetry")
}

func (p configParser) ParseDetectSSLErr(val string) {
	config.detectSSLErr = parseBool(val, "detectSSLErr")
}

func (p configParser) ParseLogFile(val string) {
	config.logFile = val
}

func (p configParser) ParseAlwaysProxy(val string) {
	config.alwaysProxy = parseBool(val, "alwaysProxy")
}

func (p configParser) ParseShadowSocks(val string) {
	if !isServerAddrValid(val) {
		fmt.Println("shadowsocks server must have port specified")
		os.Exit(1)
	}
	config.shadowSocks = val
}

func (p configParser) ParseShadowPasswd(val string) {
	config.shadowPasswd = val
}

func loadConfig() {
	f, err := openFile(config.rcFile)
	if f == nil || err != nil {
		return
	}
	defer f.Close()

	fr := bufio.NewReader(f)

	parser := reflect.ValueOf(configParser{})
	zeroMethod := reflect.Value{}

	var line string
	var n int
	for {
		n++
		line, err = ReadLine(fr)
		if err == io.EOF {
			return
		} else if err != nil {
			errl.Printf("Error reading rc file: %v\n", err)
			os.Exit(1)
		}

		if line == "" {
			continue
		}

		line = strings.TrimSpace(line)
		// Ignore comment
		if line[0] == '#' {
			continue
		}

		v := strings.Split(line, "=")
		if len(v) != 2 {
			fmt.Println("Config error: syntax error on line", n)
			os.Exit(1)
		}
		key, val := strings.TrimSpace(v[0]), strings.TrimSpace(v[1])

		methodName := "Parse" + strings.ToUpper(key[0:1]) + key[1:]
		method := parser.MethodByName(methodName)
		if method == zeroMethod {
			fmt.Printf("Config error: no such option \"%s\"\n", key)
			os.Exit(1)
		}
		args := []reflect.Value{reflect.ValueOf(val)}
		method.Call(args)
	}
}

func setSelfURL() {
	_, port := splitHostPort(config.listenAddr)
	selfURL127 = "127.0.0.1:" + port
	selfURLLH = "localhost:" + port
}
<commit_msg>Print error message to stdout during init config.<commit_after>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"os/user"
	"path"
	"reflect"
	"strconv"
	"strings"
)

var (
	homeDir    string
	selfURL127 string // 127.0.0.1:listenAddr
	selfURLLH  string // localhost:listenAddr
)

const (
	dotDir             = ".cow"
	blockedFname       = "auto-blocked"
	directFname        = "auto-direct"
	alwaysBlockedFname = "blocked"
	alwaysDirectFname  = "direct"
	chouFname          = "chou"
	rcFname            = "rc"

	version = "0.3.4"
)

var config struct {
	listenAddr    string
	socksAddr     string
	numProc       int
	sshServer     string
	updateBlocked bool
	updateDirect  bool
	autoRetry     bool
	detectSSLErr  bool
	logFile       string
	alwaysProxy   bool
	printVer      bool

	// For shadowsocks server
	shadowSocks  string
	shadowPasswd string

	// These are for internal use
	dir               string // directory containing config file and blocked site list
	blockedFile       string // contains blocked domains
	directFile        string // contains sites that can be directly accessed
	alwaysDirectFile  string
	alwaysBlockedFile string
	chouFile          string // chou feng, sites which will be temporary blocked
	rcFile            string
}

func printVersion() {
	fmt.Println("cow version", version)
}

func init() {
	u, err := user.Current()
	if err != nil {
		fmt.Printf("Can't get user information %v", err)
		os.Exit(1)
	}
	homeDir = u.HomeDir

	flag.StringVar(&config.listenAddr, "listen", "127.0.0.1:7777", "proxy server listen address")
	flag.StringVar(&config.socksAddr, "socks", "127.0.0.1:1080", "socks proxy address")
	flag.IntVar(&config.numProc, "core", 2, "number of cores to use")
	flag.StringVar(&config.sshServer, "sshServer", "", "remote server which will ssh to and provide sock server")
	flag.BoolVar(&config.updateBlocked, "updateBlocked", true, "update blocked site list")
	flag.BoolVar(&config.updateDirect, "updateDirect", true, "update direct site list")
	flag.BoolVar(&config.autoRetry, "autoRetry", false, "automatically retry timeout requests using socks proxy")
	flag.BoolVar(&config.detectSSLErr, "detectSSLErr", true, "detect SSL error based on how soon client closes connection")
	flag.StringVar(&config.logFile, "logFile", "", "write output to file, empty means stdout")
	flag.BoolVar(&config.alwaysProxy, "alwaysProxy", false, "always use parent proxy")
	flag.BoolVar(&config.printVer, "version", false, "print version")

	flag.StringVar(&config.shadowSocks, "shadowSocks", "", "shadowsocks server address")
	flag.StringVar(&config.shadowPasswd, "shadowPasswd", "", "shadowsocks password")

	config.dir = path.Join(homeDir, dotDir)
	config.blockedFile = path.Join(config.dir, blockedFname)
	config.directFile = path.Join(config.dir, directFname)
	config.alwaysBlockedFile = path.Join(config.dir, alwaysBlockedFname)
	config.alwaysDirectFile = path.Join(config.dir, alwaysDirectFname)
	config.chouFile = path.Join(config.dir, chouFname)
	config.rcFile = path.Join(config.dir, rcFname)

	// Make it easy to find config directory on windows
	if isWindows() {
		fmt.Println("Config directory:", config.dir)
	}
}

// Tries to open a file, if file not exist, return both nil for os.File and
// err
func openFile(path string) (f *os.File, err error) {
	if f, err = os.Open(path); err != nil {
		if os.IsNotExist(err) {
			return nil, nil
		}
		errl.Println("Error opening file:", path, err)
		return nil, err
	}
	return
}

func parseBool(v string, msg string) bool {
	switch v {
	case "true":
		return true
	case "false":
		return false
	default:
		fmt.Printf("%s should be true or false\n", msg)
		os.Exit(1)
	}
	return false
}

type configParser struct{}

func (p configParser) ParseListen(val string) {
	config.listenAddr = val
}

func isServerAddrValid(val string) bool {
	if val == "" {
		return true
	}
	_, port := splitHostPort(val)
	if port == "" {
		return false
	}
	return true
}

func (p configParser) ParseSocks(val string) {
	if !isServerAddrValid(val) {
		fmt.Println("socks server must have port specified")
		os.Exit(1)
	}
	config.socksAddr = val
}

func (p configParser) ParseCore(val string) {
	if val == "" {
		return
	}
	var err error
	config.numProc, err = strconv.Atoi(val)
	if err != nil {
		fmt.Printf("Config error: core number %s %v", val, err)
		os.Exit(1)
	}
}

func (p configParser) ParseSshServer(val string) {
	config.sshServer = val
}

func (p configParser) ParseUpdateBlocked(val string) {
	config.updateBlocked = parseBool(val, "updateBlocked")
}

func (p configParser) ParseUpdateDirect(val string) {
	config.updateDirect = parseBool(val, "updateDirect")
}

func (p configParser) ParseAutoRetry(val string) {
	config.autoRetry = parseBool(val, "autoRetry")
}

func (p configParser) ParseDetectSSLErr(val string) {
	config.detectSSLErr = parseBool(val, "detectSSLErr")
}

func (p configParser) ParseLogFile(val string) {
	config.logFile = val
}

func (p configParser) ParseAlwaysProxy(val string) {
	config.alwaysProxy = parseBool(val, "alwaysProxy")
}

func (p configParser) ParseShadowSocks(val string) {
	if !isServerAddrValid(val) {
		fmt.Println("shadowsocks server must have port specified")
		os.Exit(1)
	}
	config.shadowSocks = val
}

func (p configParser) ParseShadowPasswd(val string) {
	config.shadowPasswd = val
}

func loadConfig() {
	f, err := openFile(config.rcFile)
	if f == nil || err != nil {
		return
	}
	defer f.Close()

	fr := bufio.NewReader(f)

	parser := reflect.ValueOf(configParser{})
	zeroMethod := reflect.Value{}

	var line string
	var n int
	for {
		n++
		line, err = ReadLine(fr)
		if err == io.EOF {
			return
		} else if err != nil {
			errl.Printf("Error reading rc file: %v\n", err)
			os.Exit(1)
		}

		if line == "" {
			continue
		}

		line = strings.TrimSpace(line)
		// Ignore comment
		if line[0] == '#' {
			continue
		}

		v := strings.Split(line, "=")
		if len(v) != 2 {
			fmt.Println("Config error: syntax error on line", n)
			os.Exit(1)
		}
		key, val := strings.TrimSpace(v[0]), strings.TrimSpace(v[1])

		methodName := "Parse" + strings.ToUpper(key[0:1]) + key[1:]
		method := parser.MethodByName(methodName)
		if method == zeroMethod {
			fmt.Printf("Config error: no such option \"%s\"\n", key)
			os.Exit(1)
		}
		args := []reflect.Value{reflect.ValueOf(val)}
		method.Call(args)
	}
}

func setSelfURL() {
	_, port := splitHostPort(config.listenAddr)
	selfURL127 = "127.0.0.1:" + port
	selfURLLH = "localhost:" + port
}
<|endoftext|>


<commit_before>package golds

const version = "0.0.0"

// Container basic interface for all collections
type Container interface {
	// Size returns amount of elements inside a collection
	Size() int

	// IsEmpty returns true if collection is empty
	IsEmpty() bool

	// Clear removes all elements from the collection
	Clear()
}
<commit_msg>all: Less interface (#42)<commit_after>package golds

const version = "0.0.0"

// Container basic interface for all collections
type Container interface {
	// Size returns amount of elements inside a collection
	Size() int

	// IsEmpty returns true if collection is empty
	IsEmpty() bool

	// Clear removes all elements from the collection
	Clear()
}

// Item is an interface for comparable items
// contains only one method Less, which return true
// if an element is less than given
type Item interface {
	Less(than interface{}) bool
}
<|endoftext|>


<commit_before>package main

import "runtime"

const (
	KiteVersion = "0.0.1"

	// Name is the user facing name for this binary. Internally we call it
	// klientctl to avoid confusion.
	Name = "kd"

	// KlientName is the user facing name for klient.
	KlientName = "KD Daemon"

	// KlientAddress is url of locally running klient to connect to send
	// user commands.
	KlientAddress = "http://127.0.0.1:56789/kite"

	// KiteHome is full path to the kite key that we will use to authenticate
	// to the given klient.
	KiteHome = "/etc/kite"

	// KlientDirectory is full path to directory that holds klient.
	KlientDirectory = "/opt/kite/klient"

	// KlientctlDirectory is full path to directory that holds klientctl.
	KlientctlDirectory = "/usr/local/bin"

	// KontrolUrl is the url to connect to authenticate local klient and get
	// list of machines.
	KontrolUrl = "https://koding.com/kontrol/kite"

	// Version is the current version of klientctl. This number is used
	// by CheckUpdate to determine if current version is behind or equal to latest
	// version on S3 bucket.
	Version = 8

	osName = runtime.GOOS

	// S3UpdateLocation is publically accessible url to check for new updates.
	S3UpdateLocation = "https://koding-kd.s3.amazonaws.com/latest-version.txt"

	// S3KlientctlPath is publically accessible url for latest version of klient.
	// Each OS has its own version of binary, identifiable by OS suffix.
	S3KlientPath = "https://koding-kd.s3.amazonaws.com/klient-" + osName

	// S3KlientctlPath is publically accessible url for latest version of
	// klientctl. Each OS has its own version of binary, identifiable by suffix.
	S3KlientctlPath = "https://koding-kd.s3.amazonaws.com/klientctl-" + osName

	// SSHDefaultKeyDir is the default directory that stores users ssh key pairs.
	SSHDefaultKeyDir = ".ssh"

	// SSHDefaultKeyDir is the default name of the ssh key pair.
	SSHDefaultKeyName = "kd-ssh-key"
)
<commit_msg>Bump version to 9<commit_after>package main

import "runtime"

const (
	KiteVersion = "0.0.1"

	// Name is the user facing name for this binary. Internally we call it
	// klientctl to avoid confusion.
	Name = "kd"

	// KlientName is the user facing name for klient.
	KlientName = "KD Daemon"

	// KlientAddress is url of locally running klient to connect to send
	// user commands.
	KlientAddress = "http://127.0.0.1:56789/kite"

	// KiteHome is full path to the kite key that we will use to authenticate
	// to the given klient.
	KiteHome = "/etc/kite"

	// KlientDirectory is full path to directory that holds klient.
	KlientDirectory = "/opt/kite/klient"

	// KlientctlDirectory is full path to directory that holds klientctl.
	KlientctlDirectory = "/usr/local/bin"

	// KontrolUrl is the url to connect to authenticate local klient and get
	// list of machines.
	KontrolUrl = "https://koding.com/kontrol/kite"

	// Version is the current version of klientctl. This number is used
	// by CheckUpdate to determine if current version is behind or equal to latest
	// version on S3 bucket.
	Version = 9

	osName = runtime.GOOS

	// S3UpdateLocation is publically accessible url to check for new updates.
	S3UpdateLocation = "https://koding-kd.s3.amazonaws.com/latest-version.txt"

	// S3KlientctlPath is publically accessible url for latest version of klient.
	// Each OS has its own version of binary, identifiable by OS suffix.
	S3KlientPath = "https://koding-kd.s3.amazonaws.com/klient-" + osName

	// S3KlientctlPath is publically accessible url for latest version of
	// klientctl. Each OS has its own version of binary, identifiable by suffix.
	S3KlientctlPath = "https://koding-kd.s3.amazonaws.com/klientctl-" + osName

	// SSHDefaultKeyDir is the default directory that stores users ssh key pairs.
	SSHDefaultKeyDir = ".ssh"

	// SSHDefaultKeyDir is the default name of the ssh key pair.
	SSHDefaultKeyName = "kd-ssh-key"
)
<|endoftext|>


<commit_before>package lex

// xgo/lex/lex_input_test.go

import (
	"fmt"
	. "launchpad.net/gocheck"
)
var _ = fmt.Print

func (s *XLSuite) TestS (c *C) {

	whitespace := []byte(" \n\r\t")
	for i := 0; i < len(whitespace) ; i++ {
		c.Assert(IsS(whitespace[i]), Equals, true)
	}
}
<commit_msg>adding a little nihongo<commit_after>package lex

// xgo/lex/lex_input_test.go

import (
	"fmt"
	. "launchpad.net/gocheck"
	"unicode/utf8"
)
var _ = fmt.Print

func (s *XLSuite) TestS (c *C) {

	whitespace := []byte(" \n\r\t")
	for i := 0; i < len(whitespace) ; i++ {
		c.Assert(IsS(whitespace[i]), Equals, true)
	}

	nihongo := "This is \u65e5\u672c\u8a93"
	// 3 bytes per kanji
	c.Assert(len(nihongo), Equals, 17)
	c.Assert(utf8.RuneCountInString(nihongo), Equals, 11)
	fmt.Printf("THE ENTIRE STRING:     '%s'\n", nihongo)
	fmt.Printf("A CHARACTER AT A TIME: '")

	// This prints out each Unicode character, each rune, as expected.
	for _, ch := range nihongo {
		fmt.Printf("%c", ch)
	}
	fmt.Println("'")

	tokyo := "私たちは、約3年半、東京の若松町に住んでいました。"
	c.Assert(utf8.RuneCountInString(tokyo), Equals, 25)
	// 3 bytes per kanji less two
	c.Assert(len(tokyo), Equals, 73)

	for _, ch := range tokyo {
		fmt.Printf("%#U\n", ch)
	}
	fmt.Println("'")
}
<|endoftext|>