<commit_before>package extract

import (
	"bytes"
	"net/http"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/koffeinsource/kaffeeshare/data"
	"github.com/koffeinsource/kaffeeshare/extract/plugins"
	"github.com/koffeinsource/kaffeeshare/request"
)

// ItemFromURL creates an Item from the passed url
func ItemFromURL(sourceURL string, r *http.Request, log request.Context) data.Item {

	// Create return value with default values
	returnee := data.Item{
		Caption:   sourceURL,
		URL:       sourceURL,
		CreatedAt: time.Now(),
	}

	contentType, body, err := GetURL(sourceURL, r)
	if err != nil {
		log.Errorf(err.Error())
		return returnee
	}

	//  log.Infof(contentType)
	switch {
	case strings.Contains(contentType, "image/"):
		plugins.Image(&returnee, sourceURL, contentType, log)
	case strings.Contains(contentType, "text/html"):

		// TODO Good check if page is UTF-8 and convert with go-iconv

		doc, err := goquery.NewDocumentFromReader(bytes.NewReader(body))
		if err != nil {
			log.Errorf("Problem parsing body. " + sourceURL + " - " + err.Error())
			return returnee
		}

		// Make sure to call this one first
		plugins.DefaultHTML(&returnee, sourceURL, doc, log)

		plugins.Amazon(&returnee, sourceURL, doc, log)

		plugins.Imgurl(&returnee, sourceURL, doc, log)
		plugins.Gfycat(&returnee, sourceURL, doc, log)

		plugins.Fefe(&returnee, sourceURL, doc, log)

		plugins.Youtube(&returnee, sourceURL, doc, log)
		plugins.Vimeo(&returnee, sourceURL, doc, log)

		plugins.Dilbert(&returnee, sourceURL, doc, log)
		plugins.Garfield(&returnee, sourceURL, doc, log)
		plugins.Xkcd(&returnee, sourceURL, doc, log)
		plugins.Littlegamers(&returnee, sourceURL, doc, log)

		plugins.Pastebin(&returnee, sourceURL, doc, log)
	default:
	}

	return returnee
}
<commit_msg>Added support for non-UTF8 charsets.<commit_after>package extract

import (
	"bytes"
	"net/http"
	"strings"
	"time"

	"github.com/PuerkitoBio/goquery"
	"github.com/koffeinsource/kaffeeshare/data"
	"github.com/koffeinsource/kaffeeshare/extract/plugins"
	"github.com/koffeinsource/kaffeeshare/request"
	"golang.org/x/net/html/charset"
)

// ItemFromURL creates an Item from the passed url
func ItemFromURL(sourceURL string, r *http.Request, log request.Context) data.Item {

	// Create return value with default values
	returnee := data.Item{
		Caption:   sourceURL,
		URL:       sourceURL,
		CreatedAt: time.Now(),
	}

	contentType, body, err := GetURL(sourceURL, r)
	if err != nil {
		log.Errorf(err.Error())
		return returnee
	}

	//  log.Infof(contentType)
	switch {
	case strings.Contains(contentType, "image/"):
		plugins.Image(&returnee, sourceURL, contentType, log)
	case strings.Contains(contentType, "text/html"):

		var doc *goquery.Document

		charsetReader, err := charset.NewReader(bytes.NewReader(body), contentType)
		if err == nil {
			doc, err = goquery.NewDocumentFromReader(charsetReader)
		} else {
			doc, err = goquery.NewDocumentFromReader(bytes.NewReader(body))
		}

		if err != nil {
			log.Errorf("Problem parsing body. " + sourceURL + " - " + err.Error())
			return returnee
		}

		// Make sure to call this one first
		plugins.DefaultHTML(&returnee, sourceURL, doc, log)

		plugins.Amazon(&returnee, sourceURL, doc, log)

		plugins.Imgurl(&returnee, sourceURL, doc, log)
		plugins.Gfycat(&returnee, sourceURL, doc, log)

		plugins.Fefe(&returnee, sourceURL, doc, log)

		plugins.Youtube(&returnee, sourceURL, doc, log)
		plugins.Vimeo(&returnee, sourceURL, doc, log)

		plugins.Dilbert(&returnee, sourceURL, doc, log)
		plugins.Garfield(&returnee, sourceURL, doc, log)
		plugins.Xkcd(&returnee, sourceURL, doc, log)
		plugins.Littlegamers(&returnee, sourceURL, doc, log)

		plugins.Pastebin(&returnee, sourceURL, doc, log)
	default:
	}

	return returnee
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"syscall"
	"unsafe"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
)

const mapMaxSize = 1e4

type Binary struct {
	Asset   []byte
	Name    string
	BaseDir string
}

func NewBinary(name string) Binary {
	wd, err := os.Getwd()
	if err != nil {
		wd = "/"
	}
	return Binary{
		Name:    name,
		BaseDir: wd,
	}
}

func (b *Binary) FileName() string {
	return strings.Replace(b.Name, "/", "_", -1)
}

func (b *Binary) FilePath() string {
	return filepath.Join(b.BaseDir, b.FileName())
}

func (b *Binary) TempPath() string {
	// FIXME: ensure using memory instead of disk if p ossible
	return filepath.Join(os.TempDir(), b.FileName())
}

func (b *Binary) Uninstall(filepath string) error {
	logrus.Infof("Uninstalling binary %q (%s)", b.Name, filepath)

	if _, err := os.Stat(filepath); os.IsNotExist(err) {
		logrus.Debugf("Asset %q not installed, nothing to do", filepath)
		return nil
	}

	return os.Remove(filepath)
}

func (b *Binary) Install(filepath string) error {
	logrus.Infof("Installing binary %q (%s)", b.Name, filepath)

	if _, err := os.Stat(filepath); !os.IsNotExist(err) {
		logrus.Debugf("Asset already installed: %q", filepath)
		return nil
	}

	asset, err := Asset(b.Name)
	if err != nil {
		return fmt.Errorf("failed to load the asset %q: %v", b.Name, err)
	}

	length := len(asset)
	size := int(unsafe.Sizeof(0)) * length
	if size > mapMaxSize*int(unsafe.Sizeof(0)) {
		return fmt.Errorf("file too big for current map size: %d > %d", size, mapMaxSize*int(unsafe.Sizeof(0)))
	}

	logrus.Debugf("Creating map file: %q", filepath)
	mapFile, err := os.Create(filepath)
	if err != nil {
		return fmt.Errorf("failed to create map file: %v", err)
	}

	logrus.Debugf("Seeking file")
	if _, err = mapFile.Seek(int64(length-1), 0); err != nil {
		return fmt.Errorf("failed to seek: %v", err)
	}

	logrus.Debugf("Writing to file")
	if _, err = mapFile.Write([]byte(" ")); err != nil {
		return fmt.Errorf("failed to write to file: %v", err)
	}

	logrus.Debugf("MMAPing")
	fd := int(mapFile.Fd())
	mmap, err := syscall.Mmap(fd, 0, size, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
	if err != nil {
		return fmt.Errorf("failed to mmap: %v", err)
	}

	logrus.Debugf("Filling array var")
	mapArray := (*[mapMaxSize]byte)(unsafe.Pointer(&mmap[0]))
	for i := 0; i < length; i++ {
		mapArray[i] = asset[i]
	}
	// fmt.Println(*mapArray)

	logrus.Debugf("MUNMAPing")
	if err = syscall.Munmap(mmap); err != nil {
		return fmt.Errorf("failed to munmap: %v", err)
	}

	logrus.Debugf("Closing")
	if err = mapFile.Close(); err != nil {
		return fmt.Errorf("failed to close: %v", err)
	}

	logrus.Debugf("Chmoding binary")
	if err = os.Chmod(filepath, 0777); err != nil {
		return fmt.Errorf("failed to chmod program: %v", err)
	}

	return nil
}

func (b *Binary) Execute(args []string) error {
	filepath := b.TempPath()
	logrus.Infof("Executing binary %q (%s)", b.Name, filepath)
	if len(args) > 0 {
		logrus.Infof("args=%v", args)
	}

	// temporary
	if err := b.Uninstall(filepath); err != nil {
		logrus.Debugf("Failed to uninstall temporary binary %q: %v", filepath, err)
	}

	if err := b.Install(filepath); err != nil {
		return err
	}
	// FIXME: delete early
	defer b.Uninstall(filepath)

	cmd := exec.Command(filepath, args...)
	cmd.Stdout = os.Stdout
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Start()

	return cmd.Wait()
}

func GetBinaryByName(name string) (*Binary, error) {
	for _, assetName := range AssetNames() {
		if name == assetName {
			bin := NewBinary(assetName)
			return &bin, nil
		}
	}
	for _, assetName := range AssetNames() {
		if name == filepath.Base(assetName) {
			bin := NewBinary(assetName)
			return &bin, nil
		}
	}
	return nil, fmt.Errorf("No match")
}

func ActionExecute(c *cli.Context) {
	bin, err := GetBinaryByName(c.Command.Name)
	if err != nil {
		logrus.Fatalf("No such binary %q: %v", c.Command.Name, err)
	}
	binaryUseContext(&bin, c)

	if err := bin.Execute(c.Args()); err != nil {
		logrus.Fatalf("Failed to execute binary: %v", err)
	}
}

func binaryUseContext(bin *Binary, context *cli.Context) {
	if basedir := context.Parent().String("basedir"); basedir != "" {
		bin.BaseDir = basedir
	}
}

func ActionInstall(c *cli.Context) {
	for _, name := range AssetNames() {
		bin := NewBinary(name)
		binaryUseContext(&bin, c)

		if err := bin.Install(bin.FilePath()); err != nil {
			logrus.Fatalf("Failed to install binary: %v", err)
		}
	}
}
func ActionUninstall(c *cli.Context) {
	for _, name := range AssetNames() {
		bin := NewBinary(name)
		binaryUseContext(&bin, c)

		if err := bin.Uninstall(bin.FilePath()); err != nil {
			logrus.Fatalf("Failed to uninstall binary: %v", err)
		}
	}
}

func hookBefore(c *cli.Context) error {
	if c.Bool("debug") {
		os.Setenv("MB_DEBUG", "1")
	}
	initLogging()
	return nil
}

func initLogging() {
	if os.Getenv("MB_DEBUG") == "1" {
		logrus.SetLevel(logrus.DebugLevel)
	} else {
		logrus.SetLevel(logrus.WarnLevel)
	}
}

func main() {
	// Checking if file is a symlink to mister-bin or mister-bin itself
	fi, err := os.Lstat(os.Args[0])
	if err != nil {
		logrus.Fatalf("Failed to lstat %q: %v", os.Args[0], err)
	}

	// we are a symlink, direct execution
	if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
		initLogging()
		bin, err := GetBinaryByName(filepath.Base(os.Args[0]))
		if err != nil {
			logrus.Fatalf("No such binary %q: %v", filepath.Base(os.Args[0]), err)
		}

		if err := bin.Execute(os.Args[1:]); err != nil {
			logrus.Fatalf("Failed to execute binary: %v", err)
		}
		return
	}

	// we are not a symlink, standard menu
	app := cli.NewApp()
	app.Name = "Mister Bin"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:   "debug, D",
			EnvVar: "MB_DEBUG",
		},
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name: "basedir",
		},
	}

	app.Before = hookBefore

	app.Commands = []cli.Command{
		{
			Name:   "install",
			Action: ActionInstall,
		},
		{
			Name:   "uninstall",
			Action: ActionUninstall,
		},
	}

	for _, name := range AssetNames() {
		command := cli.Command{
			Name:   filepath.Base(name),
			Action: ActionExecute,
		}
		app.Commands = append(app.Commands, command)
	}

	app.Run(os.Args)
}
<commit_msg>Support symlink install<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"syscall"
	"unsafe"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
)

const mapMaxSize = 1e4

const (
	InstallBinary = iota
	InstallSymlink
)

type Binary struct {
	Asset         []byte
	Name          string
	BaseDir       string
	InstallMethod int
}

func NewBinary(name string) Binary {
	wd, err := os.Getwd()
	if err != nil {
		wd = "/"
	}
	return Binary{
		Name:          name,
		BaseDir:       wd,
		InstallMethod: InstallBinary,
	}
}

func (b *Binary) FullPathFileName() string {
	return strings.Replace(b.Name, "/", "_", -1)
}

func (b *Binary) FileName() string {
	return path.Base(b.Name)
}

func (b *Binary) FilePath() string {
	return filepath.Join(b.BaseDir, b.FileName())
}

func (b *Binary) TempPath() string {
	// FIXME: ensure using memory instead of disk if p ossible
	return filepath.Join(os.TempDir(), b.FileName())
}

func (b *Binary) Uninstall(filepath string) error {
	logrus.Infof("Uninstalling binary %q (%s)", b.Name, filepath)

	if _, err := os.Stat(filepath); os.IsNotExist(err) {
		logrus.Debugf("Asset %q not installed, nothing to do", filepath)
		return nil
	}

	return os.Remove(filepath)
}

func (b *Binary) Install(filepath string) error {
	switch b.InstallMethod {
	case InstallBinary:
		return b.InstallBinary(filepath)
	case InstallSymlink:
		return b.InstallSymlink(filepath)
	}
	return fmt.Errorf("Invalid install method")
}

func (b *Binary) InstallSymlink(installPath string) error {
	logrus.Infof("Installing symlink %q (%s)", b.Name, installPath)
	misterBinPath, err := filepath.Abs(os.Args[0])
	if err != nil {
		return err
	}
	return os.Symlink(misterBinPath, installPath)
}

func (b *Binary) InstallBinary(filepath string) error {
	logrus.Infof("Installing binary %q (%s)", b.Name, filepath)

	if _, err := os.Stat(filepath); !os.IsNotExist(err) {
		logrus.Debugf("Asset already installed: %q", filepath)
		return nil
	}

	asset, err := Asset(b.Name)
	if err != nil {
		return fmt.Errorf("failed to load the asset %q: %v", b.Name, err)
	}

	length := len(asset)
	size := int(unsafe.Sizeof(0)) * length
	if size > mapMaxSize*int(unsafe.Sizeof(0)) {
		return fmt.Errorf("file too big for current map size: %d > %d", size, mapMaxSize*int(unsafe.Sizeof(0)))
	}

	logrus.Debugf("Creating map file: %q", filepath)
	mapFile, err := os.Create(filepath)
	if err != nil {
		return fmt.Errorf("failed to create map file: %v", err)
	}

	logrus.Debugf("Seeking file")
	if _, err = mapFile.Seek(int64(length-1), 0); err != nil {
		return fmt.Errorf("failed to seek: %v", err)
	}

	logrus.Debugf("Writing to file")
	if _, err = mapFile.Write([]byte(" ")); err != nil {
		return fmt.Errorf("failed to write to file: %v", err)
	}

	logrus.Debugf("MMAPing")
	fd := int(mapFile.Fd())
	mmap, err := syscall.Mmap(fd, 0, size, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
	if err != nil {
		return fmt.Errorf("failed to mmap: %v", err)
	}

	logrus.Debugf("Filling array var")
	mapArray := (*[mapMaxSize]byte)(unsafe.Pointer(&mmap[0]))
	for i := 0; i < length; i++ {
		mapArray[i] = asset[i]
	}
	// fmt.Println(*mapArray)

	logrus.Debugf("MUNMAPing")
	if err = syscall.Munmap(mmap); err != nil {
		return fmt.Errorf("failed to munmap: %v", err)
	}

	logrus.Debugf("Closing")
	if err = mapFile.Close(); err != nil {
		return fmt.Errorf("failed to close: %v", err)
	}

	logrus.Debugf("Chmoding binary")
	if err = os.Chmod(filepath, 0777); err != nil {
		return fmt.Errorf("failed to chmod program: %v", err)
	}

	return nil
}

func (b *Binary) Execute(args []string) error {
	filepath := b.TempPath()
	logrus.Infof("Executing binary %q (%s)", b.Name, filepath)
	if len(args) > 0 {
		logrus.Infof("args=%v", args)
	}

	// temporary
	if err := b.Uninstall(filepath); err != nil {
		logrus.Debugf("Failed to uninstall temporary binary %q: %v", filepath, err)
	}

	if err := b.Install(filepath); err != nil {
		return err
	}
	// FIXME: delete early
	defer b.Uninstall(filepath)

	cmd := exec.Command(filepath, args...)
	cmd.Stdout = os.Stdout
	cmd.Stdin = os.Stdin
	cmd.Stderr = os.Stderr
	cmd.Start()

	return cmd.Wait()
}

func GetBinaryByName(name string) (*Binary, error) {
	for _, assetName := range AssetNames() {
		if name == assetName {
			bin := NewBinary(assetName)
			return &bin, nil
		}
	}
	for _, assetName := range AssetNames() {
		if name == filepath.Base(assetName) {
			bin := NewBinary(assetName)
			return &bin, nil
		}
	}
	return nil, fmt.Errorf("No match")
}

func ActionExecute(c *cli.Context) {
	bin, err := GetBinaryByName(c.Command.Name)
	if err != nil {
		logrus.Fatalf("No such binary %q: %v", c.Command.Name, err)
	}
	binaryUseContext(bin, c)

	if err := bin.Execute(c.Args()); err != nil {
		logrus.Fatalf("Failed to execute binary: %v", err)
	}
}

func binaryUseContext(bin *Binary, context *cli.Context) {
	if basedir := context.Parent().String("basedir"); basedir != "" {
		bin.BaseDir = basedir
	}
	if basedir := context.String("basedir"); basedir != "" {
		bin.BaseDir = basedir
	}
	if symlinks := context.Bool("symlinks"); symlinks {
		bin.InstallMethod = InstallSymlink
	}
}

func ActionInstall(c *cli.Context) {
	for _, name := range AssetNames() {
		bin := NewBinary(name)
		binaryUseContext(&bin, c)

		if err := bin.Install(bin.FilePath()); err != nil {
			logrus.Fatalf("Failed to install binary: %v", err)
		}
	}
}
func ActionUninstall(c *cli.Context) {
	for _, name := range AssetNames() {
		bin := NewBinary(name)
		binaryUseContext(&bin, c)

		if err := bin.Uninstall(bin.FilePath()); err != nil {
			logrus.Fatalf("Failed to uninstall binary: %v", err)
		}
	}
}

func hookBefore(c *cli.Context) error {
	if c.Bool("debug") {
		os.Setenv("MB_DEBUG", "1")
	}
	initLogging()
	return nil
}

func initLogging() {
	if os.Getenv("MB_DEBUG") == "1" {
		logrus.SetLevel(logrus.DebugLevel)
	} else {
		logrus.SetLevel(logrus.WarnLevel)
	}
}

func main() {
	// Checking if file is a symlink to mister-bin or mister-bin itself
	fi, err := os.Lstat(os.Args[0])
	if err != nil {
		logrus.Fatalf("Failed to lstat %q: %v", os.Args[0], err)
	}

	// we are a symlink, direct execution
	if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
		initLogging()
		bin, err := GetBinaryByName(filepath.Base(os.Args[0]))
		if err != nil {
			logrus.Fatalf("No such binary %q: %v", filepath.Base(os.Args[0]), err)
		}

		if err := bin.Execute(os.Args[1:]); err != nil {
			logrus.Fatalf("Failed to execute binary: %v", err)
		}
		return
	}

	// we are not a symlink, standard menu
	app := cli.NewApp()
	app.Name = "Mister Bin"

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name:   "debug, D",
			EnvVar: "MB_DEBUG",
		},
	}

	app.Before = hookBefore

	app.Commands = []cli.Command{
		{
			Name:   "install",
			Action: ActionInstall,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "basedir",
					Usage: "Base dir to install binaries to",
				},
				cli.BoolFlag{
					Name:  "symlinks",
					Usage: " Create symlinks instead of real binaries",
				},
			},
		},
		{
			Name:   "uninstall",
			Action: ActionUninstall,
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "basedir",
					Usage: "Base dir to uninstall binaries from",
				},
			},
		},
	}

	for _, name := range AssetNames() {
		command := cli.Command{
			Name:   filepath.Base(name),
			Action: ActionExecute,
		}
		app.Commands = append(app.Commands, command)
	}

	app.Run(os.Args)
}
<|endoftext|>


<commit_before>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package lang

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"testing"

	"github.com/getgauge/common"
	"github.com/getgauge/gauge/config"
	gm "github.com/getgauge/gauge/gauge_messages"
	"github.com/getgauge/gauge/runner"
	"github.com/getgauge/gauge/util"
	"github.com/sourcegraph/go-langserver/pkg/lsp"
	"github.com/sourcegraph/jsonrpc2"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

type mockLspClient struct {
	response interface{}
	err      error
}

func (r *mockLspClient) GetStepNames(ctx context.Context, in *gm.StepNamesRequest, opts ...grpc.CallOption) (*gm.StepNamesResponse, error) {
	return r.response.(*gm.StepNamesResponse), r.err
}
func (r *mockLspClient) CacheFile(ctx context.Context, in *gm.CacheFileRequest, opts ...grpc.CallOption) (*gm.Empty, error) {
	return r.response.(*gm.Empty), r.err
}
func (r *mockLspClient) GetStepPositions(ctx context.Context, in *gm.StepPositionsRequest, opts ...grpc.CallOption) (*gm.StepPositionsResponse, error) {
	return r.response.(*gm.StepPositionsResponse), r.err
}
func (r *mockLspClient) GetImplementationFiles(ctx context.Context, in *gm.Empty, opts ...grpc.CallOption) (*gm.ImplementationFileListResponse, error) {
	return r.response.(*gm.ImplementationFileListResponse), r.err
}
func (r *mockLspClient) ImplementStub(ctx context.Context, in *gm.StubImplementationCodeRequest, opts ...grpc.CallOption) (*gm.FileDiff, error) {
	return r.response.(*gm.FileDiff), r.err
}
func (r *mockLspClient) ValidateStep(ctx context.Context, in *gm.StepValidateRequest, opts ...grpc.CallOption) (*gm.StepValidateResponse, error) {
	return r.response.(*gm.StepValidateResponse), r.err
}
func (r *mockLspClient) Refactor(ctx context.Context, in *gm.RefactorRequest, opts ...grpc.CallOption) (*gm.RefactorResponse, error) {
	return r.response.(*gm.RefactorResponse), r.err
}
func (r *mockLspClient) GetStepName(ctx context.Context, in *gm.StepNameRequest, opts ...grpc.CallOption) (*gm.StepNameResponse, error) {
	return r.response.(*gm.StepNameResponse), r.err
}

func (r *mockLspClient) GetGlobPatterns(ctx context.Context, in *gm.Empty, opts ...grpc.CallOption) (*gm.ImplementationFileGlobPatternResponse, error) {
	return r.response.(*gm.ImplementationFileGlobPatternResponse), r.err
}

func (r *mockLspClient) KillProcess(ctx context.Context, in *gm.KillProcessRequest, opts ...grpc.CallOption) (*gm.Empty, error) {
	return nil, nil
}

func TestGetImplementationFilesShouldReturnFilePaths(t *testing.T) {

	var params = struct {
		Concept bool
	}{}

	b, _ := json.Marshal(params)
	p := json.RawMessage(b)

	response := &gm.ImplementationFileListResponse{
		ImplementationFilePaths: []string{"file"},
	}
	lRunner.runner = &runner.GrpcRunner{Client: &mockLspClient{response: response}, Timeout: time.Second * 30}
	implFiles, err := getImplFiles(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	want := []string{"file"}

	if !reflect.DeepEqual(implFiles, want) {
		t.Errorf("want: `%s`,\n got: `%s`", want, implFiles)
	}
}

func TestGetImplementationFilesShouldReturnEmptyArrayForNoImplementationFiles(t *testing.T) {
	var params = struct {
		Concept bool
	}{}

	b, _ := json.Marshal(params)
	p := json.RawMessage(b)
	response := &gm.ImplementationFileListResponse{
		ImplementationFilePaths: nil,
	}
	lRunner.runner = &runner.GrpcRunner{Client: &mockLspClient{response: response}, Timeout: time.Second * 30}

	implFiles, err := getImplFiles(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	want := []string{}

	if !reflect.DeepEqual(implFiles, want) {
		t.Errorf("want: `%s`,\n got: `%s`", want, implFiles)
	}
}

func TestGetImplementationFilesShouldReturnEmptyArrayForNoConceptFiles(t *testing.T) {
	type cptParam struct {
		Concept bool `json:"concept"`
	}

	params := cptParam{Concept: true}

	b, _ := json.Marshal(params)
	p := json.RawMessage(b)

	util.GetConceptFiles = func() []string {
		return nil
	}

	cptFiles, err := getImplFiles(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	want := []string{}

	if !reflect.DeepEqual(cptFiles, want) {
		t.Errorf("want: `%s`,\n got: `%s`", want, cptFiles)
	}
}

func TestGetImplementationFilesShouldReturnFilePathsForConcept(t *testing.T) {
	type implFileParam struct {
		Concept bool `json:"concept"`
	}

	params := implFileParam{Concept: true}

	b, _ := json.Marshal(params)
	p := json.RawMessage(b)

	util.GetConceptFiles = func() []string {
		return []string{"file.cpt"}
	}

	implFiles, err := getImplFiles(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	want := []string{"file.cpt"}

	if !reflect.DeepEqual(implFiles, want) {
		t.Errorf("want: `%s`,\n got: `%s`", want, implFiles)
	}
}

func TestPutStubImplementationShouldReturnFileDiff(t *testing.T) {
	type stubImpl struct {
		ImplementationFilePath string   `json:"implementationFilePath"`
		Codes                  []string `json:"codes"`
	}
	cwd, _ := os.Getwd()
	dummyFilePath := filepath.Join(filepath.Join(cwd, "_testdata"), "dummyFile.txt")
	stubImplParams := stubImpl{ImplementationFilePath: dummyFilePath, Codes: []string{"code"}}

	b, _ := json.Marshal(stubImplParams)
	p := json.RawMessage(b)
	response := &gm.FileDiff{
		FilePath: "file",
		TextDiffs: []*gm.TextDiff{
			{
				Span: &gm.Span{
					Start:     1,
					StartChar: 2,
					End:       3,
					EndChar:   4,
				},
				Content: "file content",
			},
		},
	}
	lRunner.runner = &runner.GrpcRunner{Client: &mockLspClient{response: response}, Timeout: time.Second * 30}

	stubImplResponse, err := putStubImpl(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	var want lsp.WorkspaceEdit
	want.Changes = make(map[string][]lsp.TextEdit, 0)
	uri := util.ConvertPathToURI("file")
	textEdit := lsp.TextEdit{
		NewText: "file content",
		Range: lsp.Range{
			Start: lsp.Position{Line: 1, Character: 2},
			End:   lsp.Position{Line: 3, Character: 4},
		},
	}
	want.Changes[string(uri)] = append(want.Changes[string(uri)], textEdit)

	if !reflect.DeepEqual(stubImplResponse, want) {
		t.Errorf("want: `%v`,\n got: `%v`", want, stubImplResponse)
	}
}

func TestGenerateConceptShouldReturnFileDiff(t *testing.T) {
	cwd, _ := os.Getwd()
	testData := filepath.Join(cwd, "_testdata")

	extractConcpetParam := concpetInfo{
		ConceptName: "# foo bar\n* ",
		ConceptFile: "New File",
		Dir:         testData,
	}
	b, _ := json.Marshal(extractConcpetParam)
	p := json.RawMessage(b)

	response, err := generateConcept(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	var want lsp.WorkspaceEdit
	want.Changes = make(map[string][]lsp.TextEdit, 0)
	uri := util.ConvertPathToURI(filepath.Join(testData, "concept1.cpt"))
	textEdit := lsp.TextEdit{
		NewText: "# foo bar\n* ",
		Range: lsp.Range{
			Start: lsp.Position{Line: 0, Character: 0},
			End:   lsp.Position{Line: 0, Character: 0},
		},
	}
	want.Changes[string(uri)] = append(want.Changes[string(uri)], textEdit)

	if !reflect.DeepEqual(want, response) {
		t.Errorf("want: `%v`,\n got: `%v`", want, response)
	}
}

func TestGenerateConceptWithParam(t *testing.T) {
	cwd, _ := os.Getwd()
	testData := filepath.Join(cwd, "_testdata")

	extractConcpetParam := concpetInfo{
		ConceptName: "# foo bar <some>\n* ",
		ConceptFile: "New File",
		Dir:         testData,
	}
	b, _ := json.Marshal(extractConcpetParam)
	p := json.RawMessage(b)

	response, err := generateConcept(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	var want lsp.WorkspaceEdit
	want.Changes = make(map[string][]lsp.TextEdit, 0)
	uri := util.ConvertPathToURI(filepath.Join(testData, "concept1.cpt"))
	textEdit := lsp.TextEdit{
		NewText: "# foo bar <some>\n* ",
		Range: lsp.Range{
			Start: lsp.Position{Line: 0, Character: 0},
			End:   lsp.Position{Line: 0, Character: 0},
		},
	}
	want.Changes[string(uri)] = append(want.Changes[string(uri)], textEdit)

	if !reflect.DeepEqual(want, response) {
		t.Errorf("want: `%v`,\n got: `%v`", want, response)
	}
}

func TestGenerateConceptInExisitingFile(t *testing.T) {
	cwd, _ := os.Getwd()
	testData := filepath.Join(cwd, "_testdata")
	cptFile := filepath.Join(testData, "some.cpt")

	extractConcpetParam := concpetInfo{
		ConceptName: "# foo bar <some>\n* ",
		ConceptFile: cptFile,
		Dir:         testData,
	}
	b, _ := json.Marshal(extractConcpetParam)
	p := json.RawMessage(b)

	response, err := generateConcept(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	var want lsp.WorkspaceEdit
	want.Changes = make(map[string][]lsp.TextEdit, 0)

	textEdit := lsp.TextEdit{
		NewText: "# concept heading\n* with a step\n\n# foo bar <some>\n* ",
		Range: lsp.Range{
			Start: lsp.Position{Line: 0, Character: 0},
			End:   lsp.Position{Line: 2, Character: 0},
		},
	}
	uri := string(util.ConvertPathToURI(cptFile))

	want.Changes[uri] = append(want.Changes[uri], textEdit)

	if !reflect.DeepEqual(want, response) {
		t.Errorf("want: `%v`,\n got: `%v`", want, response)
	}
}

func TestGenerateConceptInNewFileWhenDefaultExisits(t *testing.T) {
	cwd, _ := os.Getwd()
	testData := filepath.Join(cwd, "_testdata")

	cptFile := filepath.Join(testData, "concept1.cpt")
	ioutil.WriteFile(cptFile, []byte(""), common.NewFilePermissions)
	defer common.Remove(cptFile)

	extractConcpetParam := concpetInfo{
		ConceptName: "# foo bar <some>\n* ",
		ConceptFile: "New File",
		Dir:         testData,
	}
	b, _ := json.Marshal(extractConcpetParam)
	p := json.RawMessage(b)

	response, err := generateConcept(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	uri := util.ConvertPathToURI(filepath.Join(testData, "concept2.cpt"))

	var want lsp.WorkspaceEdit
	want.Changes = make(map[string][]lsp.TextEdit, 0)

	textEdit := lsp.TextEdit{
		NewText: "# foo bar <some>\n* ",
		Range: lsp.Range{
			Start: lsp.Position{Line: 0, Character: 0},
			End:   lsp.Position{Line: 0, Character: 0},
		},
	}
	want.Changes[string(uri)] = append(want.Changes[string(uri)], textEdit)

	if !reflect.DeepEqual(want, response) {
		t.Errorf("want: `%v`,\n got: `%v`", want, response)
	}
}
<commit_msg>fixed compile errors<commit_after>// Copyright 2015 ThoughtWorks, Inc.

// This file is part of Gauge.

// Gauge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Gauge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Gauge.  If not, see <http://www.gnu.org/licenses/>.

package lang

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"testing"
	"time"

	"github.com/getgauge/common"
	gm "github.com/getgauge/gauge/gauge_messages"
	"github.com/getgauge/gauge/runner"
	"github.com/getgauge/gauge/util"
	"github.com/sourcegraph/go-langserver/pkg/lsp"
	"github.com/sourcegraph/jsonrpc2"
	"golang.org/x/net/context"
	"google.golang.org/grpc"
)

type mockLspClient struct {
	response interface{}
	err      error
}

func (r *mockLspClient) GetStepNames(ctx context.Context, in *gm.StepNamesRequest, opts ...grpc.CallOption) (*gm.StepNamesResponse, error) {
	return r.response.(*gm.StepNamesResponse), r.err
}
func (r *mockLspClient) CacheFile(ctx context.Context, in *gm.CacheFileRequest, opts ...grpc.CallOption) (*gm.Empty, error) {
	return r.response.(*gm.Empty), r.err
}
func (r *mockLspClient) GetStepPositions(ctx context.Context, in *gm.StepPositionsRequest, opts ...grpc.CallOption) (*gm.StepPositionsResponse, error) {
	return r.response.(*gm.StepPositionsResponse), r.err
}
func (r *mockLspClient) GetImplementationFiles(ctx context.Context, in *gm.Empty, opts ...grpc.CallOption) (*gm.ImplementationFileListResponse, error) {
	return r.response.(*gm.ImplementationFileListResponse), r.err
}
func (r *mockLspClient) ImplementStub(ctx context.Context, in *gm.StubImplementationCodeRequest, opts ...grpc.CallOption) (*gm.FileDiff, error) {
	return r.response.(*gm.FileDiff), r.err
}
func (r *mockLspClient) ValidateStep(ctx context.Context, in *gm.StepValidateRequest, opts ...grpc.CallOption) (*gm.StepValidateResponse, error) {
	return r.response.(*gm.StepValidateResponse), r.err
}
func (r *mockLspClient) Refactor(ctx context.Context, in *gm.RefactorRequest, opts ...grpc.CallOption) (*gm.RefactorResponse, error) {
	return r.response.(*gm.RefactorResponse), r.err
}
func (r *mockLspClient) GetStepName(ctx context.Context, in *gm.StepNameRequest, opts ...grpc.CallOption) (*gm.StepNameResponse, error) {
	return r.response.(*gm.StepNameResponse), r.err
}

func (r *mockLspClient) GetGlobPatterns(ctx context.Context, in *gm.Empty, opts ...grpc.CallOption) (*gm.ImplementationFileGlobPatternResponse, error) {
	return r.response.(*gm.ImplementationFileGlobPatternResponse), r.err
}

func (r *mockLspClient) KillProcess(ctx context.Context, in *gm.KillProcessRequest, opts ...grpc.CallOption) (*gm.Empty, error) {
	return nil, nil
}

func TestGetImplementationFilesShouldReturnFilePaths(t *testing.T) {

	var params = struct {
		Concept bool
	}{}

	b, _ := json.Marshal(params)
	p := json.RawMessage(b)

	response := &gm.ImplementationFileListResponse{
		ImplementationFilePaths: []string{"file"},
	}
	lRunner.runner = &runner.GrpcRunner{Client: &mockLspClient{response: response}, Timeout: time.Second * 30}
	implFiles, err := getImplFiles(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	want := []string{"file"}

	if !reflect.DeepEqual(implFiles, want) {
		t.Errorf("want: `%s`,\n got: `%s`", want, implFiles)
	}
}

func TestGetImplementationFilesShouldReturnEmptyArrayForNoImplementationFiles(t *testing.T) {
	var params = struct {
		Concept bool
	}{}

	b, _ := json.Marshal(params)
	p := json.RawMessage(b)
	response := &gm.ImplementationFileListResponse{
		ImplementationFilePaths: nil,
	}
	lRunner.runner = &runner.GrpcRunner{Client: &mockLspClient{response: response}, Timeout: time.Second * 30}

	implFiles, err := getImplFiles(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	want := []string{}

	if !reflect.DeepEqual(implFiles, want) {
		t.Errorf("want: `%s`,\n got: `%s`", want, implFiles)
	}
}

func TestGetImplementationFilesShouldReturnEmptyArrayForNoConceptFiles(t *testing.T) {
	type cptParam struct {
		Concept bool `json:"concept"`
	}

	params := cptParam{Concept: true}

	b, _ := json.Marshal(params)
	p := json.RawMessage(b)

	util.GetConceptFiles = func() []string {
		return nil
	}

	cptFiles, err := getImplFiles(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	want := []string{}

	if !reflect.DeepEqual(cptFiles, want) {
		t.Errorf("want: `%s`,\n got: `%s`", want, cptFiles)
	}
}

func TestGetImplementationFilesShouldReturnFilePathsForConcept(t *testing.T) {
	type implFileParam struct {
		Concept bool `json:"concept"`
	}

	params := implFileParam{Concept: true}

	b, _ := json.Marshal(params)
	p := json.RawMessage(b)

	util.GetConceptFiles = func() []string {
		return []string{"file.cpt"}
	}

	implFiles, err := getImplFiles(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	want := []string{"file.cpt"}

	if !reflect.DeepEqual(implFiles, want) {
		t.Errorf("want: `%s`,\n got: `%s`", want, implFiles)
	}
}

func TestPutStubImplementationShouldReturnFileDiff(t *testing.T) {
	type stubImpl struct {
		ImplementationFilePath string   `json:"implementationFilePath"`
		Codes                  []string `json:"codes"`
	}
	cwd, _ := os.Getwd()
	dummyFilePath := filepath.Join(filepath.Join(cwd, "_testdata"), "dummyFile.txt")
	stubImplParams := stubImpl{ImplementationFilePath: dummyFilePath, Codes: []string{"code"}}

	b, _ := json.Marshal(stubImplParams)
	p := json.RawMessage(b)
	response := &gm.FileDiff{
		FilePath: "file",
		TextDiffs: []*gm.TextDiff{
			{
				Span: &gm.Span{
					Start:     1,
					StartChar: 2,
					End:       3,
					EndChar:   4,
				},
				Content: "file content",
			},
		},
	}
	lRunner.runner = &runner.GrpcRunner{Client: &mockLspClient{response: response}, Timeout: time.Second * 30}

	stubImplResponse, err := putStubImpl(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	var want lsp.WorkspaceEdit
	want.Changes = make(map[string][]lsp.TextEdit, 0)
	uri := util.ConvertPathToURI("file")
	textEdit := lsp.TextEdit{
		NewText: "file content",
		Range: lsp.Range{
			Start: lsp.Position{Line: 1, Character: 2},
			End:   lsp.Position{Line: 3, Character: 4},
		},
	}
	want.Changes[string(uri)] = append(want.Changes[string(uri)], textEdit)

	if !reflect.DeepEqual(stubImplResponse, want) {
		t.Errorf("want: `%v`,\n got: `%v`", want, stubImplResponse)
	}
}

func TestGenerateConceptShouldReturnFileDiff(t *testing.T) {
	cwd, _ := os.Getwd()
	testData := filepath.Join(cwd, "_testdata")

	extractConcpetParam := concpetInfo{
		ConceptName: "# foo bar\n* ",
		ConceptFile: "New File",
		Dir:         testData,
	}
	b, _ := json.Marshal(extractConcpetParam)
	p := json.RawMessage(b)

	response, err := generateConcept(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	var want lsp.WorkspaceEdit
	want.Changes = make(map[string][]lsp.TextEdit, 0)
	uri := util.ConvertPathToURI(filepath.Join(testData, "concept1.cpt"))
	textEdit := lsp.TextEdit{
		NewText: "# foo bar\n* ",
		Range: lsp.Range{
			Start: lsp.Position{Line: 0, Character: 0},
			End:   lsp.Position{Line: 0, Character: 0},
		},
	}
	want.Changes[string(uri)] = append(want.Changes[string(uri)], textEdit)

	if !reflect.DeepEqual(want, response) {
		t.Errorf("want: `%v`,\n got: `%v`", want, response)
	}
}

func TestGenerateConceptWithParam(t *testing.T) {
	cwd, _ := os.Getwd()
	testData := filepath.Join(cwd, "_testdata")

	extractConcpetParam := concpetInfo{
		ConceptName: "# foo bar <some>\n* ",
		ConceptFile: "New File",
		Dir:         testData,
	}
	b, _ := json.Marshal(extractConcpetParam)
	p := json.RawMessage(b)

	response, err := generateConcept(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	var want lsp.WorkspaceEdit
	want.Changes = make(map[string][]lsp.TextEdit, 0)
	uri := util.ConvertPathToURI(filepath.Join(testData, "concept1.cpt"))
	textEdit := lsp.TextEdit{
		NewText: "# foo bar <some>\n* ",
		Range: lsp.Range{
			Start: lsp.Position{Line: 0, Character: 0},
			End:   lsp.Position{Line: 0, Character: 0},
		},
	}
	want.Changes[string(uri)] = append(want.Changes[string(uri)], textEdit)

	if !reflect.DeepEqual(want, response) {
		t.Errorf("want: `%v`,\n got: `%v`", want, response)
	}
}

func TestGenerateConceptInExisitingFile(t *testing.T) {
	cwd, _ := os.Getwd()
	testData := filepath.Join(cwd, "_testdata")
	cptFile := filepath.Join(testData, "some.cpt")

	extractConcpetParam := concpetInfo{
		ConceptName: "# foo bar <some>\n* ",
		ConceptFile: cptFile,
		Dir:         testData,
	}
	b, _ := json.Marshal(extractConcpetParam)
	p := json.RawMessage(b)

	response, err := generateConcept(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	var want lsp.WorkspaceEdit
	want.Changes = make(map[string][]lsp.TextEdit, 0)

	textEdit := lsp.TextEdit{
		NewText: "# concept heading\n* with a step\n\n# foo bar <some>\n* ",
		Range: lsp.Range{
			Start: lsp.Position{Line: 0, Character: 0},
			End:   lsp.Position{Line: 2, Character: 0},
		},
	}
	uri := string(util.ConvertPathToURI(cptFile))

	want.Changes[uri] = append(want.Changes[uri], textEdit)

	if !reflect.DeepEqual(want, response) {
		t.Errorf("want: `%v`,\n got: `%v`", want, response)
	}
}

func TestGenerateConceptInNewFileWhenDefaultExisits(t *testing.T) {
	cwd, _ := os.Getwd()
	testData := filepath.Join(cwd, "_testdata")

	cptFile := filepath.Join(testData, "concept1.cpt")
	ioutil.WriteFile(cptFile, []byte(""), common.NewFilePermissions)
	defer common.Remove(cptFile)

	extractConcpetParam := concpetInfo{
		ConceptName: "# foo bar <some>\n* ",
		ConceptFile: "New File",
		Dir:         testData,
	}
	b, _ := json.Marshal(extractConcpetParam)
	p := json.RawMessage(b)

	response, err := generateConcept(&jsonrpc2.Request{Params: &p})

	if err != nil {
		t.Fatalf("Got error %s", err.Error())
	}

	uri := util.ConvertPathToURI(filepath.Join(testData, "concept2.cpt"))

	var want lsp.WorkspaceEdit
	want.Changes = make(map[string][]lsp.TextEdit, 0)

	textEdit := lsp.TextEdit{
		NewText: "# foo bar <some>\n* ",
		Range: lsp.Range{
			Start: lsp.Position{Line: 0, Character: 0},
			End:   lsp.Position{Line: 0, Character: 0},
		},
	}
	want.Changes[string(uri)] = append(want.Changes[string(uri)], textEdit)

	if !reflect.DeepEqual(want, response) {
		t.Errorf("want: `%v`,\n got: `%v`", want, response)
	}
}
<|endoftext|>


<commit_before>package container

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/server/httputils"
	"github.com/docker/docker/pkg/stdcopy"
	"github.com/docker/engine-api/types"
	"golang.org/x/net/context"
)

func (s *containerRouter) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	eConfig, err := s.backend.ContainerExecInspect(vars["id"])
	if err != nil {
		return err
	}

	return httputils.WriteJSON(w, http.StatusOK, eConfig)
}

func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := httputils.ParseForm(r); err != nil {
		return err
	}
	if err := httputils.CheckForJSON(r); err != nil {
		return err
	}
	name := vars["name"]

	execConfig := &types.ExecConfig{}
	if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil {
		return err
	}
	execConfig.Container = name

	if len(execConfig.Cmd) == 0 {
		return fmt.Errorf("No exec command specified")
	}

	// Register an instance of Exec in container.
	id, err := s.backend.ContainerExecCreate(execConfig)
	if err != nil {
		logrus.Errorf("Error setting up exec command in container %s: %v", name, err)
		return err
	}

	return httputils.WriteJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{
		ID: id,
	})
}

// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := httputils.ParseForm(r); err != nil {
		return err
	}

	version := httputils.VersionFromContext(ctx)
	if version.GreaterThan("1.21") {
		if err := httputils.CheckForJSON(r); err != nil {
			return err
		}
	}

	var (
		execName                  = vars["name"]
		stdin, inStream           io.ReadCloser
		stdout, stderr, outStream io.Writer
	)

	execStartCheck := &types.ExecStartCheck{}
	if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil {
		return err
	}

	if exists, err := s.backend.ExecExists(execName); !exists {
		return err
	}

	if !execStartCheck.Detach {
		var err error
		// Setting up the streaming http interface.
		inStream, outStream, err = httputils.HijackConnection(w)
		if err != nil {
			return err
		}
		defer httputils.CloseStreams(inStream, outStream)

		if _, ok := r.Header["Upgrade"]; ok {
			fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
		} else {
			fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
		}

		stdin = inStream
		stdout = outStream
		if !execStartCheck.Tty {
			stderr = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
			stdout = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
		}
	}

	// Now run the user process in container.
	if err := s.backend.ContainerExecStart(execName, stdin, stdout, stderr); err != nil {
		if execStartCheck.Detach {
			return err
		}
		stdout.Write([]byte(err.Error()))
		logrus.Errorf("Error running exec in container: %v\n", err)
		return err
	}
	return nil
}

func (s *containerRouter) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := httputils.ParseForm(r); err != nil {
		return err
	}
	height, err := strconv.Atoi(r.Form.Get("h"))
	if err != nil {
		return err
	}
	width, err := strconv.Atoi(r.Form.Get("w"))
	if err != nil {
		return err
	}

	return s.backend.ContainerExecResize(vars["name"], height, width)
}
<commit_msg>Do not return error on hijacked connection for docker exec<commit_after>package container

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strconv"

	"github.com/Sirupsen/logrus"
	"github.com/docker/docker/api/server/httputils"
	"github.com/docker/docker/pkg/stdcopy"
	"github.com/docker/engine-api/types"
	"golang.org/x/net/context"
)

func (s *containerRouter) getExecByID(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	eConfig, err := s.backend.ContainerExecInspect(vars["id"])
	if err != nil {
		return err
	}

	return httputils.WriteJSON(w, http.StatusOK, eConfig)
}

func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := httputils.ParseForm(r); err != nil {
		return err
	}
	if err := httputils.CheckForJSON(r); err != nil {
		return err
	}
	name := vars["name"]

	execConfig := &types.ExecConfig{}
	if err := json.NewDecoder(r.Body).Decode(execConfig); err != nil {
		return err
	}
	execConfig.Container = name

	if len(execConfig.Cmd) == 0 {
		return fmt.Errorf("No exec command specified")
	}

	// Register an instance of Exec in container.
	id, err := s.backend.ContainerExecCreate(execConfig)
	if err != nil {
		logrus.Errorf("Error setting up exec command in container %s: %v", name, err)
		return err
	}

	return httputils.WriteJSON(w, http.StatusCreated, &types.ContainerExecCreateResponse{
		ID: id,
	})
}

// TODO(vishh): Refactor the code to avoid having to specify stream config as part of both create and start.
func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := httputils.ParseForm(r); err != nil {
		return err
	}

	version := httputils.VersionFromContext(ctx)
	if version.GreaterThan("1.21") {
		if err := httputils.CheckForJSON(r); err != nil {
			return err
		}
	}

	var (
		execName                  = vars["name"]
		stdin, inStream           io.ReadCloser
		stdout, stderr, outStream io.Writer
	)

	execStartCheck := &types.ExecStartCheck{}
	if err := json.NewDecoder(r.Body).Decode(execStartCheck); err != nil {
		return err
	}

	if exists, err := s.backend.ExecExists(execName); !exists {
		return err
	}

	if !execStartCheck.Detach {
		var err error
		// Setting up the streaming http interface.
		inStream, outStream, err = httputils.HijackConnection(w)
		if err != nil {
			return err
		}
		defer httputils.CloseStreams(inStream, outStream)

		if _, ok := r.Header["Upgrade"]; ok {
			fmt.Fprintf(outStream, "HTTP/1.1 101 UPGRADED\r\nContent-Type: application/vnd.docker.raw-stream\r\nConnection: Upgrade\r\nUpgrade: tcp\r\n\r\n")
		} else {
			fmt.Fprintf(outStream, "HTTP/1.1 200 OK\r\nContent-Type: application/vnd.docker.raw-stream\r\n\r\n")
		}

		stdin = inStream
		stdout = outStream
		if !execStartCheck.Tty {
			stderr = stdcopy.NewStdWriter(outStream, stdcopy.Stderr)
			stdout = stdcopy.NewStdWriter(outStream, stdcopy.Stdout)
		}
	}

	// Now run the user process in container.
	if err := s.backend.ContainerExecStart(execName, stdin, stdout, stderr); err != nil {
		if execStartCheck.Detach {
			return err
		}
		stdout.Write([]byte(err.Error()))
		logrus.Errorf("Error running exec in container: %v\n", err)
	}
	return nil
}

func (s *containerRouter) postContainerExecResize(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
	if err := httputils.ParseForm(r); err != nil {
		return err
	}
	height, err := strconv.Atoi(r.Form.Get("h"))
	if err != nil {
		return err
	}
	width, err := strconv.Atoi(r.Form.Get("w"))
	if err != nil {
		return err
	}

	return s.backend.ContainerExecResize(vars["name"], height, width)
}
<|endoftext|>


<commit_before>package rollbar

import (
	"bytes"
	"encoding/json"
	"fmt"
	"hash/adler32"
	"io"
	"net/http"
	"net/url"
	"os"
	"reflect"
	"regexp"
	"runtime"
	"strings"
	"sync"
	"time"
)

const (
	// NAME is the name of this notifier library as reported to the Rollbar API.
	NAME = "go-rollbar"

	// VERSION is the version number of this notifier library as reported to the
	// Rollbar API.
	VERSION = "0.4.0"

	// CRIT is the critical Rollbar severity level as reported to the Rollbar
	// API.
	CRIT = "critical"

	// ERR is the error Rollbar severity level as reported to the Rollbar API.
	ERR = "error"

	// WARN is the warning Rollbar severity level as reported to the Rollbar API.
	WARN = "warning"

	// INFO is the info Rollbar severity level as reported to the Rollbar API.
	INFO = "info"

	// DEBUG is the debug Rollbar severity level as reported to the Rollbar API.
	DEBUG = "debug"

	// FILTERED is the text that replaces all sensitive values in items sent to
	// the Rollbar API.
	FILTERED = "[FILTERED]"
)

var (
	// Token is the Rollbar access token under which all items will be reported.
	// If Token is blank, no errors will be reported to Rollbar.
	Token = ""

	// Environment is the environment under which all items will be reported.
	Environment = "development"

	// Platform is the platform reported for all Rollbar items. The default is
	// the running operating system (darwin, freebsd, linux, etc.) but it can
	// also be application specific (client, heroku, etc.).
	Platform = runtime.GOOS

	// Endpoint is the URL destination for all Rollbar item POST requests.
	Endpoint = "https://api.rollbar.com/api/1/item/"

	// Buffer is the maximum number of errors that will be queued for sending.
	// When the buffer is full, new errors are dropped on the floor until the API
	// can catch up.
	Buffer = 1000

	// FilterFields is a regular expression that matches field names that should
	// not be sent to Rollbar. Values for these fields are replaced with
	// "[FILTERED]".
	FilterFields = regexp.MustCompile("password|secret|token")

	// ErrorWriter is the destination for errors encountered while POSTing items
	// to Rollbar. By default, this is stderr. This can be nil.
	ErrorWriter io.Writer = os.Stderr

	// CodeVersion is the optional code version reported to the Rollbar API for
	// all items.
	CodeVersion = ""

	bodyChannel chan map[string]interface{}
	waitGroup   sync.WaitGroup
	postErrors  chan error
	nilErrTitle = "<nil>"
)

// Field is a custom data field used to report arbitrary data to the Rollbar
// API.
type Field struct {
	Name string
	Data interface{}
}

// -- Setup

func init() {
	bodyChannel = make(chan map[string]interface{}, Buffer)
	postErrors = make(chan error, Buffer)

	go func() {
		var err error
		for body := range bodyChannel {
			err = post(body)
			if err != nil {
				if len(postErrors) == cap(postErrors) {
					<-postErrors
				}
				postErrors <- err
			}
			waitGroup.Done()
		}
		close(postErrors)
	}()
}

// -- Error reporting

func Errorf(level string, format string, args ...interface{}) {
	ErrorWithStackSkip(level, fmt.Errorf(format, args...), 1)
}

// Error asynchronously sends an error to Rollbar with the given severity
// level. You can pass, optionally, custom Fields to be passed on to Rollbar.
func Error(level string, err error, fields ...*Field) {
	ErrorWithStackSkip(level, err, 1, fields...)
}

// ErrorWithStackSkip asynchronously sends an error to Rollbar with the given
// severity level and a given number of stack trace frames skipped. You can
// pass, optionally, custom Fields to be passed on to Rollbar.
func ErrorWithStackSkip(level string, err error, skip int, fields ...*Field) {
	stack := BuildStack(2 + skip)
	ErrorWithStack(level, err, stack, fields...)
}

// ErrorWithStack asynchronously sends and error to Rollbar with the given
// stacktrace and (optionally) custom Fields to be passed on to Rollbar.
func ErrorWithStack(level string, err error, stack Stack, fields ...*Field) {
	buildAndPushError(level, err, stack, fields...)
}

// RequestError asynchronously sends an error to Rollbar with the given
// severity level and request-specific information. You can pass, optionally,
// custom Fields to be passed on to Rollbar.
func RequestError(level string, r *http.Request, err error, fields ...*Field) {
	RequestErrorWithStackSkip(level, r, err, 1, fields...)
}

// RequestErrorWithStackSkip asynchronously sends an error to Rollbar with the
// given severity level and a given number of stack trace frames skipped, in
// addition to extra request-specific information. You can pass, optionally,
// custom Fields to be passed on to Rollbar.
func RequestErrorWithStackSkip(level string, r *http.Request, err error, skip int, fields ...*Field) {
	stack := BuildStack(2 + skip)
	RequestErrorWithStack(level, r, err, stack, fields...)
}

// RequestErrorWithStack asynchronously sends an error to Rollbar with the
// given severity level, request-specific information provided by the given
// http.Request, and a custom Stack. You You can pass, optionally, custom
// Fields to be passed on to Rollbar.
func RequestErrorWithStack(level string, r *http.Request, err error, stack Stack, fields ...*Field) {
	buildAndPushError(level, err, stack, append(fields, &Field{Name: "request", Data: errorRequest(r)})...)
}

func buildError(level string, err error, stack Stack, fields ...*Field) map[string]interface{} {
	title := nilErrTitle
	if err != nil {
		title = err.Error()
	}

	body := buildBody(level, title)
	data := body["data"].(map[string]interface{})
	errBody := errorBody(err, stack)
	data["body"] = errBody

	for _, field := range fields {
		data[field.Name] = field.Data
	}

	return body
}

func buildAndPushError(level string, err error, stack Stack, fields ...*Field) {
	push(buildError(level, err, stack, fields...))
}

// -- Message reporting

// Message asynchronously sends a message to Rollbar with the given severity
// level.
func Message(level string, msg string) {
	body := buildBody(level, msg)
	data := body["data"].(map[string]interface{})
	data["body"] = messageBody(msg)

	push(body)
}

// -- Misc.

// PostErrors returns a channel that receives all errors encountered while
// POSTing items to the Rollbar API.
func PostErrors() <-chan error {
	return postErrors
}

// Wait will block until the queue of errors / messages is empty. This allows
// you to ensure that errors / messages are sent to Rollbar before exiting an
// application.
func Wait() {
	waitGroup.Wait()
}

// Build the main JSON structure that will be sent to Rollbar with the
// appropriate metadata.
func buildBody(level, title string) map[string]interface{} {
	timestamp := time.Now().Unix()
	hostname, _ := os.Hostname()

	data := map[string]interface{}{
		"environment": Environment,
		"title":       title,
		"level":       level,
		"timestamp":   timestamp,
		"platform":    Platform,
		"language":    "go",
		"server": map[string]interface{}{
			"host": hostname,
		},
		"notifier": map[string]interface{}{
			"name":    NAME,
			"version": VERSION,
		},
	}
	if CodeVersion != "" {
		data["code_version"] = CodeVersion
	}

	return map[string]interface{}{
		"access_token": Token,
		"data":         data,
	}
}

// errorBody generates a Rollbar error body with a given stack trace.
func errorBody(err error, stack Stack) map[string]interface{} {
	message := nilErrTitle
	if err != nil {
		message = err.Error()
	}

	errBody := map[string]interface{}{
		"trace": map[string]interface{}{
			"frames": stack,
			"exception": map[string]interface{}{
				"class":   errorClass(err),
				"message": message,
			},
		},
	}
	return errBody
}

// errorRequest extracts details from a Request in a format that Rollbar
// accepts.
func errorRequest(r *http.Request) map[string]interface{} {
	cleanQuery := filterParams(r.URL.Query())

	return map[string]interface{}{
		"url":     r.URL.String(),
		"method":  r.Method,
		"headers": flattenValues(r.Header),

		// GET params
		"query_string": url.Values(cleanQuery).Encode(),
		"GET":          flattenValues(cleanQuery),

		// POST / PUT params
		"POST":    flattenValues(filterParams(r.Form)),
		"user_ip": r.RemoteAddr,
	}
}

// filterParams filters sensitive information like passwords from being sent to
// Rollbar.
func filterParams(values map[string][]string) map[string][]string {
	for key := range values {
		if FilterFields.Match([]byte(key)) {
			values[key] = []string{FILTERED}
		}
	}

	return values
}

func flattenValues(values map[string][]string) map[string]interface{} {
	result := make(map[string]interface{})

	for k, v := range values {
		if len(v) == 1 {
			result[k] = v[0]
		} else {
			result[k] = v
		}
	}

	return result
}

// Build a message inner-body for the given message string.
func messageBody(s string) map[string]interface{} {
	return map[string]interface{}{
		"message": map[string]interface{}{
			"body": s,
		},
	}
}

func errorClass(err error) string {
	if err == nil {
		return nilErrTitle
	}

	class := reflect.TypeOf(err).String()
	if class == "" {
		return "panic"
	} else if class == "*errors.errorString" {
		checksum := adler32.Checksum([]byte(err.Error()))
		return fmt.Sprintf("{%x}", checksum)
	} else {
		return strings.TrimPrefix(class, "*")
	}
}

// -- POST handling

// Queue the given JSON body to be POSTed to Rollbar.
func push(body map[string]interface{}) {
	if len(bodyChannel) < Buffer {
		waitGroup.Add(1)
		bodyChannel <- body
	} else {
		stderr("buffer full, dropping error on the floor")
	}
}

// POST the given JSON body to Rollbar synchronously.
func post(body map[string]interface{}) error {
	if len(Token) == 0 {
		stderr("empty token")
		return nil
	}

	jsonBody, err := json.Marshal(body)
	if err != nil {
		stderr("failed to encode payload: %s", err.Error())
		return err
	}

	resp, err := http.Post(Endpoint, "application/json", bytes.NewReader(jsonBody))
	if err != nil {
		stderr("POST failed: %s", err.Error())
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		stderr("received response: %s", resp.Status)
		return ErrHTTPError(resp.StatusCode)
	}

	return nil
}

// -- stderr
func stderr(format string, args ...interface{}) {
	if ErrorWriter != nil {
		format = "Rollbar error: " + format + "\n"
		fmt.Fprintf(ErrorWriter, format, args...)
	}
}
<commit_msg>Documented Errorf<commit_after>package rollbar

import (
	"bytes"
	"encoding/json"
	"fmt"
	"hash/adler32"
	"io"
	"net/http"
	"net/url"
	"os"
	"reflect"
	"regexp"
	"runtime"
	"strings"
	"sync"
	"time"
)

const (
	// NAME is the name of this notifier library as reported to the Rollbar API.
	NAME = "go-rollbar"

	// VERSION is the version number of this notifier library as reported to the
	// Rollbar API.
	VERSION = "0.4.0"

	// CRIT is the critical Rollbar severity level as reported to the Rollbar
	// API.
	CRIT = "critical"

	// ERR is the error Rollbar severity level as reported to the Rollbar API.
	ERR = "error"

	// WARN is the warning Rollbar severity level as reported to the Rollbar API.
	WARN = "warning"

	// INFO is the info Rollbar severity level as reported to the Rollbar API.
	INFO = "info"

	// DEBUG is the debug Rollbar severity level as reported to the Rollbar API.
	DEBUG = "debug"

	// FILTERED is the text that replaces all sensitive values in items sent to
	// the Rollbar API.
	FILTERED = "[FILTERED]"
)

var (
	// Token is the Rollbar access token under which all items will be reported.
	// If Token is blank, no errors will be reported to Rollbar.
	Token = ""

	// Environment is the environment under which all items will be reported.
	Environment = "development"

	// Platform is the platform reported for all Rollbar items. The default is
	// the running operating system (darwin, freebsd, linux, etc.) but it can
	// also be application specific (client, heroku, etc.).
	Platform = runtime.GOOS

	// Endpoint is the URL destination for all Rollbar item POST requests.
	Endpoint = "https://api.rollbar.com/api/1/item/"

	// Buffer is the maximum number of errors that will be queued for sending.
	// When the buffer is full, new errors are dropped on the floor until the API
	// can catch up.
	Buffer = 1000

	// FilterFields is a regular expression that matches field names that should
	// not be sent to Rollbar. Values for these fields are replaced with
	// "[FILTERED]".
	FilterFields = regexp.MustCompile("password|secret|token")

	// ErrorWriter is the destination for errors encountered while POSTing items
	// to Rollbar. By default, this is stderr. This can be nil.
	ErrorWriter io.Writer = os.Stderr

	// CodeVersion is the optional code version reported to the Rollbar API for
	// all items.
	CodeVersion = ""

	bodyChannel chan map[string]interface{}
	waitGroup   sync.WaitGroup
	postErrors  chan error
	nilErrTitle = "<nil>"
)

// Field is a custom data field used to report arbitrary data to the Rollbar
// API.
type Field struct {
	Name string
	Data interface{}
}

// -- Setup

func init() {
	bodyChannel = make(chan map[string]interface{}, Buffer)
	postErrors = make(chan error, Buffer)

	go func() {
		var err error
		for body := range bodyChannel {
			err = post(body)
			if err != nil {
				if len(postErrors) == cap(postErrors) {
					<-postErrors
				}
				postErrors <- err
			}
			waitGroup.Done()
		}
		close(postErrors)
	}()
}

// -- Error reporting

// Errorf asynchronously sends an error to Rollbar with the given severity
// level. You can pass, optionally, a format specifier that the error message
// will be formatted according to.
func Errorf(level string, format string, args ...interface{}) {
	ErrorWithStackSkip(level, fmt.Errorf(format, args...), 1)
}

// Error asynchronously sends an error to Rollbar with the given severity
// level. You can pass, optionally, custom Fields to be passed on to Rollbar.
func Error(level string, err error, fields ...*Field) {
	ErrorWithStackSkip(level, err, 1, fields...)
}

// ErrorWithStackSkip asynchronously sends an error to Rollbar with the given
// severity level and a given number of stack trace frames skipped. You can
// pass, optionally, custom Fields to be passed on to Rollbar.
func ErrorWithStackSkip(level string, err error, skip int, fields ...*Field) {
	stack := BuildStack(2 + skip)
	ErrorWithStack(level, err, stack, fields...)
}

// ErrorWithStack asynchronously sends and error to Rollbar with the given
// stacktrace and (optionally) custom Fields to be passed on to Rollbar.
func ErrorWithStack(level string, err error, stack Stack, fields ...*Field) {
	buildAndPushError(level, err, stack, fields...)
}

// RequestError asynchronously sends an error to Rollbar with the given
// severity level and request-specific information. You can pass, optionally,
// custom Fields to be passed on to Rollbar.
func RequestError(level string, r *http.Request, err error, fields ...*Field) {
	RequestErrorWithStackSkip(level, r, err, 1, fields...)
}

// RequestErrorWithStackSkip asynchronously sends an error to Rollbar with the
// given severity level and a given number of stack trace frames skipped, in
// addition to extra request-specific information. You can pass, optionally,
// custom Fields to be passed on to Rollbar.
func RequestErrorWithStackSkip(level string, r *http.Request, err error, skip int, fields ...*Field) {
	stack := BuildStack(2 + skip)
	RequestErrorWithStack(level, r, err, stack, fields...)
}

// RequestErrorWithStack asynchronously sends an error to Rollbar with the
// given severity level, request-specific information provided by the given
// http.Request, and a custom Stack. You You can pass, optionally, custom
// Fields to be passed on to Rollbar.
func RequestErrorWithStack(level string, r *http.Request, err error, stack Stack, fields ...*Field) {
	buildAndPushError(level, err, stack, append(fields, &Field{Name: "request", Data: errorRequest(r)})...)
}

func buildError(level string, err error, stack Stack, fields ...*Field) map[string]interface{} {
	title := nilErrTitle
	if err != nil {
		title = err.Error()
	}

	body := buildBody(level, title)
	data := body["data"].(map[string]interface{})
	errBody := errorBody(err, stack)
	data["body"] = errBody

	for _, field := range fields {
		data[field.Name] = field.Data
	}

	return body
}

func buildAndPushError(level string, err error, stack Stack, fields ...*Field) {
	push(buildError(level, err, stack, fields...))
}

// -- Message reporting

// Message asynchronously sends a message to Rollbar with the given severity
// level.
func Message(level string, msg string) {
	body := buildBody(level, msg)
	data := body["data"].(map[string]interface{})
	data["body"] = messageBody(msg)

	push(body)
}

// -- Misc.

// PostErrors returns a channel that receives all errors encountered while
// POSTing items to the Rollbar API.
func PostErrors() <-chan error {
	return postErrors
}

// Wait will block until the queue of errors / messages is empty. This allows
// you to ensure that errors / messages are sent to Rollbar before exiting an
// application.
func Wait() {
	waitGroup.Wait()
}

// Build the main JSON structure that will be sent to Rollbar with the
// appropriate metadata.
func buildBody(level, title string) map[string]interface{} {
	timestamp := time.Now().Unix()
	hostname, _ := os.Hostname()

	data := map[string]interface{}{
		"environment": Environment,
		"title":       title,
		"level":       level,
		"timestamp":   timestamp,
		"platform":    Platform,
		"language":    "go",
		"server": map[string]interface{}{
			"host": hostname,
		},
		"notifier": map[string]interface{}{
			"name":    NAME,
			"version": VERSION,
		},
	}
	if CodeVersion != "" {
		data["code_version"] = CodeVersion
	}

	return map[string]interface{}{
		"access_token": Token,
		"data":         data,
	}
}

// errorBody generates a Rollbar error body with a given stack trace.
func errorBody(err error, stack Stack) map[string]interface{} {
	message := nilErrTitle
	if err != nil {
		message = err.Error()
	}

	errBody := map[string]interface{}{
		"trace": map[string]interface{}{
			"frames": stack,
			"exception": map[string]interface{}{
				"class":   errorClass(err),
				"message": message,
			},
		},
	}
	return errBody
}

// errorRequest extracts details from a Request in a format that Rollbar
// accepts.
func errorRequest(r *http.Request) map[string]interface{} {
	cleanQuery := filterParams(r.URL.Query())

	return map[string]interface{}{
		"url":     r.URL.String(),
		"method":  r.Method,
		"headers": flattenValues(r.Header),

		// GET params
		"query_string": url.Values(cleanQuery).Encode(),
		"GET":          flattenValues(cleanQuery),

		// POST / PUT params
		"POST":    flattenValues(filterParams(r.Form)),
		"user_ip": r.RemoteAddr,
	}
}

// filterParams filters sensitive information like passwords from being sent to
// Rollbar.
func filterParams(values map[string][]string) map[string][]string {
	for key := range values {
		if FilterFields.Match([]byte(key)) {
			values[key] = []string{FILTERED}
		}
	}

	return values
}

func flattenValues(values map[string][]string) map[string]interface{} {
	result := make(map[string]interface{})

	for k, v := range values {
		if len(v) == 1 {
			result[k] = v[0]
		} else {
			result[k] = v
		}
	}

	return result
}

// Build a message inner-body for the given message string.
func messageBody(s string) map[string]interface{} {
	return map[string]interface{}{
		"message": map[string]interface{}{
			"body": s,
		},
	}
}

func errorClass(err error) string {
	if err == nil {
		return nilErrTitle
	}

	class := reflect.TypeOf(err).String()
	if class == "" {
		return "panic"
	} else if class == "*errors.errorString" {
		checksum := adler32.Checksum([]byte(err.Error()))
		return fmt.Sprintf("{%x}", checksum)
	} else {
		return strings.TrimPrefix(class, "*")
	}
}

// -- POST handling

// Queue the given JSON body to be POSTed to Rollbar.
func push(body map[string]interface{}) {
	if len(bodyChannel) < Buffer {
		waitGroup.Add(1)
		bodyChannel <- body
	} else {
		stderr("buffer full, dropping error on the floor")
	}
}

// POST the given JSON body to Rollbar synchronously.
func post(body map[string]interface{}) error {
	if len(Token) == 0 {
		stderr("empty token")
		return nil
	}

	jsonBody, err := json.Marshal(body)
	if err != nil {
		stderr("failed to encode payload: %s", err.Error())
		return err
	}

	resp, err := http.Post(Endpoint, "application/json", bytes.NewReader(jsonBody))
	if err != nil {
		stderr("POST failed: %s", err.Error())
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != 200 {
		stderr("received response: %s", resp.Status)
		return ErrHTTPError(resp.StatusCode)
	}

	return nil
}

// -- stderr
func stderr(format string, args ...interface{}) {
	if ErrorWriter != nil {
		format = "Rollbar error: " + format + "\n"
		fmt.Fprintf(ErrorWriter, format, args...)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/route53"
	"github.com/aws/aws-sdk-go/service/route53/route53iface"
)

var logpath = os.Getenv("HOME") + "/.cache/lacrosse.log"
var comment = "Updated by lacrosse: github.com/lowply/lacrosse"

type Route53 struct {
	Client route53iface.Route53API
	Id     string
	Req    *Request
}

func NewRoute53(args []string) (*Route53, error) {
	config := &aws.Config{
		Credentials: credentials.NewSharedCredentials("", req.Profile),
	}

	sess, err := session.NewSession(config)
	if err != nil {
		return nil, err
	}

	req, err := NewRequest(args[1:])
	if err != nil {
		return nil, err
	}

	r := &Route53{
		Client: route53.New(sess),
		Id:     "",
		Req:    req,
	}

	return r, nil
}

func (r *Route53) GetHostedZoneId(domain string) (string, error) {
	params := &route53.ListHostedZonesInput{}
	resp, err := r.Client.ListHostedZones(params)
	if err != nil {
		return "", err
	}
	for _, v := range resp.HostedZones {
		if *v.Name == domain+"." {
			return strings.Split(*v.Id, "/")[2], nil
		}
	}
	return "", errors.New("Domain " + domain + " was not found in the hosted zone list.")
}

func (r *Route53) CheckStatus(resp *route53.ChangeResourceRecordSetsOutput) error {
	id := &route53.GetChangeInput{Id: resp.ChangeInfo.Id}
	fmt.Println("Waiting for request " + *id.Id + " to be reflected...")
	err := r.Client.WaitUntilResourceRecordSetsChanged(id)
	if err != nil {
		return err
	}
	fmt.Println("Done.")
	return nil
}

func (r *Route53) CreateNewParams() *route53.ChangeResourceRecordSetsInput {
	params := &route53.ChangeResourceRecordSetsInput{
		ChangeBatch: &route53.ChangeBatch{
			Changes: []*route53.Change{
				{
					Action: aws.String(r.Req.Action),
					ResourceRecordSet: &route53.ResourceRecordSet{
						Name: aws.String(r.Req.Domain),
						Type: aws.String(r.Req.Type),
						ResourceRecords: []*route53.ResourceRecord{
							{
								Value: aws.String(r.Req.Value),
							},
						},
						TTL: aws.Int64(r.Req.TTL),
					},
				},
			},
			Comment: aws.String(comment),
		},
		HostedZoneId: aws.String(r.Id),
	}
	return params
}

func (r *Route53) Logger() error {
	_ = os.Mkdir(path.Dir(logpath), 0777)

	logfile, err := os.OpenFile(logpath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		return err
	}

	b, err := json.Marshal(r.Req)
	if err != nil {
		return err
	}

	logfile.Write(b)
	logfile.WriteString("\n")
	return nil
}

func (r *Route53) RequestChange() error {
	id, err := r.GetHostedZoneId(r.Req.Domain)
	if err != nil {
		return err
	}
	r.Id = id

	params := r.CreateNewParams()

	resp, err := r.Client.ChangeResourceRecordSets(params)
	if err != nil {
		return err
	}

	err = r.CheckStatus(resp)
	if err != nil {
		return err
	}

	err = r.Logger()
	if err != nil {
		return err
	}
	return nil
}
<commit_msg>Fix a bug<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"os"
	"path"
	"strings"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/route53"
	"github.com/aws/aws-sdk-go/service/route53/route53iface"
)

var logpath = os.Getenv("HOME") + "/.cache/lacrosse.log"
var comment = "Updated by lacrosse: github.com/lowply/lacrosse"

type Route53 struct {
	Client route53iface.Route53API
	Id     string
	Req    *Request
}

func NewRoute53(args []string) (*Route53, error) {
	req, err := NewRequest(args[1:])
	if err != nil {
		return nil, err
	}

	config := &aws.Config{
		Credentials: credentials.NewSharedCredentials("", req.Profile),
	}

	sess, err := session.NewSession(config)
	if err != nil {
		return nil, err
	}

	r := &Route53{
		Client: route53.New(sess),
		Id:     "",
		Req:    req,
	}

	return r, nil
}

func (r *Route53) GetHostedZoneId(domain string) (string, error) {
	params := &route53.ListHostedZonesInput{}
	resp, err := r.Client.ListHostedZones(params)
	if err != nil {
		return "", err
	}
	for _, v := range resp.HostedZones {
		if *v.Name == domain+"." {
			return strings.Split(*v.Id, "/")[2], nil
		}
	}
	return "", errors.New("Domain " + domain + " was not found in the hosted zone list.")
}

func (r *Route53) CheckStatus(resp *route53.ChangeResourceRecordSetsOutput) error {
	id := &route53.GetChangeInput{Id: resp.ChangeInfo.Id}
	fmt.Println("Waiting for request " + *id.Id + " to be reflected...")
	err := r.Client.WaitUntilResourceRecordSetsChanged(id)
	if err != nil {
		return err
	}
	fmt.Println("Done.")
	return nil
}

func (r *Route53) CreateNewParams() *route53.ChangeResourceRecordSetsInput {
	params := &route53.ChangeResourceRecordSetsInput{
		ChangeBatch: &route53.ChangeBatch{
			Changes: []*route53.Change{
				{
					Action: aws.String(r.Req.Action),
					ResourceRecordSet: &route53.ResourceRecordSet{
						Name: aws.String(r.Req.Domain),
						Type: aws.String(r.Req.Type),
						ResourceRecords: []*route53.ResourceRecord{
							{
								Value: aws.String(r.Req.Value),
							},
						},
						TTL: aws.Int64(r.Req.TTL),
					},
				},
			},
			Comment: aws.String(comment),
		},
		HostedZoneId: aws.String(r.Id),
	}
	return params
}

func (r *Route53) Logger() error {
	_ = os.Mkdir(path.Dir(logpath), 0777)

	logfile, err := os.OpenFile(logpath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
	if err != nil {
		return err
	}

	b, err := json.Marshal(r.Req)
	if err != nil {
		return err
	}

	logfile.Write(b)
	logfile.WriteString("\n")
	return nil
}

func (r *Route53) RequestChange() error {
	id, err := r.GetHostedZoneId(r.Req.Domain)
	if err != nil {
		return err
	}
	r.Id = id

	params := r.CreateNewParams()

	resp, err := r.Client.ChangeResourceRecordSets(params)
	if err != nil {
		return err
	}

	err = r.CheckStatus(resp)
	if err != nil {
		return err
	}

	err = r.Logger()
	if err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package githttp

import (
	"log"
	"net/http"
	"regexp"
	"strings"
)

type Service struct {
	Method  string
	Handler func(HandlerReq) error
	Rpc     string
}

type HandlerReq struct {
	w    http.ResponseWriter
	r    *http.Request
	Rpc  string
	Dir  string
	File string
}

// Routing regexes
var (
	_serviceRpcUpload  = regexp.MustCompile("(.*?)/git-upload-pack$")
	_serviceRpcReceive = regexp.MustCompile("(.*?)/git-receive-pack$")
	_getInfoRefs       = regexp.MustCompile("(.*?)/info/refs$")
	_getHead           = regexp.MustCompile("(.*?)/HEAD$")
	_getAlternates     = regexp.MustCompile("(.*?)/objects/info/alternates$")
	_getHttpAlternates = regexp.MustCompile("(.*?)/objects/info/http-alternates$")
	_getInfoPacks      = regexp.MustCompile("(.*?)/objects/info/packs$")
	_getInfoFile       = regexp.MustCompile("(.*?)/objects/info/[^/]*$")
	_getLooseObject    = regexp.MustCompile("(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$")
	_getPackFile       = regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.pack$")
	_getIdxFile        = regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.idx$")
)

func (g *GitHttp) services() map[*regexp.Regexp]Service {
	return map[*regexp.Regexp]Service{
		_serviceRpcUpload:  Service{"POST", g.serviceRpc, "upload-pack"},
		_serviceRpcReceive: Service{"POST", g.serviceRpc, "receive-pack"},
		_getInfoRefs:       Service{"GET", g.getInfoRefs, ""},
		_getHead:           Service{"GET", g.getTextFile, ""},
		_getAlternates:     Service{"GET", g.getTextFile, ""},
		_getHttpAlternates: Service{"GET", g.getTextFile, ""},
		_getInfoPacks:      Service{"GET", g.getInfoPacks, ""},
		_getInfoFile:       Service{"GET", g.getTextFile, ""},
		_getLooseObject:    Service{"GET", g.getLooseObject, ""},
		_getPackFile:       Service{"GET", g.getPackFile, ""},
		_getIdxFile:        Service{"GET", g.getIdxFile, ""},
	}
}

// getService return's the service corresponding to the
// current http.Request's URL
// as well as the name of the repo
func (g *GitHttp) getService(path string) (string, *Service) {
	for re, service := range g.services() {
		if m := re.FindStringSubmatch(path); m != nil {
			return m[1], &service
		}
	}

	// No match
	return "", nil
}

// Request handling function
func (g *GitHttp) requestHandler(w http.ResponseWriter, r *http.Request) {
	log.Printf("%s %s %s %s", r.RemoteAddr, r.Method, r.URL.Path, r.Proto)

	// Get service for URL
	repo, service := g.getService(r.URL.Path)

	// No url match
	if service == nil {
		renderNotFound(w)
		return
	}

	// Bad method
	if service.Method != r.Method {
		renderMethodNotAllowed(w, r)
		return
	}

	// Rpc type
	rpc := service.Rpc

	// Get specific file
	file := strings.Replace(r.URL.Path, repo+"/", "", 1)

	// Resolve directory
	dir, err := g.getGitDir(repo)

	// Repo not found on disk
	if err != nil {
		log.Print(err)
		renderNotFound(w)
		return
	}

	// Build request info for handler
	hr := HandlerReq{w, r, rpc, dir, file}

	// Call handler
	service.Handler(hr)
}
<commit_msg>Handle errors in requestHandler()<commit_after>package githttp

import (
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
)

type Service struct {
	Method  string
	Handler func(HandlerReq) error
	Rpc     string
}

type HandlerReq struct {
	w    http.ResponseWriter
	r    *http.Request
	Rpc  string
	Dir  string
	File string
}

// Routing regexes
var (
	_serviceRpcUpload  = regexp.MustCompile("(.*?)/git-upload-pack$")
	_serviceRpcReceive = regexp.MustCompile("(.*?)/git-receive-pack$")
	_getInfoRefs       = regexp.MustCompile("(.*?)/info/refs$")
	_getHead           = regexp.MustCompile("(.*?)/HEAD$")
	_getAlternates     = regexp.MustCompile("(.*?)/objects/info/alternates$")
	_getHttpAlternates = regexp.MustCompile("(.*?)/objects/info/http-alternates$")
	_getInfoPacks      = regexp.MustCompile("(.*?)/objects/info/packs$")
	_getInfoFile       = regexp.MustCompile("(.*?)/objects/info/[^/]*$")
	_getLooseObject    = regexp.MustCompile("(.*?)/objects/[0-9a-f]{2}/[0-9a-f]{38}$")
	_getPackFile       = regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.pack$")
	_getIdxFile        = regexp.MustCompile("(.*?)/objects/pack/pack-[0-9a-f]{40}\\.idx$")
)

func (g *GitHttp) services() map[*regexp.Regexp]Service {
	return map[*regexp.Regexp]Service{
		_serviceRpcUpload:  Service{"POST", g.serviceRpc, "upload-pack"},
		_serviceRpcReceive: Service{"POST", g.serviceRpc, "receive-pack"},
		_getInfoRefs:       Service{"GET", g.getInfoRefs, ""},
		_getHead:           Service{"GET", g.getTextFile, ""},
		_getAlternates:     Service{"GET", g.getTextFile, ""},
		_getHttpAlternates: Service{"GET", g.getTextFile, ""},
		_getInfoPacks:      Service{"GET", g.getInfoPacks, ""},
		_getInfoFile:       Service{"GET", g.getTextFile, ""},
		_getLooseObject:    Service{"GET", g.getLooseObject, ""},
		_getPackFile:       Service{"GET", g.getPackFile, ""},
		_getIdxFile:        Service{"GET", g.getIdxFile, ""},
	}
}

// getService return's the service corresponding to the
// current http.Request's URL
// as well as the name of the repo
func (g *GitHttp) getService(path string) (string, *Service) {
	for re, service := range g.services() {
		if m := re.FindStringSubmatch(path); m != nil {
			return m[1], &service
		}
	}

	// No match
	return "", nil
}

// Request handling function
func (g *GitHttp) requestHandler(w http.ResponseWriter, r *http.Request) {
	log.Printf("%s %s %s %s", r.RemoteAddr, r.Method, r.URL.Path, r.Proto)

	// Get service for URL
	repo, service := g.getService(r.URL.Path)

	// No url match
	if service == nil {
		renderNotFound(w)
		return
	}

	// Bad method
	if service.Method != r.Method {
		renderMethodNotAllowed(w, r)
		return
	}

	// Rpc type
	rpc := service.Rpc

	// Get specific file
	file := strings.Replace(r.URL.Path, repo+"/", "", 1)

	// Resolve directory
	dir, err := g.getGitDir(repo)

	// Repo not found on disk
	if err != nil {
		renderNotFound(w)
		return
	}

	// Build request info for handler
	hr := HandlerReq{w, r, rpc, dir, file}

	// Call handler
	if err := service.Handler(hr); err != nil {
		if os.IsNotExist(err) {
			renderNotFound(w)
			return
		}
		switch err.(type) {
			case *ErrorNoAccess:
				renderNoAccess(w)
				return
		}
		http.Error(w, err.Error(), 500)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/ant0ine/go-json-rest/rest"
	"github.com/mendersoftware/artifacts/config"
	"github.com/mendersoftware/artifacts/controllers"
	"github.com/mendersoftware/artifacts/handlers"
	"github.com/mendersoftware/artifacts/models/fileservice/s3"
	"github.com/mendersoftware/artifacts/models/images/memmap"
	"github.com/mendersoftware/artifacts/utils/safemap"
)

// NewRouter defines all REST API routes.
func NewRouter(c config.ConfigReader) (rest.App, error) {

	images := memmap.NewImagesInMem(safemap.NewStringMap())

	bucket := c.GetString(SettingAweS3Bucket)
	region := c.GetString(SettingAwsS3Region)

	var fileStorage *s3.SimpleStorageService

	if c.IsSet(SettingsAwsAuth) {
		fileStorage = s3.NewSimpleStorageServiceStatic(
			bucket,
			c.GetString(SettingAwsAuthKeyId),
			c.GetString(SettingAwsAuthSecret),
			region,
			c.GetString(SettingAwsAuthToken),
		)
	} else {
		fileStorage = s3.NewSimpleStorageServiceDefaults(bucket, region)
	}

	meta := handlers.NewImageMeta(controllers.NewImagesController(images, fileStorage))

	app, err := rest.MakeRouter(
		rest.Get("/api/0.0.1/images", meta.Lookup),
		rest.Post("/api/0.0.1/images", meta.Create),
		rest.Options("/api/0.0.1/images", handlers.NewOptionsHandler(handlers.HttpMethodGet,
			handlers.HttpMethodPost).Handle),

		rest.Get("/api/0.0.1/images/:id", meta.Get),
		rest.Put("/api/0.0.1/images/:id", meta.Edit),
		rest.Delete("/api/0.0.1/images/:id", meta.Delete),
		rest.Options("/api/0.0.1/images/:id", handlers.NewOptionsHandler(handlers.HttpMethodGet,
			handlers.HttpMethodPut, handlers.HttpMethodDelete).Handle),

		rest.Get("/api/0.0.1/images/:id/upload", meta.UploadLink),
		rest.Options("/api/0.0.1/images/:id/upload", handlers.NewOptionsHandler(handlers.HttpMethodGet).Handle),

		rest.Get("/api/0.0.1/images/:id/download", meta.DownloadLink),
		rest.Options("/api/0.0.1/images/:id/download", handlers.NewOptionsHandler(handlers.HttpMethodGet).Handle),
	)

	return app, err
}
<commit_msg>Refactor routing.go to simplify code.<commit_after>package main

import (
	"github.com/ant0ine/go-json-rest/rest"
	"github.com/mendersoftware/artifacts/config"
	"github.com/mendersoftware/artifacts/controllers"
	"github.com/mendersoftware/artifacts/handlers"
	"github.com/mendersoftware/artifacts/models/fileservice"
	"github.com/mendersoftware/artifacts/models/fileservice/s3"
	"github.com/mendersoftware/artifacts/models/images/memmap"
	"github.com/mendersoftware/artifacts/utils/safemap"
)

func SetupFileStorage(c config.ConfigReader) fileservice.FileServiceModelI {

	bucket := c.GetString(SettingAweS3Bucket)
	region := c.GetString(SettingAwsS3Region)

	if c.IsSet(SettingsAwsAuth) {
		return s3.NewSimpleStorageServiceStatic(
			bucket,
			c.GetString(SettingAwsAuthKeyId),
			c.GetString(SettingAwsAuthSecret),
			region,
			c.GetString(SettingAwsAuthToken),
		)
	}

	return s3.NewSimpleStorageServiceDefaults(bucket, region)
}

// NewRouter defines all REST API routes.
func NewRouter(c config.ConfigReader) (rest.App, error) {

	images := memmap.NewImagesInMem(safemap.NewStringMap())
	meta := handlers.NewImageMeta(controllers.NewImagesController(images, SetupFileStorage(c)))

	app, err := rest.MakeRouter(
		rest.Get("/api/0.0.1/images", meta.Lookup),
		rest.Post("/api/0.0.1/images", meta.Create),
		rest.Options("/api/0.0.1/images", handlers.NewOptionsHandler(handlers.HttpMethodGet,
			handlers.HttpMethodPost).Handle),

		rest.Get("/api/0.0.1/images/:id", meta.Get),
		rest.Put("/api/0.0.1/images/:id", meta.Edit),
		rest.Delete("/api/0.0.1/images/:id", meta.Delete),
		rest.Options("/api/0.0.1/images/:id", handlers.NewOptionsHandler(handlers.HttpMethodGet,
			handlers.HttpMethodPut, handlers.HttpMethodDelete).Handle),

		rest.Get("/api/0.0.1/images/:id/upload", meta.UploadLink),
		rest.Options("/api/0.0.1/images/:id/upload", handlers.NewOptionsHandler(handlers.HttpMethodGet).Handle),

		rest.Get("/api/0.0.1/images/:id/download", meta.DownloadLink),
		rest.Options("/api/0.0.1/images/:id/download", handlers.NewOptionsHandler(handlers.HttpMethodGet).Handle),
	)

	return app, err
}
<|endoftext|>


<commit_before>// (C) 1990-2016.  Robert W Solomon.  All rights reserved.
// rpn.go
package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"strconv"
	"strings"
	//
	"src/getcommandline"
	hpcalc "src/hpcalc2"
	"src/makesubst"
)

const LastCompiled = "13 June 2021"

/*
REVISION HISTORY
----------------
 1 Dec 89 -- Changed prompt.
24 Dec 91 -- Converted to M-2 V 4.00.  Changed params to GETRESULT.
25 Jul 93 -- Output result without trailing insignificant zeros,
	                 imported UL2, and changed prompt again.
 3 Mar 96 -- Fixed bug in string display if real2str fails because
	                 number is too large (ie, Avogadro's Number).
18 May 03 -- First Win32 version.  And changed name.
 1 Apr 13 -- Back to console mode pgm that will read from the cmdline.  Intended to be a quick and useful little utility.
	                 And will save/restore the stack to/from a file.
 2 May 13 -- Will use console mode flag for HPCALC, so it will write to console instead of the terminal module routines.
	                 And I now have the skipline included in MiscStdInOut so it is removed from here.
15 Oct 13 -- Now writing for gm2 under linux.
22 Jul 14 -- Converting to Ada.
 6 Dec 14 -- Converting to cpp.
20 Dec 14 -- Added macros for date and time last compiled.
31 Dec 14 -- Started coding HOL command.
 1 Jan 15 -- After getting HOL command to work, I did more fiddling to further understand c-strings and c++ string class.
10 Jan 15 -- Playing with string conversions and number formatting.
 5 Nov 15 -- Added the RECIP, CURT, VOL commands to hpcalc.cpp
22 Nov 15 -- Noticed that T1 and T2 stack operations are not correct.  This effects HP2cursed and rpnc.
13 Apr 16 -- Adding undo and redo commands, which operate on the entire stack not just X register.
 2 Jul 16 -- Fixed help to include PI command, and changed pivot for JUL command.  See hpcalcc.cpp
 7 Jul 16 -- Added UP command to hpcalcc.cpp
 8 Jul 16 -- Added display of stack dump to always happen, and a start up message.
22 Aug 16 -- Started conversion to Go.
28 Aug 16 -- added makesubst capability for substitutions = -> + and ; -> *
28 Nov 16 -- Backported stringslice return of hpcalc so can use the new, improved hpcalc.
23 Feb 17 -- Made "?" equivalent to "help"
26 Mar 17 -- Changed startup message to include written in Go.
22 Aug 18 -- Learning about code folding
 2 Oct 18 -- Now using code folding.  za normal mode command toggles the fold mode where cursor is.
 8 Feb 20 -- Added PopX to hpcalc.go, and will test it here.
 9 Apr 20 -- Will add the suppressdump map I've been using for a while in rpng.
 8 Nov 20 -- Now will use hpcalc2.  I'm adding toclip, fromclip (based on code from "Go Standard Library Cookbook") to hpcalc2.
	                And finally removed code that was commented out long ago.
13 Jun 31 -- Converted code to use modules
*/

var suppressDump map[string]bool

func main() {
	var R float64
	var INBUF, ans string
	const StackFileName = "RPNStack.sav"
	var stringslice []string

	var Stk hpcalc.StackType // used when time to write out the stack upon exit.

	var err error

	suppressDump = make(map[string]bool)
	suppressDump["PRIME"] = true
	suppressDump["HEX"] = true
	suppressDump["DOW"] = true
	suppressDump["HOL"] = true
	suppressDump["ABOUT"] = true
	suppressDump["HELP"] = true
	suppressDump["TOCLIP"] = true
	suppressDump["DUMP"] = true
	suppressDump["DUMPFIX"] = true
	suppressDump["DUMPFIXED"] = true
	suppressDump["DUMPFLOAT"] = true
	suppressDump["?"] = true
	//        suppressDump[""] = true

	allowDumpFlag := true

	StackFileExists := true
	InputByteSlice := make([]byte, 8*hpcalc.StackSize) // I hope this is a slice of 64 bytes, ie, 8*8.

	if InputByteSlice, err = ioutil.ReadFile(StackFileName); err != nil {
		fmt.Printf(" Error from ioutil.ReadFile.  Probably because no Stack File found: %v\n", err)
		StackFileExists = false
	}
	if StackFileExists { // I'll read all into memory.
		for i := 0; i < hpcalc.StackSize*8; i = i + 8 {
			buf := bytes.NewReader(InputByteSlice[i : i+8])
			err := binary.Read(buf, binary.LittleEndian, &R)
			if err != nil {
				fmt.Printf(" binary.Read failed with error of %v \n", err)
				StackFileExists = false
			}
			hpcalc.PUSHX(R)
		} // loop to extract each 8 byte chunk to convert to a longreal (float64) and push onto the hpcalc stack.
	} // stackfileexists

	hpcalc.PushMatrixStacks()

	fmt.Println(" HP-type RPN calculator written in Go.  Last compiled ", LastCompiled, "by", runtime.Version())
	fmt.Println()

	scanner := bufio.NewScanner(os.Stdin)
	if len(os.Args) > 1 {
		INBUF = getcommandline.GetCommandLineString()
		INBUF = makesubst.MakeSubst(INBUF)
	} else {
		fmt.Print(" Enter calculation, HELP or Enter to exit: ")
		scanner.Scan()
		INBUF = scanner.Text()
		if err := scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, "reading standard input:", err)
			os.Exit(1)
		}
		if len(INBUF) == 0 {
			os.Exit(0)
		}
		INBUF = makesubst.MakeSubst(INBUF)
	} // if command tail exists

	hpcalc.PushMatrixStacks()

	for len(INBUF) > 0 {  // main reading loop
		R, stringslice = hpcalc.GetResult(INBUF)
		ans = strconv.FormatFloat(R, 'g', -1, 64)
		ans = hpcalc.CropNStr(ans)
		if R > 10000 {
			ans = hpcalc.AddCommas(ans)
		}
		fmt.Println()
		fmt.Println()
		for _, ss := range stringslice {
			fmt.Println(ss)
			allowDumpFlag = false // Don't update stack if any strings were returned from hpcalc.GetResult()
		}

		if strings.ToLower(INBUF) == "about" {
			fmt.Println(" Last compiled rpn.go ", LastCompiled)
			allowDumpFlag = false
		}

		INBUF = strings.ToUpper(INBUF)
		if suppressDump[INBUF] {
			allowDumpFlag = false
		}
		//		if !(strings.HasPrefix(INBUF, "DUMP") || INBUF == "HELP" || INBUF == "?") { // old way of suppressing DUMP: if just did it, or if HELP called to not scroll help off screen.
		if allowDumpFlag {
			_, stringslice = hpcalc.GetResult("DUMP") // discard result.  Only need stack dump general executed.
			for _, ss := range stringslice {
				fmt.Println(ss)
			}
		}

		fmt.Println()
		fmt.Print("                                            Result = ")
		hpcalc.OutputFixedOrFloat(R)
		fmt.Println("         |    ", ans)
		fmt.Print(" Enter calculation, HELP or Enter to exit: ")
		scanner.Scan()
		INBUF = scanner.Text()
		if err := scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, "reading standard input:", err)
			os.Exit(1)
		}
		INBUF = makesubst.MakeSubst(INBUF)
		allowDumpFlag = true
	}

	// Now that I've got this working, I'm taking notes.  The binary.Write appends to the buf after each
	// call, since I'm not doing anthing to the bytes.Buffer to reset it.  I don't need a separate slice of
	// bytes to accumulate the stack for output.  I just have to reverse the order I write them out so that
	// they are read in correctly, without reversing the stack after each write.  I could reset the
	// buf.Bytes each time if I wanted.  I tested that and it works.  But it is unnecessary for my needs so
	// I commented it out.

	Stk = hpcalc.GETSTACK()
	//  OutputByteSlice := make([]byte,0,8*hpcalc.StackSize);  // each stack element is a float64, and there are StackSize of these (now StackSize=8), so this is a slice of 64 bytes
	buf := new(bytes.Buffer)

	for i := hpcalc.T1; i >= hpcalc.X; i-- { // in reverse.  for range cannot go in reverse.
		r := Stk[i]
		err := binary.Write(buf, binary.LittleEndian, r)
		if err != nil {
			fmt.Printf(" binary.write into buf failed with error %v \n", err)
			os.Exit(1)
		}
		// {{{
		//    fmt.Println(" Got Stk.  buf.Bytes len =",len(buf.Bytes()),". buf.Bytes: ",buf.Bytes());
		//    OutputByteSlice = append(OutputByteSlice,buf.Bytes()...);
		//    fmt.Println(" Length of OutByteSlice after append operation ",len(OutputByteSlice));
		//    buf.Reset();
		// }}}
	}
	err = ioutil.WriteFile(StackFileName, buf.Bytes(), os.ModePerm) // os.ModePerm = 0777
	if err != nil {
		fmt.Printf(" ioutil.WriteFile failed with error %v \n", err)
	}
} // main in rpn.go
<commit_msg>06/19/2021 05:51:23 PM rpn/rpn.go<commit_after>// (C) 1990-2016.  Robert W Solomon.  All rights reserved.
// rpn.go
package main

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"os"
	"runtime"
	"strconv"
	"strings"
	//
	"src/getcommandline"
	hpcalc "src/hpcalc2"
	"src/makesubst"
)

const LastCompiled = "19 June 2021"

/*
REVISION HISTORY
----------------
 1 Dec 89 -- Changed prompt.
24 Dec 91 -- Converted to M-2 V 4.00.  Changed params to GETRESULT.
25 Jul 93 -- Output result without trailing insignificant zeros,
	                 imported UL2, and changed prompt again.
 3 Mar 96 -- Fixed bug in string display if real2str fails because
	                 number is too large (ie, Avogadro's Number).
18 May 03 -- First Win32 version.  And changed name.
 1 Apr 13 -- Back to console mode pgm that will read from the cmdline.  Intended to be a quick and useful little utility.
	                 And will save/restore the stack to/from a file.
 2 May 13 -- Will use console mode flag for HPCALC, so it will write to console instead of the terminal module routines.
	                 And I now have the skipline included in MiscStdInOut so it is removed from here.
15 Oct 13 -- Now writing for gm2 under linux.
22 Jul 14 -- Converting to Ada.
 6 Dec 14 -- Converting to cpp.
20 Dec 14 -- Added macros for date and time last compiled.
31 Dec 14 -- Started coding HOL command.
 1 Jan 15 -- After getting HOL command to work, I did more fiddling to further understand c-strings and c++ string class.
10 Jan 15 -- Playing with string conversions and number formatting.
 5 Nov 15 -- Added the RECIP, CURT, VOL commands to hpcalc.cpp
22 Nov 15 -- Noticed that T1 and T2 stack operations are not correct.  This effects HP2cursed and rpnc.
13 Apr 16 -- Adding undo and redo commands, which operate on the entire stack not just X register.
 2 Jul 16 -- Fixed help to include PI command, and changed pivot for JUL command.  See hpcalcc.cpp
 7 Jul 16 -- Added UP command to hpcalcc.cpp
 8 Jul 16 -- Added display of stack dump to always happen, and a start up message.
22 Aug 16 -- Started conversion to Go.
28 Aug 16 -- added makesubst capability for substitutions = -> + and ; -> *
28 Nov 16 -- Backported stringslice return of hpcalc so can use the new, improved hpcalc.
23 Feb 17 -- Made "?" equivalent to "help"
26 Mar 17 -- Changed startup message to include written in Go.
22 Aug 18 -- Learning about code folding
 2 Oct 18 -- Now using code folding.  za normal mode command toggles the fold mode where cursor is.
 8 Feb 20 -- Added PopX to hpcalc.go, and will test it here.
 9 Apr 20 -- Will add the suppressdump map I've been using for a while in rpng.
 8 Nov 20 -- Now will use hpcalc2.  I'm adding toclip, fromclip (based on code from "Go Standard Library Cookbook") to hpcalc2.
	                And finally removed code that was commented out long ago.
13 Jun 21 -- Converted code to use modules
19 Jun 21 -- Now uses the new MAP code written in hpcalc2 that does not require calling MapClose, which was never done here anyway.
*/

var suppressDump map[string]bool

func main() {
	var R float64
	var INBUF, ans string
	const StackFileName = "RPNStack.sav"
	var stringslice []string

	var Stk hpcalc.StackType // used when time to write out the stack upon exit.

	var err error

	suppressDump = make(map[string]bool)
	suppressDump["PRIME"] = true
	suppressDump["HEX"] = true
	suppressDump["DOW"] = true
	suppressDump["HOL"] = true
	suppressDump["ABOUT"] = true
	suppressDump["HELP"] = true
	suppressDump["TOCLIP"] = true
	suppressDump["DUMP"] = true
	suppressDump["DUMPFIX"] = true
	suppressDump["DUMPFIXED"] = true
	suppressDump["DUMPFLOAT"] = true
	suppressDump["?"] = true
	//        suppressDump[""] = true

	allowDumpFlag := true

	StackFileExists := true
	InputByteSlice := make([]byte, 8*hpcalc.StackSize) // I hope this is a slice of 64 bytes, ie, 8*8.

	if InputByteSlice, err = ioutil.ReadFile(StackFileName); err != nil {
		fmt.Printf(" Error from ioutil.ReadFile.  Probably because no Stack File found: %v\n", err)
		StackFileExists = false
	}
	if StackFileExists { // I'll read all into memory.
		for i := 0; i < hpcalc.StackSize*8; i = i + 8 {
			buf := bytes.NewReader(InputByteSlice[i : i+8])
			err := binary.Read(buf, binary.LittleEndian, &R)
			if err != nil {
				fmt.Printf(" binary.Read failed with error of %v \n", err)
				StackFileExists = false
			}
			hpcalc.PUSHX(R)
		} // loop to extract each 8 byte chunk to convert to a longreal (float64) and push onto the hpcalc stack.
	} // stackfileexists

	hpcalc.PushMatrixStacks()

	fmt.Println(" HP-type RPN calculator written in Go.  Last compiled ", LastCompiled, "by", runtime.Version())
	fmt.Println()

	scanner := bufio.NewScanner(os.Stdin)
	if len(os.Args) > 1 {
		INBUF = getcommandline.GetCommandLineString()
		INBUF = makesubst.MakeSubst(INBUF)
	} else {
		fmt.Print(" Enter calculation, HELP or Enter to exit: ")
		scanner.Scan()
		INBUF = scanner.Text()
		if err := scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, "reading standard input:", err)
			os.Exit(1)
		}
		if len(INBUF) == 0 {
			os.Exit(0)
		}
		INBUF = makesubst.MakeSubst(INBUF)
	} // if command tail exists

	hpcalc.PushMatrixStacks()

	for len(INBUF) > 0 {  // main reading loop
		R, stringslice = hpcalc.GetResult(INBUF)
		ans = strconv.FormatFloat(R, 'g', -1, 64)
		ans = hpcalc.CropNStr(ans)
		if R > 10000 {
			ans = hpcalc.AddCommas(ans)
		}
		fmt.Println()
		fmt.Println()
		for _, ss := range stringslice {
			fmt.Println(ss)
			allowDumpFlag = false // Don't update stack if any strings were returned from hpcalc.GetResult()
		}

		if strings.ToLower(INBUF) == "about" {
			fmt.Println(" Last compiled rpn.go ", LastCompiled)
			allowDumpFlag = false
		}

		INBUF = strings.ToUpper(INBUF)
		if suppressDump[INBUF] {
			allowDumpFlag = false
		}

		if allowDumpFlag {
			_, stringslice = hpcalc.GetResult("DUMP") // discard result.  Only need stack dump general executed.
			for _, ss := range stringslice {
				fmt.Println(ss)
			}
		}

		fmt.Println()
		fmt.Print("                                            Result = ")
		hpcalc.OutputFixedOrFloat(R)
		fmt.Println("         |    ", ans)
		fmt.Print(" Enter calculation, HELP or Enter to exit: ")
		scanner.Scan()
		INBUF = scanner.Text()
		if err := scanner.Err(); err != nil {
			fmt.Fprintln(os.Stderr, "reading standard input:", err)
			os.Exit(1)
		}
		INBUF = makesubst.MakeSubst(INBUF)
		allowDumpFlag = true
	}

	// Now that I've got this working, I'm taking notes.  The binary.Write appends to the buf after each
	// call, since I'm not doing anthing to the bytes.Buffer to reset it.  I don't need a separate slice of
	// bytes to accumulate the stack for output.  I just have to reverse the order I write them out so that
	// they are read in correctly, without reversing the stack after each write.  I could reset the
	// buf.Bytes each time if I wanted.  I tested that and it works.  But it is unnecessary for my needs so
	// I commented it out.

	Stk = hpcalc.GETSTACK()
	//  OutputByteSlice := make([]byte,0,8*hpcalc.StackSize);  // each stack element is a float64, and there are StackSize of these (now StackSize=8), so this is a slice of 64 bytes
	buf := new(bytes.Buffer)

	for i := hpcalc.T1; i >= hpcalc.X; i-- { // in reverse.  for range cannot go in reverse.
		r := Stk[i]
		err := binary.Write(buf, binary.LittleEndian, r)
		if err != nil {
			fmt.Printf(" binary.write into buf failed with error %v \n", err)
			os.Exit(1)
		}
	}
	err = ioutil.WriteFile(StackFileName, buf.Bytes(), os.ModePerm) // os.ModePerm = 0777
	if err != nil {
		fmt.Printf(" ioutil.WriteFile failed with error %v \n", err)
	}
} // main in rpn.go
<|endoftext|>