<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package metrics

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/juju/errors"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/loggo"
	"github.com/juju/utils"
	corecharm "gopkg.in/juju/charm.v5"

	"github.com/juju/juju/worker/uniter/runner/jujuc"
)

var logger = loggo.GetLogger("juju.worker.uniter.metrics")

type metricFile struct {
	*os.File
	finalName string
}

func createMetricFile(path string) (*metricFile, error) {
	dir, base := filepath.Dir(path), filepath.Base(path)
	if !filepath.IsAbs(dir) {
		return nil, errors.Errorf("not an absolute path: %q", path)
	}

	workUUID, err := utils.NewUUID()
	if err != nil {
		return nil, errors.Trace(err)
	}
	workName := filepath.Join(dir, fmt.Sprintf(".%s.inc-%s", base, workUUID.String()))

	f, err := os.Create(workName)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return &metricFile{File: f, finalName: path}, nil
}

// Close implements io.Closer.
func (f *metricFile) Close() error {
	err := f.File.Close()
	if err != nil {
		return errors.Trace(err)
	}
	ok, err := utils.MoveFile(f.Name(), f.finalName)
	if err != nil {
		if !ok {
			return errors.Trace(err)
		}
		logger.Errorf("failed to remove temporary file %q: %v", f.Name(), err)
	}
	return nil
}

// MetricBatch stores the information relevant to a single metrics batch.
type MetricBatch struct {
	CharmURL string         `json:"charmurl"`
	UUID     string         `json:"uuid"`
	Created  time.Time      `json:"created"`
	Metrics  []jujuc.Metric `json:"metrics"`
}

// APIMetricBatch converts the specified MetricBatch to a params.MetricBatch,
// which can then be sent to the state server.
func APIMetricBatch(batch MetricBatch) params.MetricBatch {
	metrics := make([]params.Metric, len(batch.Metrics))
	for i, metric := range batch.Metrics {
		metrics[i] = params.Metric{Key: metric.Key, Value: metric.Value, Time: metric.Time}
	}
	return params.MetricBatch{
		UUID:     batch.UUID,
		CharmURL: batch.CharmURL,
		Created:  batch.Created,
		Metrics:  metrics,
	}
}

// MetricsMetadata is used to store metadata for the current metric batch.
type MetricsMetadata struct {
	CharmURL string    `json:"charmurl"`
	UUID     string    `json:"uuid"`
	Created  time.Time `json:"created"`
}

// JSONMetricRecorder implements the MetricsRecorder interface
// and writes metrics to a spool directory for store-and-forward.
type JSONMetricRecorder struct {
	spoolDir     string
	validMetrics map[string]corecharm.Metric
	charmURL     string
	uuid         utils.UUID
	created      time.Time

	lock sync.Mutex

	file io.Closer
	enc  *json.Encoder
}

// NewJSONMetricRecorder creates a new JSON metrics recorder.
// It checks if the metrics spool directory exists, if it does not - it is created. Then
// it tries to find an unused metric batch UUID 3 times.
func NewJSONMetricRecorder(spoolDir string, metrics map[string]corecharm.Metric, charmURL string) (rec *JSONMetricRecorder, rErr error) {
	if err := checkSpoolDir(spoolDir); err != nil {
		return nil, errors.Trace(err)
	}

	mbUUID, err := utils.NewUUID()
	if err != nil {
		return nil, errors.Trace(err)
	}

	recorder := &JSONMetricRecorder{
		spoolDir:     spoolDir,
		uuid:         mbUUID,
		charmURL:     charmURL,
		created:      time.Now().UTC(),
		validMetrics: metrics,
	}
	if err := recorder.open(); err != nil {
		return nil, errors.Trace(err)
	}
	return recorder, nil
}

// Close implements the MetricsRecorder interface.
func (m *JSONMetricRecorder) Close() error {
	m.lock.Lock()
	defer m.lock.Unlock()

	err := m.file.Close()
	if err != nil {
		return errors.Trace(err)
	}

	// We have an exclusive lock on this metric batch here, because
	// metricsFile.Close was able to rename the final filename atomically.
	//
	// Now write the meta file so that JSONMetricReader discovers a finished
	// pair of files.
	err = m.recordMetaData()
	if err != nil {
		return errors.Trace(err)
	}

	return nil
}

// AddMetric implements the MetricsRecorder interface.
func (m *JSONMetricRecorder) AddMetric(key, value string, created time.Time) error {
	if !m.IsDeclaredMetric(key) {
		return errors.Errorf("metric key %q not declared by the charm", key)
	}
	m.lock.Lock()
	defer m.lock.Unlock()
	return errors.Trace(m.enc.Encode(jujuc.Metric{Key: key, Value: value, Time: created}))
}

// IsDeclaredMetric returns true if the metric recorder is permitted to store this metric.
// Returns false if the uniter using this recorder doesn't define this metric.
func (m *JSONMetricRecorder) IsDeclaredMetric(key string) bool {
	_, ok := m.validMetrics[key]
	return ok
}

func (m *JSONMetricRecorder) open() error {
	dataFile := filepath.Join(m.spoolDir, m.uuid.String())
	if _, err := os.Stat(dataFile); err != nil && !os.IsNotExist(err) {
		if err != nil {
			return errors.Annotatef(err, "failed to stat file %s", dataFile)
		}
		return errors.Errorf("file %s already exists", dataFile)
	}

	dataWriter, err := createMetricFile(dataFile)
	if err != nil {
		return errors.Trace(err)
	}
	m.file = dataWriter
	m.enc = json.NewEncoder(dataWriter)
	return nil
}

func checkSpoolDir(path string) error {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		err := os.MkdirAll(path, 0755)
		if err != nil {
			return errors.Trace(err)
		}
	} else if err != nil {
		return errors.Trace(err)
	}
	return nil
}

func (m *JSONMetricRecorder) recordMetaData() error {
	metaFile := filepath.Join(m.spoolDir, fmt.Sprintf("%s.meta", m.uuid.String()))
	if _, err := os.Stat(metaFile); !os.IsNotExist(err) {
		if err != nil {
			return errors.Annotatef(err, "failed to stat file %s", metaFile)
		}
		return errors.Errorf("file %s already exists", metaFile)
	}

	metadata := MetricsMetadata{
		CharmURL: m.charmURL,
		UUID:     m.uuid.String(),
		Created:  m.created,
	}
	// The use of a metricFile here ensures that the JSONMetricReader will only
	// find a fully-written metafile.
	metaWriter, err := createMetricFile(metaFile)
	if err != nil {
		return errors.Trace(err)
	}
	defer metaWriter.Close()
	enc := json.NewEncoder(metaWriter)
	err = enc.Encode(metadata)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}

// JSONMetricsReader reads metrics batches stored in the spool directory.
type JSONMetricReader struct {
	dir string
}

// NewJSONMetricsReader creates a new JSON metrics reader for the specified spool directory.
func NewJSONMetricReader(spoolDir string) (*JSONMetricReader, error) {
	if _, err := os.Stat(spoolDir); err != nil {
		return nil, errors.Annotatef(err, "failed to open spool directory %q", spoolDir)
	}
	return &JSONMetricReader{
		dir: spoolDir,
	}, nil
}

// Read implements the MetricsReader interface.
// Due to the way the batches are stored in the file system,
// they will be returned in an arbitrary order. This does not affect the behavior.
func (r *JSONMetricReader) Read() ([]MetricBatch, error) {
	var batches []MetricBatch

	walker := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return errors.Trace(err)
		}
		if info.IsDir() && path != r.dir {
			return filepath.SkipDir
		} else if !strings.HasSuffix(info.Name(), ".meta") {
			return nil
		}

		batch, err := decodeBatch(path)
		if err != nil {
			return errors.Trace(err)
		}
		batch.Metrics, err = decodeMetrics(filepath.Join(r.dir, batch.UUID))
		if err != nil {
			return errors.Trace(err)
		}
		if len(batch.Metrics) > 0 {
			batches = append(batches, batch)
		}
		return nil
	}
	if err := filepath.Walk(r.dir, walker); err != nil {
		return nil, errors.Trace(err)
	}
	return batches, nil
}

// Remove implements the MetricsReader interface.
func (r *JSONMetricReader) Remove(uuid string) error {
	metaFile := filepath.Join(r.dir, fmt.Sprintf("%s.meta", uuid))
	dataFile := filepath.Join(r.dir, uuid)
	err := os.Remove(metaFile)
	if err != nil && !os.IsNotExist(err) {
		return errors.Trace(err)
	}
	err = os.Remove(dataFile)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}

// Close implements the MetricsReader interface.
func (r *JSONMetricReader) Close() error {
	return nil
}

func decodeBatch(file string) (MetricBatch, error) {
	var batch MetricBatch
	f, err := os.Open(file)
	if err != nil {
		return MetricBatch{}, errors.Trace(err)
	}
	defer f.Close()
	dec := json.NewDecoder(f)
	err = dec.Decode(&batch)
	if err != nil {
		return MetricBatch{}, errors.Trace(err)
	}
	return batch, nil
}

func decodeMetrics(file string) ([]jujuc.Metric, error) {
	var metrics []jujuc.Metric
	f, err := os.Open(file)
	if err != nil {
		return nil, errors.Trace(err)
	}
	defer f.Close()
	dec := json.NewDecoder(f)
	for {
		var metric jujuc.Metric
		err := dec.Decode(&metric)
		if err == io.EOF {
			break
		} else if err != nil {
			return nil, errors.Trace(err)
		}
		metrics = append(metrics, metric)
	}
	return metrics, nil
}
<commit_msg>Add comment explaining the need for and use of the MoveFile bool.<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package metrics

import (
	"encoding/json"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/juju/errors"
	"github.com/juju/juju/apiserver/params"
	"github.com/juju/loggo"
	"github.com/juju/utils"
	corecharm "gopkg.in/juju/charm.v5"

	"github.com/juju/juju/worker/uniter/runner/jujuc"
)

var logger = loggo.GetLogger("juju.worker.uniter.metrics")

type metricFile struct {
	*os.File
	finalName string
}

func createMetricFile(path string) (*metricFile, error) {
	dir, base := filepath.Dir(path), filepath.Base(path)
	if !filepath.IsAbs(dir) {
		return nil, errors.Errorf("not an absolute path: %q", path)
	}

	workUUID, err := utils.NewUUID()
	if err != nil {
		return nil, errors.Trace(err)
	}
	workName := filepath.Join(dir, fmt.Sprintf(".%s.inc-%s", base, workUUID.String()))

	f, err := os.Create(workName)
	if err != nil {
		return nil, errors.Trace(err)
	}
	return &metricFile{File: f, finalName: path}, nil
}

// Close implements io.Closer.
func (f *metricFile) Close() error {
	err := f.File.Close()
	if err != nil {
		return errors.Trace(err)
	}
	ok, err := utils.MoveFile(f.Name(), f.finalName)
	if err != nil {
		// ok can be true even when there is an error completing the move, on
		// platforms that implement it in multiple steps that can fail
		// separately. POSIX for example, uses link(2) to claim the new
		// location atomically, followed by an unlink(2) to release the old
		// location.
		if !ok {
			return errors.Trace(err)
		}
		logger.Errorf("failed to remove temporary file %q: %v", f.Name(), err)
	}
	return nil
}

// MetricBatch stores the information relevant to a single metrics batch.
type MetricBatch struct {
	CharmURL string         `json:"charmurl"`
	UUID     string         `json:"uuid"`
	Created  time.Time      `json:"created"`
	Metrics  []jujuc.Metric `json:"metrics"`
}

// APIMetricBatch converts the specified MetricBatch to a params.MetricBatch,
// which can then be sent to the state server.
func APIMetricBatch(batch MetricBatch) params.MetricBatch {
	metrics := make([]params.Metric, len(batch.Metrics))
	for i, metric := range batch.Metrics {
		metrics[i] = params.Metric{Key: metric.Key, Value: metric.Value, Time: metric.Time}
	}
	return params.MetricBatch{
		UUID:     batch.UUID,
		CharmURL: batch.CharmURL,
		Created:  batch.Created,
		Metrics:  metrics,
	}
}

// MetricsMetadata is used to store metadata for the current metric batch.
type MetricsMetadata struct {
	CharmURL string    `json:"charmurl"`
	UUID     string    `json:"uuid"`
	Created  time.Time `json:"created"`
}

// JSONMetricRecorder implements the MetricsRecorder interface
// and writes metrics to a spool directory for store-and-forward.
type JSONMetricRecorder struct {
	spoolDir     string
	validMetrics map[string]corecharm.Metric
	charmURL     string
	uuid         utils.UUID
	created      time.Time

	lock sync.Mutex

	file io.Closer
	enc  *json.Encoder
}

// NewJSONMetricRecorder creates a new JSON metrics recorder.
// It checks if the metrics spool directory exists, if it does not - it is created. Then
// it tries to find an unused metric batch UUID 3 times.
func NewJSONMetricRecorder(spoolDir string, metrics map[string]corecharm.Metric, charmURL string) (rec *JSONMetricRecorder, rErr error) {
	if err := checkSpoolDir(spoolDir); err != nil {
		return nil, errors.Trace(err)
	}

	mbUUID, err := utils.NewUUID()
	if err != nil {
		return nil, errors.Trace(err)
	}

	recorder := &JSONMetricRecorder{
		spoolDir:     spoolDir,
		uuid:         mbUUID,
		charmURL:     charmURL,
		created:      time.Now().UTC(),
		validMetrics: metrics,
	}
	if err := recorder.open(); err != nil {
		return nil, errors.Trace(err)
	}
	return recorder, nil
}

// Close implements the MetricsRecorder interface.
func (m *JSONMetricRecorder) Close() error {
	m.lock.Lock()
	defer m.lock.Unlock()

	err := m.file.Close()
	if err != nil {
		return errors.Trace(err)
	}

	// We have an exclusive lock on this metric batch here, because
	// metricsFile.Close was able to rename the final filename atomically.
	//
	// Now write the meta file so that JSONMetricReader discovers a finished
	// pair of files.
	err = m.recordMetaData()
	if err != nil {
		return errors.Trace(err)
	}

	return nil
}

// AddMetric implements the MetricsRecorder interface.
func (m *JSONMetricRecorder) AddMetric(key, value string, created time.Time) error {
	if !m.IsDeclaredMetric(key) {
		return errors.Errorf("metric key %q not declared by the charm", key)
	}
	m.lock.Lock()
	defer m.lock.Unlock()
	return errors.Trace(m.enc.Encode(jujuc.Metric{Key: key, Value: value, Time: created}))
}

// IsDeclaredMetric returns true if the metric recorder is permitted to store this metric.
// Returns false if the uniter using this recorder doesn't define this metric.
func (m *JSONMetricRecorder) IsDeclaredMetric(key string) bool {
	_, ok := m.validMetrics[key]
	return ok
}

func (m *JSONMetricRecorder) open() error {
	dataFile := filepath.Join(m.spoolDir, m.uuid.String())
	if _, err := os.Stat(dataFile); err != nil && !os.IsNotExist(err) {
		if err != nil {
			return errors.Annotatef(err, "failed to stat file %s", dataFile)
		}
		return errors.Errorf("file %s already exists", dataFile)
	}

	dataWriter, err := createMetricFile(dataFile)
	if err != nil {
		return errors.Trace(err)
	}
	m.file = dataWriter
	m.enc = json.NewEncoder(dataWriter)
	return nil
}

func checkSpoolDir(path string) error {
	if _, err := os.Stat(path); os.IsNotExist(err) {
		err := os.MkdirAll(path, 0755)
		if err != nil {
			return errors.Trace(err)
		}
	} else if err != nil {
		return errors.Trace(err)
	}
	return nil
}

func (m *JSONMetricRecorder) recordMetaData() error {
	metaFile := filepath.Join(m.spoolDir, fmt.Sprintf("%s.meta", m.uuid.String()))
	if _, err := os.Stat(metaFile); !os.IsNotExist(err) {
		if err != nil {
			return errors.Annotatef(err, "failed to stat file %s", metaFile)
		}
		return errors.Errorf("file %s already exists", metaFile)
	}

	metadata := MetricsMetadata{
		CharmURL: m.charmURL,
		UUID:     m.uuid.String(),
		Created:  m.created,
	}
	// The use of a metricFile here ensures that the JSONMetricReader will only
	// find a fully-written metafile.
	metaWriter, err := createMetricFile(metaFile)
	if err != nil {
		return errors.Trace(err)
	}
	defer metaWriter.Close()
	enc := json.NewEncoder(metaWriter)
	err = enc.Encode(metadata)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}

// JSONMetricsReader reads metrics batches stored in the spool directory.
type JSONMetricReader struct {
	dir string
}

// NewJSONMetricsReader creates a new JSON metrics reader for the specified spool directory.
func NewJSONMetricReader(spoolDir string) (*JSONMetricReader, error) {
	if _, err := os.Stat(spoolDir); err != nil {
		return nil, errors.Annotatef(err, "failed to open spool directory %q", spoolDir)
	}
	return &JSONMetricReader{
		dir: spoolDir,
	}, nil
}

// Read implements the MetricsReader interface.
// Due to the way the batches are stored in the file system,
// they will be returned in an arbitrary order. This does not affect the behavior.
func (r *JSONMetricReader) Read() ([]MetricBatch, error) {
	var batches []MetricBatch

	walker := func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return errors.Trace(err)
		}
		if info.IsDir() && path != r.dir {
			return filepath.SkipDir
		} else if !strings.HasSuffix(info.Name(), ".meta") {
			return nil
		}

		batch, err := decodeBatch(path)
		if err != nil {
			return errors.Trace(err)
		}
		batch.Metrics, err = decodeMetrics(filepath.Join(r.dir, batch.UUID))
		if err != nil {
			return errors.Trace(err)
		}
		if len(batch.Metrics) > 0 {
			batches = append(batches, batch)
		}
		return nil
	}
	if err := filepath.Walk(r.dir, walker); err != nil {
		return nil, errors.Trace(err)
	}
	return batches, nil
}

// Remove implements the MetricsReader interface.
func (r *JSONMetricReader) Remove(uuid string) error {
	metaFile := filepath.Join(r.dir, fmt.Sprintf("%s.meta", uuid))
	dataFile := filepath.Join(r.dir, uuid)
	err := os.Remove(metaFile)
	if err != nil && !os.IsNotExist(err) {
		return errors.Trace(err)
	}
	err = os.Remove(dataFile)
	if err != nil {
		return errors.Trace(err)
	}
	return nil
}

// Close implements the MetricsReader interface.
func (r *JSONMetricReader) Close() error {
	return nil
}

func decodeBatch(file string) (MetricBatch, error) {
	var batch MetricBatch
	f, err := os.Open(file)
	if err != nil {
		return MetricBatch{}, errors.Trace(err)
	}
	defer f.Close()
	dec := json.NewDecoder(f)
	err = dec.Decode(&batch)
	if err != nil {
		return MetricBatch{}, errors.Trace(err)
	}
	return batch, nil
}

func decodeMetrics(file string) ([]jujuc.Metric, error) {
	var metrics []jujuc.Metric
	f, err := os.Open(file)
	if err != nil {
		return nil, errors.Trace(err)
	}
	defer f.Close()
	dec := json.NewDecoder(f)
	for {
		var metric jujuc.Metric
		err := dec.Decode(&metric)
		if err == io.EOF {
			break
		} else if err != nil {
			return nil, errors.Trace(err)
		}
		metrics = append(metrics, metric)
	}
	return metrics, nil
}
<|endoftext|>


<commit_before>package cmd

import (
	"os/exec"

	"github.com/markbates/buffalo/buffalo/cmd/generate"
	"github.com/markbates/gentronics"
)

func newAppGenerator() *gentronics.Generator {
	g := gentronics.New()
	g.Add(gentronics.NewFile("main.go", nMain))
	g.Add(gentronics.NewFile("Procfile", nProcfile))
	g.Add(gentronics.NewFile("Procfile.development", nProcfileDev))
	g.Add(gentronics.NewFile(".buffalo.dev.yml", nRefresh))
	g.Add(gentronics.NewFile("actions/app.go", nApp))
	g.Add(gentronics.NewFile("actions/home.go", nHomeHandler))
	g.Add(gentronics.NewFile("actions/home_test.go", nHomeHandlerTest))
	g.Add(gentronics.NewFile("actions/render.go", nRender))
	g.Add(gentronics.NewFile("grifts/routes.go", nGriftRoutes))
	g.Add(gentronics.NewFile("templates/index.html", nIndexHTML))
	g.Add(gentronics.NewFile("templates/application.html", nApplicationHTML))
	g.Add(gentronics.NewFile("assets/application.js", ""))
	g.Add(gentronics.NewFile("assets/application.css", nApplicationCSS))
	g.Add(gentronics.NewFile(".gitignore", nGitignore))
	g.Add(gentronics.NewCommand(goGet("github.com/markbates/refresh/...")))
	g.Add(gentronics.NewCommand(goInstall("github.com/markbates/refresh")))
	g.Add(gentronics.NewCommand(goGet("github.com/markbates/grift/...")))
	g.Add(gentronics.NewCommand(goInstall("github.com/markbates/grift")))
	g.Add(generate.NewJQueryGenerator())
	g.Add(generate.NewBootstrapGenerator())
	g.Add(newSodaGenerator())
	g.Add(gentronics.NewCommand(appGoGet()))
	g.Add(generate.Fmt)
	return g
}

func appGoGet() *exec.Cmd {
	appArgs := []string{"get", "-t"}
	if verbose {
		appArgs = append(appArgs, "-v")
	}
	appArgs = append(appArgs, "./...")
	return exec.Command("go", appArgs...)
}

const nMain = `package main

import (
	"log"
	"net/http"

	"{{.actionsPath}}"
)

func main() {
	port := defaults.String(os.Getenv("PORT"), "3000")
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), actions.App()))
}

`
const nApp = `package actions

import (
	"net/http"

	"github.com/markbates/buffalo"
	{{if .withPop -}}
	"github.com/markbates/buffalo/middleware"
	"{{.modelsPath}}"
	{{end -}}
)

var ENV = defaults.String(os.Getenv("GO_ENV"), "development")

// App is where all routes and middleware for buffalo
// should be defined. This is the nerve center of your
// application.
func App() http.Handler {
	a := buffalo.Automatic(buffalo.Options{
		Env: ENV,
	})

	{{if .withPop -}}
	a.Use(middleware.PopTransaction(models.DB))
	{{end -}}

	a.ServeFiles("/assets", assetsPath())
	a.GET("/", HomeHandler)

	return a
}
`

const nRender = `package actions

import (
	"net/http"
	"path"
	"runtime"

	"github.com/markbates/buffalo/render"
)

var r *render.Engine

func init() {
	r = render.New(render.Options{
		TemplatesPath: fromHere("../templates"),
		HTMLLayout:    "application.html",
	})
}

func assetsPath() http.Dir {
	return http.Dir(fromHere("../assets"))
}

func fromHere(p string) string {
	_, filename, _, _ := runtime.Caller(1)
	return path.Join(path.Dir(filename), p)
}
`

const nHomeHandler = `package actions

import "github.com/markbates/buffalo"

// HomeHandler is a default handler to serve up
// a home page.
func HomeHandler(c buffalo.Context) error {
	return c.Render(200, r.HTML("index.html"))
}
`

const nHomeHandlerTest = `package actions_test

import (
	"testing"

	"{{.actionsPath}}"
	"github.com/markbates/willie"
	"github.com/stretchr/testify/require"
)

func Test_HomeHandler(t *testing.T) {
	r := require.New(t)

	w := willie.New(actions.App())
	res := w.Request("/").Get()

	r.Equal(200, res.Code)
	r.Contains(res.Body.String(), "Welcome to Buffalo!")
}
`

const nIndexHTML = `<h1>Welcome to Buffalo!</h1>`

const nApplicationHTML = `<html>
<head>
  <meta charset="utf-8">
  <title>Buffalo - {{ .titleName }}</title>
  {{if .withBootstrap -}}
  <link rel="stylesheet" href="/assets/bootstrap.css" type="text/css" media="all" />
  {{end -}}
  <link rel="stylesheet" href="/assets/application.css" type="text/css" media="all" />
</head>
<body>

  {{"{{"}} yield {{"}}"}}

  {{if .withJQuery -}}
  <script src="/assets/jquery.js" type="text/javascript" charset="utf-8"></script>
  {{end -}}
  {{if .withBootstrap -}}
  <script src="/assets/bootstrap.js" type="text/javascript" charset="utf-8"></script>
  {{end -}}
  <script src="/assets/application.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
`

const nApplicationCSS = `body {
  font-family: helvetica;
}
`

const nGitignore = `vendor/
**/*.log
**/*.sqlite
bin/
node_modules/
{{ .name }}
`

const nGriftRoutes = `package grifts

import (
	"os"

	"github.com/markbates/buffalo"
	. "github.com/markbates/grift/grift"
	"{{.actionsPath}}"
	"github.com/olekukonko/tablewriter"
)

var _ = Add("routes", func(c *Context) error {
	a := actions.App().(*buffalo.App)
	routes := a.Routes()

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Method", "Path", "Handler"})
	for _, r := range routes {
		table.Append([]string{r.Method, r.Path, r.HandlerName})
	}
	table.SetCenterSeparator("|")
	table.SetAlignment(tablewriter.ALIGN_LEFT)
	table.Render()
	return nil
})`

const nRefresh = `app_root: .
ignored_folders:
- vendor
- log
- tmp
included_extensions:
- .go
- .html
build_path: /tmp
build_delay: 200ns
binary_name: {{.name}}-build
command_flags: []
enable_colors: true
log_name: buffalo
`

const nProcfile = `web: {{.name}}`
const nProcfileDev = `web: buffalo dev`
<commit_msg>added the correct imports to generated code<commit_after>package cmd

import (
	"os/exec"

	"github.com/markbates/buffalo/buffalo/cmd/generate"
	"github.com/markbates/gentronics"
)

func newAppGenerator() *gentronics.Generator {
	g := gentronics.New()
	g.Add(gentronics.NewFile("main.go", nMain))
	g.Add(gentronics.NewFile("Procfile", nProcfile))
	g.Add(gentronics.NewFile("Procfile.development", nProcfileDev))
	g.Add(gentronics.NewFile(".buffalo.dev.yml", nRefresh))
	g.Add(gentronics.NewFile("actions/app.go", nApp))
	g.Add(gentronics.NewFile("actions/home.go", nHomeHandler))
	g.Add(gentronics.NewFile("actions/home_test.go", nHomeHandlerTest))
	g.Add(gentronics.NewFile("actions/render.go", nRender))
	g.Add(gentronics.NewFile("grifts/routes.go", nGriftRoutes))
	g.Add(gentronics.NewFile("templates/index.html", nIndexHTML))
	g.Add(gentronics.NewFile("templates/application.html", nApplicationHTML))
	g.Add(gentronics.NewFile("assets/application.js", ""))
	g.Add(gentronics.NewFile("assets/application.css", nApplicationCSS))
	g.Add(gentronics.NewFile(".gitignore", nGitignore))
	g.Add(gentronics.NewCommand(goGet("github.com/markbates/refresh/...")))
	g.Add(gentronics.NewCommand(goInstall("github.com/markbates/refresh")))
	g.Add(gentronics.NewCommand(goGet("github.com/markbates/grift/...")))
	g.Add(gentronics.NewCommand(goInstall("github.com/markbates/grift")))
	g.Add(generate.NewJQueryGenerator())
	g.Add(generate.NewBootstrapGenerator())
	g.Add(newSodaGenerator())
	g.Add(gentronics.NewCommand(appGoGet()))
	g.Add(generate.Fmt)
	return g
}

func appGoGet() *exec.Cmd {
	appArgs := []string{"get", "-t"}
	if verbose {
		appArgs = append(appArgs, "-v")
	}
	appArgs = append(appArgs, "./...")
	return exec.Command("go", appArgs...)
}

const nMain = `package main

import (
	"fmt"
	"log"
	"net/http"
	"os"

	"{{.actionsPath}}"
	"github.com/markbates/going/defaults"
)

func main() {
	port := defaults.String(os.Getenv("PORT"), "3000")
	log.Fatal(http.ListenAndServe(fmt.Sprintf(":%s", port), actions.App()))
}

`
const nApp = `package actions

import (
	"net/http"
	"os"

	"github.com/markbates/buffalo"
	{{if .withPop -}}
	"github.com/markbates/buffalo/middleware"
	"{{.modelsPath}}"
	{{end -}}
	"github.com/markbates/going/defaults"
)

var ENV = defaults.String(os.Getenv("GO_ENV"), "development")

// App is where all routes and middleware for buffalo
// should be defined. This is the nerve center of your
// application.
func App() http.Handler {
	a := buffalo.Automatic(buffalo.Options{
		Env: ENV,
	})

	{{if .withPop -}}
	a.Use(middleware.PopTransaction(models.DB))
	{{end -}}

	a.ServeFiles("/assets", assetsPath())
	a.GET("/", HomeHandler)

	return a
}
`

const nRender = `package actions

import (
	"net/http"
	"path"
	"runtime"

	"github.com/markbates/buffalo/render"
)

var r *render.Engine

func init() {
	r = render.New(render.Options{
		TemplatesPath: fromHere("../templates"),
		HTMLLayout:    "application.html",
	})
}

func assetsPath() http.Dir {
	return http.Dir(fromHere("../assets"))
}

func fromHere(p string) string {
	_, filename, _, _ := runtime.Caller(1)
	return path.Join(path.Dir(filename), p)
}
`

const nHomeHandler = `package actions

import "github.com/markbates/buffalo"

// HomeHandler is a default handler to serve up
// a home page.
func HomeHandler(c buffalo.Context) error {
	return c.Render(200, r.HTML("index.html"))
}
`

const nHomeHandlerTest = `package actions_test

import (
	"testing"

	"{{.actionsPath}}"
	"github.com/markbates/willie"
	"github.com/stretchr/testify/require"
)

func Test_HomeHandler(t *testing.T) {
	r := require.New(t)

	w := willie.New(actions.App())
	res := w.Request("/").Get()

	r.Equal(200, res.Code)
	r.Contains(res.Body.String(), "Welcome to Buffalo!")
}
`

const nIndexHTML = `<h1>Welcome to Buffalo!</h1>`

const nApplicationHTML = `<html>
<head>
  <meta charset="utf-8">
  <title>Buffalo - {{ .titleName }}</title>
  {{if .withBootstrap -}}
  <link rel="stylesheet" href="/assets/bootstrap.css" type="text/css" media="all" />
  {{end -}}
  <link rel="stylesheet" href="/assets/application.css" type="text/css" media="all" />
</head>
<body>

  {{"{{"}} yield {{"}}"}}

  {{if .withJQuery -}}
  <script src="/assets/jquery.js" type="text/javascript" charset="utf-8"></script>
  {{end -}}
  {{if .withBootstrap -}}
  <script src="/assets/bootstrap.js" type="text/javascript" charset="utf-8"></script>
  {{end -}}
  <script src="/assets/application.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>
`

const nApplicationCSS = `body {
  font-family: helvetica;
}
`

const nGitignore = `vendor/
**/*.log
**/*.sqlite
bin/
node_modules/
{{ .name }}
`

const nGriftRoutes = `package grifts

import (
	"os"

	"github.com/markbates/buffalo"
	. "github.com/markbates/grift/grift"
	"{{.actionsPath}}"
	"github.com/olekukonko/tablewriter"
)

var _ = Add("routes", func(c *Context) error {
	a := actions.App().(*buffalo.App)
	routes := a.Routes()

	table := tablewriter.NewWriter(os.Stdout)
	table.SetHeader([]string{"Method", "Path", "Handler"})
	for _, r := range routes {
		table.Append([]string{r.Method, r.Path, r.HandlerName})
	}
	table.SetCenterSeparator("|")
	table.SetAlignment(tablewriter.ALIGN_LEFT)
	table.Render()
	return nil
})`

const nRefresh = `app_root: .
ignored_folders:
- vendor
- log
- tmp
included_extensions:
- .go
- .html
build_path: /tmp
build_delay: 200ns
binary_name: {{.name}}-build
command_flags: []
enable_colors: true
log_name: buffalo
`

const nProcfile = `web: {{.name}}`
const nProcfileDev = `web: buffalo dev`
<|endoftext|>


<commit_before>package luar

import (
	"fmt"
	"reflect"

	"github.com/yuin/gopher-lua"
)

var typeMetatable map[string]map[string]lua.LGFunction

func init() {
	typeMetatable = map[string]map[string]lua.LGFunction{
		"chan": {
			"__index":    chanIndex,
			"__tostring": baseToString,
			"__eq":       baseEqual,
		},
		"map": {
			"__index":    mapIndex,
			"__newindex": mapNewIndex,
			"__len":      mapLen,
			"__call":     mapCall,
			"__tostring": baseToString,
			"__eq":       baseEqual,
		},
		"ptr": {
			"__index":    ptrIndex,
			"__newindex": ptrNewIndex,
			"__tostring": baseToString,
			"__eq":       baseEqual,
		},
		"slice": {
			"__index":    sliceIndex,
			"__newindex": sliceNewIndex,
			"__len":      sliceLen,
			"__tostring": baseToString,
			"__eq":       baseEqual,
		},
		"struct": {
			"__index":    structIndex,
			"__newindex": structNewIndex,
			"__tostring": baseToString,
		},
		"type": {
			"__call":     typeCall,
			"__tostring": baseToString,
		},
	}
}

func baseToString(L *lua.LState) int {
	ud := L.CheckUserData(1)
	value := reflect.ValueOf(ud.Value)

	if value.CanInterface() {
		val := value.Interface()
		if stringer, ok := val.(fmt.Stringer); ok {
			L.Push(lua.LString(stringer.String()))
			return 1
		}
	}

	L.Push(lua.LString(value.String()))
	return 1
}

func baseEqual(L *lua.LState) int {
	ud1 := L.CheckUserData(1)
	ud2 := L.CheckUserData(2)
	L.Push(lua.LBool(ud1.Value == ud2.Value))
	return 1
}

func ensureMetatable(L *lua.LState) *lua.LTable {
	const metatableKey = lua.LString("github.com/layeh/gopher-luar")
	v := L.G.Registry.RawGetH(metatableKey)
	if v != lua.LNil {
		return v.(*lua.LTable)
	}
	newTable := L.NewTable()
	for typeName, typeMethods := range typeMetatable {
		typeTable := L.NewTable()
		typeTable.RawSetH(lua.LString("__metatable"), lua.LTrue)
		for methodName, methodFunc := range typeMethods {
			typeTable.RawSetH(lua.LString(methodName), L.NewFunction(methodFunc))
		}
		newTable.RawSetH(lua.LString(typeName), typeTable)
	}
	L.G.Registry.RawSetH(metatableKey, newTable)
	return newTable
}

// New creates and returns a new lua.LValue for the given value.
//
// The following types are supported:
//  reflect.Kind    gopher-lua Type
//  nil             LNil
//  Bool            LBool
//  Int             LNumber
//  Int8            LNumber
//  Int16           LNumber
//  Int32           LNumber
//  Int64           LNumber
//  Uint            LNumber
//  Uint8           LNumber
//  Uint32          LNumber
//  Uint64          LNumber
//  Float32         LNumber
//  Float64         LNumber
//  Chan            *LUserData
//  Interface       *LUserData
//  Func            *lua.LFunction
//  Map             *LUserData
//  Ptr             *LUserData
//  Slice           *LUserData
//  String          LString
//  Struct          *LUserData
//  UnsafePointer   *LUserData
func New(L *lua.LState, value interface{}) lua.LValue {
	if value == nil {
		return lua.LNil
	}
	if lval, ok := value.(lua.LValue); ok {
		return lval
	}
	table := ensureMetatable(L)

	val := reflect.ValueOf(value)
	switch val.Kind() {
	case reflect.Bool:
		return lua.LBool(val.Bool())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return lua.LNumber(float64(val.Int()))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return lua.LNumber(float64(val.Uint()))
	case reflect.Float32, reflect.Float64:
		return lua.LNumber(val.Float())
	case reflect.Chan:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("chan"))
		return ud
	case reflect.Func:
		return funcWrapper(L, val)
	case reflect.Interface:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	case reflect.Map:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("map"))
		return ud
	case reflect.Ptr:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("ptr"))
		return ud
	case reflect.Slice:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("slice"))
		return ud
	case reflect.String:
		return lua.LString(val.String())
	case reflect.Struct:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("struct"))
		return ud
	case reflect.UnsafePointer:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	}
	return nil
}

// NewType returns a new type creator for the given value's type.
//
// When the lua.LValue is called, a new value will be created that is the
// same type as value's type.
func NewType(L *lua.LState, value interface{}) lua.LValue {
	table := ensureMetatable(L)

	valueType := reflect.TypeOf(value)
	ud := L.NewUserData()
	ud.Value = valueType
	ud.Metatable = table.RawGetH(lua.LString("type"))
	return ud
}

func lValueToReflect(v lua.LValue, hint reflect.Type) reflect.Value {
	switch converted := v.(type) {
	case lua.LBool:
		return reflect.ValueOf(bool(converted))
	case lua.LChannel:
		return reflect.ValueOf(converted)
	case lua.LNumber:
		return reflect.ValueOf(converted).Convert(hint)
	case *lua.LFunction:
		return reflect.ValueOf(converted)
	case *lua.LNilType:
		return reflect.Zero(hint)
	case *lua.LState:
		return reflect.ValueOf(converted)
	case lua.LString:
		return reflect.ValueOf(string(converted))
	case *lua.LTable:
		return reflect.ValueOf(converted)
	case *lua.LUserData:
		return reflect.ValueOf(converted.Value)
	}
	panic("fatal lValueToReflect error")
	return reflect.Value{}
}
<commit_msg>remove go vet warning<commit_after>package luar

import (
	"fmt"
	"reflect"

	"github.com/yuin/gopher-lua"
)

var typeMetatable map[string]map[string]lua.LGFunction

func init() {
	typeMetatable = map[string]map[string]lua.LGFunction{
		"chan": {
			"__index":    chanIndex,
			"__tostring": baseToString,
			"__eq":       baseEqual,
		},
		"map": {
			"__index":    mapIndex,
			"__newindex": mapNewIndex,
			"__len":      mapLen,
			"__call":     mapCall,
			"__tostring": baseToString,
			"__eq":       baseEqual,
		},
		"ptr": {
			"__index":    ptrIndex,
			"__newindex": ptrNewIndex,
			"__tostring": baseToString,
			"__eq":       baseEqual,
		},
		"slice": {
			"__index":    sliceIndex,
			"__newindex": sliceNewIndex,
			"__len":      sliceLen,
			"__tostring": baseToString,
			"__eq":       baseEqual,
		},
		"struct": {
			"__index":    structIndex,
			"__newindex": structNewIndex,
			"__tostring": baseToString,
		},
		"type": {
			"__call":     typeCall,
			"__tostring": baseToString,
		},
	}
}

func baseToString(L *lua.LState) int {
	ud := L.CheckUserData(1)
	value := reflect.ValueOf(ud.Value)

	if value.CanInterface() {
		val := value.Interface()
		if stringer, ok := val.(fmt.Stringer); ok {
			L.Push(lua.LString(stringer.String()))
			return 1
		}
	}

	L.Push(lua.LString(value.String()))
	return 1
}

func baseEqual(L *lua.LState) int {
	ud1 := L.CheckUserData(1)
	ud2 := L.CheckUserData(2)
	L.Push(lua.LBool(ud1.Value == ud2.Value))
	return 1
}

func ensureMetatable(L *lua.LState) *lua.LTable {
	const metatableKey = lua.LString("github.com/layeh/gopher-luar")
	v := L.G.Registry.RawGetH(metatableKey)
	if v != lua.LNil {
		return v.(*lua.LTable)
	}
	newTable := L.NewTable()
	for typeName, typeMethods := range typeMetatable {
		typeTable := L.NewTable()
		typeTable.RawSetH(lua.LString("__metatable"), lua.LTrue)
		for methodName, methodFunc := range typeMethods {
			typeTable.RawSetH(lua.LString(methodName), L.NewFunction(methodFunc))
		}
		newTable.RawSetH(lua.LString(typeName), typeTable)
	}
	L.G.Registry.RawSetH(metatableKey, newTable)
	return newTable
}

// New creates and returns a new lua.LValue for the given value.
//
// The following types are supported:
//  reflect.Kind    gopher-lua Type
//  nil             LNil
//  Bool            LBool
//  Int             LNumber
//  Int8            LNumber
//  Int16           LNumber
//  Int32           LNumber
//  Int64           LNumber
//  Uint            LNumber
//  Uint8           LNumber
//  Uint32          LNumber
//  Uint64          LNumber
//  Float32         LNumber
//  Float64         LNumber
//  Chan            *LUserData
//  Interface       *LUserData
//  Func            *lua.LFunction
//  Map             *LUserData
//  Ptr             *LUserData
//  Slice           *LUserData
//  String          LString
//  Struct          *LUserData
//  UnsafePointer   *LUserData
func New(L *lua.LState, value interface{}) lua.LValue {
	if value == nil {
		return lua.LNil
	}
	if lval, ok := value.(lua.LValue); ok {
		return lval
	}
	table := ensureMetatable(L)

	val := reflect.ValueOf(value)
	switch val.Kind() {
	case reflect.Bool:
		return lua.LBool(val.Bool())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return lua.LNumber(float64(val.Int()))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return lua.LNumber(float64(val.Uint()))
	case reflect.Float32, reflect.Float64:
		return lua.LNumber(val.Float())
	case reflect.Chan:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("chan"))
		return ud
	case reflect.Func:
		return funcWrapper(L, val)
	case reflect.Interface:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	case reflect.Map:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("map"))
		return ud
	case reflect.Ptr:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("ptr"))
		return ud
	case reflect.Slice:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("slice"))
		return ud
	case reflect.String:
		return lua.LString(val.String())
	case reflect.Struct:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("struct"))
		return ud
	case reflect.UnsafePointer:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	}
	return nil
}

// NewType returns a new type creator for the given value's type.
//
// When the lua.LValue is called, a new value will be created that is the
// same type as value's type.
func NewType(L *lua.LState, value interface{}) lua.LValue {
	table := ensureMetatable(L)

	valueType := reflect.TypeOf(value)
	ud := L.NewUserData()
	ud.Value = valueType
	ud.Metatable = table.RawGetH(lua.LString("type"))
	return ud
}

func lValueToReflect(v lua.LValue, hint reflect.Type) reflect.Value {
	switch converted := v.(type) {
	case lua.LBool:
		return reflect.ValueOf(bool(converted))
	case lua.LChannel:
		return reflect.ValueOf(converted)
	case lua.LNumber:
		return reflect.ValueOf(converted).Convert(hint)
	case *lua.LFunction:
		return reflect.ValueOf(converted)
	case *lua.LNilType:
		return reflect.Zero(hint)
	case *lua.LState:
		return reflect.ValueOf(converted)
	case lua.LString:
		return reflect.ValueOf(string(converted))
	case *lua.LTable:
		return reflect.ValueOf(converted)
	case *lua.LUserData:
		return reflect.ValueOf(converted.Value)
	}
	panic("fatal lValueToReflect error")
}
<|endoftext|>


<commit_before>package luar

import (
	"fmt"
	"reflect"

	"github.com/yuin/gopher-lua"
)

var wrapperMetatable map[string]map[string]lua.LGFunction

func init() {
	wrapperMetatable = map[string]map[string]lua.LGFunction{
		"chan": {
			"__index":    chanIndex,
			"__len":      chanLen,
			"__tostring": allTostring,
			"__eq":       chanEq,
		},
		"map": {
			"__index":    mapIndex,
			"__newindex": mapNewIndex,
			"__len":      mapLen,
			"__call":     mapCall,
			"__tostring": allTostring,
			"__eq":       mapEq,
		},
		"ptr": {
			"__index":    ptrIndex,
			"__newindex": ptrNewIndex,
			"__pow":      ptrPow,
			"__call":     ptrCall,
			"__tostring": allTostring,
			"__unm":      ptrUnm,
			"__eq":       ptrEq,
		},
		"slice": {
			"__index":    sliceIndex,
			"__newindex": sliceNewIndex,
			"__len":      sliceLen,
			"__tostring": allTostring,
			"__eq":       sliceEq,
		},
		"struct": {
			"__index":    structIndex,
			"__newindex": structNewIndex,
			"__call":     structCall,
			"__tostring": allTostring,
		},
		"type": {
			"__call":     typeCall,
			"__tostring": allTostring,
			"__eq":       typeEq,
		},
	}
}

func ensureMetatable(L *lua.LState) *lua.LTable {
	const metatableKey = lua.LString("github.com/layeh/gopher-luar")
	v := L.G.Registry.RawGetH(metatableKey)
	if v != lua.LNil {
		return v.(*lua.LTable)
	}
	newTable := L.NewTable()

	for typeName, meta := range wrapperMetatable {
		typeTable := L.NewTable()
		typeTable.RawSetH(lua.LString("__metatable"), lua.LTrue)
		for methodName, methodFunc := range meta {
			typeTable.RawSetH(lua.LString(methodName), L.NewFunction(methodFunc))
		}
		newTable.RawSetH(lua.LString(typeName), typeTable)
	}

	L.G.Registry.RawSetH(metatableKey, newTable)
	return newTable
}

func allTostring(L *lua.LState) int {
	ud := L.CheckUserData(1)
	value := ud.Value
	if stringer, ok := value.(fmt.Stringer); ok {
		L.Push(lua.LString(stringer.String()))
	} else {
		L.Push(lua.LString(fmt.Sprintf("userdata (luar): %p", ud)))
	}
	return 1
}

// New creates and returns a new lua.LValue for the given value.
//
// The following types are supported:
//  Kind            gopher-lua Type
//  -------------------------------
//  nil             LNil
//  Bool            LBool
//  Int             LNumber
//  Int8            LNumber
//  Int16           LNumber
//  Int32           LNumber
//  Int64           LNumber
//  Uint            LNumber
//  Uint8           LNumber
//  Uint32          LNumber
//  Uint64          LNumber
//  Float32         LNumber
//  Float64         LNumber
//  Complex64       *LUserData
//  Complex128      *LUserData
//  Array           *LUserData
//  Chan            *LUserData
//  Interface       *LUserData
//  Func            *lua.LFunction
//  Map             *LUserData
//  Ptr             *LUserData
//  Slice           *LUserData
//  String          LString
//  Struct          *LUserData
//  UnsafePointer   *LUserData
func New(L *lua.LState, value interface{}) lua.LValue {
	if value == nil {
		return lua.LNil
	}
	if lval, ok := value.(lua.LValue); ok {
		return lval
	}

	val := reflect.ValueOf(value)
	switch val.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		if val.IsNil() {
			return lua.LNil
		}
	}

	table := ensureMetatable(L)

	switch val.Kind() {
	case reflect.Bool:
		return lua.LBool(val.Bool())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return lua.LNumber(float64(val.Int()))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return lua.LNumber(float64(val.Uint()))
	case reflect.Float32, reflect.Float64:
		return lua.LNumber(val.Float())
	case reflect.Chan:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("chan"))
		return ud
	case reflect.Func:
		return funcWrapper(L, val)
	case reflect.Interface:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	case reflect.Map:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("map"))
		return ud
	case reflect.Ptr:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("ptr"))
		return ud
	case reflect.Slice:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("slice"))
		return ud
	case reflect.String:
		return lua.LString(val.String())
	case reflect.Struct:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetH(lua.LString("struct"))
		return ud
	default:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	}
}

// NewType returns a new type creator for the given value's type.
//
// When the lua.LValue is called, a new value will be created that is the
// same type as value's type.
func NewType(L *lua.LState, value interface{}) lua.LValue {
	table := ensureMetatable(L)

	val := reflect.TypeOf(value)
	ud := L.NewUserData()
	ud.Value = val
	ud.Metatable = table.RawGetH(lua.LString("type"))
	return ud
}

func lValueToReflect(v lua.LValue, hint reflect.Type) reflect.Value {
	if hint == refTypeLuaLValue {
		return reflect.ValueOf(v)
	}
	switch converted := v.(type) {
	case lua.LBool:
		return reflect.ValueOf(bool(converted))
	case lua.LChannel:
		return reflect.ValueOf(converted)
	case lua.LNumber:
		return reflect.ValueOf(converted).Convert(hint)
	case *lua.LFunction:
		return reflect.ValueOf(converted)
	case *lua.LNilType:
		return reflect.Zero(hint)
	case *lua.LState:
		return reflect.ValueOf(converted)
	case lua.LString:
		return reflect.ValueOf(string(converted))
	case *lua.LTable:
		return reflect.ValueOf(converted)
	case *lua.LUserData:
		return reflect.ValueOf(converted.Value)
	}
	panic("fatal lValueToReflect error")
}
<commit_msg>replace Raw*H with Raw*String, where possible<commit_after>package luar

import (
	"fmt"
	"reflect"

	"github.com/yuin/gopher-lua"
)

var wrapperMetatable map[string]map[string]lua.LGFunction

func init() {
	wrapperMetatable = map[string]map[string]lua.LGFunction{
		"chan": {
			"__index":    chanIndex,
			"__len":      chanLen,
			"__tostring": allTostring,
			"__eq":       chanEq,
		},
		"map": {
			"__index":    mapIndex,
			"__newindex": mapNewIndex,
			"__len":      mapLen,
			"__call":     mapCall,
			"__tostring": allTostring,
			"__eq":       mapEq,
		},
		"ptr": {
			"__index":    ptrIndex,
			"__newindex": ptrNewIndex,
			"__pow":      ptrPow,
			"__call":     ptrCall,
			"__tostring": allTostring,
			"__unm":      ptrUnm,
			"__eq":       ptrEq,
		},
		"slice": {
			"__index":    sliceIndex,
			"__newindex": sliceNewIndex,
			"__len":      sliceLen,
			"__tostring": allTostring,
			"__eq":       sliceEq,
		},
		"struct": {
			"__index":    structIndex,
			"__newindex": structNewIndex,
			"__call":     structCall,
			"__tostring": allTostring,
		},
		"type": {
			"__call":     typeCall,
			"__tostring": allTostring,
			"__eq":       typeEq,
		},
	}
}

func ensureMetatable(L *lua.LState) *lua.LTable {
	const metatableKey = "github.com/layeh/gopher-luar"
	v := L.G.Registry.RawGetString(metatableKey)
	if v != lua.LNil {
		return v.(*lua.LTable)
	}
	newTable := L.NewTable()

	for typeName, meta := range wrapperMetatable {
		typeTable := L.NewTable()
		typeTable.RawSetString("__metatable", lua.LTrue)
		for methodName, methodFunc := range meta {
			typeTable.RawSetString(methodName, L.NewFunction(methodFunc))
		}
		newTable.RawSetString(typeName, typeTable)
	}

	L.G.Registry.RawSetString(metatableKey, newTable)
	return newTable
}

func allTostring(L *lua.LState) int {
	ud := L.CheckUserData(1)
	value := ud.Value
	if stringer, ok := value.(fmt.Stringer); ok {
		L.Push(lua.LString(stringer.String()))
	} else {
		L.Push(lua.LString(fmt.Sprintf("userdata (luar): %p", ud)))
	}
	return 1
}

// New creates and returns a new lua.LValue for the given value.
//
// The following types are supported:
//  Kind            gopher-lua Type
//  -------------------------------
//  nil             LNil
//  Bool            LBool
//  Int             LNumber
//  Int8            LNumber
//  Int16           LNumber
//  Int32           LNumber
//  Int64           LNumber
//  Uint            LNumber
//  Uint8           LNumber
//  Uint32          LNumber
//  Uint64          LNumber
//  Float32         LNumber
//  Float64         LNumber
//  Complex64       *LUserData
//  Complex128      *LUserData
//  Array           *LUserData
//  Chan            *LUserData
//  Interface       *LUserData
//  Func            *lua.LFunction
//  Map             *LUserData
//  Ptr             *LUserData
//  Slice           *LUserData
//  String          LString
//  Struct          *LUserData
//  UnsafePointer   *LUserData
func New(L *lua.LState, value interface{}) lua.LValue {
	if value == nil {
		return lua.LNil
	}
	if lval, ok := value.(lua.LValue); ok {
		return lval
	}

	val := reflect.ValueOf(value)
	switch val.Kind() {
	case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice:
		if val.IsNil() {
			return lua.LNil
		}
	}

	table := ensureMetatable(L)

	switch val.Kind() {
	case reflect.Bool:
		return lua.LBool(val.Bool())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return lua.LNumber(float64(val.Int()))
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return lua.LNumber(float64(val.Uint()))
	case reflect.Float32, reflect.Float64:
		return lua.LNumber(val.Float())
	case reflect.Chan:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetString("chan")
		return ud
	case reflect.Func:
		return funcWrapper(L, val)
	case reflect.Interface:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	case reflect.Map:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetString("map")
		return ud
	case reflect.Ptr:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetString("ptr")
		return ud
	case reflect.Slice:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetString("slice")
		return ud
	case reflect.String:
		return lua.LString(val.String())
	case reflect.Struct:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		ud.Metatable = table.RawGetString("struct")
		return ud
	default:
		ud := L.NewUserData()
		ud.Value = val.Interface()
		return ud
	}
}

// NewType returns a new type creator for the given value's type.
//
// When the lua.LValue is called, a new value will be created that is the
// same type as value's type.
func NewType(L *lua.LState, value interface{}) lua.LValue {
	table := ensureMetatable(L)

	val := reflect.TypeOf(value)
	ud := L.NewUserData()
	ud.Value = val
	ud.Metatable = table.RawGetString("type")
	return ud
}

func lValueToReflect(v lua.LValue, hint reflect.Type) reflect.Value {
	if hint == refTypeLuaLValue {
		return reflect.ValueOf(v)
	}
	switch converted := v.(type) {
	case lua.LBool:
		return reflect.ValueOf(bool(converted))
	case lua.LChannel:
		return reflect.ValueOf(converted)
	case lua.LNumber:
		return reflect.ValueOf(converted).Convert(hint)
	case *lua.LFunction:
		return reflect.ValueOf(converted)
	case *lua.LNilType:
		return reflect.Zero(hint)
	case *lua.LState:
		return reflect.ValueOf(converted)
	case lua.LString:
		return reflect.ValueOf(string(converted))
	case *lua.LTable:
		return reflect.ValueOf(converted)
	case *lua.LUserData:
		return reflect.ValueOf(converted.Value)
	}
	panic("fatal lValueToReflect error")
}
<|endoftext|>


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

package cmd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/cilium/cilium/pkg/defaults"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/test/helpers"

	"github.com/sirupsen/logrus"
)

// BugtoolConfiguration creates and loads the configuration file used to run
// the commands. The only commands not managed by the configuration is initial
// setup, for ex. searching for Cilium daemonset pods or running uname.
type BugtoolConfiguration struct {
	// Commands is the exact commands that will be run by the bugtool
	Commands []string `json:"commands"`
}

func setupDefaultConfig(path string, k8sPods []string, confDir, cmdDir string) (*BugtoolConfiguration, error) {
	c := BugtoolConfiguration{defaultCommands(confDir, cmdDir, k8sPods)}
	return &c, save(&c, path)
}

func defaultCommands(confDir string, cmdDir string, k8sPods []string) []string {
	var commands []string
	// Not expecting all of the commands to be available
	commands = []string{
		// Host and misc
		"ps auxfw",
		"hostname",
		"ip a",
		"ip r",
		"ip link",
		"uname -a",
		"dig",
		"netstat -a",
		"pidstat",
		"arp",
		"top -b -n 1",
		"uptime",
		"dmesg --time-format=iso",
		"bpftool map show",
		"bpftool prog show",
		// Versions
		"docker version",
		"docker info",
		// Docker and Kubernetes logs from systemd
		"journalctl -u cilium*",
		"journalctl -u kubelet",
		// iptables
		"iptables-save",
		"iptables -S",
		"ip6tables -S",
		"iptables -L -v",
		"ip rule",
		// gops
		fmt.Sprintf("gops memstats $(pidof %s)", helpers.AgentDaemon),
		fmt.Sprintf("gops stack $(pidof %s)", helpers.AgentDaemon),
		fmt.Sprintf("gops stats $(pidof %s)", helpers.AgentDaemon),
		// Get list of open file descriptors managed by the agent
		fmt.Sprintf("ls -la /proc/$(pidof %s)/fd", helpers.AgentDaemon),
	}

	// Commands that require variables and / or more configuration are added
	// separately below
	commands = append(commands, catCommands()...)
	commands = append(commands, ethoolCommands()...)
	commands = append(commands, copyConfigCommands(confDir, k8sPods)...)
	commands = append(commands, copyCiliumInfoCommands(cmdDir, k8sPods)...)

	return k8sCommands(commands, k8sPods)
}

func save(c *BugtoolConfiguration, path string) error {
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("Failed to open file %s for writing: %s", path, err)
	}
	defer f.Close()

	data, err := json.MarshalIndent(c, "", "\t")
	if err != nil {
		return fmt.Errorf("Cannot marshal config %s", err)
	}
	err = ioutil.WriteFile(path, data, 0644)
	if err != nil {
		return fmt.Errorf("Cannot write config %s", err)
	}
	return nil
}

func loadConfigFile(path string) (*BugtoolConfiguration, error) {
	var content []byte
	var err error
	logrus.WithField(logfields.Path, path).Debug("Loading file")

	content, err = ioutil.ReadFile(path)

	if err != nil {
		return nil, err
	}

	var c BugtoolConfiguration
	err = json.Unmarshal(content, &c)
	return &c, err
}

func catCommands() []string {
	files := []string{
		"/proc/sys/net/core/bpf_jit_enable",
		"/proc/kallsyms",
		"/etc/resolv.conf",
		"/var/log/docker.log",
		"/var/log/daemon.log",
		"/var/log/messages",
	}
	// Only print the files that do exist to reduce number of errors in
	// archive
	commands := []string{}
	for _, f := range files {
		if _, err := os.Stat(f); os.IsNotExist(err) {
			continue
		}
		commands = append(commands, fmt.Sprintf("cat %s", f))
	}
	// TODO: handle K8s case as well.
	return commands
}

func copyConfigCommands(confDir string, k8sPods []string) []string {
	commands := []string{}
	// Location is a convenience structure to avoid too many long lines
	type Location struct {
		Src string
		Dst string
	}

	// These locations don't depend on the kernel version for running so we
	// can add them in this scope.
	locations := []Location{
		{"/proc/config", fmt.Sprintf("%s/kernel-config", confDir)},
		{"/proc/config.gz", fmt.Sprintf("%s/kernel-config.gz", confDir)},
	}

	// The following lines copy the kernel configuration. This code is
	// duplicated for the non Kubernetes case. The variables preventing
	// them to be one block is the pod prefix and namespace used in the
	// path. This should be refactored.
	if len(k8sPods) == 0 {
		kernel, _ := execCommand("uname -r")
		kernel = strings.TrimSpace(kernel)
		// Append the boot config for the current kernel
		l := Location{fmt.Sprintf("/boot/config-%s", kernel),
			fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
		locations = append(locations, l)

		// Use the locations to create command strings
		for _, location := range locations {
			if _, err := os.Stat(location.Src); os.IsNotExist(err) {
				continue
			}
			commands = append(commands, fmt.Sprintf("cp %s %s", location.Src, location.Dst))
		}
	} else {
		// If there are multiple pods, we want to get all of the kernel
		// configs. Therefore we need copy commands for all the pods.
		for _, pod := range k8sPods {
			prompt := podPrefix(pod, "uname -r")
			kernel, _ := execCommand(prompt)
			kernel = strings.TrimSpace(kernel)
			l := Location{fmt.Sprintf("/boot/config-%s", kernel),
				fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
			locations = append(locations, l)

			// The location is mostly the same but the command is
			// prepended with 'kubectl` and the path contains the
			// namespace and pod. For ex:
			// kubectl cp kube-system/cilium-kg8lv:/tmp/cilium-bugtool-243785589.tar /tmp/cilium-bugtool-243785589.tar
			for _, location := range locations {
				kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, location.Src)
				cmd := fmt.Sprintf("%s %s %s %s", "kubectl", "cp", kubectlArg, location.Dst)
				commands = append(commands, cmd)
			}
		}
	}
	return commands
}

func copyCiliumInfoCommands(cmdDir string, k8sPods []string) []string {
	// Most of the output should come via debuginfo but also adding
	// these ones for skimming purposes
	ciliumCommands := []string{
		"cilium debuginfo",
		"cilium config",
		"cilium bpf tunnel list",
		"cilium bpf lb list",
		"cilium bpf endpoint list",
		"cilium bpf ct list global",
		"cilium bpf proxy list",
		"cilium bpf ipcache list",
		"cilium status --verbose",
		"cilium identity list",
		"cilium-health status",
	}
	var commands []string

	stateDir := filepath.Join(defaults.RuntimePath, defaults.StateDir)
	if len(k8sPods) == 0 { // Assuming this is a non k8s deployment
		dst := filepath.Join(cmdDir, defaults.StateDir)
		commands = append(commands, fmt.Sprintf("cp -r %s %s", stateDir, dst))
		for _, cmd := range ciliumCommands {
			// Add the host flag if set
			if len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}
			commands = append(commands, cmd)
		}
	} else { // Found k8s pods
		for _, pod := range k8sPods {
			dst := filepath.Join(cmdDir, fmt.Sprintf("%s-%s", pod, defaults.StateDir))
			kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, stateDir)
			// kubectl cp kube-system/cilium-xrzwr:/var/run/cilium/state cilium-xrzwr-state
			commands = append(commands, fmt.Sprintf("kubectl cp %s %s", kubectlArg, dst))
			for _, cmd := range ciliumCommands {
				// Add the host flag if set
				if len(host) > 0 {
					cmd = fmt.Sprintf("%s -H %s", cmd, host)
				}
				commands = append(commands, podPrefix(pod, cmd))
			}
		}
	}

	return commands
}

func k8sCommands(allCommands []string, pods []string) []string {
	// These commands do not require a pod argument
	var commands = []string{
		"kubectl get nodes -o wide",
		"kubectl describe nodes",
		"kubectl get pods,svc --all-namespaces",
		"kubectl version",
	}

	// Prepare to run all the commands inside of the pod(s)
	for _, pod := range pods {
		for _, cmd := range allCommands {
			// Add the host flag if set
			if strings.HasPrefix(cmd, "cilium") &&
				!strings.Contains(cmd, "-H") && len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}

			if !strings.Contains(cmd, "kubectl exec") {
				cmd = podPrefix(pod, cmd)
			}
			commands = append(commands, cmd)
		}

		// Retrieve current version of pod logs
		cmd := fmt.Sprintf("kubectl -n %s logs --timestamps %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		// Retrieve previous version of pod logs
		cmd = fmt.Sprintf("kubectl -n %s logs --timestamps -p %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		cmd = fmt.Sprintf("kubectl -n %s describe pod %s", k8sNamespace, pod)
		commands = append(commands, cmd)
	}

	if len(pods) == 0 {
		allCommands = append(allCommands, commands...)
		return allCommands
	}

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

package cmd

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/cilium/cilium/pkg/defaults"
	"github.com/cilium/cilium/pkg/logging/logfields"
	"github.com/cilium/cilium/test/helpers"

	"github.com/sirupsen/logrus"
)

// BugtoolConfiguration creates and loads the configuration file used to run
// the commands. The only commands not managed by the configuration is initial
// setup, for ex. searching for Cilium daemonset pods or running uname.
type BugtoolConfiguration struct {
	// Commands is the exact commands that will be run by the bugtool
	Commands []string `json:"commands"`
}

func setupDefaultConfig(path string, k8sPods []string, confDir, cmdDir string) (*BugtoolConfiguration, error) {
	c := BugtoolConfiguration{defaultCommands(confDir, cmdDir, k8sPods)}
	return &c, save(&c, path)
}

func defaultCommands(confDir string, cmdDir string, k8sPods []string) []string {
	var commands []string
	// Not expecting all of the commands to be available
	commands = []string{
		// Host and misc
		"ps auxfw",
		"hostname",
		"ip a",
		"ip r",
		"ip link",
		"uname -a",
		"dig",
		"netstat -a",
		"pidstat",
		"arp",
		"top -b -n 1",
		"uptime",
		"dmesg --time-format=iso",
		"bpftool map show",
		"bpftool prog show",
		// Versions
		"docker version",
		"docker info",
		// Docker and Kubernetes logs from systemd
		"journalctl -u cilium*",
		"journalctl -u kubelet",
		// iptables
		"iptables-save",
		"iptables -S",
		"ip6tables -S",
		"iptables -L -v",
		"ip rule",
		// gops
		fmt.Sprintf("gops memstats $(pidof %s)", helpers.AgentDaemon),
		fmt.Sprintf("gops stack $(pidof %s)", helpers.AgentDaemon),
		fmt.Sprintf("gops stats $(pidof %s)", helpers.AgentDaemon),
		// Get list of open file descriptors managed by the agent
		fmt.Sprintf("ls -la /proc/$(pidof %s)/fd", helpers.AgentDaemon),
	}

	// Commands that require variables and / or more configuration are added
	// separately below
	commands = append(commands, catCommands()...)
	commands = append(commands, ethoolCommands()...)
	commands = append(commands, copyConfigCommands(confDir, k8sPods)...)
	commands = append(commands, copyCiliumInfoCommands(cmdDir, k8sPods)...)

	return k8sCommands(commands, k8sPods)
}

func save(c *BugtoolConfiguration, path string) error {
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("Failed to open file %s for writing: %s", path, err)
	}
	defer f.Close()

	data, err := json.MarshalIndent(c, "", "\t")
	if err != nil {
		return fmt.Errorf("Cannot marshal config %s", err)
	}
	err = ioutil.WriteFile(path, data, 0644)
	if err != nil {
		return fmt.Errorf("Cannot write config %s", err)
	}
	return nil
}

func loadConfigFile(path string) (*BugtoolConfiguration, error) {
	var content []byte
	var err error
	logrus.WithField(logfields.Path, path).Debug("Loading file")

	content, err = ioutil.ReadFile(path)

	if err != nil {
		return nil, err
	}

	var c BugtoolConfiguration
	err = json.Unmarshal(content, &c)
	return &c, err
}

func catCommands() []string {
	files := []string{
		"/proc/sys/net/core/bpf_jit_enable",
		"/proc/kallsyms",
		"/etc/resolv.conf",
		"/var/log/docker.log",
		"/var/log/daemon.log",
		"/var/log/messages",
	}
	// Only print the files that do exist to reduce number of errors in
	// archive
	commands := []string{}
	for _, f := range files {
		if _, err := os.Stat(f); os.IsNotExist(err) {
			continue
		}
		commands = append(commands, fmt.Sprintf("cat %s", f))
	}
	// TODO: handle K8s case as well.
	return commands
}

func copyConfigCommands(confDir string, k8sPods []string) []string {
	commands := []string{}
	// Location is a convenience structure to avoid too many long lines
	type Location struct {
		Src string
		Dst string
	}

	// These locations don't depend on the kernel version for running so we
	// can add them in this scope.
	locations := []Location{
		{"/proc/config", fmt.Sprintf("%s/kernel-config", confDir)},
		{"/proc/config.gz", fmt.Sprintf("%s/kernel-config.gz", confDir)},
	}

	// The following lines copy the kernel configuration. This code is
	// duplicated for the non Kubernetes case. The variables preventing
	// them to be one block is the pod prefix and namespace used in the
	// path. This should be refactored.
	if len(k8sPods) == 0 {
		kernel, _ := execCommand("uname -r")
		kernel = strings.TrimSpace(kernel)
		// Append the boot config for the current kernel
		l := Location{fmt.Sprintf("/boot/config-%s", kernel),
			fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
		locations = append(locations, l)

		// Use the locations to create command strings
		for _, location := range locations {
			if _, err := os.Stat(location.Src); os.IsNotExist(err) {
				continue
			}
			commands = append(commands, fmt.Sprintf("cp %s %s", location.Src, location.Dst))
		}
	} else {
		// If there are multiple pods, we want to get all of the kernel
		// configs. Therefore we need copy commands for all the pods.
		for _, pod := range k8sPods {
			prompt := podPrefix(pod, "uname -r")
			kernel, _ := execCommand(prompt)
			kernel = strings.TrimSpace(kernel)
			l := Location{fmt.Sprintf("/boot/config-%s", kernel),
				fmt.Sprintf("%s/kernel-config-%s", confDir, kernel)}
			locations = append(locations, l)

			// The location is mostly the same but the command is
			// prepended with 'kubectl` and the path contains the
			// namespace and pod. For ex:
			// kubectl cp kube-system/cilium-kg8lv:/tmp/cilium-bugtool-243785589.tar /tmp/cilium-bugtool-243785589.tar
			for _, location := range locations {
				kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, location.Src)
				cmd := fmt.Sprintf("%s %s %s %s", "kubectl", "cp", kubectlArg, location.Dst)
				commands = append(commands, cmd)
			}
		}
	}
	return commands
}

func copyCiliumInfoCommands(cmdDir string, k8sPods []string) []string {
	// Most of the output should come via debuginfo but also adding
	// these ones for skimming purposes
	ciliumCommands := []string{
		"cilium debuginfo",
		"cilium config",
		"cilium bpf tunnel list",
		"cilium bpf lb list",
		"cilium bpf endpoint list",
		"cilium bpf ct list global",
		"cilium bpf proxy list",
		"cilium bpf ipcache list",
		"cilium status --verbose",
		"cilium identity list",
		"cilium map list --verbose",
		"cilium-health status",
	}
	var commands []string

	stateDir := filepath.Join(defaults.RuntimePath, defaults.StateDir)
	if len(k8sPods) == 0 { // Assuming this is a non k8s deployment
		dst := filepath.Join(cmdDir, defaults.StateDir)
		commands = append(commands, fmt.Sprintf("cp -r %s %s", stateDir, dst))
		for _, cmd := range ciliumCommands {
			// Add the host flag if set
			if len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}
			commands = append(commands, cmd)
		}
	} else { // Found k8s pods
		for _, pod := range k8sPods {
			dst := filepath.Join(cmdDir, fmt.Sprintf("%s-%s", pod, defaults.StateDir))
			kubectlArg := fmt.Sprintf("%s/%s:%s", k8sNamespace, pod, stateDir)
			// kubectl cp kube-system/cilium-xrzwr:/var/run/cilium/state cilium-xrzwr-state
			commands = append(commands, fmt.Sprintf("kubectl cp %s %s", kubectlArg, dst))
			for _, cmd := range ciliumCommands {
				// Add the host flag if set
				if len(host) > 0 {
					cmd = fmt.Sprintf("%s -H %s", cmd, host)
				}
				commands = append(commands, podPrefix(pod, cmd))
			}
		}
	}

	return commands
}

func k8sCommands(allCommands []string, pods []string) []string {
	// These commands do not require a pod argument
	var commands = []string{
		"kubectl get nodes -o wide",
		"kubectl describe nodes",
		"kubectl get pods,svc --all-namespaces",
		"kubectl version",
	}

	// Prepare to run all the commands inside of the pod(s)
	for _, pod := range pods {
		for _, cmd := range allCommands {
			// Add the host flag if set
			if strings.HasPrefix(cmd, "cilium") &&
				!strings.Contains(cmd, "-H") && len(host) > 0 {
				cmd = fmt.Sprintf("%s -H %s", cmd, host)
			}

			if !strings.Contains(cmd, "kubectl exec") {
				cmd = podPrefix(pod, cmd)
			}
			commands = append(commands, cmd)
		}

		// Retrieve current version of pod logs
		cmd := fmt.Sprintf("kubectl -n %s logs --timestamps %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		// Retrieve previous version of pod logs
		cmd = fmt.Sprintf("kubectl -n %s logs --timestamps -p %s", k8sNamespace, pod)
		commands = append(commands, cmd)

		cmd = fmt.Sprintf("kubectl -n %s describe pod %s", k8sNamespace, pod)
		commands = append(commands, cmd)
	}

	if len(pods) == 0 {
		allCommands = append(allCommands, commands...)
		return allCommands
	}

	return commands
}
<|endoftext|>


<commit_before>package gomua

import "fmt"

// Mail interface defines mail to be read.
// This can be a threaded list of messages, or a single message.
//
// String() should return a string representing what the user needs to see
// to further interact with the Mail. For a single message, this should be
// simply the message. For a threaded list of messages, this might be a list
// of all messages in the thread, or possibly a just newest unread message?
//
// Summary() should return a short string that can fit on one line, suitable
// for printing as 1 item in a list on a screen.
// For instance, for a single message:
//     Test Message from Frenata <mr.k.frenata@gmail.com>
type Mail interface {
	String() string
	Summary() string
}

func (m *Message) String() string {
	var output string = fmt.Sprintf("From: %v\n", m.Header.Get("From")) +
		fmt.Sprintf("To: %v\n", m.Header.Get("To")) +
		fmt.Sprintf("Date: %v\n", m.Header.Get("Date")) +
		fmt.Sprintf("Subject: %v\n", m.Header.Get("Subject")) +
		fmt.Sprintf("\n%s\n", m.Content)

	return output
}

func (m *Message) Summary() string {
	subject := m.Header.Get("Subject")
	from := m.Header.Get("From")
	return fmt.Sprintf("%s from %s", color(subject, "31"), color(from, "33"))
}

// adds ANSI color to text
func color(s string, color string) string {
	return "\033[" + color + "m" + s + "\033[0m"
}
<commit_msg>trying to get messages to only display text/plain type content<commit_after>package gomua

import (
	"bufio"
	"bytes"
	"fmt"
	"strings"
)

// Mail interface defines mail to be read.
// This can be a threaded list of messages, or a single message.
//
// String() should return a string representing what the user needs to see
// to further interact with the Mail. For a single message, this should be
// simply the message. For a threaded list of messages, this might be a list
// of all messages in the thread, or possibly a just newest unread message?
//
// Summary() should return a short string that can fit on one line, suitable
// for printing as 1 item in a list on a screen.
// For instance, for a single message:
//     Test Message from Frenata <mr.k.frenata@gmail.com>
type Mail interface {
	String() string
	Summary() string
}

func (m *Message) String() string {
	var output string = fmt.Sprintf("From: %v\n", m.Header.Get("From")) +
		fmt.Sprintf("To: %v\n", m.Header.Get("To")) +
		fmt.Sprintf("Date: %v\n", m.Header.Get("Date")) +
		fmt.Sprintf("Subject: %v\n", m.Header.Get("Subject"))

		//output += fmt.Sprintf("\n%s\n", m.Content)

	var bound string
	var boundB bool = false
	t := m.Header.Get("Content-Type")
	//for _, t := range ctypes {
	if strings.Contains(t, "boundary=") {
		bs := strings.Split(t, "boundary=")
		bound = "--" + bs[1]
		boundB = true
	}
	//}

	raw := bufio.NewScanner(strings.NewReader(m.Content))
	buf := new(bytes.Buffer)
	var write bool = true
	for raw.Scan() {
		line := raw.Text()
		if strings.Contains(line, "Content-Type:") {
			write = false
		}

		if !strings.Contains(line, "Content-Transfer-Encoding") {
			if !boundB || boundB && line != bound {
				if write {
					buf.WriteString(line + "\r\n")
				}
			}
		}

		if strings.Contains(line, "Content-Type: text/plain") {
			write = true
		}
	}
	output += fmt.Sprintf("\n%s\n", buf.Bytes())

	return output
}

func (m *Message) Summary() string {
	subject := m.Header.Get("Subject")
	from := m.Header.Get("From")
	return fmt.Sprintf("%s from %s", color(subject, "31"), color(from, "33"))
}

// adds ANSI color to text
func color(s string, color string) string {
	return "\033[" + color + "m" + s + "\033[0m"
}
<|endoftext|>


<commit_before>package doozer

import (
	"doozer/ack"
	"doozer/client"
	"doozer/gc"
	"doozer/lock"
	"doozer/member"
	"doozer/paxos"
	"doozer/server"
	"doozer/session"
	"doozer/store"
	"doozer/util"
	"doozer/web"
	"net"
	"os"
)

const (
	alpha           = 50
	pulseInterval   = 1e9
)

const slot = "/doozer/slot"

var slots = store.MustCompileGlob("/doozer/slot/*")

func Main(clusterName, attachAddr string, udpConn net.PacketConn, listener, webListener net.Listener) {
	logger := util.NewLogger("main")

	var err os.Error

	listenAddr := listener.Addr().String()

	cal := make(chan int)

	var cl *client.Client
	self := util.RandId()
	st := store.New()
	if attachAddr == "" { // we are the only node in a new cluster
		set(st, "/doozer/info/"+self+"/public-addr", listenAddr, store.Missing)
		set(st, "/doozer/info/"+self+"/hostname", os.Getenv("HOSTNAME"), store.Missing)
		set(st, "/doozer/members/"+self, listenAddr, store.Missing)
		set(st, "/doozer/slot/"+"1", self, store.Missing)
		set(st, "/ping", "pong", store.Missing)

		close(cal)

		cl = client.New("local", listenAddr) // TODO use real cluster name
	} else {
		cl = client.New("local", attachAddr) // TODO use real cluster name

		path := "/doozer/info/" + self + "/public-addr"
		_, err = cl.Set(path, store.Clobber, []byte(listenAddr))
		if err != nil {
			panic(err)
		}

		path = "/doozer/info/" + self + "/hostname"
		_, err = cl.Set(path, store.Clobber, []byte(os.Getenv("HOSTNAME")))
		if err != nil {
			panic(err)
		}

		joinSeqn, snap, err := cl.Join(self, listenAddr)
		if err != nil {
			panic(err)
		}

		done := make(chan int)
		st.Ops <- store.Op{1, snap}

		go advanceUntil(cl, done)

		go func() {
			st.Sync(joinSeqn + alpha)
			close(done)
			activate(st, self, cl)
			close(cal)
		}()

		// TODO sink needs a way to pick up missing values if there are any
		// gaps in its sequence
	}

	acker := ack.Ackify(udpConn)

	mg := paxos.NewManager(self, alpha, st, paxos.Encoder{acker})

	if attachAddr == "" {
		// Skip ahead alpha steps so that the registrar can provide a
		// meaningful cluster.
		n := <-st.Seqns
		for i := n + 1; i < n+alpha; i++ {
			st.Ops <- store.Op{i, store.Nop}
		}
	}

	go func() {
		<-cal
		go lock.Clean(st, mg)
		go session.Clean(st, mg)
		go member.Clean(st, mg)
		go gc.Pulse(self, st.Seqns, mg, pulseInterval)
		go gc.Clean(st)
	}()

	sv := &server.Server{listenAddr, st, mg, self}

	go func() {
		cas := store.Missing
		for {
			cas, err = cl.Checkin(self, cas)
			if err != nil {
				panic(err) // this is fatal
			}
		}
	}()

	go func() {
		err := sv.Serve(listener, cal)
		if err != nil {
			panic(err)
		}
	}()

	if webListener != nil {
		web.Store = st
		web.ClusterName = clusterName
		go web.Serve(webListener)
	}

	decoder := paxos.Decoder{mg}
	for {
		data, addr, err := acker.ReadFrom()
		if err == os.EINVAL {
			break
		}
		if err != nil {
			logger.Println(err)
			continue
		}
		decoder.WriteFrom(addr, data)
	}
}

func activate(st *store.Store, self string, c *client.Client) {
	logger := util.NewLogger("activate")
	w := store.NewWatch(st, slots)

	for _, base := range store.GetDir(st, slot) {
		p := slot + "/" + base
		v, cas := st.Get(p)
		if cas != store.Dir && v[0] == "" {
			_, err := c.Set(p, cas, []byte(self))
			if err != nil {
				logger.Println(err)
				continue
			}

			w.Stop()
			close(w.C)
			break
		}
	}

	for ev := range w.C {
		// TODO ev.IsEmpty()
		if ev.IsSet() && ev.Body == "" {
			_, err := c.Set(ev.Path, ev.Cas, []byte(self))
			if err != nil {
				logger.Println(err)
				continue
			}
			w.Stop()
			close(w.C)
		}
	}
}

func advanceUntil(cl *client.Client, done chan int) {
	for _, ok := <-done; !ok; _, ok = <-done {
		cl.Noop()
	}
}

func set(st *store.Store, path, body string, cas int64) {
	mut := store.MustEncodeSet(path, body, cas)
	st.Ops <- store.Op{1 + <-st.Seqns, mut}
}
<commit_msg>connect to self when self is a CAL<commit_after>package doozer

import (
	"doozer/ack"
	"doozer/client"
	"doozer/gc"
	"doozer/lock"
	"doozer/member"
	"doozer/paxos"
	"doozer/server"
	"doozer/session"
	"doozer/store"
	"doozer/util"
	"doozer/web"
	"net"
	"os"
)

const (
	alpha           = 50
	pulseInterval   = 1e9
)

const slot = "/doozer/slot"

var slots = store.MustCompileGlob("/doozer/slot/*")

func Main(clusterName, attachAddr string, udpConn net.PacketConn, listener, webListener net.Listener) {
	logger := util.NewLogger("main")

	var err os.Error

	listenAddr := listener.Addr().String()

	cal := make(chan int)

	var cl *client.Client
	self := util.RandId()
	st := store.New()
	if attachAddr == "" { // we are the only node in a new cluster
		set(st, "/doozer/info/"+self+"/public-addr", listenAddr, store.Missing)
		set(st, "/doozer/info/"+self+"/hostname", os.Getenv("HOSTNAME"), store.Missing)
		set(st, "/doozer/members/"+self, listenAddr, store.Missing)
		set(st, "/doozer/slot/"+"1", self, store.Missing)
		set(st, "/ping", "pong", store.Missing)

		close(cal)

		cl = client.New("local", listenAddr) // TODO use real cluster name
	} else {
		cl = client.New("local", attachAddr) // TODO use real cluster name

		path := "/doozer/info/" + self + "/public-addr"
		_, err = cl.Set(path, store.Clobber, []byte(listenAddr))
		if err != nil {
			panic(err)
		}

		path = "/doozer/info/" + self + "/hostname"
		_, err = cl.Set(path, store.Clobber, []byte(os.Getenv("HOSTNAME")))
		if err != nil {
			panic(err)
		}

		joinSeqn, snap, err := cl.Join(self, listenAddr)
		if err != nil {
			panic(err)
		}

		done := make(chan int)
		st.Ops <- store.Op{1, snap}

		go advanceUntil(cl, done)

		go func() {
			st.Sync(joinSeqn + alpha)
			close(done)
			activate(st, self, cl)
			close(cal)
		}()

		// TODO sink needs a way to pick up missing values if there are any
		// gaps in its sequence
	}

	acker := ack.Ackify(udpConn)

	mg := paxos.NewManager(self, alpha, st, paxos.Encoder{acker})

	if attachAddr == "" {
		// Skip ahead alpha steps so that the registrar can provide a
		// meaningful cluster.
		n := <-st.Seqns
		for i := n + 1; i < n+alpha; i++ {
			st.Ops <- store.Op{i, store.Nop}
		}
	}

	go func() {
		<-cal
		go lock.Clean(st, mg)
		go session.Clean(st, mg)
		go member.Clean(st, mg)
		go gc.Pulse(self, st.Seqns, mg, pulseInterval)
		go gc.Clean(st)
	}()

	sv := &server.Server{listenAddr, st, mg, self}

	go func() {
		cas := store.Missing

		// slave
		for {
			if closed(cal) {
				break
			}
			cas, err = cl.Checkin(self, cas)
			if err != nil {
				panic(err) // this is fatal
			}
		}

		// CAL
		cl = client.New("local", listenAddr)
		for {
			cas, err = cl.Checkin(self, cas)
			if err != nil {
				panic(err) // this is fatal
			}
		}
	}()

	go func() {
		err := sv.Serve(listener, cal)
		if err != nil {
			panic(err)
		}
	}()

	if webListener != nil {
		web.Store = st
		web.ClusterName = clusterName
		go web.Serve(webListener)
	}

	decoder := paxos.Decoder{mg}
	for {
		data, addr, err := acker.ReadFrom()
		if err == os.EINVAL {
			break
		}
		if err != nil {
			logger.Println(err)
			continue
		}
		decoder.WriteFrom(addr, data)
	}
}

func activate(st *store.Store, self string, c *client.Client) {
	logger := util.NewLogger("activate")
	w := store.NewWatch(st, slots)

	for _, base := range store.GetDir(st, slot) {
		p := slot + "/" + base
		v, cas := st.Get(p)
		if cas != store.Dir && v[0] == "" {
			_, err := c.Set(p, cas, []byte(self))
			if err != nil {
				logger.Println(err)
				continue
			}

			w.Stop()
			close(w.C)
			break
		}
	}

	for ev := range w.C {
		// TODO ev.IsEmpty()
		if ev.IsSet() && ev.Body == "" {
			_, err := c.Set(ev.Path, ev.Cas, []byte(self))
			if err != nil {
				logger.Println(err)
				continue
			}
			w.Stop()
			close(w.C)
		}
	}
}

func advanceUntil(cl *client.Client, done chan int) {
	for _, ok := <-done; !ok; _, ok = <-done {
		cl.Noop()
	}
}

func set(st *store.Store, path, body string, cas int64) {
	mut := store.MustEncodeSet(path, body, cas)
	st.Ops <- store.Op{1 + <-st.Seqns, mut}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/facebookgo/grace/gracehttp"
	"github.com/gin-gonic/gin"
	"html/template"
	"net/http"
	"sync"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"

	local "github.com/eirka/eirka-index/config"
)

var (
	sitemap map[string]*SiteData
	mu      sync.RWMutex
)

func init() {

	// map to hold site data so we dont hit the database every time
	sitemap = make(map[string]*SiteData)

	// Database connection settings
	dbase := db.Database{
		User:           local.Settings.Database.User,
		Password:       local.Settings.Database.Password,
		Proto:          local.Settings.Database.Proto,
		Host:           local.Settings.Database.Host,
		Database:       local.Settings.Database.Database,
		MaxIdle:        local.Settings.Database.MaxIdle,
		MaxConnections: local.Settings.Database.MaxConnections,
	}

	// Set up DB connection
	dbase.NewDb()

	// Get limits and stuff from database
	config.GetDatabaseSettings()

}

func main() {

	// parse our template
	t := template.Must(template.New("templates").Delims("[[", "]]").Parse(index))
	t = template.Must(t.Parse(head))
	t = template.Must(t.Parse(header))
	t = template.Must(t.Parse(navmenu))
	t = template.Must(t.ParseGlob(fmt.Sprintf("%s/includes/*.tmpl", local.Settings.Directories.AssetsDir)))

	r := gin.Default()

	// load template into gin
	r.SetHTMLTemplate(t)

	// use the details middleware
	r.Use(Details())

	r.GET("/", IndexController)
	r.GET("/page/:id", IndexController)
	r.GET("/thread/:id/:page", IndexController)
	r.GET("/directory", IndexController)
	r.GET("/image/:id", IndexController)
	r.GET("/tags/:page", IndexController)
	r.GET("/tags", IndexController)
	r.GET("/tag/:id/:page", IndexController)
	r.GET("/account", IndexController)
	r.GET("/trending", IndexController)
	r.GET("/favorites/:page", IndexController)
	r.GET("/favorites", IndexController)
	r.GET("/error", IndexController)

	r.NoRoute(ErrorController)

	s := &http.Server{
		Addr:    fmt.Sprintf("%s:%d", local.Settings.Index.Address, local.Settings.Index.Port),
		Handler: r,
	}

	gracehttp.Serve(s)

}
<commit_msg>fix vars<commit_after>package main

import (
	"fmt"
	"github.com/facebookgo/grace/gracehttp"
	"github.com/gin-gonic/gin"
	"html/template"
	"net/http"
	"sync"

	"github.com/eirka/eirka-libs/config"
	"github.com/eirka/eirka-libs/db"

	local "github.com/eirka/eirka-index/config"
)

var (
	sitemap = make(map[string]*SiteData)
	mu      = new(sync.RWMutex)
)

func init() {

	// Database connection settings
	dbase := db.Database{
		User:           local.Settings.Database.User,
		Password:       local.Settings.Database.Password,
		Proto:          local.Settings.Database.Proto,
		Host:           local.Settings.Database.Host,
		Database:       local.Settings.Database.Database,
		MaxIdle:        local.Settings.Database.MaxIdle,
		MaxConnections: local.Settings.Database.MaxConnections,
	}

	// Set up DB connection
	dbase.NewDb()

	// Get limits and stuff from database
	config.GetDatabaseSettings()

}

func main() {

	// parse our template
	t := template.Must(template.New("templates").Delims("[[", "]]").Parse(index))
	t = template.Must(t.Parse(head))
	t = template.Must(t.Parse(header))
	t = template.Must(t.Parse(navmenu))
	t = template.Must(t.ParseGlob(fmt.Sprintf("%s/includes/*.tmpl", local.Settings.Directories.AssetsDir)))

	r := gin.Default()

	// load template into gin
	r.SetHTMLTemplate(t)

	// use the details middleware
	r.Use(Details())

	r.GET("/", IndexController)
	r.GET("/page/:id", IndexController)
	r.GET("/thread/:id/:page", IndexController)
	r.GET("/directory", IndexController)
	r.GET("/image/:id", IndexController)
	r.GET("/tags/:page", IndexController)
	r.GET("/tags", IndexController)
	r.GET("/tag/:id/:page", IndexController)
	r.GET("/account", IndexController)
	r.GET("/trending", IndexController)
	r.GET("/favorites/:page", IndexController)
	r.GET("/favorites", IndexController)
	r.GET("/error", IndexController)

	r.NoRoute(ErrorController)

	s := &http.Server{
		Addr:    fmt.Sprintf("%s:%d", local.Settings.Index.Address, local.Settings.Index.Port),
		Handler: r,
	}

	gracehttp.Serve(s)

}
<|endoftext|>


<commit_before>package main

import (
	"github.com/go-martini/martini"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/render"
	"github.com/martini-contrib/sessions"
	"github.com/martini-contrib/strict"
	"html"
	"html/template"
	"log"
	"os"
	"time"
)

func main() {

	helpers := template.FuncMap{
		// Unescape unescapes and parses HTML from database objects.
		// Used in templates such as "/post/display.tmpl"
		"unescape": func(s string) template.HTML {
			return template.HTML(html.UnescapeString(s))
		},
		// Title renders post name as a page title.
		// Otherwise it defaults to Vertigo.
		"title": func(t interface{}) string {
			post, exists := t.(Post)
			if exists {
				return post.Title
			}
			return "Vertigo"
		},
		// Date helper returns unix date as more readable one in string format.
		"date": func(d int64) string {
			return time.Unix(d, 0).String()
		},
	}

	m := martini.Classic()
	store := sessions.NewCookieStore([]byte(os.Getenv("vertigo_hash")))
	m.Use(sessions.Sessions("user", store))
	m.Use(middleware())
	m.Use(strict.Strict)
	m.Use(render.Renderer(render.Options{
		Layout: "layout",
		Funcs:  []template.FuncMap{helpers}, // Specify helper function maps for templates to access.
	}))

	m.Get("/", Homepage)

	m.Group("/feeds", func(r martini.Router) {
		r.Get("", func(res render.Render) {
			res.Redirect("/feeds/rss", 302)
		})
		r.Get("/atom", ReadFeed)
		r.Get("/rss", ReadFeed)
	})

	m.Group("/post", func(r martini.Router) {

		// Please note that `/new` route has to be before the `/:title` route. Otherwise the program will try
		// to fetch for Post named "new".
		// For now I'll keep it this way to streamline route naming.
		r.Get("/new", ProtectedPage, func(res render.Render) {
			res.HTML(200, "post/new", nil)
		})
		r.Get("/:title", ReadPost)
		r.Get("/:title/edit", EditPost)
		r.Post("/:title/edit", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Post{}), binding.ErrorHandler, UpdatePost)
		r.Get("/:title/delete", DeletePost)
		r.Get("/:title/publish", PublishPost)
		r.Post("/new", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Post{}), binding.ErrorHandler, CreatePost)
		r.Post("/search", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Search{}), binding.ErrorHandler, SearchPost)

	})

	m.Group("/user", func(r martini.Router) {

		r.Get("", ProtectedPage, ReadUser)
		//r.Post("/delete", strict.ContentType("application/x-www-form-urlencoded"), ProtectedPage, binding.Form(Person{}), DeleteUser)

		r.Get("/register", SessionRedirect, func(res render.Render) {
			res.HTML(200, "user/register", nil)
		})
		r.Post("/register", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Person{}), binding.ErrorHandler, CreateUser)

		r.Get("/login", SessionRedirect, func(res render.Render) {
			res.HTML(200, "user/login", nil)
		})
		r.Post("/login", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Person{}), LoginUser)
		r.Get("/logout", LogoutUser)

	})

	m.Group("/api", func(r martini.Router) {

		r.Get("", func(res render.Render) {
			res.HTML(200, "api/index", nil)
		})
		r.Get("/users", ReadUsers)
		r.Get("/user/:id", ReadUser)
		//r.Delete("/user", DeleteUser)
		r.Post("/user", strict.ContentType("application/json"), binding.Json(Person{}), binding.ErrorHandler, CreateUser)
		r.Post("/user/login", strict.ContentType("application/json"), binding.Json(Person{}), binding.ErrorHandler, LoginUser)
		r.Get("/user/logout", LogoutUser)

		r.Get("/posts", ReadPosts)
		r.Get("/post/:title", ReadPost)
		r.Post("/post", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, CreatePost)
		r.Get("/post/:title/publish")
		r.Post("/post/:title/edit", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, UpdatePost)
		r.Get("/post/:title/delete", DeletePost)
		r.Post("/post", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, CreatePost)
		r.Post("/post/search/:query", strict.ContentType("application/json"), binding.Json(Search{}), binding.ErrorHandler, SearchPost)

	})

	m.Router.NotFound(strict.MethodNotAllowed, strict.NotFound)
	m.Run()

	log.Println("Vertigo started")
}
<commit_msg>remove log println which never runs<commit_after>package main

import (
	"github.com/go-martini/martini"
	"github.com/martini-contrib/binding"
	"github.com/martini-contrib/render"
	"github.com/martini-contrib/sessions"
	"github.com/martini-contrib/strict"
	"html"
	"html/template"
	"os"
	"time"
)

func main() {

	helpers := template.FuncMap{
		// Unescape unescapes and parses HTML from database objects.
		// Used in templates such as "/post/display.tmpl"
		"unescape": func(s string) template.HTML {
			return template.HTML(html.UnescapeString(s))
		},
		// Title renders post name as a page title.
		// Otherwise it defaults to Vertigo.
		"title": func(t interface{}) string {
			post, exists := t.(Post)
			if exists {
				return post.Title
			}
			return "Vertigo"
		},
		// Date helper returns unix date as more readable one in string format.
		"date": func(d int64) string {
			return time.Unix(d, 0).String()
		},
	}

	m := martini.Classic()
	store := sessions.NewCookieStore([]byte(os.Getenv("vertigo_hash")))
	m.Use(sessions.Sessions("user", store))
	m.Use(middleware())
	m.Use(strict.Strict)
	m.Use(render.Renderer(render.Options{
		Layout: "layout",
		Funcs:  []template.FuncMap{helpers}, // Specify helper function maps for templates to access.
	}))

	m.Get("/", Homepage)

	m.Group("/feeds", func(r martini.Router) {
		r.Get("", func(res render.Render) {
			res.Redirect("/feeds/rss", 302)
		})
		r.Get("/atom", ReadFeed)
		r.Get("/rss", ReadFeed)
	})

	m.Group("/post", func(r martini.Router) {

		// Please note that `/new` route has to be before the `/:title` route. Otherwise the program will try
		// to fetch for Post named "new".
		// For now I'll keep it this way to streamline route naming.
		r.Get("/new", ProtectedPage, func(res render.Render) {
			res.HTML(200, "post/new", nil)
		})
		r.Get("/:title", ReadPost)
		r.Get("/:title/edit", EditPost)
		r.Post("/:title/edit", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Post{}), binding.ErrorHandler, UpdatePost)
		r.Get("/:title/delete", DeletePost)
		r.Get("/:title/publish", PublishPost)
		r.Post("/new", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Post{}), binding.ErrorHandler, CreatePost)
		r.Post("/search", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Search{}), binding.ErrorHandler, SearchPost)

	})

	m.Group("/user", func(r martini.Router) {

		r.Get("", ProtectedPage, ReadUser)
		//r.Post("/delete", strict.ContentType("application/x-www-form-urlencoded"), ProtectedPage, binding.Form(Person{}), DeleteUser)

		r.Get("/register", SessionRedirect, func(res render.Render) {
			res.HTML(200, "user/register", nil)
		})
		r.Post("/register", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Person{}), binding.ErrorHandler, CreateUser)

		r.Get("/login", SessionRedirect, func(res render.Render) {
			res.HTML(200, "user/login", nil)
		})
		r.Post("/login", strict.ContentType("application/x-www-form-urlencoded"), binding.Form(Person{}), LoginUser)
		r.Get("/logout", LogoutUser)

	})

	m.Group("/api", func(r martini.Router) {

		r.Get("", func(res render.Render) {
			res.HTML(200, "api/index", nil)
		})
		r.Get("/users", ReadUsers)
		r.Get("/user/:id", ReadUser)
		//r.Delete("/user", DeleteUser)
		r.Post("/user", strict.ContentType("application/json"), binding.Json(Person{}), binding.ErrorHandler, CreateUser)
		r.Post("/user/login", strict.ContentType("application/json"), binding.Json(Person{}), binding.ErrorHandler, LoginUser)
		r.Get("/user/logout", LogoutUser)

		r.Get("/posts", ReadPosts)
		r.Get("/post/:title", ReadPost)
		r.Post("/post", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, CreatePost)
		r.Get("/post/:title/publish")
		r.Post("/post/:title/edit", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, UpdatePost)
		r.Get("/post/:title/delete", DeletePost)
		r.Post("/post", strict.ContentType("application/json"), binding.Json(Post{}), binding.ErrorHandler, CreatePost)
		r.Post("/post/search/:query", strict.ContentType("application/json"), binding.Json(Search{}), binding.ErrorHandler, SearchPost)

	})

	m.Router.NotFound(strict.MethodNotAllowed, strict.NotFound)
	m.Run()

}
<|endoftext|>