<commit_before>package rest

import (
	"net/http"

	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"
	apirequest "k8s.io/apiserver/pkg/endpoints/request"
	"k8s.io/apiserver/pkg/registry/rest"
	"k8s.io/kubernetes/pkg/api"
)

// HookHandler is a Kubernetes API compatible webhook that is able to get access to the raw request
// and response. Used when adapting existing webhook code to the Kubernetes patterns.
type HookHandler interface {
	ServeHTTP(w http.ResponseWriter, r *http.Request, ctx apirequest.Context, name, subpath string) error
}

type httpHookHandler struct {
	http.Handler
}

func (h httpHookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, ctx apirequest.Context, name, subpath string) error {
	h.Handler.ServeHTTP(w, r)
	return nil
}

// WebHook provides a reusable rest.Storage implementation for linking a generic WebHook handler
// into the Kube API pattern. It is intended to be used with GET or POST against a resource's
// named path, possibly as a subresource. The handler has access to the extracted information
// from the Kube apiserver including the context, the name, and the subpath.
type WebHook struct {
	h        HookHandler
	allowGet bool
}

var _ rest.Connecter = &WebHook{}

// NewWebHook creates an adapter that implements rest.Connector for the given HookHandler.
func NewWebHook(handler HookHandler, allowGet bool) *WebHook {
	return &WebHook{
		h:        handler,
		allowGet: allowGet,
	}
}

// NewHTTPWebHook creates an adapter that implements rest.Connector for the given http.Handler.
func NewHTTPWebHook(handler http.Handler, allowGet bool) *WebHook {
	return &WebHook{
		h:        httpHookHandler{handler},
		allowGet: allowGet,
	}
}

// New() responds with the status object.
func (h *WebHook) New() runtime.Object {
	return &metav1.Status{}
}

// Connect responds to connections with a ConnectHandler
func (h *WebHook) Connect(ctx apirequest.Context, name string, options runtime.Object, responder rest.Responder) (http.Handler, error) {
	return &WebHookHandler{
		handler:   h.h,
		ctx:       ctx,
		name:      name,
		options:   options.(*api.PodProxyOptions),
		responder: responder,
	}, nil
}

// NewConnectionOptions identifies the options that should be passed to this hook
func (h *WebHook) NewConnectOptions() (runtime.Object, bool, string) {
	return &api.PodProxyOptions{}, true, "path"
}

// ConnectMethods returns the supported web hook types.
func (h *WebHook) ConnectMethods() []string {
	if h.allowGet {
		return []string{"GET", "POST"}
	}
	return []string{"POST"}
}

// WebHookHandler responds to web hook requests from the master.
type WebHookHandler struct {
	handler   HookHandler
	ctx       apirequest.Context
	name      string
	options   *api.PodProxyOptions
	responder rest.Responder
}

var _ http.Handler = &WebHookHandler{}

func (h *WebHookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if err := h.handler.ServeHTTP(w, r, h.ctx, h.name, h.options.Path); err != nil {
		h.responder.Error(err)
		return
	}
	w.WriteHeader(http.StatusOK)
}
<commit_msg>fix: return Build, not Status in build webhook New()<commit_after>package rest

import (
	"net/http"

	"k8s.io/apimachinery/pkg/runtime"
	apirequest "k8s.io/apiserver/pkg/endpoints/request"
	"k8s.io/apiserver/pkg/registry/rest"
	"k8s.io/kubernetes/pkg/api"

	buildapi "github.com/openshift/origin/pkg/build/api"
)

// HookHandler is a Kubernetes API compatible webhook that is able to get access to the raw request
// and response. Used when adapting existing webhook code to the Kubernetes patterns.
type HookHandler interface {
	ServeHTTP(w http.ResponseWriter, r *http.Request, ctx apirequest.Context, name, subpath string) error
}

type httpHookHandler struct {
	http.Handler
}

func (h httpHookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request, ctx apirequest.Context, name, subpath string) error {
	h.Handler.ServeHTTP(w, r)
	return nil
}

// WebHook provides a reusable rest.Storage implementation for linking a generic WebHook handler
// into the Kube API pattern. It is intended to be used with GET or POST against a resource's
// named path, possibly as a subresource. The handler has access to the extracted information
// from the Kube apiserver including the context, the name, and the subpath.
type WebHook struct {
	h        HookHandler
	allowGet bool
}

var _ rest.Connecter = &WebHook{}

// NewWebHook creates an adapter that implements rest.Connector for the given HookHandler.
func NewWebHook(handler HookHandler, allowGet bool) *WebHook {
	return &WebHook{
		h:        handler,
		allowGet: allowGet,
	}
}

// NewHTTPWebHook creates an adapter that implements rest.Connector for the given http.Handler.
func NewHTTPWebHook(handler http.Handler, allowGet bool) *WebHook {
	return &WebHook{
		h:        httpHookHandler{handler},
		allowGet: allowGet,
	}
}

// New() responds with the status object.
func (h *WebHook) New() runtime.Object {
	return &buildapi.Build{}
}

// Connect responds to connections with a ConnectHandler
func (h *WebHook) Connect(ctx apirequest.Context, name string, options runtime.Object, responder rest.Responder) (http.Handler, error) {
	return &WebHookHandler{
		handler:   h.h,
		ctx:       ctx,
		name:      name,
		options:   options.(*api.PodProxyOptions),
		responder: responder,
	}, nil
}

// NewConnectionOptions identifies the options that should be passed to this hook
func (h *WebHook) NewConnectOptions() (runtime.Object, bool, string) {
	return &api.PodProxyOptions{}, true, "path"
}

// ConnectMethods returns the supported web hook types.
func (h *WebHook) ConnectMethods() []string {
	if h.allowGet {
		return []string{"GET", "POST"}
	}
	return []string{"POST"}
}

// WebHookHandler responds to web hook requests from the master.
type WebHookHandler struct {
	handler   HookHandler
	ctx       apirequest.Context
	name      string
	options   *api.PodProxyOptions
	responder rest.Responder
}

var _ http.Handler = &WebHookHandler{}

func (h *WebHookHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if err := h.handler.ServeHTTP(w, r, h.ctx, h.name, h.options.Path); err != nil {
		h.responder.Error(err)
		return
	}
	w.WriteHeader(http.StatusOK)
}
<|endoftext|>


<commit_before>package main

import (
	"time"
	"flag"

	"github.com/mitchellh/cli"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"strconv"
	"strings"
	"github.com/aws/aws-sdk-go/service/iam"
	"regexp"
)

type DeleteCommand struct {
	Ui 			cli.Ui
	InstanceId 	string
	OlderThan 	string
	DryRun		bool
}

// descriptions for args
var deleteDscrInstanceId = "The EC2 instance from which the AMIs to be deleted were originally created"
var deleteOlderThan = "Delete AMIs older than the specified time; accepts formats like '30d' or '4h'"
var deleteDscrDryRun = "Execute a simulated run. Lists AMIs to be deleted, but does not actually delete them."

func (c *DeleteCommand) Help() string {
	return `ec2-snapper create <args> [--help]

Create an AMI of the given EC2 instance.

Available args are:
--instance      ` + deleteDscrInstanceId + `
--older-than    ` + deleteOlderThan + `
--dry-run       ` + deleteDscrDryRun
}

func (c *DeleteCommand) Synopsis() string {
	return "Delete the specified AMIs"
}

func (c *DeleteCommand) Run(args []string) int {

	// Handle the command-line args
	cmdFlags := flag.NewFlagSet("delete", flag.ExitOnError)
	cmdFlags.Usage = func() { c.Ui.Output(c.Help()) }

	cmdFlags.StringVar(&c.InstanceId, "instance", "", deleteDscrInstanceId)
	cmdFlags.StringVar(&c.OlderThan, "older-than", "", deleteOlderThan)
	cmdFlags.BoolVar(&c.DryRun, "dry-run", false, deleteDscrDryRun)

	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	// Check for required command-line args
	if c.InstanceId == "" {
		c.Ui.Error("ERROR: The argument '--instance' is required.")
		return 1
	}

	if c.OlderThan == "" {
		c.Ui.Error("ERROR: The argument '--older-than' is required.")
		return 1
	}

	// Warn the user that this is a dry run
	if c.DryRun {
		c.Ui.Warn("WARNING: This is a dry run, and no actions will be taken, despite what any output may say!")
	}

	// Create an EC2 service object; AWS region is picked up from the "AWS_REGION" env var.
	svc := ec2.New(nil)

	// Get a list of the existing AMIs that were created for the given EC2 instances
	resp, err := svc.DescribeImages(&ec2.DescribeImagesInput{
		Filters: []*ec2.Filter{
			&ec2.Filter{
				Name: aws.String("tag:ec2-snapper-instance-id"),
				Values: []*string{&c.InstanceId},
			},
		},
	})
	if err != nil {
		panic(err)
	}
	if len(resp.Images) == 0 {
		c.Ui.Error("No AMIs were found for EC2 instance \"" + c.InstanceId + "\"")
		return 0
	}

	// Parse our date range
	match, _ := regexp.MatchString("^[0-9]*(h|d)$", c.OlderThan)
	if ! match {
		c.Ui.Error("The --older-than value of \"" + c.OlderThan + "\" is not formatted properly.  Use formats like 30d or 24h")
		return 0
	}

	var hours float64
	// We were given a time like "12h"
	if match, _ := regexp.MatchString("^[0-9]*(h)$", c.OlderThan); match {
		hours, _ = strconv.ParseFloat(c.OlderThan[0:len(c.OlderThan)-1], 64)
	}

	// We were given a time like "15d"
	if match, _ := regexp.MatchString("^[0-9]*(d)$", c.OlderThan); match {
		hours, _ = strconv.ParseFloat(c.OlderThan[0:len(c.OlderThan)-1], 64)
		hours *= 24
	}

	// Now filter the AMIs to only include those within our date range
	var filteredAmis[]*ec2.Image
	for i := 0; i < len(resp.Images); i++ {
		now := time.Now()
		creationDate, err := time.Parse(time.RFC3339Nano, *resp.Images[i].CreationDate)
		if err != nil {
			panic(err)
		}

		duration := now.Sub(creationDate)

		if duration.Hours() > hours {
			c.Ui.Error(duration.String())
			filteredAmis = append(filteredAmis, resp.Images[i])
		}
	}

	// Get the AWS Account ID of the current AWS account
	// We need this to do a more efficient lookup on the snapshot volumes
	// - Per http://docs.aws.amazon.com/general/latest/gr/acct-identifiers.html, we assume the Account Id is always 12 digits
	// - Per http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arn-syntax-iam, we assume the current user's ARN
	//   is always of the form arn:aws:iam::account-id:user/user-name
	svcIam := iam.New(nil)

	respIam, err := svcIam.GetUser(&iam.GetUserInput{})
	awsAccountId := strings.Split(*respIam.User.ARN, ":")[4]
	c.Ui.Output("==> Identified current AWS Account Id as " + awsAccountId)

	// Get a list of every single snapshot in our account
	// (I wasn't able to find a better way to filter these, but suggestions welcome!)
	respDscrSnapshots, err := svc.DescribeSnapshots(&ec2.DescribeSnapshotsInput{
		OwnerIDs: []*string{&awsAccountId},
	})
	if err != nil {
		panic(err)
	}
	c.Ui.Output("==> Found " + strconv.Itoa(len(respDscrSnapshots.Snapshots)) + " snapshots in our account to search through.")

	// Begin deleting AMIs...
	for i := 0; i < len(filteredAmis); i++ {
		// Step 1: De-register the AMI
		c.Ui.Output(*filteredAmis[i].ImageID + ": De-registering...")
		_, err := svc.DeregisterImage(&ec2.DeregisterImageInput{
			DryRun: &c.DryRun,
			ImageID: filteredAmis[i].ImageID,
		})
		if err != nil {
			if ! strings.Contains(err.Error(), "DryRunOperation") {
				panic(err)
			}
		}

		// Step 2: Delete the corresponding AMI snapshot
		// Look at the "description" for each Snapshot to see if it contains our AMI id
		snapshotId := ""
		for j := 0; j < len(respDscrSnapshots.Snapshots); j++ {
			if strings.Contains(*respDscrSnapshots.Snapshots[j].Description, *filteredAmis[i].ImageID) {
				snapshotId = *respDscrSnapshots.Snapshots[j].SnapshotID
				break
			}
		}

		c.Ui.Output(*filteredAmis[i].ImageID + ": Deleting snapshot " + snapshotId + "...")
		svc.DeleteSnapshot(&ec2.DeleteSnapshotInput{
			DryRun: &c.DryRun,
			SnapshotID: &snapshotId,
		})

		c.Ui.Output(*filteredAmis[i].ImageID + ": Done!")
		c.Ui.Output("")
	}

	// Generate a nicely formatted timestamp for right now
	//	const dateLayoutForAmiName = "2006-01-02 at 15_04_05 (MST)"
	time.Now()
	//t := time.Now()

	if c.DryRun {
		c.Ui.Info("==> DRY RUN. Had this not been a dry run, " + strconv.Itoa(len(filteredAmis)) + " AMI's and their corresponding snapshots would have been deleted.")
	} else {
		c.Ui.Info("==> Success! Deleted " + strconv.Itoa(len(filteredAmis)) + " AMI's and their corresponding snapshots.")
	}
	return 0
}

<commit_msg>Added support for --older-than for minutes<commit_after>package main

import (
	"time"
	"flag"

	"github.com/mitchellh/cli"
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/service/ec2"
	"strconv"
	"strings"
	"github.com/aws/aws-sdk-go/service/iam"
	"regexp"
)

type DeleteCommand struct {
	Ui 			cli.Ui
	InstanceId 	string
	OlderThan 	string
	DryRun		bool
}

// descriptions for args
var deleteDscrInstanceId = "The EC2 instance from which the AMIs to be deleted were originally created"
var deleteOlderThan = "Delete AMIs older than the specified time; accepts formats like '30d' or '4h'"
var deleteDscrDryRun = "Execute a simulated run. Lists AMIs to be deleted, but does not actually delete them."

func (c *DeleteCommand) Help() string {
	return `ec2-snapper create <args> [--help]

Create an AMI of the given EC2 instance.

Available args are:
--instance      ` + deleteDscrInstanceId + `
--older-than    ` + deleteOlderThan + `
--dry-run       ` + deleteDscrDryRun
}

func (c *DeleteCommand) Synopsis() string {
	return "Delete the specified AMIs"
}

func (c *DeleteCommand) Run(args []string) int {

	// Handle the command-line args
	cmdFlags := flag.NewFlagSet("delete", flag.ExitOnError)
	cmdFlags.Usage = func() { c.Ui.Output(c.Help()) }

	cmdFlags.StringVar(&c.InstanceId, "instance", "", deleteDscrInstanceId)
	cmdFlags.StringVar(&c.OlderThan, "older-than", "", deleteOlderThan)
	cmdFlags.BoolVar(&c.DryRun, "dry-run", false, deleteDscrDryRun)

	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	// Check for required command-line args
	if c.InstanceId == "" {
		c.Ui.Error("ERROR: The argument '--instance' is required.")
		return 1
	}

	if c.OlderThan == "" {
		c.Ui.Error("ERROR: The argument '--older-than' is required.")
		return 1
	}

	// Warn the user that this is a dry run
	if c.DryRun {
		c.Ui.Warn("WARNING: This is a dry run, and no actions will be taken, despite what any output may say!")
	}

	// Create an EC2 service object; AWS region is picked up from the "AWS_REGION" env var.
	svc := ec2.New(nil)

	// Get a list of the existing AMIs that were created for the given EC2 instances
	resp, err := svc.DescribeImages(&ec2.DescribeImagesInput{
		Filters: []*ec2.Filter{
			&ec2.Filter{
				Name: aws.String("tag:ec2-snapper-instance-id"),
				Values: []*string{&c.InstanceId},
			},
		},
	})
	if err != nil {
		panic(err)
	}
	if len(resp.Images) == 0 {
		c.Ui.Error("No AMIs were found for EC2 instance \"" + c.InstanceId + "\"")
		return 0
	}

	// Parse our date range
	match, _ := regexp.MatchString("^[0-9]*(h|d|m)$", c.OlderThan)
	if ! match {
		c.Ui.Error("The --older-than value of \"" + c.OlderThan + "\" is not formatted properly.  Use formats like 30d or 24h")
		return 0
	}

	var minutes float64
	var hours float64

	// We were given a time like "12h"
	if match, _ := regexp.MatchString("^[0-9]*(h)$", c.OlderThan); match {
		hours, _ = strconv.ParseFloat(c.OlderThan[0:len(c.OlderThan)-1], 64)
	}

	// We were given a time like "15d"
	if match, _ := regexp.MatchString("^[0-9]*(d)$", c.OlderThan); match {
		hours, _ = strconv.ParseFloat(c.OlderThan[0:len(c.OlderThan)-1], 64)
		hours *= 24
	}

	// We were given a time like "5m"
	if match, _ := regexp.MatchString("^[0-9]*(m)$", c.OlderThan); match {
		minutes, _ = strconv.ParseFloat(c.OlderThan[0:len(c.OlderThan)-1], 64)
		hours = minutes/60
	}

	// Get the AWS Account ID of the current AWS account
	// We need this to do a more efficient lookup on the snapshot volumes
	// - Per http://docs.aws.amazon.com/general/latest/gr/acct-identifiers.html, we assume the Account Id is always 12 digits
	// - Per http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#arn-syntax-iam, we assume the current user's ARN
	//   is always of the form arn:aws:iam::account-id:user/user-name
	svcIam := iam.New(nil)

	respIam, err := svcIam.GetUser(&iam.GetUserInput{})
	awsAccountId := strings.Split(*respIam.User.ARN, ":")[4]
	c.Ui.Output("==> Identified current AWS Account Id as " + awsAccountId)

	// Now filter the AMIs to only include those within our date range
	var filteredAmis[]*ec2.Image
	for i := 0; i < len(resp.Images); i++ {
		now := time.Now()
		creationDate, err := time.Parse(time.RFC3339Nano, *resp.Images[i].CreationDate)
		if err != nil {
			panic(err)
		}

		duration := now.Sub(creationDate)

		if duration.Hours() > hours {
			filteredAmis = append(filteredAmis, resp.Images[i])
		}
	}
	c.Ui.Output("==> Found " + strconv.Itoa(len(filteredAmis)) + " total AMIs for deletion.")

	// Get a list of every single snapshot in our account
	// (I wasn't able to find a better way to filter these, but suggestions welcome!)
	respDscrSnapshots, err := svc.DescribeSnapshots(&ec2.DescribeSnapshotsInput{
		OwnerIDs: []*string{&awsAccountId},
	})
	if err != nil {
		panic(err)
	}
	c.Ui.Output("==> Found " + strconv.Itoa(len(respDscrSnapshots.Snapshots)) + " total snapshots in our account.")

	// Begin deleting AMIs...
	for i := 0; i < len(filteredAmis); i++ {
		// Step 1: De-register the AMI
		c.Ui.Output(*filteredAmis[i].ImageID + ": De-registering AMI named \"" + *filteredAmis[i].Name + "\"...")
		_, err := svc.DeregisterImage(&ec2.DeregisterImageInput{
			DryRun: &c.DryRun,
			ImageID: filteredAmis[i].ImageID,
		})
		if err != nil {
			if ! strings.Contains(err.Error(), "DryRunOperation") {
				panic(err)
			}
		}

		// Step 2: Delete the corresponding AMI snapshot
		// Look at the "description" for each Snapshot to see if it contains our AMI id
		snapshotId := ""
		for j := 0; j < len(respDscrSnapshots.Snapshots); j++ {
			if strings.Contains(*respDscrSnapshots.Snapshots[j].Description, *filteredAmis[i].ImageID) {
				snapshotId = *respDscrSnapshots.Snapshots[j].SnapshotID
				break
			}
		}

		c.Ui.Output(*filteredAmis[i].ImageID + ": Deleting snapshot " + snapshotId + "...")
		svc.DeleteSnapshot(&ec2.DeleteSnapshotInput{
			DryRun: &c.DryRun,
			SnapshotID: &snapshotId,
		})

		c.Ui.Output(*filteredAmis[i].ImageID + ": Done!")
		c.Ui.Output("")
	}

	// Generate a nicely formatted timestamp for right now
	//	const dateLayoutForAmiName = "2006-01-02 at 15_04_05 (MST)"
	time.Now()
	//t := time.Now()

	if c.DryRun {
		c.Ui.Info("==> DRY RUN. Had this not been a dry run, " + strconv.Itoa(len(filteredAmis)) + " AMI's and their corresponding snapshots would have been deleted.")
	} else {
		c.Ui.Info("==> Success! Deleted " + strconv.Itoa(len(filteredAmis)) + " AMI's and their corresponding snapshots.")
	}
	return 0
}

<|endoftext|>


<commit_before>// Copyright 2010 The GoGo Authors. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import "./libgogo/_obj/libgogo"

//
// Struct holding the information about a file that is compiled
//
type FileInfo struct {
    filename string;
    lineCounter uint64;
    charCounter uint64;
    fd uint64;
};

//
// Fileinformation for all files that are compiled in this run
// Is limited by 10 to reduce memory etc.
//
var fileInfo [10]FileInfo;
var fileInfoLen uint64 = 0;
var curFileIndex uint64 = 0;

//
// A very basic debug flag
// Set to 1000 to enable all parsing strings
//
var DEBUG_LEVEL uint64 = 0;

//
// Entry point of the compiler
//
func main() {
    var errno uint64;
    var i uint64;

    libgogo.GetArgv()

    if libgogo.Argc <= 1 {
        libgogo.ExitError("Usage: gogo file1.go [file2.go ...]",1);
    }

    if libgogo.Argc > 11 {
        libgogo.ExitError("Cannot compile more than 10 files at once",1);
    }

    for i=1; i < libgogo.Argc ; i= i+1 {
        curFileIndex = i-1;
        fileInfo[curFileIndex].filename = libgogo.Argv[i];
        fileInfo[curFileIndex].lineCounter = 1;
        fileInfo[curFileIndex].charCounter = 1;

        fileInfo[curFileIndex].fd = libgogo.FileOpen(libgogo.Argv[i], 0);
        if (fileInfo[curFileIndex].fd == 0) {
            GlobalError("Cannot open file.");
        }
    }
    fileInfoLen = i-1;

    for curFileIndex=0;curFileIndex<fileInfoLen;curFileIndex=curFileIndex+1 {
        Parse();
    }

    for curFileIndex=0;curFileIndex<fileInfoLen;curFileIndex=curFileIndex+1 {
        errno = libgogo.FileClose(fileInfo[curFileIndex].fd);
        if errno != 0 {
            GlobalError("Cannot close file.");
        }
    }

    //TEMP DEBUG: symbol table
		/*libgogo.PrintTypes(libgogo.Types);
		libgogo.PrintObjects(libgogo.GlobalObjects);*/
    //---
}
<commit_msg>gogo.go: Corrected overlooked missing semicolon which has not been recognized by the parser (and still is ?!)<commit_after>// Copyright 2010 The GoGo Authors. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import "./libgogo/_obj/libgogo"

//
// Struct holding the information about a file that is compiled
//
type FileInfo struct {
    filename string;
    lineCounter uint64;
    charCounter uint64;
    fd uint64;
};

//
// Fileinformation for all files that are compiled in this run
// Is limited by 10 to reduce memory etc.
//
var fileInfo [10]FileInfo;
var fileInfoLen uint64 = 0;
var curFileIndex uint64 = 0;

//
// A very basic debug flag
// Set to 1000 to enable all parsing strings
//
var DEBUG_LEVEL uint64 = 0;

//
// Entry point of the compiler
//
func main() {
    var errno uint64;
    var i uint64;

    libgogo.GetArgv();

    if libgogo.Argc <= 1 {
        libgogo.ExitError("Usage: gogo file1.go [file2.go ...]",1);
    }

    if libgogo.Argc > 11 {
        libgogo.ExitError("Cannot compile more than 10 files at once",1);
    }

    for i=1; i < libgogo.Argc ; i= i+1 {
        curFileIndex = i-1;
        fileInfo[curFileIndex].filename = libgogo.Argv[i];
        fileInfo[curFileIndex].lineCounter = 1;
        fileInfo[curFileIndex].charCounter = 1;

        fileInfo[curFileIndex].fd = libgogo.FileOpen(libgogo.Argv[i], 0);
        if (fileInfo[curFileIndex].fd == 0) {
            GlobalError("Cannot open file.");
        }
    }
    fileInfoLen = i-1;

    for curFileIndex=0;curFileIndex<fileInfoLen;curFileIndex=curFileIndex+1 {
        Parse();
    }

    for curFileIndex=0;curFileIndex<fileInfoLen;curFileIndex=curFileIndex+1 {
        errno = libgogo.FileClose(fileInfo[curFileIndex].fd);
        if errno != 0 {
            GlobalError("Cannot close file.");
        }
    }

    //TEMP DEBUG: symbol table
		/*libgogo.PrintTypes(libgogo.Types);
		libgogo.PrintObjects(libgogo.GlobalObjects);*/
    //---
}
<|endoftext|>


<commit_before>package matstack

import (
	"errors"
	"fmt"

	"github.com/go-gl/mathgl/mgl32"
)

// A matrix stack is a linear fully-persistent data structure of matrix multiplications
// Each push to a MatStack multiplies the current top of the stack with thew new matrix
// and appends it to the top. Each pop undoes the previous multiplication.
//
// This is extremely useful for scenegraphs, where you can push the transformation of the current
// object for children to use, and pop the transformation before returning to the parent.
type MatStack []mgl32.Mat4

// Returns a matrix stack where the top element is the identity.
func NewMatStack() *MatStack {
	ms := make(MatStack, 1)
	ms[0] = mgl32.Ident4()

	return &ms
}

// Multiplies the current top matrix by m, and pushes the result
// on the stack.
func (ms *MatStack) Push(m mgl32.Mat4) {
	prev := (*ms)[len(*ms)-1]
	(*ms) = append(*ms, prev.Mul4(m))
}

// Pops the current matrix off the top of the stack and returns it.
// If the matrix stack only has one element left, this will return an error.
func (ms *MatStack) Pop() (mgl32.Mat4, error) {
	if len(*ms) == 1 {
		return mgl32.Mat4{}, errors.New("attempt to pop last element of the stack; Matrix Stack must have at least one element")
	}

	retVal := (*ms)[len(*ms)-1]

	(*ms) = (*ms)[:len(*ms)-1]

	return retVal, nil
}

// Returns the value of the current top element of the stack, without
// removing it.
func (ms *MatStack) Peek() mgl32.Mat4 {
	return (*ms)[len(*ms)-1]
}

// Returns the size of the matrix stack. This value will never be less
// than 1.
func (ms *MatStack) Len() int {
	return len(*ms)
}

// This cuts down the matrix as if Pop had been called n times. If n would
// bring the matrix down below 1 element, this does nothing and returns an error.
func (ms *MatStack) Unwind(n int) error {
	if n > len(*ms)-1 {
		return errors.New("Cannot unwind a matrix to below 1 value")
	}

	(*ms) = (*ms)[:len(*ms)-n]
	return nil
}

// Copy will create a new "branch" of the current matrix stack,
// the copy will contain all elements of the current stack in a new stack. Changes to
// one will never affect the other.
func (ms *MatStack) Copy() *MatStack {
	v := append(MatStack{}, (*ms)...)
	return &v
}

// Reseed is tricky. It attempts to seed an arbitrary point in the matrix and replay all transformations
// as if that point in the push had been the argument "change" instead of the original value.
// The matrix stack does NOT keep track of arguments so this is done via consecutive inverses.
// If the inverse of element i can be found, we can calculate the transformation that was given at point i+1.
// This transformation can then be multiplied by the NEW matrix at point i to complete the "what if".
// If no such inverse can be found at any given point along the rebase, it will be aborted, and the original
// stack will NOT be visibly affected. The error returned will be of type NoInverseError.
//
// If n is out of bounds (n <= 0 || n >= len(*ms)), a generic error from the errors package will be returned.
//
// If you have the old transformations retained, it is recommended
// that you use Unwind followed by Push(change) and then further calling Push for each transformation. Rebase is
// imprecise by nature, and sometimes impossible. It's also expensive due to the inverse calculation at each point.
func (ms *MatStack) Reseed(n int, change mgl32.Mat4) error {
	if n >= len(*ms) || n <= 0 {
		return errors.New("Cannot rebase at the given point on the stack, it is out of bounds.")
	}

	return ms.reseed(n, change)
}

// Operates like reseed with no bounds checking; allows us to overwrite
// the leading identity matrix with Rebase.
func (ms *MatStack) reseed(n int, change mgl32.Mat4) error {
	backup := []mgl32.Mat4((*ms)[n:])
	backup = append([]mgl32.Mat4{}, backup...) // copy into new slice

	curr := (*ms)[n]
	(*ms)[n] = (*ms)[n-1].Mul4(change)

	for i := n + 1; i < len(*ms); i++ {
		inv := curr.Inv()

		blank := mgl32.Mat4{}
		if inv == blank {
			ms.undoRebase(n, backup)
			return NoInverseError{Loc: i - 1, Mat: curr}
		}

		ghost := inv.Mul4((*ms)[i])

		curr = (*ms)[i]
		(*ms)[i] = (*ms)[i-1].Mul4(ghost)
	}

	return nil
}

func (ms *MatStack) undoRebase(n int, prev []mgl32.Mat4) {
	for i := n; i < len(*ms); i++ {
		(*ms)[i] = prev[i-n]
	}
}

// Rebase replays the current matrix stack as if the transformation that occurred at index "from"
// in ms had instead started at the top of m.
//
// If this completes insuccessfully, m and ms will not be altered,
// if this completes successfuly ms and m will point to the same underlying slice, with the Ident4
// at the bottom of m being the new stack bottom.
func Rebase(ms *MatStack, from int, m *MatStack) (*MatStack, error) {
	if from <= 0 || from >= len(*ms) {
		return nil, errors.New("Cannot rebase, index out of range")
	}

	// Shift tmp so that the element immediately
	// preceding our target is the "top" element of the list.
	tmp := ms.Copy()
	if from == 1 {
		(*tmp) = append(*tmp, mgl32.Mat4{})
	}
	copy((*tmp)[1:], (*tmp)[from-1:])
	if from-2 > 0 {
		(*tmp) = (*tmp)[:len(*tmp)-(from-2)]
	}

	err := tmp.Reseed(1, m.Peek())
	if err != nil {
		return nil, err
	}

	(*tmp) = append(*m, (*tmp)[2:]...)

	return tmp, nil
}

// A NoInverseError is returned on rebase when an inverse cannot be found along the chain,
// due to a transformation projecting the matrix into a singularity. The values include the matrix
// no inverse can be found for, and the location of that matrix.
type NoInverseError struct {
	Mat mgl32.Mat4
	Loc int
}

func (nie NoInverseError) Error() string {
	return fmt.Sprintf("cannot find inverse of matrix %v at location %d in matrix stack, aborting rebase/reseed")
}
<commit_msg>Documentation update<commit_after>package matstack

import (
	"errors"
	"fmt"

	"github.com/go-gl/mathgl/mgl32"
)

// A matrix stack is a linear fully-persistent data structure of matrix multiplications
// Each push to a MatStack multiplies the current top of the stack with thew new matrix
// and appends it to the top. Each pop undoes the previous multiplication.
//
// This is extremely useful for scenegraphs, where you can push the transformation of the current
// object for children to use, and pop the transformation before returning to the parent.
type MatStack []mgl32.Mat4

// Returns a matrix stack where the top element is the identity.
func NewMatStack() *MatStack {
	ms := make(MatStack, 1)
	ms[0] = mgl32.Ident4()

	return &ms
}

// Multiplies the current top matrix by m, and pushes the result
// on the stack.
func (ms *MatStack) Push(m mgl32.Mat4) {
	prev := (*ms)[len(*ms)-1]
	(*ms) = append(*ms, prev.Mul4(m))
}

// Pops the current matrix off the top of the stack and returns it.
// If the matrix stack only has one element left, this will return an error.
func (ms *MatStack) Pop() (mgl32.Mat4, error) {
	if len(*ms) == 1 {
		return mgl32.Mat4{}, errors.New("attempt to pop last element of the stack; Matrix Stack must have at least one element")
	}

	retVal := (*ms)[len(*ms)-1]

	(*ms) = (*ms)[:len(*ms)-1]

	return retVal, nil
}

// Returns the value of the current top element of the stack, without
// removing it.
func (ms *MatStack) Peek() mgl32.Mat4 {
	return (*ms)[len(*ms)-1]
}

// Returns the size of the matrix stack. This value will never be less
// than 1.
func (ms *MatStack) Len() int {
	return len(*ms)
}

// This cuts down the matrix as if Pop had been called n times. If n would
// bring the matrix down below 1 element, this does nothing and returns an error.
func (ms *MatStack) Unwind(n int) error {
	if n > len(*ms)-1 {
		return errors.New("Cannot unwind a matrix to below 1 value")
	}

	(*ms) = (*ms)[:len(*ms)-n]
	return nil
}

// Copy will create a new "branch" of the current matrix stack,
// the copy will contain all elements of the current stack in a new stack. Changes to
// one will never affect the other.
func (ms *MatStack) Copy() *MatStack {
	v := append(MatStack{}, (*ms)...)
	return &v
}

// Reseed is tricky. It attempts to seed an arbitrary point in the matrix and replay all transformations
// as if that point in the push had been the argument "change" instead of the original value.
// The matrix stack does NOT keep track of arguments so this is done via consecutive inverses.
// If the inverse of element i can be found, we can calculate the transformation that was given at point i+1.
// This transformation can then be multiplied by the NEW matrix at point i to complete the "what if".
// If no such inverse can be found at any given point along the rebase, it will be aborted, and the original
// stack will NOT be visibly affected. The error returned will be of type NoInverseError.
//
// If n is out of bounds (n <= 0 || n >= len(*ms)), a generic error from the errors package will be returned.
//
// If you have the old transformations retained, it is recommended
// that you use Unwind followed by Push(change) and then further calling Push for each transformation. Rebase is
// imprecise by nature, and sometimes impossible. It's also expensive due to the inverse calculation at each point.
func (ms *MatStack) Reseed(n int, change mgl32.Mat4) error {
	if n >= len(*ms) || n <= 0 {
		return errors.New("Cannot rebase at the given point on the stack, it is out of bounds.")
	}

	return ms.reseed(n, change)
}

// Operates like reseed with no bounds checking; allows us to overwrite
// the leading identity matrix with Rebase.
func (ms *MatStack) reseed(n int, change mgl32.Mat4) error {
	backup := []mgl32.Mat4((*ms)[n:])
	backup = append([]mgl32.Mat4{}, backup...) // copy into new slice

	curr := (*ms)[n]
	(*ms)[n] = (*ms)[n-1].Mul4(change)

	for i := n + 1; i < len(*ms); i++ {
		inv := curr.Inv()

		blank := mgl32.Mat4{}
		if inv == blank {
			ms.undoRebase(n, backup)
			return NoInverseError{Loc: i - 1, Mat: curr}
		}

		ghost := inv.Mul4((*ms)[i])

		curr = (*ms)[i]
		(*ms)[i] = (*ms)[i-1].Mul4(ghost)
	}

	return nil
}

func (ms *MatStack) undoRebase(n int, prev []mgl32.Mat4) {
	for i := n; i < len(*ms); i++ {
		(*ms)[i] = prev[i-n]
	}
}

// Rebase replays the current matrix stack as if the transformation that occurred at index "from"
// in ms had instead started at the top of m.
//
// This returns a brand new stack containing all of m followed by all transformations
// at from and after on ms as if they has been done on m instead.
func Rebase(ms *MatStack, from int, m *MatStack) (*MatStack, error) {
	if from <= 0 || from >= len(*ms) {
		return nil, errors.New("Cannot rebase, index out of range")
	}

	// Shift tmp so that the element immediately
	// preceding our target is the "top" element of the list.
	tmp := ms.Copy()
	if from == 1 {
		(*tmp) = append(*tmp, mgl32.Mat4{})
	}
	copy((*tmp)[1:], (*tmp)[from-1:])
	if from-2 > 0 {
		(*tmp) = (*tmp)[:len(*tmp)-(from-2)]
	}

	err := tmp.Reseed(1, m.Peek())
	if err != nil {
		return nil, err
	}

	(*tmp) = append(*m, (*tmp)[2:]...)

	return tmp, nil
}

// A NoInverseError is returned on rebase when an inverse cannot be found along the chain,
// due to a transformation projecting the matrix into a singularity. The values include the matrix
// no inverse can be found for, and the location of that matrix.
type NoInverseError struct {
	Mat mgl32.Mat4
	Loc int
}

func (nie NoInverseError) Error() string {
	return fmt.Sprintf("cannot find inverse of matrix %v at location %d in matrix stack, aborting rebase/reseed")
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/gdamore/tcell"
	"strings"
)

const helpTxt = `Press Ctrl-q to quit help

Micro keybindings:

Ctrl-q:   Quit
Ctrl-s:   Save
Ctrl-o:   Open file

Ctrl-z:   Undo
Ctrl-y:   Redo

Ctrl-a:   Select all

Ctrl-c:   Copy
Ctrl-x:   Cut
Ctrl-v:   Paste

Ctrl-h:   Open help

Ctrl-u:   Half page up
Ctrl-d:   Half page down
PageUp:   Page up
PageDown: Page down

Ctrl-e:   Set option

Micro options:

colorscheme: loads the colorscheme stored in ~/.micro/colorschemes/'option'.micro
	default value: 'default'

tabsize: sets the tab size to 'option'
	default value: '4'
`

// DisplayHelp displays the help txt
// It blocks the main loop
func DisplayHelp() {
	topline := 0
	_, height := screen.Size()
	screen.HideCursor()
	totalLines := strings.Split(helpTxt, "\n")
	for {
		screen.Clear()

		lineEnd := topline + height
		if lineEnd > len(totalLines) {
			lineEnd = len(totalLines)
		}
		lines := totalLines[topline:lineEnd]
		for y, line := range lines {
			for x, ch := range line {
				st := tcell.StyleDefault
				screen.SetContent(x, y, ch, nil, st)
			}
		}

		screen.Show()

		event := screen.PollEvent()
		switch e := event.(type) {
		case *tcell.EventResize:
			_, height = e.Size()
		case *tcell.EventKey:
			switch e.Key() {
			case tcell.KeyUp:
				if topline > 0 {
					topline--
				}
			case tcell.KeyDown:
				if topline < len(totalLines)-height {
					topline++
				}
			case tcell.KeyCtrlQ, tcell.KeyCtrlW, tcell.KeyEscape, tcell.KeyCtrlC:
				return
			}
		}
	}
}
<commit_msg>Update help text<commit_after>package main

import (
	"github.com/gdamore/tcell"
	"strings"
)

const helpTxt = `Press Ctrl-q to quit help

Micro keybindings:

Ctrl-q:   Quit
Ctrl-s:   Save
Ctrl-o:   Open file

Ctrl-z:   Undo
Ctrl-y:   Redo

Ctrl-a:   Select all

Ctrl-c:   Copy
Ctrl-x:   Cut
Ctrl-v:   Paste

Ctrl-h:   Open help

Ctrl-u:   Half page up
Ctrl-d:   Half page down
PageUp:   Page up
PageDown: Page down

Ctrl-e:   Execute a command

Possible commands:

'quit': Quits micro
'save': saves the current buffer
'set option value': sets the option to value. Please see the next section for a list of options you can set

Micro options:

colorscheme: loads the colorscheme stored in ~/.micro/colorschemes/'option'.micro
	default value: 'default'

tabsize: sets the tab size to 'option'
	default value: '4'
`

// DisplayHelp displays the help txt
// It blocks the main loop
func DisplayHelp() {
	topline := 0
	_, height := screen.Size()
	screen.HideCursor()
	totalLines := strings.Split(helpTxt, "\n")
	for {
		screen.Clear()

		lineEnd := topline + height
		if lineEnd > len(totalLines) {
			lineEnd = len(totalLines)
		}
		lines := totalLines[topline:lineEnd]
		for y, line := range lines {
			for x, ch := range line {
				st := tcell.StyleDefault
				screen.SetContent(x, y, ch, nil, st)
			}
		}

		screen.Show()

		event := screen.PollEvent()
		switch e := event.(type) {
		case *tcell.EventResize:
			_, height = e.Size()
		case *tcell.EventKey:
			switch e.Key() {
			case tcell.KeyUp:
				if topline > 0 {
					topline--
				}
			case tcell.KeyDown:
				if topline < len(totalLines)-height {
					topline++
				}
			case tcell.KeyCtrlQ, tcell.KeyCtrlW, tcell.KeyEscape, tcell.KeyCtrlC:
				return
			}
		}
	}
}
<|endoftext|>


<commit_before>package common

import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"unicode"

	"github.com/ryanuber/columnize"
	"golang.org/x/sync/errgroup"
)

type errfunc func() error

// AppRoot returns the app root path
func AppRoot(appName string) string {
	dokkuRoot := MustGetEnv("DOKKU_ROOT")
	return fmt.Sprintf("%v/%v", dokkuRoot, appName)
}

// AppHostRoot returns the app root path
func AppHostRoot(appName string) string {
	dokkuHostRoot := MustGetEnv("DOKKU_HOST_ROOT")
	return fmt.Sprintf("%v/%v", dokkuHostRoot, appName)
}

// AskForDestructiveConfirmation checks for confirmation on destructive actions
func AskForDestructiveConfirmation(name string, objectType string) error {
	LogWarn("WARNING: Potentially Destructive Action")
	LogWarn(fmt.Sprintf("This command will destroy %v %v.", objectType, name))
	LogWarn(fmt.Sprintf("To proceed, type \"%v\"", name))
	fmt.Print("> ")
	var response string
	_, err := fmt.Scanln(&response)
	if err != nil {
		return err
	}

	if response != name {
		LogStderr("Confirmation did not match test. Aborted.")
		os.Exit(1)
		return nil
	}

	return nil
}

// CommandUsage outputs help for a command
func CommandUsage(helpHeader string, helpContent string) {
	config := columnize.DefaultConfig()
	config.Delim = ","
	config.Prefix = "    "
	config.Empty = ""
	content := strings.Split(helpContent, "\n")[1:]
	fmt.Println(helpHeader)
	fmt.Println(columnize.Format(content, config))
}

// GetAppScheduler fetches the scheduler for a given application
func GetAppScheduler(appName string) string {
	appScheduler := ""
	globalScheduler := ""

	ctx := context.Background()
	errs, ctx := errgroup.WithContext(ctx)

	if appName != "--global" {
		errs.Go(func() error {
			appScheduler = getAppScheduler(appName)
			return nil
		})
	}
	errs.Go(func() error {
		globalScheduler = GetGlobalScheduler()
		return nil
	})
	errs.Wait()

	if appScheduler == "" {
		appScheduler = globalScheduler
	}
	return appScheduler
}

func getAppScheduler(appName string) string {
	b, _ := PlugnTriggerOutput("config-get", []string{appName, "DOKKU_SCHEDULER"}...)
	value := strings.TrimSpace(string(b[:]))
	if value != "" {
		return value
	}
	return ""
}

// GetGlobalScheduler fetchs the global scheduler
func GetGlobalScheduler() string {
	b, _ := PlugnTriggerOutput("config-get-global", []string{"DOKKU_SCHEDULER"}...)
	value := strings.TrimSpace(string(b[:]))
	if value != "" {
		return value
	}

	return "docker-local"
}

// GetDeployingAppImageName returns deploying image identifier for a given app, tag tuple. validate if tag is presented
func GetDeployingAppImageName(appName, imageTag, imageRepo string) (string, error) {
	imageRemoteRepository := ""
	newImageTag := ""
	newImageRepo := ""

	ctx := context.Background()
	errs, ctx := errgroup.WithContext(ctx)
	errs.Go(func() error {
		b, err := PlugnTriggerOutput("deployed-app-repository", []string{appName}...)
		if err == nil {
			imageRemoteRepository = strings.TrimSpace(string(b[:]))
		}
		return err
	})
	errs.Go(func() error {
		b, err := PlugnTriggerOutput("deployed-app-image-tag", []string{appName}...)
		if err == nil {
			newImageTag = strings.TrimSpace(string(b[:]))
		}
		return err
	})

	errs.Go(func() error {
		b, err := PlugnTriggerOutput("deployed-app-image-repo", []string{appName}...)
		if err == nil {
			newImageTag = strings.TrimSpace(string(b[:]))
		}
		return err
	})

	if err := errs.Wait(); err != nil {
		return "", err
	}

	if newImageRepo != "" {
		imageRepo = newImageRepo
	}
	if newImageTag != "" {
		imageTag = newImageTag
	}
	if imageRepo == "" {
		imageRepo = GetAppImageRepo(appName)
	}
	if imageTag == "" {
		imageTag = "latest"
	}

	imageName := fmt.Sprintf("%s%s:%s", imageRemoteRepository, imageRepo, imageTag)
	if !VerifyImage(imageName) {
		return "", fmt.Errorf("App image (%s) not found", imageName)
	}
	return imageName, nil
}

// GetAppImageRepo is the central definition of a dokku image repo pattern
func GetAppImageRepo(appName string) string {
	return strings.Join([]string{"dokku", appName}, "/")
}

// GetAppContainerIDs returns a list of docker container ids for given app and optional container_type
func GetAppContainerIDs(appName string, containerType string) ([]string, error) {
	var containerIDs []string
	appRoot := AppRoot(appName)
	containerFilePath := fmt.Sprintf("%v/CONTAINER", appRoot)
	_, err := os.Stat(containerFilePath)
	if !os.IsNotExist(err) {
		containerIDs = append(containerIDs, ReadFirstLine(containerFilePath))
	}

	containerPattern := fmt.Sprintf("%v/CONTAINER.*", appRoot)
	if containerType != "" {
		containerPattern = fmt.Sprintf("%v/CONTAINER.%v.*", appRoot, containerType)
		if strings.Contains(".", containerType) {
			containerPattern = fmt.Sprintf("%v/CONTAINER.%v", appRoot, containerType)
		}
	}

	files, _ := filepath.Glob(containerPattern)
	for _, containerFile := range files {
		containerIDs = append(containerIDs, ReadFirstLine(containerFile))
	}

	return containerIDs, nil
}

// GetAppRunningContainerIDs return a list of running docker container ids for given app and optional container_type
func GetAppRunningContainerIDs(appName string, containerType string) ([]string, error) {
	var runningContainerIDs []string
	if !IsDeployed(appName) {
		LogFail(fmt.Sprintf("App %v has not been deployed", appName))
	}

	containerIDs, err := GetAppContainerIDs(appName, containerType)
	if err != nil {
		return runningContainerIDs, nil
	}
	for _, containerID := range containerIDs {
		if ContainerIsRunning(containerID) {
			runningContainerIDs = append(runningContainerIDs, containerID)
		}
	}

	return runningContainerIDs, nil
}

// GetRunningImageTag retrieves current image tag for a given app and returns empty string if no deployed containers are found
func GetRunningImageTag(appName string) (string, error) {
	containerIDs, err := GetAppContainerIDs(appName, "")
	if err != nil {
		return "", err
	}

	for _, containerID := range containerIDs {
		if image, err := DockerInspect(containerID, "{{ .Config.Image }}"); err == nil {
			return strings.Split(image, ":")[1], nil
		}
	}

	return "", errors.New("No image tag found")
}

// DokkuApps returns a list of all local apps
func DokkuApps() (apps []string, err error) {
	dokkuRoot := MustGetEnv("DOKKU_ROOT")
	files, err := ioutil.ReadDir(dokkuRoot)
	if err != nil {
		err = fmt.Errorf("You haven't deployed any applications yet")
		return
	}

	for _, f := range files {
		appRoot := AppRoot(f.Name())
		if !DirectoryExists(appRoot) {
			continue
		}
		if strings.HasPrefix(f.Name(), ".") {
			continue
		}
		apps = append(apps, f.Name())
	}

	if len(apps) == 0 {
		err = fmt.Errorf("You haven't deployed any applications yet")
		return
	}

	return
}

// GetAppImageName returns image identifier for a given app, tag tuple. validate if tag is presented
func GetAppImageName(appName, imageTag, imageRepo string) (imageName string) {
	if imageRepo == "" {
		imageRepo = GetAppImageRepo(appName)
	}

	if imageTag == "" {
		imageName = fmt.Sprintf("%v:latest", imageRepo)
	} else {
		imageName = fmt.Sprintf("%v:%v", imageRepo, imageTag)
		if !VerifyImage(imageName) {
			LogFail(fmt.Sprintf("App image (%s) not found", imageName))
		}
	}
	return
}

// IsDeployed returns true if given app has a running container
func IsDeployed(appName string) bool {
	scheduler := GetAppScheduler(appName)
	_, err := PlugnTriggerOutput("scheduler-is-deployed", []string{scheduler, appName}...)
	return err == nil
}

// MustGetEnv returns env variable or fails if it's not set
func MustGetEnv(key string) (val string) {
	val = os.Getenv(key)
	if val == "" {
		LogFail(fmt.Sprintf("%s not set!", key))
	}
	return
}

// GetenvWithDefault returns env variable or defaultValue if it's not set
func GetenvWithDefault(key string, defaultValue string) (val string) {
	val = os.Getenv(key)
	if val == "" {
		val = defaultValue
	}
	return
}

// ParseReportArgs splits out flags from non-flags for input into report commands
func ParseReportArgs(pluginName string, arguments []string) ([]string, string, error) {
	osArgs := []string{}
	infoFlags := []string{}
	for _, argument := range arguments {
		if strings.HasPrefix(argument, "--") {
			infoFlags = append(infoFlags, argument)
		} else {
			osArgs = append(osArgs, argument)
		}
	}

	if len(infoFlags) == 0 {
		return osArgs, "", nil
	}
	if len(infoFlags) == 1 {
		return osArgs, infoFlags[0], nil
	}
	return osArgs, "", fmt.Errorf("%s:report command allows only a single flag", pluginName)
}

// ReportSingleApp is an internal function that displays a report for an app
func ReportSingleApp(reportType string, appName string, infoFlag string, infoFlags map[string]string, trimPrefix bool, uppercaseFirstCharacter bool) error {
	flags := []string{}
	for key := range infoFlags {
		flags = append(flags, key)
	}
	sort.Strings(flags)

	if len(infoFlag) == 0 {
		LogInfo2Quiet(fmt.Sprintf("%s %v information", appName, reportType))
		for _, k := range flags {
			v := infoFlags[k]
			prefix := "--"
			if trimPrefix {
				prefix = fmt.Sprintf("--%v-", reportType)
			}

			key := strings.Replace(strings.Replace(strings.TrimPrefix(k, prefix), "-", " ", -1), ".", " ", -1)

			if uppercaseFirstCharacter {
				key = UcFirst(key)
			}

			LogVerbose(fmt.Sprintf("%s%s", RightPad(fmt.Sprintf("%s:", key), 31, " "), v))
		}
		return nil
	}

	for _, k := range flags {
		if infoFlag == k {
			v := infoFlags[k]
			fmt.Println(v)
			return nil
		}
	}

	keys := reflect.ValueOf(infoFlags).MapKeys()
	strkeys := make([]string, len(keys))
	for i := 0; i < len(keys); i++ {
		strkeys[i] = keys[i].String()
	}

	return fmt.Errorf("Invalid flag passed, valid flags: %s", strings.Join(strkeys, ", "))
}

// RightPad right-pads the string with pad up to len runes
func RightPad(str string, length int, pad string) string {
	return str + times(pad, length-len(str))
}

// ShiftString removes the first and returns that entry as well as the rest of the list
func ShiftString(a []string) (string, []string) {
	if len(a) == 0 {
		return "", a
	}

	return a[0], a[1:]
}

// StripInlineComments removes bash-style comment from input line
func StripInlineComments(text string) string {
	b := []byte(text)
	re := regexp.MustCompile("(?s)#.*")
	b = re.ReplaceAll(b, nil)
	return strings.TrimSpace(string(b))
}

// SuppressOutput suppresses the output of a function unless there is an error
func SuppressOutput(f errfunc) error {
	rescueStdout := os.Stdout
	r, w, _ := os.Pipe()
	os.Stdout = w

	err := f()

	w.Close()
	out, _ := ioutil.ReadAll(r)
	os.Stdout = rescueStdout

	if err != nil {
		fmt.Printf(string(out[:]))
	}

	return err
}

// ToBool returns a bool value for a given string
func ToBool(s string) bool {
	return s == "true"
}

// ToInt returns an int value for a given string
func ToInt(s string, defaultValue int) int {
	i, err := strconv.Atoi(s)
	if err != nil {
		return defaultValue
	}

	return i
}

// UcFirst uppercases the first character in a string
func UcFirst(str string) string {
	for i, v := range str {
		return string(unicode.ToUpper(v)) + str[i+1:]
	}
	return ""
}

// IsValidAppName verifies that the app name matches naming restrictions
func IsValidAppName(appName string) error {
	if appName == "" {
		return errors.New("Please specify an app to run the command on")
	}

	r, _ := regexp.Compile("^[a-z0-9][^/:_A-Z]*$")
	if r.MatchString(appName) {
		return nil
	}

	return errors.New("App name must begin with lowercase alphanumeric character, and cannot include uppercase characters, colons, or underscores")
}

// isValidAppNameOld verifies that the app name matches the old naming restrictions
func isValidAppNameOld(appName string) error {
	if appName == "" {
		return errors.New("Please specify an app to run the command on")
	}

	r, _ := regexp.Compile("^[a-z0-9][^/:A-Z]*$")
	if r.MatchString(appName) {
		return nil
	}

	return errors.New("App name must begin with lowercase alphanumeric character, and cannot include uppercase characters, or colons")
}

// VerifyAppName checks if an app conforming to either the old or new
// naming conventions exists
func VerifyAppName(appName string) error {
	newErr := IsValidAppName(appName)
	oldErr := isValidAppNameOld(appName)
	if newErr != nil && oldErr != nil {
		return newErr
	}

	appRoot := AppRoot(appName)
	if !DirectoryExists(appRoot) {
		return fmt.Errorf("App %s does not exist", appName)
	}

	return nil
}

func times(str string, n int) (out string) {
	for i := 0; i < n; i++ {
		out += str
	}
	return
}
<commit_msg>fix: set correct variable for app image repo<commit_after>package common

import (
	"context"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"strings"
	"unicode"

	"github.com/ryanuber/columnize"
	"golang.org/x/sync/errgroup"
)

type errfunc func() error

// AppRoot returns the app root path
func AppRoot(appName string) string {
	dokkuRoot := MustGetEnv("DOKKU_ROOT")
	return fmt.Sprintf("%v/%v", dokkuRoot, appName)
}

// AppHostRoot returns the app root path
func AppHostRoot(appName string) string {
	dokkuHostRoot := MustGetEnv("DOKKU_HOST_ROOT")
	return fmt.Sprintf("%v/%v", dokkuHostRoot, appName)
}

// AskForDestructiveConfirmation checks for confirmation on destructive actions
func AskForDestructiveConfirmation(name string, objectType string) error {
	LogWarn("WARNING: Potentially Destructive Action")
	LogWarn(fmt.Sprintf("This command will destroy %v %v.", objectType, name))
	LogWarn(fmt.Sprintf("To proceed, type \"%v\"", name))
	fmt.Print("> ")
	var response string
	_, err := fmt.Scanln(&response)
	if err != nil {
		return err
	}

	if response != name {
		LogStderr("Confirmation did not match test. Aborted.")
		os.Exit(1)
		return nil
	}

	return nil
}

// CommandUsage outputs help for a command
func CommandUsage(helpHeader string, helpContent string) {
	config := columnize.DefaultConfig()
	config.Delim = ","
	config.Prefix = "    "
	config.Empty = ""
	content := strings.Split(helpContent, "\n")[1:]
	fmt.Println(helpHeader)
	fmt.Println(columnize.Format(content, config))
}

// GetAppScheduler fetches the scheduler for a given application
func GetAppScheduler(appName string) string {
	appScheduler := ""
	globalScheduler := ""

	ctx := context.Background()
	errs, ctx := errgroup.WithContext(ctx)

	if appName != "--global" {
		errs.Go(func() error {
			appScheduler = getAppScheduler(appName)
			return nil
		})
	}
	errs.Go(func() error {
		globalScheduler = GetGlobalScheduler()
		return nil
	})
	errs.Wait()

	if appScheduler == "" {
		appScheduler = globalScheduler
	}
	return appScheduler
}

func getAppScheduler(appName string) string {
	b, _ := PlugnTriggerOutput("config-get", []string{appName, "DOKKU_SCHEDULER"}...)
	value := strings.TrimSpace(string(b[:]))
	if value != "" {
		return value
	}
	return ""
}

// GetGlobalScheduler fetchs the global scheduler
func GetGlobalScheduler() string {
	b, _ := PlugnTriggerOutput("config-get-global", []string{"DOKKU_SCHEDULER"}...)
	value := strings.TrimSpace(string(b[:]))
	if value != "" {
		return value
	}

	return "docker-local"
}

// GetDeployingAppImageName returns deploying image identifier for a given app, tag tuple. validate if tag is presented
func GetDeployingAppImageName(appName, imageTag, imageRepo string) (string, error) {
	imageRemoteRepository := ""
	newImageTag := ""
	newImageRepo := ""

	ctx := context.Background()
	errs, ctx := errgroup.WithContext(ctx)
	errs.Go(func() error {
		b, err := PlugnTriggerOutput("deployed-app-repository", []string{appName}...)
		if err == nil {
			imageRemoteRepository = strings.TrimSpace(string(b[:]))
		}
		return err
	})
	errs.Go(func() error {
		b, err := PlugnTriggerOutput("deployed-app-image-tag", []string{appName}...)
		if err == nil {
			newImageTag = strings.TrimSpace(string(b[:]))
		}
		return err
	})

	errs.Go(func() error {
		b, err := PlugnTriggerOutput("deployed-app-image-repo", []string{appName}...)
		if err == nil {
			newImageRepo = strings.TrimSpace(string(b[:]))
		}
		return err
	})

	if err := errs.Wait(); err != nil {
		return "", err
	}

	if newImageRepo != "" {
		imageRepo = newImageRepo
	}
	if newImageTag != "" {
		imageTag = newImageTag
	}
	if imageRepo == "" {
		imageRepo = GetAppImageRepo(appName)
	}
	if imageTag == "" {
		imageTag = "latest"
	}

	imageName := fmt.Sprintf("%s%s:%s", imageRemoteRepository, imageRepo, imageTag)
	if !VerifyImage(imageName) {
		return "", fmt.Errorf("App image (%s) not found", imageName)
	}
	return imageName, nil
}

// GetAppImageRepo is the central definition of a dokku image repo pattern
func GetAppImageRepo(appName string) string {
	return strings.Join([]string{"dokku", appName}, "/")
}

// GetAppContainerIDs returns a list of docker container ids for given app and optional container_type
func GetAppContainerIDs(appName string, containerType string) ([]string, error) {
	var containerIDs []string
	appRoot := AppRoot(appName)
	containerFilePath := fmt.Sprintf("%v/CONTAINER", appRoot)
	_, err := os.Stat(containerFilePath)
	if !os.IsNotExist(err) {
		containerIDs = append(containerIDs, ReadFirstLine(containerFilePath))
	}

	containerPattern := fmt.Sprintf("%v/CONTAINER.*", appRoot)
	if containerType != "" {
		containerPattern = fmt.Sprintf("%v/CONTAINER.%v.*", appRoot, containerType)
		if strings.Contains(".", containerType) {
			containerPattern = fmt.Sprintf("%v/CONTAINER.%v", appRoot, containerType)
		}
	}

	files, _ := filepath.Glob(containerPattern)
	for _, containerFile := range files {
		containerIDs = append(containerIDs, ReadFirstLine(containerFile))
	}

	return containerIDs, nil
}

// GetAppRunningContainerIDs return a list of running docker container ids for given app and optional container_type
func GetAppRunningContainerIDs(appName string, containerType string) ([]string, error) {
	var runningContainerIDs []string
	if !IsDeployed(appName) {
		LogFail(fmt.Sprintf("App %v has not been deployed", appName))
	}

	containerIDs, err := GetAppContainerIDs(appName, containerType)
	if err != nil {
		return runningContainerIDs, nil
	}
	for _, containerID := range containerIDs {
		if ContainerIsRunning(containerID) {
			runningContainerIDs = append(runningContainerIDs, containerID)
		}
	}

	return runningContainerIDs, nil
}

// GetRunningImageTag retrieves current image tag for a given app and returns empty string if no deployed containers are found
func GetRunningImageTag(appName string) (string, error) {
	containerIDs, err := GetAppContainerIDs(appName, "")
	if err != nil {
		return "", err
	}

	for _, containerID := range containerIDs {
		if image, err := DockerInspect(containerID, "{{ .Config.Image }}"); err == nil {
			return strings.Split(image, ":")[1], nil
		}
	}

	return "", errors.New("No image tag found")
}

// DokkuApps returns a list of all local apps
func DokkuApps() (apps []string, err error) {
	dokkuRoot := MustGetEnv("DOKKU_ROOT")
	files, err := ioutil.ReadDir(dokkuRoot)
	if err != nil {
		err = fmt.Errorf("You haven't deployed any applications yet")
		return
	}

	for _, f := range files {
		appRoot := AppRoot(f.Name())
		if !DirectoryExists(appRoot) {
			continue
		}
		if strings.HasPrefix(f.Name(), ".") {
			continue
		}
		apps = append(apps, f.Name())
	}

	if len(apps) == 0 {
		err = fmt.Errorf("You haven't deployed any applications yet")
		return
	}

	return
}

// GetAppImageName returns image identifier for a given app, tag tuple. validate if tag is presented
func GetAppImageName(appName, imageTag, imageRepo string) (imageName string) {
	if imageRepo == "" {
		imageRepo = GetAppImageRepo(appName)
	}

	if imageTag == "" {
		imageName = fmt.Sprintf("%v:latest", imageRepo)
	} else {
		imageName = fmt.Sprintf("%v:%v", imageRepo, imageTag)
		if !VerifyImage(imageName) {
			LogFail(fmt.Sprintf("App image (%s) not found", imageName))
		}
	}
	return
}

// IsDeployed returns true if given app has a running container
func IsDeployed(appName string) bool {
	scheduler := GetAppScheduler(appName)
	_, err := PlugnTriggerOutput("scheduler-is-deployed", []string{scheduler, appName}...)
	return err == nil
}

// MustGetEnv returns env variable or fails if it's not set
func MustGetEnv(key string) (val string) {
	val = os.Getenv(key)
	if val == "" {
		LogFail(fmt.Sprintf("%s not set!", key))
	}
	return
}

// GetenvWithDefault returns env variable or defaultValue if it's not set
func GetenvWithDefault(key string, defaultValue string) (val string) {
	val = os.Getenv(key)
	if val == "" {
		val = defaultValue
	}
	return
}

// ParseReportArgs splits out flags from non-flags for input into report commands
func ParseReportArgs(pluginName string, arguments []string) ([]string, string, error) {
	osArgs := []string{}
	infoFlags := []string{}
	for _, argument := range arguments {
		if strings.HasPrefix(argument, "--") {
			infoFlags = append(infoFlags, argument)
		} else {
			osArgs = append(osArgs, argument)
		}
	}

	if len(infoFlags) == 0 {
		return osArgs, "", nil
	}
	if len(infoFlags) == 1 {
		return osArgs, infoFlags[0], nil
	}
	return osArgs, "", fmt.Errorf("%s:report command allows only a single flag", pluginName)
}

// ReportSingleApp is an internal function that displays a report for an app
func ReportSingleApp(reportType string, appName string, infoFlag string, infoFlags map[string]string, trimPrefix bool, uppercaseFirstCharacter bool) error {
	flags := []string{}
	for key := range infoFlags {
		flags = append(flags, key)
	}
	sort.Strings(flags)

	if len(infoFlag) == 0 {
		LogInfo2Quiet(fmt.Sprintf("%s %v information", appName, reportType))
		for _, k := range flags {
			v := infoFlags[k]
			prefix := "--"
			if trimPrefix {
				prefix = fmt.Sprintf("--%v-", reportType)
			}

			key := strings.Replace(strings.Replace(strings.TrimPrefix(k, prefix), "-", " ", -1), ".", " ", -1)

			if uppercaseFirstCharacter {
				key = UcFirst(key)
			}

			LogVerbose(fmt.Sprintf("%s%s", RightPad(fmt.Sprintf("%s:", key), 31, " "), v))
		}
		return nil
	}

	for _, k := range flags {
		if infoFlag == k {
			v := infoFlags[k]
			fmt.Println(v)
			return nil
		}
	}

	keys := reflect.ValueOf(infoFlags).MapKeys()
	strkeys := make([]string, len(keys))
	for i := 0; i < len(keys); i++ {
		strkeys[i] = keys[i].String()
	}

	return fmt.Errorf("Invalid flag passed, valid flags: %s", strings.Join(strkeys, ", "))
}

// RightPad right-pads the string with pad up to len runes
func RightPad(str string, length int, pad string) string {
	return str + times(pad, length-len(str))
}

// ShiftString removes the first and returns that entry as well as the rest of the list
func ShiftString(a []string) (string, []string) {
	if len(a) == 0 {
		return "", a
	}

	return a[0], a[1:]
}

// StripInlineComments removes bash-style comment from input line
func StripInlineComments(text string) string {
	b := []byte(text)
	re := regexp.MustCompile("(?s)#.*")
	b = re.ReplaceAll(b, nil)
	return strings.TrimSpace(string(b))
}

// SuppressOutput suppresses the output of a function unless there is an error
func SuppressOutput(f errfunc) error {
	rescueStdout := os.Stdout
	r, w, _ := os.Pipe()
	os.Stdout = w

	err := f()

	w.Close()
	out, _ := ioutil.ReadAll(r)
	os.Stdout = rescueStdout

	if err != nil {
		fmt.Printf(string(out[:]))
	}

	return err
}

// ToBool returns a bool value for a given string
func ToBool(s string) bool {
	return s == "true"
}

// ToInt returns an int value for a given string
func ToInt(s string, defaultValue int) int {
	i, err := strconv.Atoi(s)
	if err != nil {
		return defaultValue
	}

	return i
}

// UcFirst uppercases the first character in a string
func UcFirst(str string) string {
	for i, v := range str {
		return string(unicode.ToUpper(v)) + str[i+1:]
	}
	return ""
}

// IsValidAppName verifies that the app name matches naming restrictions
func IsValidAppName(appName string) error {
	if appName == "" {
		return errors.New("Please specify an app to run the command on")
	}

	r, _ := regexp.Compile("^[a-z0-9][^/:_A-Z]*$")
	if r.MatchString(appName) {
		return nil
	}

	return errors.New("App name must begin with lowercase alphanumeric character, and cannot include uppercase characters, colons, or underscores")
}

// isValidAppNameOld verifies that the app name matches the old naming restrictions
func isValidAppNameOld(appName string) error {
	if appName == "" {
		return errors.New("Please specify an app to run the command on")
	}

	r, _ := regexp.Compile("^[a-z0-9][^/:A-Z]*$")
	if r.MatchString(appName) {
		return nil
	}

	return errors.New("App name must begin with lowercase alphanumeric character, and cannot include uppercase characters, or colons")
}

// VerifyAppName checks if an app conforming to either the old or new
// naming conventions exists
func VerifyAppName(appName string) error {
	newErr := IsValidAppName(appName)
	oldErr := isValidAppNameOld(appName)
	if newErr != nil && oldErr != nil {
		return newErr
	}

	appRoot := AppRoot(appName)
	if !DirectoryExists(appRoot) {
		return fmt.Errorf("App %s does not exist", appName)
	}

	return nil
}

func times(str string, n int) (out string) {
	for i := 0; i < n; i++ {
		out += str
	}
	return
}
<|endoftext|>


<commit_before>package render

import (
	"image"

	"github.com/oakmound/oak/dlog"
	"github.com/oakmound/oak/oakerr"
)

// LoadSheet loads a file in some directory with sheets of (w,h) sized sprites,
// where there is pad pixels of vertical/horizontal pad between each sprite.
// This will blow away any cached sheet with the same fileName.
func LoadSheet(directory, fileName string, w, h, pad int) (*Sheet, error) {

	if w <= 0 {
		dlog.Error("Bad dimensions given to load sheet")
		return nil, oakerr.InvalidInput{InputName: "w"}
	}
	if h <= 0 {
		dlog.Error("Bad dimensions given to load sheet")
		return nil, oakerr.InvalidInput{InputName: "h"}
	}
	if pad < 0 {
		dlog.Error("Bad pad given to load sheet")
		return nil, oakerr.InvalidInput{InputName: "pad"}
	}

	var rgba *image.RGBA
	var ok bool
	var err error

	imageLock.RLock()
	rgba, ok = loadedImages[fileName]
	imageLock.RUnlock()

	if !ok {
		dlog.Verb("Missing file in loaded images: ", fileName)
		rgba, err = loadSprite(directory, fileName)
		if err != nil {
			return nil, err
		}
	}

	dlog.Verb("Loading sheet: ", fileName)

	bounds := rgba.Bounds()

	sheetW := bounds.Max.X / w
	remainderW := bounds.Max.X % w
	sheetH := bounds.Max.Y / h
	remainderH := bounds.Max.Y % h

	var widthBuffers, heightBuffers int
	if pad != 0 {
		widthBuffers = remainderW / pad
		heightBuffers = remainderH / pad
	} else {
		widthBuffers = sheetW - 1
		heightBuffers = sheetH - 1
	}

	if sheetW < 1 || sheetH < 1 ||
		widthBuffers != sheetW-1 ||
		heightBuffers != sheetH-1 {
		dlog.Error("Bad dimensions given to load sheet")
		return nil, oakerr.InvalidInput{InputName: "w,h"}
	}

	sheet := make(Sheet, sheetW)
	i := 0
	for x := 0; x < bounds.Max.X; x += (w + pad) {
		sheet[i] = make([]*image.RGBA, sheetH)
		j := 0
		for y := 0; y < bounds.Max.Y; y += (h + pad) {
			sheet[i][j] = subImage(rgba, x, y, w, h)
			j++
		}
		i++
	}

	dlog.Verb("Loaded sheet into map")
	sheetLock.Lock()
	defer sheetLock.Unlock()
	loadedSheets[fileName] = &sheet

	return loadedSheets[fileName], nil
}

// GetSheet tries to find the given file in the set of loaded sheets.
// If SheetIsLoaded(filename) is not true, this returns an error.
// Otherwise it will return the sheet as a 2d array of sprites
func GetSheet(fileName string) (*Sheet, error) {
	sheetLock.RLock()
	dlog.Verb(loadedSheets, fileName, loadedSheets[fileName])
	sh, ok := loadedSheets[fileName]
	if !ok {
		return nil, oakerr.NotFound{InputName: fileName}
	}
	sheetLock.RUnlock()
	return sh, nil
}

// LoadSheetSequence loads a sheet and then calls LoadSequence on that sheet
func LoadSheetSequence(fileName string, w, h, pad int, fps float64, frames ...int) (*Sequence, error) {
	sheet, err := LoadSheet(dir, fileName, w, h, pad)
	if err != nil {
		return nil, err
	}
	return NewSheetSequence(sheet, fps, frames...)
}

// SheetIsLoaded returns whether when LoadSheet is called, a cached sheet will
// be used, or if false that a new file will attempt to be loaded and stored
func SheetIsLoaded(fileName string) bool {
	sheetLock.RLock()
	_, ok := loadedSheets[fileName]
	sheetLock.RUnlock()
	return ok
}
<commit_msg>Add LoadSprites to render<commit_after>package render

import (
	"image"

	"github.com/oakmound/oak/dlog"
	"github.com/oakmound/oak/oakerr"
)

// LoadSprites calls LoadSheet and then Sheet.ToSprites.
func LoadSprites(directory, fileName string, w, h, pad int) ([][]*Sprite, error) {
	sh, err := LoadSheet(directory, fileName, w, h, pad)
	if sh != nil {
		return sh.ToSprites(), err
	}
	return nil, err
}

// LoadSheet loads a file in some directory with sheets of (w,h) sized sprites,
// where there is pad pixels of vertical/horizontal pad between each sprite.
// This will blow away any cached sheet with the same fileName.
func LoadSheet(directory, fileName string, w, h, pad int) (*Sheet, error) {

	if w <= 0 {
		dlog.Error("Bad dimensions given to load sheet")
		return nil, oakerr.InvalidInput{InputName: "w"}
	}
	if h <= 0 {
		dlog.Error("Bad dimensions given to load sheet")
		return nil, oakerr.InvalidInput{InputName: "h"}
	}
	if pad < 0 {
		dlog.Error("Bad pad given to load sheet")
		return nil, oakerr.InvalidInput{InputName: "pad"}
	}

	var rgba *image.RGBA
	var ok bool
	var err error

	imageLock.RLock()
	rgba, ok = loadedImages[fileName]
	imageLock.RUnlock()

	if !ok {
		dlog.Verb("Missing file in loaded images: ", fileName)
		rgba, err = loadSprite(directory, fileName)
		if err != nil {
			return nil, err
		}
	}

	dlog.Verb("Loading sheet: ", fileName)

	bounds := rgba.Bounds()

	sheetW := bounds.Max.X / w
	remainderW := bounds.Max.X % w
	sheetH := bounds.Max.Y / h
	remainderH := bounds.Max.Y % h

	var widthBuffers, heightBuffers int
	if pad != 0 {
		widthBuffers = remainderW / pad
		heightBuffers = remainderH / pad
	} else {
		widthBuffers = sheetW - 1
		heightBuffers = sheetH - 1
	}

	if sheetW < 1 || sheetH < 1 ||
		widthBuffers != sheetW-1 ||
		heightBuffers != sheetH-1 {
		dlog.Error("Bad dimensions given to load sheet")
		return nil, oakerr.InvalidInput{InputName: "w,h"}
	}

	sheet := make(Sheet, sheetW)
	i := 0
	for x := 0; x < bounds.Max.X; x += (w + pad) {
		sheet[i] = make([]*image.RGBA, sheetH)
		j := 0
		for y := 0; y < bounds.Max.Y; y += (h + pad) {
			sheet[i][j] = subImage(rgba, x, y, w, h)
			j++
		}
		i++
	}

	dlog.Verb("Loaded sheet into map")
	sheetLock.Lock()
	defer sheetLock.Unlock()
	loadedSheets[fileName] = &sheet

	return loadedSheets[fileName], nil
}

// GetSheet tries to find the given file in the set of loaded sheets.
// If SheetIsLoaded(filename) is not true, this returns an error.
// Otherwise it will return the sheet as a 2d array of sprites
func GetSheet(fileName string) (*Sheet, error) {
	sheetLock.RLock()
	dlog.Verb(loadedSheets, fileName, loadedSheets[fileName])
	sh, ok := loadedSheets[fileName]
	if !ok {
		return nil, oakerr.NotFound{InputName: fileName}
	}
	sheetLock.RUnlock()
	return sh, nil
}

// LoadSheetSequence loads a sheet and then calls LoadSequence on that sheet
func LoadSheetSequence(fileName string, w, h, pad int, fps float64, frames ...int) (*Sequence, error) {
	sheet, err := LoadSheet(dir, fileName, w, h, pad)
	if err != nil {
		return nil, err
	}
	return NewSheetSequence(sheet, fps, frames...)
}

// SheetIsLoaded returns whether when LoadSheet is called, a cached sheet will
// be used, or if false that a new file will attempt to be loaded and stored
func SheetIsLoaded(fileName string) bool {
	sheetLock.RLock()
	_, ok := loadedSheets[fileName]
	sheetLock.RUnlock()
	return ok
}
<|endoftext|>


<commit_before>package github

// TODO:
// - testing

import (
	"fmt"
	"regexp"
	"time"

	"github.com/ajm188/slack"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	ghAuth "golang.org/x/oauth2/github" // have to rename so we don't have 2 "github"s
)

var (
	ClientID     string
	ClientSecret string
	AccessToken  string
	RedirectURL  string
	Scopes       []string
	SharedClient *github.Client
)

// DefaultClient constructs a Github client based on the variables set in this
// package (ClientID, ClientSecret, AccessToken). This can be used to quickly
// create a client when you don't need any customization to the underlying
// oauth client. It uses the NoContext context from the oauth2 package. See the
// Token function for the Token it will use.
func DefaultClient() *github.Client {
	return github.NewClient(Config().Client(oauth2.NoContext, Token()))
}

// Config returns an oauth config object that can be used to generate a client
// for communicating with Github.
func Config() *oauth2.Config {
	return &oauth2.Config{
		ClientID:     ClientID,
		ClientSecret: ClientSecret,
		Endpoint:     ghAuth.Endpoint,
		RedirectURL:  RedirectURL,
		Scopes:       Scopes,
	}
}

// Token constructs a basic token, with the bare minimum amount of information
// necessary to authenticate with Github. It uses the package-wide AccessToken,
// and sets the token to never expire. "TokenType" and "RefreshToken" fields
// are left blank.
func Token() *oauth2.Token {
	var noExpire time.Time // this sets noExpire to the zero Time value
	return &oauth2.Token{
		AccessToken:  AccessToken,
		TokenType:    "", // uhhh
		RefreshToken: "",
		Expiry:       noExpire,
	}
}

// OpenIssue registers a handler that will cause the bot to open a github issue
// based on the event text.
//
// The handler is registered as a "Respond", not a "Listen" (see the docs for
// github.com/ajm188/slack for the difference). The pattern which will cause
// the handler to fire has the form 'issue me // <owner>/<repo> "<title>"
// ("<body>" ("<assignee>")?)?'.
//
// The function takes as arguments the bot to which it should register the
// handler, and a reference to a client that can authenticate with Github. If
// no client is provided, then OpenIssue will fall back to using the
// package-wide SharedClient.
//
// Users should note that an attempt to assign an issue to a Github user that
// is not a "contributor" on the repository will result in a 422 returned by
// the Github API. This will prevent the issue from being created.
//
// When an issue has successfully been created, the bot will reply to the user
// which triggered the handler with a link to the issue.
func OpenIssue(bot *slack.Bot, client *github.Client) {
	repoRe := regexp.MustCompile("issue me ([^/ ]+)/([^/ ]+)")
	argsRe := regexp.MustCompile("(\".*?[^\\\\]\")")
	if client == nil {
		client = SharedClient
	}
	issues := client.Issues

	handler := func(b *slack.Bot, event map[string]interface{}) (*slack.Message, slack.Status) {
		text := event["text"].(string)
		owner, repo, err := extractOwnerAndRepo(text, repoRe)
		if err != nil {
			return nil, slack.Continue
		}
		issueRequest, err := extractIssueArgs(text, argsRe)
		if err != nil {
			return nil, slack.Continue
		}
		issue, _, err := issues.Create(owner, repo, issueRequest)
		user := event["user"].(string)
		channel := event["channel"].(string)
		if err != nil {
			message := fmt.Sprintf(
				"I had some trouble opening an issue. Here was the error I got:\n%v",
				err)
			return bot.Mention(user, message, channel), slack.Continue
		}

		message := fmt.Sprintf(
			"I created that issue for you. You can view it here: %s",
			*issue.HTMLURL,
		)
		return bot.Mention(user, message, channel), slack.Continue
	}

	bot.RespondRegexp(repoRe, handler)
}

func extractOwnerAndRepo(text string, re *regexp.Regexp) (string, string, error) {
	m := re.FindStringSubmatch(text)
	if m == nil || len(m) < 3 {
		return "", "", &repoError{text}
	}
	return m[1], m[2], nil
}

func removeQuotes(s string) string {
	return s[1 : len(s)-1]
}

func extractIssueArgs(text string, re *regexp.Regexp) (*github.IssueRequest, error) {
	match := re.FindAllString(text, -1)
	m := make([]string, len(match))
	for i, v := range match {
		m[i] = removeQuotes(v)
	}
	if m == nil || len(m) == 0 {
		return nil, &issueError{text}
	}
	var title, body, assignee *string
	title = &m[0]
	if len(m) >= 2 {
		body = &m[1]
	}
	if len(m) >= 3 {
		assignee = &m[2]
	}
	issueState := "open"
	request := github.IssueRequest{
		Title:     title,
		Body:      body,
		Labels:    nil,
		Assignee:  assignee,
		State:     &issueState,
		Milestone: nil,
	}
	return &request, nil
}
<commit_msg>finish adding docs to github<commit_after>/*
Package github provides a plugin for building Github integrations into
github.com/ajm188/slack.

The package exports a number of package-wide variables, which may be used to
configure the parameters used for authenticating with the Github API. See the
documentation on each variable for what is is used for.

Here is an example of how one might use this library to register a hook that
opens Github issues:

    import (
        "github.com/ajm188/slack"
        "github.com/ajm188/slack/plugins/github"
    )

    func main() {
        bot := slack.NewBot(myToken)
        // configure auth for github plugin
        github.OpenIssue(bot, nil)
    }
*/
package github

// TODO:
// - testing

import (
	"fmt"
	"regexp"
	"time"

	"github.com/ajm188/slack"
	"github.com/google/go-github/github"
	"golang.org/x/oauth2"
	ghAuth "golang.org/x/oauth2/github" // have to rename so we don't have 2 "github"s
)

var (
	// ClientID is issued by Github when you register an application. You
	// should register an application for your bot, and set the ID before
	// creating a client to authenticate with Github.
	ClientID string
	// ClientSecret is the secret key used to verify your registered
	// application. You should set the secret before creating a client to
	// authenticate with Github.
	ClientSecret string
	// AccessToken is an OAuth token for the user you want your Github
	// interactions to be performed as. The bot will be commenting, opening
	// issues, etc as the user who owns this token. You should set an access
	// token before creating a client to authenticate with Github.
	AccessToken string
	// RedirectURL is the URL that Github should redirect to after a successful
	// web authentication. Since the bot does not perform web-based
	// authentication, this is likely a useless field. More information can be
	// found at https://developer.github.com/v3/oauth/#redirect-urls.
	RedirectURL string
	// Scopes is the list of scopes that the OAuth token should be limited
	// to. Since the user that created the token can specify the scopes
	// available to the token when they create it, this field is probably also
	// useless.
	Scopes []string
	// SharedClient is a variable for sharing a single OAuth client among
	// various handlers. For example, when a call to OpenIssue is made, you may
	// pass in a client of your own, if you want the issue hook to be handled
	// by a different Github user. If you do not pass in a client, then the
	// various hook methods will fall back to using this shared client.
	SharedClient *github.Client
)

// DefaultClient constructs a Github client based on the variables set in this
// package (ClientID, ClientSecret, AccessToken). This can be used to quickly
// create a client when you don't need any customization to the underlying
// oauth client. It uses the NoContext context from the oauth2 package. See the
// Token function for the Token it will use.
func DefaultClient() *github.Client {
	return github.NewClient(Config().Client(oauth2.NoContext, Token()))
}

// Config returns an oauth config object that can be used to generate a client
// for communicating with Github.
func Config() *oauth2.Config {
	return &oauth2.Config{
		ClientID:     ClientID,
		ClientSecret: ClientSecret,
		Endpoint:     ghAuth.Endpoint,
		RedirectURL:  RedirectURL,
		Scopes:       Scopes,
	}
}

// Token constructs a basic token, with the bare minimum amount of information
// necessary to authenticate with Github. It uses the package-wide AccessToken,
// and sets the token to never expire. "TokenType" and "RefreshToken" fields
// are left blank.
func Token() *oauth2.Token {
	var noExpire time.Time // this sets noExpire to the zero Time value
	return &oauth2.Token{
		AccessToken:  AccessToken,
		TokenType:    "", // uhhh
		RefreshToken: "",
		Expiry:       noExpire,
	}
}

// OpenIssue registers a handler that will cause the bot to open a github issue
// based on the event text.
//
// The handler is registered as a "Respond", not a "Listen" (see the docs for
// github.com/ajm188/slack for the difference). The pattern which will cause
// the handler to fire has the form 'issue me // <owner>/<repo> "<title>"
// ("<body>" ("<assignee>")?)?'.
//
// The function takes as arguments the bot to which it should register the
// handler, and a reference to a client that can authenticate with Github. If
// no client is provided, then OpenIssue will fall back to using the
// package-wide SharedClient.
//
// Users should note that an attempt to assign an issue to a Github user that
// is not a "contributor" on the repository will result in a 422 returned by
// the Github API. This will prevent the issue from being created.
//
// When an issue has successfully been created, the bot will reply to the user
// which triggered the handler with a link to the issue.
func OpenIssue(bot *slack.Bot, client *github.Client) {
	repoRe := regexp.MustCompile("issue me ([^/ ]+)/([^/ ]+)")
	argsRe := regexp.MustCompile("(\".*?[^\\\\]\")")
	if client == nil {
		client = SharedClient
	}
	issues := client.Issues

	handler := func(b *slack.Bot, event map[string]interface{}) (*slack.Message, slack.Status) {
		text := event["text"].(string)
		owner, repo, err := extractOwnerAndRepo(text, repoRe)
		if err != nil {
			return nil, slack.Continue
		}
		issueRequest, err := extractIssueArgs(text, argsRe)
		if err != nil {
			return nil, slack.Continue
		}
		issue, _, err := issues.Create(owner, repo, issueRequest)
		user := event["user"].(string)
		channel := event["channel"].(string)
		if err != nil {
			message := fmt.Sprintf(
				"I had some trouble opening an issue. Here was the error I got:\n%v",
				err)
			return bot.Mention(user, message, channel), slack.Continue
		}

		message := fmt.Sprintf(
			"I created that issue for you. You can view it here: %s",
			*issue.HTMLURL,
		)
		return bot.Mention(user, message, channel), slack.Continue
	}

	bot.RespondRegexp(repoRe, handler)
}

func extractOwnerAndRepo(text string, re *regexp.Regexp) (string, string, error) {
	m := re.FindStringSubmatch(text)
	if m == nil || len(m) < 3 {
		return "", "", &repoError{text}
	}
	return m[1], m[2], nil
}

func removeQuotes(s string) string {
	return s[1 : len(s)-1]
}

func extractIssueArgs(text string, re *regexp.Regexp) (*github.IssueRequest, error) {
	match := re.FindAllString(text, -1)
	m := make([]string, len(match))
	for i, v := range match {
		m[i] = removeQuotes(v)
	}
	if m == nil || len(m) == 0 {
		return nil, &issueError{text}
	}
	var title, body, assignee *string
	title = &m[0]
	if len(m) >= 2 {
		body = &m[1]
	}
	if len(m) >= 3 {
		assignee = &m[2]
	}
	issueState := "open"
	request := github.IssueRequest{
		Title:     title,
		Body:      body,
		Labels:    nil,
		Assignee:  assignee,
		State:     &issueState,
		Milestone: nil,
	}
	return &request, nil
}
<|endoftext|>


<commit_before>// Copyright 2012 Samuel Stauffer. All rights reserved.
// Use of this source code is governed by a 3-clause BSD
// license that can be found in the LICENSE file.

package reporter

import (
	"log"
	"strings"
	"time"

	"github.com/samuel/go-librato/librato"
	"github.com/samuel/go-metrics/metrics"
)

type libratoReporter struct {
	source          string
	lib             *librato.Metrics
	percentiles     []float64
	percentileNames []string
	counterCache    *counterDeltaCache
}

func NewLibratoReporter(registry metrics.Registry, interval time.Duration, username, token, source string, percentiles map[string]float64) *PeriodicReporter {
	per := metrics.DefaultPercentiles
	perNames := metrics.DefaultPercentileNames

	if percentiles != nil {
		per = make([]float64, 0)
		perNames = make([]string, 0)
		for name, p := range percentiles {
			per = append(per, p)
			perNames = append(perNames, name)
		}
	}

	lr := &libratoReporter{
		source:          source,
		lib:             &librato.Metrics{Username: username, Token: token},
		percentiles:     per,
		percentileNames: perNames,
		counterCache:    &counterDeltaCache{},
	}
	return NewPeriodicReporter(registry, interval, true, lr)
}

func (r *libratoReporter) Report(registry metrics.Registry) {
	mets := &librato.MetricsFormat{Source: r.source}
	count := 0

	registry.Do(func(name string, metric interface{}) error {
		count++
		name = strings.Replace(name, "/", ".", -1)
		switch m := metric.(type) {
		case metrics.CounterValue:
			mets.Counters = append(mets.Counters,
				librato.Metric{
					Name:  name,
					Value: float64(m),
				})
		case metrics.GaugeValue:
			mets.Gauges = append(mets.Gauges,
				librato.Metric{
					Name:  name,
					Value: float64(m),
				})
		case metrics.IntegerGauge:
			mets.Gauges = append(mets.Gauges,
				librato.Metric{
					Name:  name,
					Value: float64(m.Value()),
				})
		case metrics.Counter:
			mets.Counters = append(mets.Counters,
				librato.Metric{
					Name:  name,
					Value: float64(m.Count()),
				})
		case *metrics.EWMA:
			mets.Gauges = append(mets.Gauges,
				librato.Metric{
					Name:  name,
					Value: m.Rate(),
				})
		case *metrics.EWMAGauge:
			mets.Gauges = append(mets.Gauges,
				librato.Metric{
					Name:  name,
					Value: m.Mean(),
				})
		case *metrics.Meter:
			mets.Gauges = append(mets.Gauges,
				librato.Metric{
					Name:  name + ".1m",
					Value: m.OneMinuteRate(),
				},
				librato.Metric{
					Name:  name + ".5m",
					Value: m.FiveMinuteRate(),
				},
				librato.Metric{
					Name:  name + ".15m",
					Value: m.FifteenMinuteRate(),
				})
		case metrics.Histogram:
			count := m.Count()
			if count > 0 {
				deltaCount := r.counterCache.delta(name+".count", int64(count))
				if deltaCount > 0 {
					deltaSum := r.counterCache.delta(name+".sum", m.Sum())
					mets.Gauges = append(mets.Gauges,
						librato.Gauge{
							Name:  name,
							Count: uint64(deltaCount),
							Sum:   float64(deltaSum),
						})
				}
				percentiles := m.Percentiles(r.percentiles)
				for i, perc := range percentiles {
					mets.Gauges = append(mets.Gauges,
						librato.Metric{
							Name:  name + "." + r.percentileNames[i],
							Value: float64(perc),
						})
				}
			}
		default:
			log.Printf("Unrecognized metric type for %s: %+v", name, m)
		}
		return nil
	})

	if count > 0 {
		if err := r.lib.SendMetrics(mets); err != nil {
			log.Printf("ERR librato.SendMetrics: %+v", err)
		}
	}
}
<commit_msg>Update due to changes to go-librato<commit_after>// Copyright 2012 Samuel Stauffer. All rights reserved.
// Use of this source code is governed by a 3-clause BSD
// license that can be found in the LICENSE file.

package reporter

import (
	"log"
	"strings"
	"time"

	"github.com/samuel/go-librato/librato"
	"github.com/samuel/go-metrics/metrics"
)

type libratoReporter struct {
	source          string
	client          *librato.Client
	percentiles     []float64
	percentileNames []string
	counterCache    *counterDeltaCache
}

func NewLibratoReporter(registry metrics.Registry, interval time.Duration, username, token, source string, percentiles map[string]float64) *PeriodicReporter {
	per := metrics.DefaultPercentiles
	perNames := metrics.DefaultPercentileNames

	if percentiles != nil {
		per = make([]float64, 0)
		perNames = make([]string, 0)
		for name, p := range percentiles {
			per = append(per, p)
			perNames = append(perNames, name)
		}
	}

	lr := &libratoReporter{
		source:          source,
		client:          &librato.Client{Username: username, Token: token},
		percentiles:     per,
		percentileNames: perNames,
		counterCache:    &counterDeltaCache{},
	}
	return NewPeriodicReporter(registry, interval, true, lr)
}

func (r *libratoReporter) Report(registry metrics.Registry) {
	mets := &librato.Metrics{Source: r.source}
	count := 0

	registry.Do(func(name string, metric interface{}) error {
		count++
		name = strings.Replace(name, "/", ".", -1)
		switch m := metric.(type) {
		case metrics.CounterValue:
			mets.Counters = append(mets.Counters,
				librato.Metric{
					Name:  name,
					Value: float64(m),
				})
		case metrics.GaugeValue:
			mets.Gauges = append(mets.Gauges,
				librato.Metric{
					Name:  name,
					Value: float64(m),
				})
		case metrics.IntegerGauge:
			mets.Gauges = append(mets.Gauges,
				librato.Metric{
					Name:  name,
					Value: float64(m.Value()),
				})
		case metrics.Counter:
			mets.Counters = append(mets.Counters,
				librato.Metric{
					Name:  name,
					Value: float64(m.Count()),
				})
		case *metrics.EWMA:
			mets.Gauges = append(mets.Gauges,
				librato.Metric{
					Name:  name,
					Value: m.Rate(),
				})
		case *metrics.EWMAGauge:
			mets.Gauges = append(mets.Gauges,
				librato.Metric{
					Name:  name,
					Value: m.Mean(),
				})
		case *metrics.Meter:
			mets.Gauges = append(mets.Gauges,
				librato.Metric{
					Name:  name + ".1m",
					Value: m.OneMinuteRate(),
				},
				librato.Metric{
					Name:  name + ".5m",
					Value: m.FiveMinuteRate(),
				},
				librato.Metric{
					Name:  name + ".15m",
					Value: m.FifteenMinuteRate(),
				})
		case metrics.Histogram:
			count := m.Count()
			if count > 0 {
				deltaCount := r.counterCache.delta(name+".count", int64(count))
				if deltaCount > 0 {
					deltaSum := r.counterCache.delta(name+".sum", m.Sum())
					mets.Gauges = append(mets.Gauges,
						librato.Gauge{
							Name:  name,
							Count: uint64(deltaCount),
							Sum:   float64(deltaSum),
						})
				}
				percentiles := m.Percentiles(r.percentiles)
				for i, perc := range percentiles {
					mets.Gauges = append(mets.Gauges,
						librato.Metric{
							Name:  name + "." + r.percentileNames[i],
							Value: float64(perc),
						})
				}
			}
		default:
			log.Printf("Unrecognized metric type for %s: %+v", name, m)
		}
		return nil
	})

	if count > 0 {
		if err := r.client.SendMetrics(mets); err != nil {
			log.Printf("ERR librato.SendMetrics: %+v", err)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2010 The GoGo Authors. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import "./libgogo/_obj/libgogo"

//
// Struct holding the information about a file that is compiled
//
type FileInfo struct {
    filename string;
    lineCounter uint64;
    charCounter uint64;
    fd uint64;
};

//
// Fileinformation for all files that are compiled in this run
// Is limited by 32 to reduce memory consumption, but to allow
// self compilation via "./gogo libgogo/*.go *.go"
//
var fileInfo [32]FileInfo;
var fileInfoLen uint64 = 0;
var curFileIndex uint64 = 0;

//
// A very basic debug flag
// Set to 1000 to enable all parsing strings
// Set to 100 to enable all symbol tables
// Set to 10 to enable asm debugging
//
var DEBUG_LEVEL uint64 = 10;

//
// Entry point of the compiler
//
func main() {
    var errno uint64;
    var i uint64;
    var j uint64;
    var k uint64;
    var singleChar byte;

    libgogo.GetArgv();

    ParseOption();

    if libgogo.Argc > 34 {
        libgogo.ExitError("Cannot compile more than 32 files at once",1);
    }

    InitSymbolTable(); //Initialize symbol table
    InitFreeRegisters(); //Init registers for code generation

    ResetCode();

    for i=2; i < libgogo.Argc ; i= i+1 {
        curFileIndex = i-2;
        fileInfo[curFileIndex].filename = libgogo.Argv[i];
        fileInfo[curFileIndex].lineCounter = 1;
        fileInfo[curFileIndex].charCounter = 1;

        fileInfo[curFileIndex].fd = libgogo.FileOpen(libgogo.Argv[i], 0);
        if (fileInfo[curFileIndex].fd == 0) {
            GlobalError("Cannot open file.");
        }
    }
    fileInfoLen = i-2;

    for curFileIndex=0;curFileIndex<fileInfoLen;curFileIndex=curFileIndex+1 {
        i = libgogo.StringLength(fileInfo[curFileIndex].filename);
        if i > 2 { //Check for assembly files
            j = i - 2;
            k = i - 1;
            if (fileInfo[curFileIndex].filename[j] == '.') && (fileInfo[curFileIndex].filename[k] == 's') { //Assembly file
                if curFileIndex == 0 {
                    GlobalError("The first file in the list cannot be an assembly file");
                }
                for singleChar = libgogo.GetChar(fileInfo[curFileIndex].fd); singleChar != 0; singleChar = libgogo.GetChar(fileInfo[curFileIndex].fd) { //Copy file to output character by character
                    if singleChar == 183 /*'·'*/ { //Prepend package name
                        //PrintCodeOutput(CurrentPackage); //TODO: Fix UTF-8 corruption due to string insertion?!
                    }
                    PrintCodeOutputChar(singleChar);
                }
            } else { //Go file
                Parse();
            }
        } else { //Go file with a very short name
            Parse();
        }
    }

    for curFileIndex=0;curFileIndex<fileInfoLen;curFileIndex=curFileIndex+1 {
        errno = libgogo.FileClose(fileInfo[curFileIndex].fd);
        if errno != 0 {
            GlobalError("Cannot close file.");
        }
    }

    PrintGlobalSymbolTable();
    UndefinedForwardDeclaredTypeCheck();

    if Compile == 1 {
        i = libgogo.GetAlignedObjectListSize(GlobalObjects); //Get required data segment size
        SetDataSegmentSize(i); //Set data segment size
        PrintFile(); //Print compiled output to file
    }
}

func ParseOption() {
    var strIndicator uint64;
    var done uint64 = 0;

    // handle -h and --help
    strIndicator = libgogo.StringCompare("--help", libgogo.Argv[1]);
    if strIndicator != 0 {
        strIndicator = libgogo.StringCompare("-h", libgogo.Argv[1]);
    }

    if strIndicator == 0 {
        libgogo.PrintString("Usage: gogo option file1.go [file2.go ...]\n\n");
        libgogo.PrintString("GoGo - A go compiler\n\n");
        libgogo.PrintString("Options:\n");
        libgogo.PrintString("-h, --help     show this help message and exit\n");
        libgogo.PrintString("-p,            parser mode\n");
        libgogo.PrintString("-c             compiler mode\n");
        libgogo.PrintString("-l             linker mode\n");
        libgogo.Exit(1);
    }

    strIndicator = libgogo.StringCompare("-c", libgogo.Argv[1]);
    if (done == 0) && (strIndicator == 0) {
        Compile = 1;
        done = 1;
    }

    strIndicator = libgogo.StringCompare("-p", libgogo.Argv[1]);
    if (done == 0) && (strIndicator == 0) {
        Compile = 0;
        done = 1;
    }

    if done == 0 {
        libgogo.ExitError("Usage: gogo option file1.go [file2.go ...]",1);
    }

    if libgogo.Argc <= 2 {
        libgogo.ExitError("Usage: gogo option file1.go [file2.go ...]",1);
    }
}
<commit_msg>gogo.go: Fix UTF-8 parsing of middle dot in asm files.<commit_after>// Copyright 2010 The GoGo Authors. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import "./libgogo/_obj/libgogo"

//
// Struct holding the information about a file that is compiled
//
type FileInfo struct {
    filename string;
    lineCounter uint64;
    charCounter uint64;
    fd uint64;
};

//
// Fileinformation for all files that are compiled in this run
// Is limited by 32 to reduce memory consumption, but to allow
// self compilation via "./gogo libgogo/*.go *.go"
//
var fileInfo [32]FileInfo;
var fileInfoLen uint64 = 0;
var curFileIndex uint64 = 0;

//
// A very basic debug flag
// Set to 1000 to enable all parsing strings
// Set to 100 to enable all symbol tables
// Set to 10 to enable asm debugging
//
var DEBUG_LEVEL uint64 = 10;

//
// Entry point of the compiler
//
func main() {
    var errno uint64;
    var i uint64;
    var j uint64;
    var k uint64;
    var singleChar byte;

    libgogo.GetArgv();

    ParseOption();

    if libgogo.Argc > 34 {
        libgogo.ExitError("Cannot compile more than 32 files at once",1);
    }

    InitSymbolTable(); //Initialize symbol table
    InitFreeRegisters(); //Init registers for code generation

    ResetCode();

    for i=2; i < libgogo.Argc ; i= i+1 {
        curFileIndex = i-2;
        fileInfo[curFileIndex].filename = libgogo.Argv[i];
        fileInfo[curFileIndex].lineCounter = 1;
        fileInfo[curFileIndex].charCounter = 1;

        fileInfo[curFileIndex].fd = libgogo.FileOpen(libgogo.Argv[i], 0);
        if (fileInfo[curFileIndex].fd == 0) {
            GlobalError("Cannot open file.");
        }
    }
    fileInfoLen = i-2;

    for curFileIndex=0;curFileIndex<fileInfoLen;curFileIndex=curFileIndex+1 {
        i = libgogo.StringLength(fileInfo[curFileIndex].filename);
        if i > 2 { //Check for assembly files
            j = i - 2;
            k = i - 1;
            if (fileInfo[curFileIndex].filename[j] == '.') && (fileInfo[curFileIndex].filename[k] == 's') { //Assembly file
                if curFileIndex == 0 {
                    GlobalError("The first file in the list cannot be an assembly file");
                }
                for singleChar = libgogo.GetChar(fileInfo[curFileIndex].fd); singleChar != 0; singleChar = libgogo.GetChar(fileInfo[curFileIndex].fd) { //Copy file to output character by character
                    /* middot '·' is U+00C7 => UTF-8: C2B7*/
                    if singleChar != 194 /*C2*/ {
                        if singleChar == 183 /*B7*/ { //Prepend package name
                            PrintCodeOutput(CurrentPackage);
                            PrintCodeOutputChar(194);
                            PrintCodeOutputChar(183);
                        } else {
                            PrintCodeOutputChar(singleChar);
                        }
                    }
                }
            } else { //Go file
                Parse();
            }
        } else { //Go file with a very short name
            Parse();
        }
    }

    for curFileIndex=0;curFileIndex<fileInfoLen;curFileIndex=curFileIndex+1 {
        errno = libgogo.FileClose(fileInfo[curFileIndex].fd);
        if errno != 0 {
            GlobalError("Cannot close file.");
        }
    }

    PrintGlobalSymbolTable();
    UndefinedForwardDeclaredTypeCheck();

    if Compile == 1 {
        i = libgogo.GetAlignedObjectListSize(GlobalObjects); //Get required data segment size
        SetDataSegmentSize(i); //Set data segment size
        PrintFile(); //Print compiled output to file
    }
}

func ParseOption() {
    var strIndicator uint64;
    var done uint64 = 0;

    // handle -h and --help
    strIndicator = libgogo.StringCompare("--help", libgogo.Argv[1]);
    if strIndicator != 0 {
        strIndicator = libgogo.StringCompare("-h", libgogo.Argv[1]);
    }

    if strIndicator == 0 {
        libgogo.PrintString("Usage: gogo option file1.go [file2.go ...]\n\n");
        libgogo.PrintString("GoGo - A go compiler\n\n");
        libgogo.PrintString("Options:\n");
        libgogo.PrintString("-h, --help     show this help message and exit\n");
        libgogo.PrintString("-p,            parser mode\n");
        libgogo.PrintString("-c             compiler mode\n");
        libgogo.PrintString("-l             linker mode\n");
        libgogo.Exit(1);
    }

    strIndicator = libgogo.StringCompare("-c", libgogo.Argv[1]);
    if (done == 0) && (strIndicator == 0) {
        Compile = 1;
        done = 1;
    }

    strIndicator = libgogo.StringCompare("-p", libgogo.Argv[1]);
    if (done == 0) && (strIndicator == 0) {
        Compile = 0;
        done = 1;
    }

    if done == 0 {
        libgogo.ExitError("Usage: gogo option file1.go [file2.go ...]",1);
    }

    if libgogo.Argc <= 2 {
        libgogo.ExitError("Usage: gogo option file1.go [file2.go ...]",1);
    }
}
<|endoftext|>