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

package ast

import (
	t "github.com/google/wuffs/lang/token"
)

// Str returns a string form of n.
func (n *Expr) Str(tm *t.Map) string {
	if n == nil {
		return ""
	}
	if n.id0 == 0 && n.id1 == 0 {
		return tm.ByID(n.id2)
	}
	return string(n.appendStr(nil, tm, false, 0))
}

func (n *Expr) appendStr(buf []byte, tm *t.Map, parenthesize bool, depth uint32) []byte {
	if depth > MaxExprDepth {
		return append(buf, "!expr_recursion_depth_too_large!"...)
	}
	depth++

	if n == nil {
		return buf
	}

	if n.id0.IsXOp() {
		switch {
		case n.id0.IsXUnaryOp():
			buf = append(buf, opString(n.id0)...)
			buf = n.rhs.AsExpr().appendStr(buf, tm, true, depth)

		case n.id0.IsXBinaryOp():
			if parenthesize {
				buf = append(buf, '(')
			}
			buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
			buf = append(buf, opString(n.id0)...)
			if n.id0 == t.IDXBinaryAs {
				buf = append(buf, n.rhs.AsTypeExpr().Str(tm)...)
			} else {
				buf = n.rhs.AsExpr().appendStr(buf, tm, true, depth)
			}
			if parenthesize {
				buf = append(buf, ')')
			}

		case n.id0.IsXAssociativeOp():
			if parenthesize {
				buf = append(buf, '(')
			}
			op := opString(n.id0)
			for i, o := range n.list0 {
				if i != 0 {
					buf = append(buf, op...)
				}
				buf = o.AsExpr().appendStr(buf, tm, true, depth)
			}
			if parenthesize {
				buf = append(buf, ')')
			}
		}

	} else {
		switch n.id0 {
		case t.IDStatus:
			buf = append(buf, "status "...)
			if n.id1 != 0 {
				buf = append(buf, tm.ByID(n.id1)...)
				buf = append(buf, '.')
			}
			fallthrough

		case 0:
			buf = append(buf, tm.ByID(n.id2)...)

		case t.IDTry:
			buf = append(buf, "try "...)
			fallthrough

		case t.IDOpenParen:
			buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
			buf = append(buf, n.flags.AsEffect().String()...)
			buf = append(buf, '(')
			for i, o := range n.list0 {
				if i != 0 {
					buf = append(buf, ", "...)
				}
				buf = append(buf, tm.ByID(o.AsArg().Name())...)
				buf = append(buf, ':')
				buf = o.AsArg().Value().appendStr(buf, tm, false, depth)
			}
			buf = append(buf, ')')

		case t.IDOpenBracket:
			buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
			buf = append(buf, '[')
			buf = n.rhs.AsExpr().appendStr(buf, tm, false, depth)
			buf = append(buf, ']')

		case t.IDColon:
			buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
			buf = append(buf, '[')
			buf = n.mhs.AsExpr().appendStr(buf, tm, false, depth)
			buf = append(buf, ':')
			buf = n.rhs.AsExpr().appendStr(buf, tm, false, depth)
			buf = append(buf, ']')

		case t.IDDot:
			buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
			buf = append(buf, '.')
			buf = append(buf, tm.ByID(n.id2)...)

		case t.IDComma:
			buf = append(buf, '[')
			for i, o := range n.list0 {
				if i != 0 {
					buf = append(buf, ", "...)
				}
				buf = o.AsExpr().appendStr(buf, tm, false, depth)
			}
			buf = append(buf, ']')
		}
	}

	return buf
}

func opString(x t.ID) string {
	if x < t.ID(len(opStrings)) {
		if s := opStrings[x]; s != "" {
			return s
		}
	}
	return " no_such_Wuffs_operator "
}

var opStrings = [...]string{
	t.IDXUnaryPlus:  "+",
	t.IDXUnaryMinus: "-",
	t.IDXUnaryNot:   "not ",
	t.IDXUnaryRef:   "ref ",
	t.IDXUnaryDeref: "deref ",

	t.IDXBinaryPlus:          " + ",
	t.IDXBinaryMinus:         " - ",
	t.IDXBinaryStar:          " * ",
	t.IDXBinarySlash:         " / ",
	t.IDXBinaryShiftL:        " << ",
	t.IDXBinaryShiftR:        " >> ",
	t.IDXBinaryAmp:           " & ",
	t.IDXBinaryPipe:          " | ",
	t.IDXBinaryHat:           " ^ ",
	t.IDXBinaryTildeModPlus:  " ~mod+ ",
	t.IDXBinaryTildeModMinus: " ~mod- ",
	t.IDXBinaryTildeSatPlus:  " ~sat+ ",
	t.IDXBinaryTildeSatMinus: " ~sat- ",
	t.IDXBinaryNotEq:         " != ",
	t.IDXBinaryLessThan:      " < ",
	t.IDXBinaryLessEq:        " <= ",
	t.IDXBinaryEqEq:          " == ",
	t.IDXBinaryGreaterEq:     " >= ",
	t.IDXBinaryGreaterThan:   " > ",
	t.IDXBinaryAnd:           " and ",
	t.IDXBinaryOr:            " or ",
	t.IDXBinaryAs:            " as ",

	t.IDXAssociativePlus: " + ",
	t.IDXAssociativeStar: " * ",
	t.IDXAssociativeAmp:  " & ",
	t.IDXAssociativePipe: " | ",
	t.IDXAssociativeHat:  " ^ ",
	t.IDXAssociativeAnd:  " and ",
	t.IDXAssociativeOr:   " or ",
}

// Str returns a string form of n.
func (n *TypeExpr) Str(tm *t.Map) string {
	if n == nil {
		return ""
	}
	if n.Decorator() == 0 && n.Min() == nil && n.Max() == nil {
		return n.QID().Str(tm)
	}
	return string(n.appendStr(nil, tm, 0))
}

func (n *TypeExpr) appendStr(buf []byte, tm *t.Map, depth uint32) []byte {
	if depth > MaxTypeExprDepth {
		return append(buf, "!type_expr_recursion_depth_too_large!"...)
	}
	depth++
	if n == nil {
		return append(buf, "!invalid_type!"...)
	}

	switch n.Decorator() {
	case 0:
		buf = append(buf, n.QID().Str(tm)...)
	case t.IDNptr:
		buf = append(buf, "nptr "...)
		return n.Inner().appendStr(buf, tm, depth)
	case t.IDPtr:
		buf = append(buf, "ptr "...)
		return n.Inner().appendStr(buf, tm, depth)
	case t.IDArray:
		buf = append(buf, "array["...)
		buf = n.ArrayLength().appendStr(buf, tm, false, 0)
		buf = append(buf, "] "...)
		return n.Inner().appendStr(buf, tm, depth)
	case t.IDSlice:
		buf = append(buf, "slice "...)
		return n.Inner().appendStr(buf, tm, depth)
	case t.IDTable:
		buf = append(buf, "table "...)
		return n.Inner().appendStr(buf, tm, depth)
	case t.IDFunc:
		buf = append(buf, "func "...)
		if r := n.Receiver(); r != nil {
			buf = append(buf, '(')
			buf = r.appendStr(buf, tm, depth)
			buf = append(buf, ")."...)
		}
		return append(buf, n.FuncName().Str(tm)...)
	default:
		return append(buf, "!invalid_type!"...)
	}
	if n.Min() != nil || n.Max() != nil {
		buf = append(buf, '[')
		buf = n.Min().appendStr(buf, tm, false, 0)
		buf = append(buf, ".."...)
		buf = n.Max().appendStr(buf, tm, false, 0)
		buf = append(buf, ']')
	}
	return buf
}
<commit_msg>Add token.IDXBinaryTildeModShiftL string form<commit_after>// Copyright 2017 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ast

import (
	t "github.com/google/wuffs/lang/token"
)

// Str returns a string form of n.
func (n *Expr) Str(tm *t.Map) string {
	if n == nil {
		return ""
	}
	if n.id0 == 0 && n.id1 == 0 {
		return tm.ByID(n.id2)
	}
	return string(n.appendStr(nil, tm, false, 0))
}

func (n *Expr) appendStr(buf []byte, tm *t.Map, parenthesize bool, depth uint32) []byte {
	if depth > MaxExprDepth {
		return append(buf, "!expr_recursion_depth_too_large!"...)
	}
	depth++

	if n == nil {
		return buf
	}

	if n.id0.IsXOp() {
		switch {
		case n.id0.IsXUnaryOp():
			buf = append(buf, opString(n.id0)...)
			buf = n.rhs.AsExpr().appendStr(buf, tm, true, depth)

		case n.id0.IsXBinaryOp():
			if parenthesize {
				buf = append(buf, '(')
			}
			buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
			buf = append(buf, opString(n.id0)...)
			if n.id0 == t.IDXBinaryAs {
				buf = append(buf, n.rhs.AsTypeExpr().Str(tm)...)
			} else {
				buf = n.rhs.AsExpr().appendStr(buf, tm, true, depth)
			}
			if parenthesize {
				buf = append(buf, ')')
			}

		case n.id0.IsXAssociativeOp():
			if parenthesize {
				buf = append(buf, '(')
			}
			op := opString(n.id0)
			for i, o := range n.list0 {
				if i != 0 {
					buf = append(buf, op...)
				}
				buf = o.AsExpr().appendStr(buf, tm, true, depth)
			}
			if parenthesize {
				buf = append(buf, ')')
			}
		}

	} else {
		switch n.id0 {
		case t.IDStatus:
			buf = append(buf, "status "...)
			if n.id1 != 0 {
				buf = append(buf, tm.ByID(n.id1)...)
				buf = append(buf, '.')
			}
			fallthrough

		case 0:
			buf = append(buf, tm.ByID(n.id2)...)

		case t.IDTry:
			buf = append(buf, "try "...)
			fallthrough

		case t.IDOpenParen:
			buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
			buf = append(buf, n.flags.AsEffect().String()...)
			buf = append(buf, '(')
			for i, o := range n.list0 {
				if i != 0 {
					buf = append(buf, ", "...)
				}
				buf = append(buf, tm.ByID(o.AsArg().Name())...)
				buf = append(buf, ':')
				buf = o.AsArg().Value().appendStr(buf, tm, false, depth)
			}
			buf = append(buf, ')')

		case t.IDOpenBracket:
			buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
			buf = append(buf, '[')
			buf = n.rhs.AsExpr().appendStr(buf, tm, false, depth)
			buf = append(buf, ']')

		case t.IDColon:
			buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
			buf = append(buf, '[')
			buf = n.mhs.AsExpr().appendStr(buf, tm, false, depth)
			buf = append(buf, ':')
			buf = n.rhs.AsExpr().appendStr(buf, tm, false, depth)
			buf = append(buf, ']')

		case t.IDDot:
			buf = n.lhs.AsExpr().appendStr(buf, tm, true, depth)
			buf = append(buf, '.')
			buf = append(buf, tm.ByID(n.id2)...)

		case t.IDComma:
			buf = append(buf, '[')
			for i, o := range n.list0 {
				if i != 0 {
					buf = append(buf, ", "...)
				}
				buf = o.AsExpr().appendStr(buf, tm, false, depth)
			}
			buf = append(buf, ']')
		}
	}

	return buf
}

func opString(x t.ID) string {
	if x < t.ID(len(opStrings)) {
		if s := opStrings[x]; s != "" {
			return s
		}
	}
	return " no_such_Wuffs_operator "
}

var opStrings = [...]string{
	t.IDXUnaryPlus:  "+",
	t.IDXUnaryMinus: "-",
	t.IDXUnaryNot:   "not ",
	t.IDXUnaryRef:   "ref ",
	t.IDXUnaryDeref: "deref ",

	t.IDXBinaryPlus:           " + ",
	t.IDXBinaryMinus:          " - ",
	t.IDXBinaryStar:           " * ",
	t.IDXBinarySlash:          " / ",
	t.IDXBinaryShiftL:         " << ",
	t.IDXBinaryShiftR:         " >> ",
	t.IDXBinaryAmp:            " & ",
	t.IDXBinaryPipe:           " | ",
	t.IDXBinaryHat:            " ^ ",
	t.IDXBinaryTildeModShiftL: " ~mod<< ",
	t.IDXBinaryTildeModPlus:   " ~mod+ ",
	t.IDXBinaryTildeModMinus:  " ~mod- ",
	t.IDXBinaryTildeSatPlus:   " ~sat+ ",
	t.IDXBinaryTildeSatMinus:  " ~sat- ",
	t.IDXBinaryNotEq:          " != ",
	t.IDXBinaryLessThan:       " < ",
	t.IDXBinaryLessEq:         " <= ",
	t.IDXBinaryEqEq:           " == ",
	t.IDXBinaryGreaterEq:      " >= ",
	t.IDXBinaryGreaterThan:    " > ",
	t.IDXBinaryAnd:            " and ",
	t.IDXBinaryOr:             " or ",
	t.IDXBinaryAs:             " as ",

	t.IDXAssociativePlus: " + ",
	t.IDXAssociativeStar: " * ",
	t.IDXAssociativeAmp:  " & ",
	t.IDXAssociativePipe: " | ",
	t.IDXAssociativeHat:  " ^ ",
	t.IDXAssociativeAnd:  " and ",
	t.IDXAssociativeOr:   " or ",
}

// Str returns a string form of n.
func (n *TypeExpr) Str(tm *t.Map) string {
	if n == nil {
		return ""
	}
	if n.Decorator() == 0 && n.Min() == nil && n.Max() == nil {
		return n.QID().Str(tm)
	}
	return string(n.appendStr(nil, tm, 0))
}

func (n *TypeExpr) appendStr(buf []byte, tm *t.Map, depth uint32) []byte {
	if depth > MaxTypeExprDepth {
		return append(buf, "!type_expr_recursion_depth_too_large!"...)
	}
	depth++
	if n == nil {
		return append(buf, "!invalid_type!"...)
	}

	switch n.Decorator() {
	case 0:
		buf = append(buf, n.QID().Str(tm)...)
	case t.IDNptr:
		buf = append(buf, "nptr "...)
		return n.Inner().appendStr(buf, tm, depth)
	case t.IDPtr:
		buf = append(buf, "ptr "...)
		return n.Inner().appendStr(buf, tm, depth)
	case t.IDArray:
		buf = append(buf, "array["...)
		buf = n.ArrayLength().appendStr(buf, tm, false, 0)
		buf = append(buf, "] "...)
		return n.Inner().appendStr(buf, tm, depth)
	case t.IDSlice:
		buf = append(buf, "slice "...)
		return n.Inner().appendStr(buf, tm, depth)
	case t.IDTable:
		buf = append(buf, "table "...)
		return n.Inner().appendStr(buf, tm, depth)
	case t.IDFunc:
		buf = append(buf, "func "...)
		if r := n.Receiver(); r != nil {
			buf = append(buf, '(')
			buf = r.appendStr(buf, tm, depth)
			buf = append(buf, ")."...)
		}
		return append(buf, n.FuncName().Str(tm)...)
	default:
		return append(buf, "!invalid_type!"...)
	}
	if n.Min() != nil || n.Max() != nil {
		buf = append(buf, '[')
		buf = n.Min().appendStr(buf, tm, false, 0)
		buf = append(buf, ".."...)
		buf = n.Max().appendStr(buf, tm, false, 0)
		buf = append(buf, ']')
	}
	return buf
}
<|endoftext|>


<commit_before>package otfc

import (
	"errors"
	"log"
	"os"
	"syscall"
	"unsafe"
)

var configPtr *Config
var configMmap []byte

// Initializes the config.
func Init(fileName string) (err error) {
	log.Printf("Config File: %s", fileName)
	mapFile, err := createFile(fileName, CONFIG_FILE_SIZE)
	//mapFile, err := os.Open(fileName)
	if err != nil {
		return
	}
	// mmap the config file.
	configMmap, err := syscall.Mmap(
		int(mapFile.Fd()),
		0,
		int(CONFIG_FILE_SIZE),
		syscall.PROT_READ|syscall.PROT_WRITE,
		syscall.MAP_SHARED)
	if err != nil {
		mapFile.Close()
		log.Printf("%s\n", err)
		return
	}
	// Make sure mmap gave us enough memory.
	if len(configMmap) < int(CONFIG_FILE_SIZE) {
		err = errors.New("Insufficient memmory")
		mapFile.Close()
		return
	}
	// Convert the byte array to Config struct type.
	configPtr = (*Config)(unsafe.Pointer(&configMmap[0]))

	if configPtr.header.Version() < uint16(1) {
		configPtr.header.SetVersion(uint16(CONFIG_VERSION))
	}
	return
}

func Shutdown() {
	if configPtr == nil {
		log.Println("Nil config patr. Nothing to shutdown")
		return
	}
	syscall.Munmap(configMmap)
}

func Print() {
	log.Println("\n==================================================\n")
	PrintHeaderBlock()
	PrintIndexBlock()
	log.Println("\n==================================================\n")
}

func PrintIndexBlock() {
	configPtr.index.print()
}

func PrintHeaderBlock() {
	configPtr.header.print()
}

func createFile(fileName string, size int32) (file *os.File, err error) {
	file, err = os.Create(fileName)
	if err != nil {
		return
	}
	_, err = file.Seek(int64(size), 0)
	if err != nil {
		log.Println(err)
		return
	}

	_, err = file.Write([]byte("x"))
	if err != nil {
		log.Println(err)
		return
	}
	return
}

func Set(key string, value []byte) error {
	return configPtr.set(key, value)
}

func Get(key string) ([]byte, error) {
	//val, _ := configPtr.get(key)
	//log.Printf("Value from config.get(%s): [%s]", key, val)
	return configPtr.get(key)
}

func Delete(key string) error {
	return configPtr.delete(key)
}
<commit_msg>[OTFC] Fix typo<commit_after>package otfc

import (
	"errors"
	"log"
	"os"
	"syscall"
	"unsafe"
)

var configPtr *Config
var configMmap []byte

// Initializes the config.
func Init(fileName string) (err error) {
	log.Printf("Config File: %s", fileName)
	mapFile, err := createFile(fileName, CONFIG_FILE_SIZE)
	//mapFile, err := os.Open(fileName)
	if err != nil {
		return
	}
	// mmap the config file.
	configMmap, err := syscall.Mmap(
		int(mapFile.Fd()),
		0,
		int(CONFIG_FILE_SIZE),
		syscall.PROT_READ|syscall.PROT_WRITE,
		syscall.MAP_SHARED)
	if err != nil {
		mapFile.Close()
		log.Printf("%s\n", err)
		return
	}
	// Make sure mmap gave us enough memory.
	if len(configMmap) < int(CONFIG_FILE_SIZE) {
		err = errors.New("Insufficient memmory")
		mapFile.Close()
		return
	}
	// Convert the byte array to Config struct type.
	configPtr = (*Config)(unsafe.Pointer(&configMmap[0]))

	if configPtr.header.Version() < uint16(1) {
		configPtr.header.SetVersion(uint16(CONFIG_VERSION))
	}
	return
}

func Shutdown() {
	if configPtr == nil {
		log.Println("Nil config pointer. Nothing to shutdown")
		return
	}
	syscall.Munmap(configMmap)
}

func Print() {
	log.Println("\n==================================================\n")
	PrintHeaderBlock()
	PrintIndexBlock()
	log.Println("\n==================================================\n")
}

func PrintIndexBlock() {
	configPtr.index.print()
}

func PrintHeaderBlock() {
	configPtr.header.print()
}

func createFile(fileName string, size int32) (file *os.File, err error) {
	file, err = os.Create(fileName)
	if err != nil {
		return
	}
	_, err = file.Seek(int64(size), 0)
	if err != nil {
		log.Println(err)
		return
	}

	_, err = file.Write([]byte("x"))
	if err != nil {
		log.Println(err)
		return
	}
	return
}

func Set(key string, value []byte) error {
	return configPtr.set(key, value)
}

func Get(key string) ([]byte, error) {
	//val, _ := configPtr.get(key)
	//log.Printf("Value from config.get(%s): [%s]", key, val)
	return configPtr.get(key)
}

func Delete(key string) error {
	return configPtr.delete(key)
}
<|endoftext|>


<commit_before>package lxc

import (
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/packer"
	"time"
	"log"
	"fmt"
	"errors"
	"strings"
)

type StepWaitInit struct {
	WaitTimeout time.Duration
}

func (s *StepWaitInit) Run(state multistep.StateBag) multistep.StepAction {
	ui := state.Get("ui").(packer.Ui)

	var err error

	cancel := make(chan struct{})
	waitDone := make(chan bool, 1)
	go func() {
		ui.Say("Waiting for container to finish init...")
		err = s.waitForInit(state, cancel)
		waitDone <- true
	}()

	log.Printf("Waiting for container to finish init, up to timeout: %s", s.WaitTimeout)
	timeout := time.After(s.WaitTimeout)
WaitLoop:
	for {
		select {
		case <-waitDone:
			if err != nil {
				ui.Error(fmt.Sprintf("Error waiting for container to finish init: %s", err))
				return multistep.ActionHalt
			}

			ui.Say("Container finished init!")
			break WaitLoop
		case <-timeout:
			err := fmt.Errorf("Timeout waiting for container to finish init.")
			state.Put("error", err)
			ui.Error(err.Error())
			close(cancel)
			return multistep.ActionHalt
		case <-time.After(1 * time.Second):
			if _, ok := state.GetOk(multistep.StateCancelled); ok {
				close(cancel)
				log.Println("Interrupt detected, quitting waiting for container to finish init.")
				return multistep.ActionHalt
			}
		}
	}

	return multistep.ActionContinue
}

func (s *StepWaitInit) Cleanup(multistep.StateBag) {
}

func (s *StepWaitInit) waitForInit(state multistep.StateBag, cancel <-chan struct{}) (error) {
	config := state.Get("config").(*Config)
	mountPath := state.Get("mount_path").(string)
	wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)

	for {
		select {
		case <-cancel:
			log.Println("Cancelled. Exiting loop.")
			return errors.New("Wait cancelled")
		case <-time.After(1 * time.Second):
		}

		comm := &LxcAttachCommunicator{
			ContainerName: config.ContainerName,
			RootFs:        mountPath,
			CmdWrapper:    wrappedCommand,
		}

		runlevel, _ := comm.CheckInit()
		currentRunlevel := strings.Split(runlevel, " ")[1]

		log.Printf("Current runlevel in container: '%s'", runlevel)

		targetRunlevel := fmt.Sprintf("%d", config.TemplateConfig.TargetRunlevel)
		if currentRunlevel == targetRunlevel {
			log.Printf("Container finished init.")
			break
		}

		/*log.Println("Attempting SSH connection...")
		comm, err = ssh.New(config)
		if err != nil {
			log.Printf("SSH handshake err: %s", err)

			// Only count this as an attempt if we were able to attempt
			// to authenticate. Note this is very brittle since it depends
			// on the string of the error... but I don't see any other way.
			if strings.Contains(err.Error(), "authenticate") {
				log.Printf("Detected authentication error. Increasing handshake attempts.")
				handshakeAttempts += 1
			}

			if handshakeAttempts < 10 {
				// Try to connect via SSH a handful of times
				continue
			}

			return nil, err
		}

		break
		*/
	}

	return nil
}
<commit_msg>Correct out of range issue if runlevel output doesn't have a space.<commit_after>package lxc

import (
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/packer"
	"time"
	"log"
	"fmt"
	"errors"
	"strings"
)

type StepWaitInit struct {
	WaitTimeout time.Duration
}

func (s *StepWaitInit) Run(state multistep.StateBag) multistep.StepAction {
	ui := state.Get("ui").(packer.Ui)

	var err error

	cancel := make(chan struct{})
	waitDone := make(chan bool, 1)
	go func() {
		ui.Say("Waiting for container to finish init...")
		err = s.waitForInit(state, cancel)
		waitDone <- true
	}()

	log.Printf("Waiting for container to finish init, up to timeout: %s", s.WaitTimeout)
	timeout := time.After(s.WaitTimeout)
WaitLoop:
	for {
		select {
		case <-waitDone:
			if err != nil {
				ui.Error(fmt.Sprintf("Error waiting for container to finish init: %s", err))
				return multistep.ActionHalt
			}

			ui.Say("Container finished init!")
			break WaitLoop
		case <-timeout:
			err := fmt.Errorf("Timeout waiting for container to finish init.")
			state.Put("error", err)
			ui.Error(err.Error())
			close(cancel)
			return multistep.ActionHalt
		case <-time.After(1 * time.Second):
			if _, ok := state.GetOk(multistep.StateCancelled); ok {
				close(cancel)
				log.Println("Interrupt detected, quitting waiting for container to finish init.")
				return multistep.ActionHalt
			}
		}
	}

	return multistep.ActionContinue
}

func (s *StepWaitInit) Cleanup(multistep.StateBag) {
}

func (s *StepWaitInit) waitForInit(state multistep.StateBag, cancel <-chan struct{}) (error) {
	config := state.Get("config").(*Config)
	mountPath := state.Get("mount_path").(string)
	wrappedCommand := state.Get("wrappedCommand").(CommandWrapper)

	for {
		select {
		case <-cancel:
			log.Println("Cancelled. Exiting loop.")
			return errors.New("Wait cancelled")
		case <-time.After(1 * time.Second):
		}

		comm := &LxcAttachCommunicator{
			ContainerName: config.ContainerName,
			RootFs:        mountPath,
			CmdWrapper:    wrappedCommand,
		}

		runlevel, _ := comm.CheckInit()
		currentRunlevel := "unknown"
		if arr := strings.Split(runlevel, " ") ; len(arr) >= 2 {
			currentRunlevel = arr[1]
		}

		log.Printf("Current runlevel in container: '%s'", runlevel)

		targetRunlevel := fmt.Sprintf("%d", config.TemplateConfig.TargetRunlevel)
		if currentRunlevel == targetRunlevel {
			log.Printf("Container finished init.")
			break
		}

		/*log.Println("Attempting SSH connection...")
		comm, err = ssh.New(config)
		if err != nil {
			log.Printf("SSH handshake err: %s", err)

			// Only count this as an attempt if we were able to attempt
			// to authenticate. Note this is very brittle since it depends
			// on the string of the error... but I don't see any other way.
			if strings.Contains(err.Error(), "authenticate") {
				log.Printf("Detected authentication error. Increasing handshake attempts.")
				handshakeAttempts += 1
			}

			if handshakeAttempts < 10 {
				// Try to connect via SSH a handful of times
				continue
			}

			return nil, err
		}

		break
		*/
	}

	return nil
}
<|endoftext|>


<commit_before>package vmware

import (
	"bytes"
	gossh "code.google.com/p/go.crypto/ssh"
	"encoding/csv"
	"errors"
	"fmt"
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/communicator/ssh"
	"github.com/mitchellh/packer/packer"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"syscall"
	"time"
)

type ESX5Driver struct {
	Host      string
	Port      uint
	Username  string
	Password  string
	Datastore string

	comm packer.Communicator
}

func (d *ESX5Driver) CompactDisk(diskPathLocal string) error {
	return nil
}

func (d *ESX5Driver) CreateDisk(diskPathLocal string, size string, typeId string) error {
	diskPath := d.datastorePath(diskPathLocal)
	return d.sh("vmkfstools", "-c", size, "-d", typeId, "-a", "lsilogic", diskPath)
}

func (d *ESX5Driver) IsRunning(vmxPathLocal string) (bool, error) {
	vmxPath := d.datastorePath(vmxPathLocal)
	state, err := d.run(nil, "vim-cmd", "vmsvc/power.getstate", vmxPath)
	if err != nil {
		return false, err
	}
	return strings.Contains(state, "Powered on"), nil
}

func (d *ESX5Driver) Start(vmxPathLocal string, headless bool) error {
	return d.sh("vim-cmd", "vmsvc/power.on", d.datastorePath(vmxPathLocal))
}

func (d *ESX5Driver) Stop(vmxPathLocal string) error {
	return d.sh("vim-cmd", "vmsvc/power.off", d.datastorePath(vmxPathLocal))
}

func (d *ESX5Driver) Register(vmxPathLocal string) error {
	vmxPath := d.datastorePath(vmxPathLocal)
	if err := d.upload(vmxPathLocal, vmxPath); err != nil {
		return err
	}
	return d.sh("vim-cmd", "solo/registervm", vmxPath)
}

func (d *ESX5Driver) Unregister(vmxPathLocal string) error {
	return d.sh("vim-cmd", "vmsvc/unregister", d.datastorePath(vmxPathLocal))
}

func (d *ESX5Driver) UploadISO(localPath string) (string, error) {
	cacheRoot, _ := filepath.Abs(".")
	targetFile, err := filepath.Rel(cacheRoot, localPath)
	if err != nil {
		return "", err
	}

	if err := d.MkdirAll(filepath.Dir(targetFile)); err != nil {
		return "", err
	}

	finalPath := d.datastorePath(targetFile)
	if err := d.upload(finalPath, localPath); err != nil {
		return "", err
	}

	return finalPath, nil
}

func (d *ESX5Driver) ToolsIsoPath(string) string {
	return ""
}

func (d *ESX5Driver) DhcpLeasesPath(string) string {
	return ""
}

func (d *ESX5Driver) Verify() error {
	checks := []func() error{
		d.connect,
		d.checkSystemVersion,
		d.checkGuestIPHackEnabled,
	}

	for _, check := range checks {
		if err := check(); err != nil {
			return err
		}
	}

	return nil
}

func (d *ESX5Driver) HostIP() (string, error) {
	ip := net.ParseIP(d.Host)
	interfaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}

	for _, dev := range interfaces {
		addrs, err := dev.Addrs()
		if err != nil {
			continue
		}
		for _, addr := range addrs {
			if ipnet, ok := addr.(*net.IPNet); ok {
				if ipnet.Contains(ip) {
					return ipnet.IP.String(), nil
				}
			}
		}
	}

	return "", errors.New("Unable to determine Host IP")
}

func (d *ESX5Driver) VNCAddress(portMin, portMax uint) (string, uint) {
	var vncPort uint
	// TODO(dougm) use esxcli network ip connection list
	for port := portMin; port <= portMax; port++ {
		address := fmt.Sprintf("%s:%d", d.Host, port)
		log.Printf("Trying address: %s...", address)
		l, err := net.DialTimeout("tcp", address, 1*time.Second)

		if err == nil {
			log.Printf("%s in use", address)
			l.Close()
		} else if e, ok := err.(*net.OpError); ok {
			if e.Err == syscall.ECONNREFUSED {
				// then port should be available for listening
				vncPort = port
				break
			} else if e.Timeout() {
				log.Printf("Timeout connecting to: %s (check firewall rules)", address)
			}
		}
	}

	return d.Host, vncPort
}

func (d *ESX5Driver) SSHAddress(state multistep.StateBag) (string, error) {
	config := state.Get("config").(*config)

	if address, ok := state.GetOk("vm_address"); ok {
		return address.(string), nil
	}

	r, err := d.esxcli("network", "vm", "list")
	if err != nil {
		return "", err
	}

	record, err := r.find("Name", config.VMName)
	if err != nil {
		return "", err
	}
	wid := record["WorldID"]
	if wid == "" {
		return "", errors.New("VM WorldID not found")
	}

	r, err = d.esxcli("network", "vm", "port", "list", "-w", wid)
	if err != nil {
		return "", err
	}

	record, err = r.read()
	if err != nil {
		return "", err
	}

	if record["IPAddress"] == "0.0.0.0" {
		return "", errors.New("VM network port found, but no IP address")
	}

	address := fmt.Sprintf("%s:%d", record["IPAddress"], config.SSHPort)
	state.Put("vm_address", address)
	return address, nil
}

func (d *ESX5Driver) DirExists(path string) (bool, error) {
	err := d.sh("test", "-e", d.datastorePath(path))
	return err == nil, err
}

func (d *ESX5Driver) MkdirAll(path string) error {
	return d.sh("mkdir", "-p", d.datastorePath(path))
}

func (d *ESX5Driver) RemoveAll(path string) error {
	return d.sh("rm", "-rf", d.datastorePath(path))
}

func (d *ESX5Driver) datastorePath(path string) string {
	return filepath.Join("/vmfs/volumes", d.Datastore, path)
}

func (d *ESX5Driver) connect() error {
	address := fmt.Sprintf("%s:%d", d.Host, d.Port)

	auth := []gossh.ClientAuth{
		gossh.ClientAuthPassword(ssh.Password(d.Password)),
		gossh.ClientAuthKeyboardInteractive(
			ssh.PasswordKeyboardInteractive(d.Password)),
	}

	// TODO(dougm) KeyPath support
	sshConfig := &ssh.Config{
		Connection: ssh.ConnectFunc("tcp", address),
		SSHConfig: &gossh.ClientConfig{
			User: d.Username,
			Auth: auth,
		},
		NoPty: true,
	}

	comm, err := ssh.New(sshConfig)
	if err != nil {
		return err
	}

	d.comm = comm
	return nil
}

func (d *ESX5Driver) checkSystemVersion() error {
	r, err := d.esxcli("system", "version", "get")
	if err != nil {
		return err
	}

	record, err := r.read()
	if err != nil {
		return err
	}

	log.Printf("Connected to %s %s %s", record["Product"],
		record["Version"], record["Build"])
	return nil
}

func (d *ESX5Driver) checkGuestIPHackEnabled() error {
	r, err := d.esxcli("system", "settings", "advanced", "list", "-o", "/Net/GuestIPHack")
	if err != nil {
		return err
	}

	record, err := r.read()
	if err != nil {
		return err
	}

	if record["IntValue"] != "1" {
		return errors.New("GuestIPHack is required, enable with:\n" +
			"esxcli system settings advanced set -o /Net/GuestIPHack -i 1")
	}

	return nil
}

func (d *ESX5Driver) upload(src, dst string) error {
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()
	return d.comm.Upload(dst, f)
}

func (d *ESX5Driver) verifyChecksum(ctype string, hash string, file string) bool {
	stdin := bytes.NewBufferString(fmt.Sprintf("%s  %s", hash, file))
	_, err := d.run(stdin, fmt.Sprintf("%ssum", ctype), "-c")
	if err != nil {
		return false
	}
	return true
}

func (d *ESX5Driver) ssh(command string, stdin io.Reader) (*bytes.Buffer, error) {
	var stdout, stderr bytes.Buffer

	cmd := &packer.RemoteCmd{
		Command: command,
		Stdout:  &stdout,
		Stderr:  &stderr,
		Stdin:   stdin,
	}

	err := d.comm.Start(cmd)
	if err != nil {
		return nil, err
	}

	cmd.Wait()

	if cmd.ExitStatus != 0 {
		err = fmt.Errorf("'%s'\n\nStdout: %s\n\nStderr: %s",
			cmd.Command, stdout.String(), stderr.String())
		return nil, err
	}

	return &stdout, nil
}

func (d *ESX5Driver) run(stdin io.Reader, args ...string) (string, error) {
	stdout, err := d.ssh(strings.Join(args, " "), stdin)
	if err != nil {
		return "", err
	}
	return stdout.String(), nil
}

func (d *ESX5Driver) sh(args ...string) error {
	_, err := d.run(nil, args...)
	return err
}

func (d *ESX5Driver) esxcli(args ...string) (*esxcliReader, error) {
	stdout, err := d.ssh("esxcli --formatter csv "+strings.Join(args, " "), nil)
	if err != nil {
		return nil, err
	}
	r := csv.NewReader(bytes.NewReader(stdout.Bytes()))
	r.TrailingComma = true
	header, err := r.Read()
	if err != nil {
		return nil, err
	}
	return &esxcliReader{r, header}, nil
}

type esxcliReader struct {
	cr     *csv.Reader
	header []string
}

func (r *esxcliReader) read() (map[string]string, error) {
	fields, err := r.cr.Read()

	if err != nil {
		return nil, err
	}

	record := map[string]string{}
	for i, v := range fields {
		record[r.header[i]] = v
	}

	return record, nil
}

func (r *esxcliReader) find(key, val string) (map[string]string, error) {
	for {
		record, err := r.read()
		if err != nil {
			return nil, err
		}
		if record[key] == val {
			return record, nil
		}
	}
}
<commit_msg>builder/vmware: esx file check works properly<commit_after>package vmware

import (
	"bytes"
	gossh "code.google.com/p/go.crypto/ssh"
	"encoding/csv"
	"errors"
	"fmt"
	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/communicator/ssh"
	"github.com/mitchellh/packer/packer"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"syscall"
	"time"
)

type ESX5Driver struct {
	Host      string
	Port      uint
	Username  string
	Password  string
	Datastore string

	comm packer.Communicator
}

func (d *ESX5Driver) CompactDisk(diskPathLocal string) error {
	return nil
}

func (d *ESX5Driver) CreateDisk(diskPathLocal string, size string, typeId string) error {
	diskPath := d.datastorePath(diskPathLocal)
	return d.sh("vmkfstools", "-c", size, "-d", typeId, "-a", "lsilogic", diskPath)
}

func (d *ESX5Driver) IsRunning(vmxPathLocal string) (bool, error) {
	vmxPath := d.datastorePath(vmxPathLocal)
	state, err := d.run(nil, "vim-cmd", "vmsvc/power.getstate", vmxPath)
	if err != nil {
		return false, err
	}
	return strings.Contains(state, "Powered on"), nil
}

func (d *ESX5Driver) Start(vmxPathLocal string, headless bool) error {
	return d.sh("vim-cmd", "vmsvc/power.on", d.datastorePath(vmxPathLocal))
}

func (d *ESX5Driver) Stop(vmxPathLocal string) error {
	return d.sh("vim-cmd", "vmsvc/power.off", d.datastorePath(vmxPathLocal))
}

func (d *ESX5Driver) Register(vmxPathLocal string) error {
	vmxPath := d.datastorePath(vmxPathLocal)
	if err := d.upload(vmxPathLocal, vmxPath); err != nil {
		return err
	}
	return d.sh("vim-cmd", "solo/registervm", vmxPath)
}

func (d *ESX5Driver) Unregister(vmxPathLocal string) error {
	return d.sh("vim-cmd", "vmsvc/unregister", d.datastorePath(vmxPathLocal))
}

func (d *ESX5Driver) UploadISO(localPath string) (string, error) {
	cacheRoot, _ := filepath.Abs(".")
	targetFile, err := filepath.Rel(cacheRoot, localPath)
	if err != nil {
		return "", err
	}

	if err := d.MkdirAll(filepath.Dir(targetFile)); err != nil {
		return "", err
	}

	finalPath := d.datastorePath(targetFile)
	if err := d.upload(finalPath, localPath); err != nil {
		return "", err
	}

	return finalPath, nil
}

func (d *ESX5Driver) ToolsIsoPath(string) string {
	return ""
}

func (d *ESX5Driver) DhcpLeasesPath(string) string {
	return ""
}

func (d *ESX5Driver) Verify() error {
	checks := []func() error{
		d.connect,
		d.checkSystemVersion,
		d.checkGuestIPHackEnabled,
	}

	for _, check := range checks {
		if err := check(); err != nil {
			return err
		}
	}

	return nil
}

func (d *ESX5Driver) HostIP() (string, error) {
	ip := net.ParseIP(d.Host)
	interfaces, err := net.Interfaces()
	if err != nil {
		return "", err
	}

	for _, dev := range interfaces {
		addrs, err := dev.Addrs()
		if err != nil {
			continue
		}
		for _, addr := range addrs {
			if ipnet, ok := addr.(*net.IPNet); ok {
				if ipnet.Contains(ip) {
					return ipnet.IP.String(), nil
				}
			}
		}
	}

	return "", errors.New("Unable to determine Host IP")
}

func (d *ESX5Driver) VNCAddress(portMin, portMax uint) (string, uint) {
	var vncPort uint
	// TODO(dougm) use esxcli network ip connection list
	for port := portMin; port <= portMax; port++ {
		address := fmt.Sprintf("%s:%d", d.Host, port)
		log.Printf("Trying address: %s...", address)
		l, err := net.DialTimeout("tcp", address, 1*time.Second)

		if err == nil {
			log.Printf("%s in use", address)
			l.Close()
		} else if e, ok := err.(*net.OpError); ok {
			if e.Err == syscall.ECONNREFUSED {
				// then port should be available for listening
				vncPort = port
				break
			} else if e.Timeout() {
				log.Printf("Timeout connecting to: %s (check firewall rules)", address)
			}
		}
	}

	return d.Host, vncPort
}

func (d *ESX5Driver) SSHAddress(state multistep.StateBag) (string, error) {
	config := state.Get("config").(*config)

	if address, ok := state.GetOk("vm_address"); ok {
		return address.(string), nil
	}

	r, err := d.esxcli("network", "vm", "list")
	if err != nil {
		return "", err
	}

	record, err := r.find("Name", config.VMName)
	if err != nil {
		return "", err
	}
	wid := record["WorldID"]
	if wid == "" {
		return "", errors.New("VM WorldID not found")
	}

	r, err = d.esxcli("network", "vm", "port", "list", "-w", wid)
	if err != nil {
		return "", err
	}

	record, err = r.read()
	if err != nil {
		return "", err
	}

	if record["IPAddress"] == "0.0.0.0" {
		return "", errors.New("VM network port found, but no IP address")
	}

	address := fmt.Sprintf("%s:%d", record["IPAddress"], config.SSHPort)
	state.Put("vm_address", address)
	return address, nil
}

func (d *ESX5Driver) DirExists(path string) (bool, error) {
	err := d.sh("test", "-e", d.datastorePath(path))
	return err == nil, nil
}

func (d *ESX5Driver) MkdirAll(path string) error {
	return d.sh("mkdir", "-p", d.datastorePath(path))
}

func (d *ESX5Driver) RemoveAll(path string) error {
	return d.sh("rm", "-rf", d.datastorePath(path))
}

func (d *ESX5Driver) datastorePath(path string) string {
	return filepath.Join("/vmfs/volumes", d.Datastore, path)
}

func (d *ESX5Driver) connect() error {
	address := fmt.Sprintf("%s:%d", d.Host, d.Port)

	auth := []gossh.ClientAuth{
		gossh.ClientAuthPassword(ssh.Password(d.Password)),
		gossh.ClientAuthKeyboardInteractive(
			ssh.PasswordKeyboardInteractive(d.Password)),
	}

	// TODO(dougm) KeyPath support
	sshConfig := &ssh.Config{
		Connection: ssh.ConnectFunc("tcp", address),
		SSHConfig: &gossh.ClientConfig{
			User: d.Username,
			Auth: auth,
		},
		NoPty: true,
	}

	comm, err := ssh.New(sshConfig)
	if err != nil {
		return err
	}

	d.comm = comm
	return nil
}

func (d *ESX5Driver) checkSystemVersion() error {
	r, err := d.esxcli("system", "version", "get")
	if err != nil {
		return err
	}

	record, err := r.read()
	if err != nil {
		return err
	}

	log.Printf("Connected to %s %s %s", record["Product"],
		record["Version"], record["Build"])
	return nil
}

func (d *ESX5Driver) checkGuestIPHackEnabled() error {
	r, err := d.esxcli("system", "settings", "advanced", "list", "-o", "/Net/GuestIPHack")
	if err != nil {
		return err
	}

	record, err := r.read()
	if err != nil {
		return err
	}

	if record["IntValue"] != "1" {
		return errors.New("GuestIPHack is required, enable with:\n" +
			"esxcli system settings advanced set -o /Net/GuestIPHack -i 1")
	}

	return nil
}

func (d *ESX5Driver) upload(src, dst string) error {
	f, err := os.Open(src)
	if err != nil {
		return err
	}
	defer f.Close()
	return d.comm.Upload(dst, f)
}

func (d *ESX5Driver) verifyChecksum(ctype string, hash string, file string) bool {
	stdin := bytes.NewBufferString(fmt.Sprintf("%s  %s", hash, file))
	_, err := d.run(stdin, fmt.Sprintf("%ssum", ctype), "-c")
	if err != nil {
		return false
	}
	return true
}

func (d *ESX5Driver) ssh(command string, stdin io.Reader) (*bytes.Buffer, error) {
	var stdout, stderr bytes.Buffer

	cmd := &packer.RemoteCmd{
		Command: command,
		Stdout:  &stdout,
		Stderr:  &stderr,
		Stdin:   stdin,
	}

	err := d.comm.Start(cmd)
	if err != nil {
		return nil, err
	}

	cmd.Wait()

	if cmd.ExitStatus != 0 {
		err = fmt.Errorf("'%s'\n\nStdout: %s\n\nStderr: %s",
			cmd.Command, stdout.String(), stderr.String())
		return nil, err
	}

	return &stdout, nil
}

func (d *ESX5Driver) run(stdin io.Reader, args ...string) (string, error) {
	stdout, err := d.ssh(strings.Join(args, " "), stdin)
	if err != nil {
		return "", err
	}
	return stdout.String(), nil
}

func (d *ESX5Driver) sh(args ...string) error {
	_, err := d.run(nil, args...)
	return err
}

func (d *ESX5Driver) esxcli(args ...string) (*esxcliReader, error) {
	stdout, err := d.ssh("esxcli --formatter csv "+strings.Join(args, " "), nil)
	if err != nil {
		return nil, err
	}
	r := csv.NewReader(bytes.NewReader(stdout.Bytes()))
	r.TrailingComma = true
	header, err := r.Read()
	if err != nil {
		return nil, err
	}
	return &esxcliReader{r, header}, nil
}

type esxcliReader struct {
	cr     *csv.Reader
	header []string
}

func (r *esxcliReader) read() (map[string]string, error) {
	fields, err := r.cr.Read()

	if err != nil {
		return nil, err
	}

	record := map[string]string{}
	for i, v := range fields {
		record[r.header[i]] = v
	}

	return record, nil
}

func (r *esxcliReader) find(key, val string) (map[string]string, error) {
	for {
		record, err := r.read()
		if err != nil {
			return nil, err
		}
		if record[key] == val {
			return record, nil
		}
	}
}
<|endoftext|>


<commit_before>// +build js,!windows

package syscall

import (
	"runtime"
	"sync"
	"unsafe"

	"github.com/gopherjs/gopherjs/js"
)

type sysret struct {
	r1, r2 uintptr
	err    Errno
}

var chans = sync.Pool{New: func() interface{} { return make(chan sysret) }}

func runtime_envs() []string {
	process := js.Global.Get("process")
	if process == js.Undefined {
		return nil
	}

	jsEnv := process.Get("env")
	if jsEnv == nil {
		ch := make(chan *js.Object, 0)
		process.Call("once", "ready", func(r *js.Object) {
			ch <- r
		})
		_ = <-ch
		jsEnv = process.Get("env")
	}

	envkeys := js.Global.Get("Object").Call("keys", jsEnv)
	envs := make([]string, envkeys.Length())
	for i := 0; i < envkeys.Length(); i++ {
		key := envkeys.Index(i).String()
		envs[i] = key + "=" + jsEnv.Get(key).String()
	}
	return envs
}

func setenv_c(k, v string) {
	process := js.Global.Get("process")
	if process != js.Undefined {
		process.Get("env").Set(k, v)
	}
}

var syscallModule *js.Object
var alreadyTriedToLoad = false
var minusOne = -1

func syscall(name string) *js.Object {
	defer func() {
		recover()
		// return nil if recovered
	}()
	if syscallModule == nil {
		if alreadyTriedToLoad {
			return nil
		}
		alreadyTriedToLoad = true
		require := js.Global.Get("require")
		if require == js.Undefined {
			panic("")
		}
		syscallModule = require.Invoke("syscall")
	}
	return syscallModule.Get(name)
}

func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	if f := syscall("Syscall"); f != nil {
		ch := chans.Get().(chan sysret)
		f.Invoke(func(r *js.Object) {
			ch <- sysret{uintptr(r.Index(0).Int()), uintptr(r.Index(1).Int()), Errno(r.Index(2).Int())}
		}, trap, a1, a2, a3)
		result := <-ch
		chans.Put(ch)
		return result.r1, result.r2, result.err
		// uintptr(r.Index(0).Int()), uintptr(r.Index(1).Int()), Errno(r.Index(2).Int())
	}
	if trap == SYS_EXIT {
		runtime.Goexit()
	}
	printWarning()
	return uintptr(minusOne), 0, EACCES
}

func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	if f := syscall("Syscall6"); f != nil {
		ch := chans.Get().(chan sysret)
		f.Invoke(func(r *js.Object) {
			ch <- sysret{uintptr(r.Index(0).Int()), uintptr(r.Index(1).Int()), Errno(r.Index(2).Int())}
		}, trap, a1, a2, a3, a4, a5, a6)
		result := <-ch
		chans.Put(ch)
		return result.r1, result.r2, result.err
	}
	if trap != 202 { // kern.osrelease on OS X, happens in init of "os" package
		printWarning()
	}
	return uintptr(minusOne), 0, EACCES
}

func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	return Syscall(trap, a1, a2, a3)
}

func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	return Syscall6(trap, a1, a2, a3, a4, a5, a6)
}

func BytePtrFromString(s string) (*byte, error) {
	array := js.Global.Get("Uint8Array").New(len(s) + 1)
	for i, b := range []byte(s) {
		if b == 0 {
			return nil, EINVAL
		}
		array.SetIndex(i, b)
	}
	array.SetIndex(len(s), 0)
	return (*byte)(unsafe.Pointer(array.Unsafe())), nil
}

func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
	var err1 Errno

	if attr == nil {
		attr = &zeroProcAttr
	}
	sys := attr.Sys
	if sys == nil {
		sys = &zeroSysProcAttr
	}

	// Convert args to C form.
	argv0p, err := BytePtrFromString(argv0)
	if err != nil {
		return 0, err
	}
	argvp, err := SlicePtrFromStrings(argv)
	if err != nil {
		return 0, err
	}
	envvp, err := SlicePtrFromStrings(attr.Env)
	if err != nil {
		return 0, err
	}

	if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) {
		argvp[0] = argv0p
	}

	var chroot *byte
	chroot, err = BytePtrFromString(sys.Chroot)
	if err != nil {
		return 0, err
	}
	var dir *byte
	dir, err = BytePtrFromString(attr.Dir)
	if err != nil {
		return 0, err
	}

	// Acquire the fork lock so that no other threads
	// create new fds that are not yet close-on-exec
	// before we fork.
	ForkLock.Lock()

	// Kick off child.
	pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, 0)
	if err1 != 0 {
		err = Errno(err1)
		goto error
	}
	ForkLock.Unlock()

	// Read got EOF, so pipe closed on exec, so exec succeeded.
	return pid, nil

error:
	ForkLock.Unlock()
	return 0, err
}

func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
	const SYS_SPAWN = 326

	sysPid, _, sysErr := RawSyscall6(
		SYS_SPAWN,
		uintptr(unsafe.Pointer(dir)),
		uintptr(unsafe.Pointer(argv0)),
		uintptr(unsafe.Pointer(&argv[0])),
		uintptr(unsafe.Pointer(&envv[0])),
		uintptr(unsafe.Pointer(&attr.Files[0])),
		uintptr(0),
	)

	return int(sysPid), Errno(sysErr)

	// 	// Declare all variables at top in case any
	// 	// declarations require heap allocation (e.g., err1).
	// 	var (
	// 		r1     uintptr
	// 		err1   Errno
	// 		err2   Errno
	// 		nextfd int
	// 		i      int
	// 		p      [2]int
	// 	)

	// 	// Record parent PID so child can test if it has died.
	// 	ppid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)

	// 	// Guard against side effects of shuffling fds below.
	// 	// Make sure that nextfd is beyond any currently open files so
	// 	// that we can't run the risk of overwriting any of them.
	// 	fd := make([]int, len(attr.Files))
	// 	nextfd = len(attr.Files)
	// 	for i, ufd := range attr.Files {
	// 		if nextfd < int(ufd) {
	// 			nextfd = int(ufd)
	// 		}
	// 		fd[i] = int(ufd)
	// 	}
	// 	nextfd++

	// 	// Allocate another pipe for parent to child communication for
	// 	// synchronizing writing of User ID/Group ID mappings.
	// 	if sys.UidMappings != nil || sys.GidMappings != nil {
	// 		if err := forkExecPipe(p[:]); err != nil {
	// 			return 0, err.(Errno)
	// 		}
	// 	}

	// 	// About to call fork.
	// 	// No more allocation or calls of non-assembly functions.
	// 	runtime_BeforeFork()
	// 	r1, _, err1 = RawSyscall6(SYS_CLONE, uintptr(SIGCHLD)|sys.Cloneflags, 0, 0, 0, 0, 0)
	// 	if err1 != 0 {
	// 		runtime_AfterFork()
	// 		return 0, err1
	// 	}

	// 	if r1 != 0 {
	// 		// parent; return PID
	// 		runtime_AfterFork()
	// 		pid = int(r1)

	// 		if sys.UidMappings != nil || sys.GidMappings != nil {
	// 			Close(p[0])
	// 			err := writeUidGidMappings(pid, sys)
	// 			if err != nil {
	// 				err2 = err.(Errno)
	// 			}
	// 			RawSyscall(SYS_WRITE, uintptr(p[1]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2))
	// 			Close(p[1])
	// 		}

	// 		return pid, 0
	// 	}

	// 	// Fork succeeded, now in child.

	// 	// Wait for User ID/Group ID mappings to be written.
	// 	if sys.UidMappings != nil || sys.GidMappings != nil {
	// 		if _, _, err1 = RawSyscall(SYS_CLOSE, uintptr(p[1]), 0, 0); err1 != 0 {
	// 			goto childerror
	// 		}
	// 		r1, _, err1 = RawSyscall(SYS_READ, uintptr(p[0]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2))
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 		if r1 != unsafe.Sizeof(err2) {
	// 			err1 = EINVAL
	// 			goto childerror
	// 		}
	// 		if err2 != 0 {
	// 			err1 = err2
	// 			goto childerror
	// 		}
	// 	}

	// 	// Enable tracing if requested.
	// 	if sys.Ptrace {
	// 		_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 	}

	// 	// Session ID
	// 	if sys.Setsid {
	// 		_, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 	}

	// 	// Set process group
	// 	if sys.Setpgid || sys.Foreground {
	// 		// Place child in process group.
	// 		_, _, err1 = RawSyscall(SYS_SETPGID, 0, uintptr(sys.Pgid), 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 	}

	// 	if sys.Foreground {
	// 		pgrp := int32(sys.Pgid)
	// 		if pgrp == 0 {
	// 			r1, _, err1 = RawSyscall(SYS_GETPID, 0, 0, 0)
	// 			if err1 != 0 {
	// 				goto childerror
	// 			}

	// 			pgrp = int32(r1)
	// 		}

	// 		// Place process group in foreground.
	// 		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 	}

	// 	// Chroot
	// 	if chroot != nil {
	// 		_, _, err1 = RawSyscall(SYS_CHROOT, uintptr(unsafe.Pointer(chroot)), 0, 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 	}

	// 	// User and groups
	// 	if cred := sys.Credential; cred != nil {
	// 		ngroups := uintptr(len(cred.Groups))
	// 		if ngroups > 0 {
	// 			groups := unsafe.Pointer(&cred.Groups[0])
	// 			_, _, err1 = RawSyscall(SYS_SETGROUPS, ngroups, uintptr(groups), 0)
	// 			if err1 != 0 {
	// 				goto childerror
	// 			}
	// 		}
	// 		_, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 		_, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 	}

	// 	// Chdir
	// 	if dir != nil {
	// 		_, _, err1 = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 	}

	// 	// Parent death signal
	// 	if sys.Pdeathsig != 0 {
	// 		_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}

	// 		// Signal self if parent is already dead. This might cause a
	// 		// duplicate signal in rare cases, but it won't matter when
	// 		// using SIGKILL.
	// 		r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
	// 		if r1 != ppid {
	// 			pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
	// 			_, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
	// 			if err1 != 0 {
	// 				goto childerror
	// 			}
	// 		}
	// 	}

	// 	// Pass 1: look for fd[i] < i and move those up above len(fd)
	// 	// so that pass 2 won't stomp on an fd it needs later.
	// 	if pipe < nextfd {
	// 		_, _, err1 = RawSyscall(_SYS_dup, uintptr(pipe), uintptr(nextfd), 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 		RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
	// 		pipe = nextfd
	// 		nextfd++
	// 	}
	// 	for i = 0; i < len(fd); i++ {
	// 		if fd[i] >= 0 && fd[i] < int(i) {
	// 			_, _, err1 = RawSyscall(_SYS_dup, uintptr(fd[i]), uintptr(nextfd), 0)
	// 			if err1 != 0 {
	// 				goto childerror
	// 			}
	// 			RawSyscall(SYS_FCNTL, uintptr(nextfd), F_SETFD, FD_CLOEXEC)
	// 			fd[i] = nextfd
	// 			nextfd++
	// 			if nextfd == pipe { // don't stomp on pipe
	// 				nextfd++
	// 			}
	// 		}
	// 	}

	// 	// Pass 2: dup fd[i] down onto i.
	// 	for i = 0; i < len(fd); i++ {
	// 		if fd[i] == -1 {
	// 			RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
	// 			continue
	// 		}
	// 		if fd[i] == int(i) {
	// 			// dup2(i, i) won't clear close-on-exec flag on Linux,
	// 			// probably not elsewhere either.
	// 			_, _, err1 = RawSyscall(SYS_FCNTL, uintptr(fd[i]), F_SETFD, 0)
	// 			if err1 != 0 {
	// 				goto childerror
	// 			}
	// 			continue
	// 		}
	// 		// The new fd is created NOT close-on-exec,
	// 		// which is exactly what we want.
	// 		_, _, err1 = RawSyscall(_SYS_dup, uintptr(fd[i]), uintptr(i), 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 	}

	// 	// By convention, we don't close-on-exec the fds we are
	// 	// started with, so if len(fd) < 3, close 0, 1, 2 as needed.
	// 	// Programs that know they inherit fds >= 3 will need
	// 	// to set them close-on-exec.
	// 	for i = len(fd); i < 3; i++ {
	// 		RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
	// 	}

	// 	// Detach fd 0 from tty
	// 	if sys.Noctty {
	// 		_, _, err1 = RawSyscall(SYS_IOCTL, 0, uintptr(TIOCNOTTY), 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 	}

	// 	// Set the controlling TTY to Ctty
	// 	if sys.Setctty {
	// 		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
	// 		if err1 != 0 {
	// 			goto childerror
	// 		}
	// 	}

	// 	// Time to exec.
	// 	_, _, err1 = RawSyscall(SYS_EXECVE,
	// 		uintptr(unsafe.Pointer(argv0)),
	// 		uintptr(unsafe.Pointer(&argv[0])),
	// 		uintptr(unsafe.Pointer(&envv[0])))

	// childerror:
	// 	// send error code on pipe
	// 	RawSyscall(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
	// 	for {
	// 		RawSyscall(SYS_EXIT, 253, 0, 0)
	// 	}
}
<commit_msg>compiler/natives/syscall: remove commented out code from fork<commit_after>// +build js,!windows

package syscall

import (
	"runtime"
	"sync"
	"unsafe"

	"github.com/gopherjs/gopherjs/js"
)

type sysret struct {
	r1, r2 uintptr
	err    Errno
}

var chans = sync.Pool{New: func() interface{} { return make(chan sysret) }}

func runtime_envs() []string {
	process := js.Global.Get("process")
	if process == js.Undefined {
		return nil
	}

	jsEnv := process.Get("env")
	if jsEnv == nil {
		ch := make(chan *js.Object, 0)
		process.Call("once", "ready", func(r *js.Object) {
			ch <- r
		})
		_ = <-ch
		jsEnv = process.Get("env")
	}

	envkeys := js.Global.Get("Object").Call("keys", jsEnv)
	envs := make([]string, envkeys.Length())
	for i := 0; i < envkeys.Length(); i++ {
		key := envkeys.Index(i).String()
		envs[i] = key + "=" + jsEnv.Get(key).String()
	}
	return envs
}

func setenv_c(k, v string) {
	process := js.Global.Get("process")
	if process != js.Undefined {
		process.Get("env").Set(k, v)
	}
}

var syscallModule *js.Object
var alreadyTriedToLoad = false
var minusOne = -1

func syscall(name string) *js.Object {
	defer func() {
		recover()
		// return nil if recovered
	}()
	if syscallModule == nil {
		if alreadyTriedToLoad {
			return nil
		}
		alreadyTriedToLoad = true
		require := js.Global.Get("require")
		if require == js.Undefined {
			panic("")
		}
		syscallModule = require.Invoke("syscall")
	}
	return syscallModule.Get(name)
}

func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	if f := syscall("Syscall"); f != nil {
		ch := chans.Get().(chan sysret)
		f.Invoke(func(r *js.Object) {
			ch <- sysret{uintptr(r.Index(0).Int()), uintptr(r.Index(1).Int()), Errno(r.Index(2).Int())}
		}, trap, a1, a2, a3)
		result := <-ch
		chans.Put(ch)
		return result.r1, result.r2, result.err
		// uintptr(r.Index(0).Int()), uintptr(r.Index(1).Int()), Errno(r.Index(2).Int())
	}
	if trap == SYS_EXIT {
		runtime.Goexit()
	}
	printWarning()
	return uintptr(minusOne), 0, EACCES
}

func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	if f := syscall("Syscall6"); f != nil {
		ch := chans.Get().(chan sysret)
		f.Invoke(func(r *js.Object) {
			ch <- sysret{uintptr(r.Index(0).Int()), uintptr(r.Index(1).Int()), Errno(r.Index(2).Int())}
		}, trap, a1, a2, a3, a4, a5, a6)
		result := <-ch
		chans.Put(ch)
		return result.r1, result.r2, result.err
	}
	if trap != 202 { // kern.osrelease on OS X, happens in init of "os" package
		printWarning()
	}
	return uintptr(minusOne), 0, EACCES
}

func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
	return Syscall(trap, a1, a2, a3)
}

func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
	return Syscall6(trap, a1, a2, a3, a4, a5, a6)
}

func BytePtrFromString(s string) (*byte, error) {
	array := js.Global.Get("Uint8Array").New(len(s) + 1)
	for i, b := range []byte(s) {
		if b == 0 {
			return nil, EINVAL
		}
		array.SetIndex(i, b)
	}
	array.SetIndex(len(s), 0)
	return (*byte)(unsafe.Pointer(array.Unsafe())), nil
}

func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
	var err1 Errno

	if attr == nil {
		attr = &zeroProcAttr
	}
	sys := attr.Sys
	if sys == nil {
		sys = &zeroSysProcAttr
	}

	// Convert args to C form.
	argv0p, err := BytePtrFromString(argv0)
	if err != nil {
		return 0, err
	}
	argvp, err := SlicePtrFromStrings(argv)
	if err != nil {
		return 0, err
	}
	envvp, err := SlicePtrFromStrings(attr.Env)
	if err != nil {
		return 0, err
	}

	if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) {
		argvp[0] = argv0p
	}

	var chroot *byte
	chroot, err = BytePtrFromString(sys.Chroot)
	if err != nil {
		return 0, err
	}
	var dir *byte
	dir, err = BytePtrFromString(attr.Dir)
	if err != nil {
		return 0, err
	}

	// Acquire the fork lock so that no other threads
	// create new fds that are not yet close-on-exec
	// before we fork.
	ForkLock.Lock()

	// Kick off child.
	pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, 0)
	if err1 != 0 {
		err = Errno(err1)
		goto error
	}
	ForkLock.Unlock()

	// Read got EOF, so pipe closed on exec, so exec succeeded.
	return pid, nil

error:
	ForkLock.Unlock()
	return 0, err
}

func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
	const SYS_SPAWN = 326

	sysPid, _, sysErr := RawSyscall6(
		SYS_SPAWN,
		uintptr(unsafe.Pointer(dir)),
		uintptr(unsafe.Pointer(argv0)),
		uintptr(unsafe.Pointer(&argv[0])),
		uintptr(unsafe.Pointer(&envv[0])),
		uintptr(unsafe.Pointer(&attr.Files[0])),
		uintptr(0),
	)

	return int(sysPid), Errno(sysErr)
}
<|endoftext|>


<commit_before>package dinghy

import (
	"appengine"
	"appengine/datastore"
	"appengine/memcache"
	"encoding/xml"
	"net/http"
	"strconv"
	"time"
)

type RawFeed struct {
	XML  []byte    `datastore:",noindex"`
	Date time.Time `datastore:",noindex"`
}

type Feed struct {
	XMLName     xml.Name `xml:"feed"`
	Xmlns       string   `xml:"xmlns,attr"`
	Title       string   `xml:"title"`
	Id          string   `xml:"id"`
	Updated     string   `xml:"updated"`
	Links       *[]Link
	Author      *Author
	Entries     *[]Entry
}

type Entry struct {
	XMLName     xml.Name  `xml:"entry"`
	Title       string    `xml:"title"`
	Summary     string    `xml:"summary,omitempty"`
	Id          string    `xml:"id"`
	Updated     string    `xml:"updated"`
	Links       *[]Link
	Content     *Content
}

type Author struct {
	XMLName     xml.Name `xml:"author"`
	Name        string   `xml:"name"`
}

type Link struct {
	XMLName     xml.Name `xml:"link"`
	Rel         string   `xml:"rel,attr"`
	Href        string   `xml:"href,attr"`
	Title       string   `xml:"title,attr,omitempty"`
}

type Content struct {
	XMLName     xml.Name `xml:"content"`
	Type        string   `xml:"type,attr"`
	Content     string   `xml:",chardata"`
}

/*
 *  Feed returns an atom feed of the most recent 10 posts. We attempt to use
 *  memcache first, then the Feed datastore singleton, before generating one
 *  from scratch. The latter is very expensive, as it results in multiple calls
 *  to the datastore to query each post, and to convert the content markdown to
 *  escaped HTML.
 */
func feed(w http.ResponseWriter, r *http.Request) {
	c   := appengine.NewContext(r)
	raw := RawFeed {}
	now := time.Now()

	// If feed is in memcache, return it directly (new posts flush memcache)
	item, err := memcache.Get(c, "feed.atom")
	if err == nil {
		writeXML(item.Value, w)
		return
	}

	// If feed is in datastore and date >= most recent post date, return datastore feed

	l, err := lastPostDate(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	k := datastore.NewKey(c, "Feed", "singleton", 0, nil)
	err = datastore.Get(c, k, &raw);
	if err != nil && err != datastore.ErrNoSuchEntity {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if err == nil && raw.Date.After(l) {
		cacheOutput(c, raw.XML)
		writeXML(raw.XML, w)
		return
	}

	// Otherwise, generate feed from posts, write to datastore, memcache, and response writer
	host := appengine.DefaultVersionHostname(c)
	b, err := getBlogInfo(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	f := Feed {
		Xmlns:   "http://www.w3.org/2005/Atom",
		Title:   b.Title,
		Id:      "tag:" + host + ",2013:dinghyBlog",
		Updated: now.Format("2006-01-02T15:04:05.000-0700"),
		Author:  &Author{ Name: b.Author },
		Links:   &[]Link{
			Link{ Rel: "self", Href: "http://" + host + "/atom.xml" },
			Link{ Rel: "alternate", Href: "http://" + host + "/" },
		},
	}

	p, err := getRecentPosts(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	entries := make([]Entry, len(p))
	for i := 0; i < len(p); i++ {
		idStr := strconv.FormatInt(p[i].ID, 10)
		post, _ := getPost(idStr, c)
		entries[i] = Entry{
			Title:    post.Title,
			Summary:  post.Description,
			Id:       f.Id + ".post-" + idStr,
			Updated:  post.Date.Format("2006-01-02T15:04:05.000-0700"),
			Links:    &[]Link{
				Link{Rel: "alternate", Href: "http://" + host + "/" + idStr, Title: post.Title},
			},
			Content: &Content{Content: markdown(post.Lead, post.Content), Type: "html"},
		}
	}
	f.Entries = &entries

	output, err := xml.MarshalIndent(f, "", "    ")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Write output to datastore
	raw.XML = output
	raw.Date = now
	k = datastore.NewKey(c, "Feed", "singleton", 0, nil)
	_, err = datastore.Put(c, k, &raw)

	// If we can't write to the datastore, stop. This will prevent clients from
	// seeing updates with the same contents but different timestamps, which
	// may cause duplicate updates in readers.
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// ...and to memcache
	cacheOutput(c, output)

	// ...and to HTTP caller
	writeXML(output, w)
}

func cacheOutput(c appengine.Context, output []byte) {
	item := &memcache.Item {
	   Key: "feed.atom",
	   Value: output,
	}
	memcache.Set(c, item)
}

func writeXML(buffer []byte, w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/atom+xml")
	w.Write([]byte(xml.Header))
	w.Write(buffer)
}

func lastPostDate(c appengine.Context) (time.Time, error) {
	p := make([]Post, 0, 1)
	q := datastore.NewQuery("Post").Order("-Date").Limit(1)
	q = q.Filter("Hidden =", false);
	q = q.Project("Date")
	_, err := q.GetAll(c, &p)
	t := p[0].Date

	return t, err
}
<commit_msg>Corrected timestamp format (GAE servers are UTC, Zulu indicator needed)<commit_after>package dinghy

import (
	"appengine"
	"appengine/datastore"
	"appengine/memcache"
	"encoding/xml"
	"net/http"
	"strconv"
	"time"
)

type RawFeed struct {
	XML  []byte    `datastore:",noindex"`
	Date time.Time `datastore:",noindex"`
}

type Feed struct {
	XMLName     xml.Name `xml:"feed"`
	Xmlns       string   `xml:"xmlns,attr"`
	Title       string   `xml:"title"`
	Id          string   `xml:"id"`
	Updated     string   `xml:"updated"`
	Links       *[]Link
	Author      *Author
	Entries     *[]Entry
}

type Entry struct {
	XMLName     xml.Name  `xml:"entry"`
	Title       string    `xml:"title"`
	Summary     string    `xml:"summary,omitempty"`
	Id          string    `xml:"id"`
	Updated     string    `xml:"updated"`
	Links       *[]Link
	Content     *Content
}

type Author struct {
	XMLName     xml.Name `xml:"author"`
	Name        string   `xml:"name"`
}

type Link struct {
	XMLName     xml.Name `xml:"link"`
	Rel         string   `xml:"rel,attr"`
	Href        string   `xml:"href,attr"`
	Title       string   `xml:"title,attr,omitempty"`
}

type Content struct {
	XMLName     xml.Name `xml:"content"`
	Type        string   `xml:"type,attr"`
	Content     string   `xml:",chardata"`
}

/*
 *  Feed returns an atom feed of the most recent 10 posts. We attempt to use
 *  memcache first, then the Feed datastore singleton, before generating one
 *  from scratch. The latter is very expensive, as it results in multiple calls
 *  to the datastore to query each post, and to convert the content markdown to
 *  escaped HTML.
 */
func feed(w http.ResponseWriter, r *http.Request) {
	c   := appengine.NewContext(r)
	raw := RawFeed {}
	now := time.Now()

	// If feed is in memcache, return it directly (new posts flush memcache)
	item, err := memcache.Get(c, "feed.atom")
	if err == nil {
		writeXML(item.Value, w)
		return
	}

	// If feed is in datastore and date >= most recent post date, return datastore feed

	l, err := lastPostDate(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	k := datastore.NewKey(c, "Feed", "singleton", 0, nil)
	err = datastore.Get(c, k, &raw);
	if err != nil && err != datastore.ErrNoSuchEntity {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if err == nil && raw.Date.After(l) {
		cacheOutput(c, raw.XML)
		writeXML(raw.XML, w)
		return
	}

	// Otherwise, generate feed from posts, write to datastore, memcache, and response writer
	host := appengine.DefaultVersionHostname(c)
	b, err := getBlogInfo(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	f := Feed {
		Xmlns:   "http://www.w3.org/2005/Atom",
		Title:   b.Title,
		Id:      "tag:" + host + ",2013:dinghyBlog",
		Updated: now.Format("2006-01-02T15:04:05.000Z"),
		Author:  &Author{ Name: b.Author },
		Links:   &[]Link{
			Link{ Rel: "self", Href: "http://" + host + "/atom.xml" },
			Link{ Rel: "alternate", Href: "http://" + host + "/" },
		},
	}

	p, err := getRecentPosts(c)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	entries := make([]Entry, len(p))
	for i := 0; i < len(p); i++ {
		idStr := strconv.FormatInt(p[i].ID, 10)
		post, _ := getPost(idStr, c)
		entries[i] = Entry{
			Title:    post.Title,
			Summary:  post.Description,
			Id:       f.Id + ".post-" + idStr,
			Updated:  post.Date.Format("2006-01-02T15:04:05.000Z"),
			Links:    &[]Link{
				Link{Rel: "alternate", Href: "http://" + host + "/" + idStr, Title: post.Title},
			},
			Content: &Content{Content: markdown(post.Lead, post.Content), Type: "html"},
		}
	}
	f.Entries = &entries

	output, err := xml.MarshalIndent(f, "", "    ")
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// Write output to datastore
	raw.XML = output
	raw.Date = now
	k = datastore.NewKey(c, "Feed", "singleton", 0, nil)
	_, err = datastore.Put(c, k, &raw)

	// If we can't write to the datastore, stop. This will prevent clients from
	// seeing updates with the same contents but different timestamps, which
	// may cause duplicate updates in readers.
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	// ...and to memcache
	cacheOutput(c, output)

	// ...and to HTTP caller
	writeXML(output, w)
}

func cacheOutput(c appengine.Context, output []byte) {
	item := &memcache.Item {
	   Key: "feed.atom",
	   Value: output,
	}
	memcache.Set(c, item)
}

func writeXML(buffer []byte, w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/atom+xml")
	w.Write([]byte(xml.Header))
	w.Write(buffer)
}

func lastPostDate(c appengine.Context) (time.Time, error) {
	p := make([]Post, 0, 1)
	q := datastore.NewQuery("Post").Order("-Date").Limit(1)
	q = q.Filter("Hidden =", false);
	q = q.Project("Date")
	_, err := q.GetAll(c, &p)
	t := p[0].Date

	return t, err
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/chrisseto/pty"
	"github.com/chrisseto/sux/pansi"
	"github.com/nsf/termbox-go"
	"io"
	"os"
	"os/exec"
)

type Pane struct {
	*exec.Cmd

	cx, cy        int
	sx, sy        int
	fg, bg        termbox.Attribute
	width, height uint16
	scrollOffset  int

	Prog string
	Args []string

	Pty    *os.File
	output io.Reader
	cells  [][]termbox.Cell
}

func CreatePane(width, height uint16, prog string, args ...string) *Pane {
	return &Pane{
		Cmd: exec.Command(prog, args...),
		cx:  0, cy: 0,
		sx: 0, sy: 0,
		fg: 0, bg: 0,
		scrollOffset: 0,
		Prog:         prog, Args: args,
		width: width, height: height,
		Pty: nil,
	}
}

func (p *Pane) Start() error {
	pterm, err := pty.Start(p.Cmd)
	if err != nil {
		panic(err)
	}
	if err = pty.Setsize(pterm, p.height, p.width); err != nil {
		panic(err)
	}
	p.Pty = pterm
	p.cells = make([][]termbox.Cell, 1, p.height)
	p.cells[0] = make([]termbox.Cell, p.width)
	go p.outputPipe()
	return nil
}

func (p *Pane) Close() error {
	return p.Process.Kill()
}

func (p *Pane) Cells() [][]termbox.Cell {
	if offset := len(p.cells) + p.scrollOffset - int(p.height); offset > 0 {
		return p.cells[offset:]
	}
	return p.cells
}

func (p *Pane) Width() uint16 {
	return p.width
}

func (p *Pane) Height() uint16 {
	return p.height
}

func (p *Pane) Scroll(far int) {
	p.scrollOffset += far
	select {
	case Redraw <- struct{}{}:
	default: //Failed to send, a redraw is already happening
	}
}

func (p *Pane) Redraw() {
	for y, line := range p.Cells() {
		for x, cell := range line {
			termbox.SetCell(x, y, cell.Ch, cell.Fg, cell.Bg)
		}
	}
	termbox.SetCursor(p.Cursor())
}

func (p *Pane) Cursor() (int, int) {
	return p.cx, p.cy
}

func (p *Pane) outputPipe() {
	parser := pansi.NewParser()
	buf := make([]byte, 32*1024)
	for {
		nr, err := p.Pty.Read(buf)
		if nr > 0 {
			row := &p.cells[p.sy]

			for _, char := range buf[:nr] {
				parser.Feed(char)
				if parser.State() != nil {
					continue
				}
				if res := parser.Result(); res != nil {
					p.handleEscapeCode(res)
					parser.Clear()
					continue
				}

				switch char {
				case 0x7: //Terminal Bell. Skip for the moment
				case 0xA:
					p.sy++
					p.cy++
					p.cells = append(p.cells, make([]termbox.Cell, p.width))
					row = &p.cells[p.sy]
				case 0xD:
					p.sx = 0
					p.cx = 0
				case 0x8:
					p.sx--
					p.cx--
					(*row)[p.sx] = termbox.Cell{' ', p.fg, p.bg}
				default:
					(*row)[p.sx] = termbox.Cell{rune(char), p.fg, p.bg}
					p.sx++
					p.cx++
				}
			}

			Redraw <- struct{}{}
		}
		if err != nil {
			if err == io.EOF {
				break
			}
			panic(err)
		}

	}
}

func (p *Pane) handleEscapeCode(c *pansi.AnsiEscapeCode) {
	switch c.Type {
	case pansi.SetGraphicMode:
		p.SetGraphicMode(c.Values)
	case pansi.CursorPosition:
		p.cx, p.cy = c.Values[1], c.Values[2]
	case pansi.CursorUp:
		p.cy--
	case pansi.CursorDown:
		p.cy++
	case pansi.CursorBackward:
		p.cx--
	case pansi.CursorForward:
		p.cx++
	case pansi.EraseLine:
		row := &p.cells[p.sy]
		for i := p.cx; i < len(*row); i++ {
			(*row)[i] = termbox.Cell{' ', p.fg, p.bg}
		}
	}
}

func (p *Pane) SetGraphicMode(vals []int) {
	for i := 0; i < len(vals); i++ {
		switch vals[i] {
		case 0:
			p.fg, p.bg = 0, 0
		case 1:
			p.fg |= termbox.AttrBold
		case 38:
			i++
			switch vals[i] {
			case 5:
				i++
				p.fg = termbox.Attribute(vals[i] + 1)
			case 2:
				i += 3 //TODO
			}
		case 48:
			i++
			switch vals[i] {
			case 5:
				i++
				p.bg = termbox.Attribute(vals[i] + 1)
			case 2:
				i += 3 //TODO
			}
		}
	}
}
<commit_msg>Update to use the latest parser api<commit_after>package main

import (
	"github.com/chrisseto/pty"
	"github.com/chrisseto/sux/pansi"
	"github.com/nsf/termbox-go"
	"io"
	"os"
	"os/exec"
)

type Pane struct {
	*exec.Cmd

	cx, cy        int
	sx, sy        int
	fg, bg        termbox.Attribute
	width, height uint16
	scrollOffset  int

	Prog string
	Args []string

	Pty    *os.File
	output io.Reader
	cells  [][]termbox.Cell
}

func CreatePane(width, height uint16, prog string, args ...string) *Pane {
	return &Pane{
		Cmd: exec.Command(prog, args...),
		cx:  0, cy: 0,
		sx: 0, sy: 0,
		fg: 0, bg: 0,
		scrollOffset: 0,
		Prog:         prog, Args: args,
		width: width, height: height,
		Pty: nil,
	}
}

func (p *Pane) Start() error {
	pterm, err := pty.Start(p.Cmd)
	if err != nil {
		panic(err)
	}
	if err = pty.Setsize(pterm, p.height, p.width); err != nil {
		panic(err)
	}
	p.Pty = pterm
	p.cells = make([][]termbox.Cell, 1, p.height)
	p.cells[0] = make([]termbox.Cell, p.width)
	go p.outputPipe()
	return nil
}

func (p *Pane) Close() error {
	return p.Process.Kill()
}

func (p *Pane) Cells() [][]termbox.Cell {
	if offset := len(p.cells) + p.scrollOffset - int(p.height); offset > 0 {
		return p.cells[offset:]
	}
	return p.cells
}

func (p *Pane) Width() uint16 {
	return p.width
}

func (p *Pane) Height() uint16 {
	return p.height
}

func (p *Pane) Scroll(far int) {
	p.scrollOffset += far
	select {
	case Redraw <- struct{}{}:
	default: //Failed to send, a redraw is already happening
	}
}

func (p *Pane) Redraw() {
	for y, line := range p.Cells() {
		for x, cell := range line {
			termbox.SetCell(x, y, cell.Ch, cell.Fg, cell.Bg)
		}
	}
	termbox.SetCursor(p.Cursor())
}

func (p *Pane) Cursor() (int, int) {
	return p.cx, p.cy
}

func (p *Pane) outputPipe() {
	lexer := pansi.NewLexer()
	buf := make([]byte, 32*1024)
	// f, _ := os.Create("output.log")
	for {
		nr, err := p.Pty.Read(buf)
		if nr > 0 {
			row := &p.cells[p.sy]
			// f.Write(buf[:nr])

			for _, char := range buf[:nr] {
				lexer.Feed(char)
				if lexer.State() != pansi.Ground {
					continue
				}
				if res := lexer.Result(); res != nil {
					p.handleEscapeCode(res)
					lexer.Clear()
					continue
				}

				switch char {
				case 0x7: //Terminal Bell. Skip for the moment
				case 0xA:
					p.sy++
					p.cy++
					p.cells = append(p.cells, make([]termbox.Cell, p.width))
					row = &p.cells[p.sy]
				case 0xD:
					p.sx = 0
					p.cx = 0
				case 0x8:
					p.sx--
					p.cx--
					(*row)[p.sx] = termbox.Cell{' ', p.fg, p.bg}
				default:
					(*row)[p.sx] = termbox.Cell{rune(char), p.fg, p.bg}
					p.sx++
					p.cx++
				}
			}

			Redraw <- struct{}{}
		}
		if err != nil {
			if err == io.EOF {
				break
			}
			panic(err)
		}

	}
}

func (p *Pane) handleEscapeCode(c *pansi.AnsiEscapeCode) {
	switch c.Type {
	case pansi.SetGraphicMode:
		p.SetGraphicMode(c.Values)
	case pansi.CursorPosition:
		p.cx, p.cy = c.Values[1], c.Values[2]
	case pansi.CursorUp:
		p.cy--
	case pansi.CursorDown:
		p.cy++
	case pansi.CursorBackward:
		p.cx--
	case pansi.CursorForward:
		p.cx++
	case pansi.EraseLine:
		row := &p.cells[p.sy]
		for i := p.cx; i < len(*row); i++ {
			(*row)[i] = termbox.Cell{' ', p.fg, p.bg}
		}
	}
}

func (p *Pane) SetGraphicMode(vals []int) {
	for i := 0; i < len(vals); i++ {
		switch vals[i] {
		case 0:
			p.fg, p.bg = 0, 0
		case 1:
			p.fg |= termbox.AttrBold
		case 38:
			i++
			switch vals[i] {
			case 5:
				i++
				p.fg = termbox.Attribute(vals[i] + 1)
			case 2:
				i += 3 //TODO
			}
		case 48:
			i++
			switch vals[i] {
			case 5:
				i++
				p.bg = termbox.Attribute(vals[i] + 1)
			case 2:
				i += 3 //TODO
			}
		}
	}
}
<|endoftext|>


<commit_before>package editor

import (
	"fmt"
	"io"
)

func Help(w io.Writer) error {
	for _, x := range quickref {
		_, err := w.Write([]byte(fmt.Sprintf("%-12s%s\n", x.k, x.v)))
		if err != nil {
			return err
		}
	}
	return nil
}

// Reference: Vim's quickref.txt.
var quickref = []struct{ k, v string }{
	{"h", "left"},
	{"l", "right"},
	{"0", "to first character in the line"},
	{"^", "to first non-blank character in the line"},
	{"$", "to the last character in the line"},
	{"|", "to column N"},
	{"f", "to the Nth occurrence of {char} to the right"},
	{"F", "to the Nth occurrence of {char} to the left"},
	{"t": "till before the Nth occurrence of {char} to the right"},
	{"T": "till bl before the Nth occurrence of {char} to the left"},

	{"k", "go back history"},
	{"j", "go forward history"},

	{"-", "decrement the number at or after the cursor"},
	{"+", "increment the number at or after the cursor"},

	{"w", "N words forward"},
	{"W", "N blank-separated WORDs forward"},
	{"e", "forward to the end of the Nth word"},
	{"E", "forward to the end of the Nth blank-separated WORD"},
	{"b", "N words backward"},
	{"B", "N blank-separated WORDs backward"},
	{"ge", "backward to the end of the Nth word"},
	{"gE", "backward to the end of the Nth blank-separated WORD"},

	{"[(": "N times back to unclosed '('"},
	{"[{": "N times back to unclosed '{'"},
	{"])": "N times forward to unclosed ')'"},
	{"]}": "N times forward to unclosed '}'"},

	{"/", "search forward"},
	{"?", "search backward"},

	{"n", "repeat last search"},
	{"N", "repeat last search, in opposite direction"},

	{"a", "append text after the cursor"},
	{"A", "append text at the end of the line"},
	{"i", "insert text before the cursor"},
	{"I", "insert text before the first non-blank in the line"},
	{"gI", "insert text in column 1"},

	// insert mode...

	{"i_<Esc>", "end Insert mode, back to Normal mode"},
	{"i_CTRL-C", "like <Esc>"},

	{"i_CTRL-R", "insert the contents of a register"},
	{"i_CTRL-X", "complete the word before the cursor in various ways"},
	{"i_<BS>", "delete the character before the cursor"},
	{"i_CTRL-W", "delete word before the cursor"},
	{"i_CTRL-U", "delete all entered characters in the current line"},

	{"x", "delete N characters under and after the cursor"},
	{"<Del>", "delete N characters under and after the cursor"},
	{"X", "delete N characters before the cursor"},
	{"d", "delete the text that is moved over with {motion}"},
	{"v_d", "delete the highlighted text"},
	{"dd", "delete N lines"},
	{"D", "delete to the end of the line"},

	{"\"": "use register {char} for the next delete, yank, or put"},
	{"y": "yank the text moved over with {motion} into a register"},
	{"v_y": "yank the highlighted text into a register"},
	{"yy": "yank N lines into a register"},
	{"Y": "yank to the end of line into a register"},
	{"p": "put a register after the cursor position (N times)"},
	{"P": "put a register before the cursor position (N times)"},
}
<commit_msg>Update help for changing text<commit_after>package editor

import (
	"fmt"
	"io"
)

func Help(w io.Writer) error {
	for _, x := range quickref {
		_, err := w.Write([]byte(fmt.Sprintf("%-12s%s\n", x.k, x.v)))
		if err != nil {
			return err
		}
	}
	return nil
}

// Reference: Vim's quickref.txt.
var quickref = []struct{ k, v string }{
	{"h", "left"},
	{"l", "right"},
	{"0", "to first character in the line"},
	{"^", "to first non-blank character in the line"},
	{"$", "to the last character in the line"},
	{"|", "to column N"},
	{"f", "to the Nth occurrence of {char} to the right"},
	{"F", "to the Nth occurrence of {char} to the left"},
	{"t": "till before the Nth occurrence of {char} to the right"},
	{"T": "till bl before the Nth occurrence of {char} to the left"},

	{"k", "go back history"},
	{"j", "go forward history"},

	{"-", "decrement the number at or after the cursor"},
	{"+", "increment the number at or after the cursor"},

	{"w", "N words forward"},
	{"W", "N blank-separated WORDs forward"},
	{"e", "forward to the end of the Nth word"},
	{"E", "forward to the end of the Nth blank-separated WORD"},
	{"b", "N words backward"},
	{"B", "N blank-separated WORDs backward"},
	{"ge", "backward to the end of the Nth word"},
	{"gE", "backward to the end of the Nth blank-separated WORD"},

	{"[(": "N times back to unclosed '('"},
	{"[{": "N times back to unclosed '{'"},
	{"])": "N times forward to unclosed ')'"},
	{"]}": "N times forward to unclosed '}'"},

	{"/", "search forward"},
	{"?", "search backward"},

	{"n", "repeat last search"},
	{"N", "repeat last search, in opposite direction"},

	{"a", "append text after the cursor"},
	{"A", "append text at the end of the line"},
	{"i", "insert text before the cursor"},
	{"I", "insert text before the first non-blank in the line"},
	{"gI", "insert text in column 1"},

	// insert mode...

	{"i_<Esc>", "end Insert mode, back to Normal mode"},
	{"i_CTRL-C", "like <Esc>"},

	{"i_CTRL-R", "insert the contents of a register"},
	{"i_CTRL-X", "complete the word before the cursor in various ways"},
	{"i_<BS>", "delete the character before the cursor"},
	{"i_CTRL-W", "delete word before the cursor"},
	{"i_CTRL-U", "delete all entered characters in the current line"},

	{"x", "delete N characters under and after the cursor"},
	{"<Del>", "delete N characters under and after the cursor"},
	{"X", "delete N characters before the cursor"},
	{"d", "delete the text that is moved over with {motion}"},
	{"v_d", "delete the highlighted text"},
	{"dd", "delete N lines"},
	{"D", "delete to the end of the line"},

	{"\"": "use register {char} for the next delete, yank, or put"},
	{"y": "yank the text moved over with {motion} into a register"},
	{"v_y": "yank the highlighted text into a register"},
	{"yy": "yank N lines into a register"},
	{"Y": "yank to the end of line into a register"},
	{"p": "put a register after the cursor position (N times)"},
	{"P": "put a register before the cursor position (N times)"},

	{"r": "replace N characters with {char}"},
	{"R": "enter Replace mode"},
	{"c": "change the text that is moved over with {motion}"},
	{"v_c": "change the highlighted text"},
	{"cc": "change N lines"},
	{"C": "change to the end of the line"},
	{"~": "switch case for N characters and advance cursor"},
	{"v_~": "switch case for highlighted text"},
	{"v_u": "make highlighted text lowercase"},
	{"v_U": "make highlighted text uppercase"},
	{"g~": "switch case for the text that is moved over with {motion}"},
	{"gu": "make the text that is moved over with {motion} lowercase"},
	{"gU": "make the text that is moved over with {motion} uppercase"},
}
<|endoftext|>


<commit_before>package editor

import (
	"github.com/jantb/olive/rpc"
	"log"
	"strconv"

	"github.com/gdamore/tcell"
)

const tabSize = 4

// TODO: Move this to RPC
type requestLines struct {
	Method string `json:"method"`
	Params []int  `json:"params"`
	ViewID string `json:"view_id"`
}

type View struct {
	*LineCache
	*InputHandler

	ID        string
	view      *Viewport
	gutter    *Viewport
	xi        *rpc.Connection
	ViewID    string
	lineStart int
	lineEnd   int
}

func ralign(str string, width int) string {
	diff := width - len(str)
	res := ""
	for i := 0; i < diff; i++ {
		res += " "
	}

	res += str
	return res
}

func NewView(path string, vp *Viewport, xi *rpc.Connection) (*View, error) {
	view := &View{}
	view.view = NewViewport(vp, 3, 0)
	view.gutter = NewViewport(vp, 0, 0)
	view.xi = xi
	view.LineCache = NewLineCache()

	msg, err := xi.Request(&rpc.Request{
		Method: "new_view",
		Params: &rpc.Object{"file_path": path},
	})
	if err != nil {
		return view, err
	}

	view.ID = msg.Value.(string)
	view.InputHandler = &InputHandler{view.ID, path, xi}

	// Set scroll window size
	_, height := vp.Size()
	xi.Notify(&rpc.Request{
		Method: "edit",
		Params: &rpc.Object{
			"method":  "scroll",
			"params":  &rpc.Array{0, height - 2},
			"view_id": view.ID,
		},
	})

	return view, nil
}

func (v *View) Draw() {
	if len(v.lines) == 0 {
		return
	}

	// render line numbers
	// TODO: improve, alot... :-)
	style := defaultStyle.Foreground(tcell.ColorLightCyan)
	width := len(strconv.Itoa(len(v.lines) + v.LineCache.invalidBefore))

	v.gutter.SetWidth(width + 1)
	v.view.SetOffsetX(width + 2)
	for i := 0; i < len(v.lines); i++ {
		nLine := i + v.invalidBefore
		txt := ralign(strconv.Itoa(nLine+1), width)
		width := len(txt)
		for x := 0; x < width; x++ {
			v.gutter.SetContent(1+x, nLine, rune(txt[x]), nil, style)
		}
	}

	// TODO: Line numbers in a separate viewport
	for y, line := range v.lines {
		if line == nil {
			continue
		}
		nLine := y + v.invalidBefore
		visualX := 0
		for x, char := range []rune(line.Text) {
			// TODO: Do this somewhere else
			var style = defaultStyle
			// TODO: Reserved??
			if line.StyleIds[x] >= 2 {
				fg, _, _ := styles[line.StyleIds[x]].Decompose()
				style = style.Foreground(fg)
			}

			if char == '\t' {
				ts := tabSize - (visualX % tabSize)
				for i := 0; i < ts; i++ {
					v.view.SetContent(visualX+i, nLine, ' ', nil, style)
				}
				visualX += ts
			} else if char != '\n' {
				// TODO: Trim newline in a better way?
				v.view.SetContent(visualX, nLine, char, nil, style)
				visualX++
			}
		}
		if len(line.Cursors) != 0 {
			// TODO: Verify if xi-core will take care of tabs for us
			cX := GetCursorVisualX(line.Cursors[0], line.Text)
			// TODO: Multiple cursor support
			v.view.ShowCursor(cX, nLine)
		}
	}
	lineStart, lineEnd := v.view.GetViewport()
	if lineStart != v.lineStart || lineEnd != v.lineEnd {
		v.Scroll(lineStart, lineEnd)
		v.lineStart = lineStart
		v.lineEnd = lineEnd
	}
}

func (v *View) MakeLineVisible(line int) {
	v.view.MakeVisibleY(line)
	v.gutter.MakeVisibleY(line)
}

func (v *View) HandleEvent(ev tcell.Event) {
	switch e := ev.(type) {
	case *tcell.EventKey:
		ctrl := e.Modifiers()&tcell.ModCtrl != 0
		alt := e.Modifiers()&tcell.ModAlt != 0

		if e.Key() == tcell.KeyRune && !ctrl && !alt {
			v.Insert(string(e.Rune()))
		} else {
			if ctrl && alt {
				switch e.Name() {
				case "Alt+Ctrl+L":
					//	log.Println(goPlugin.Format(path))

				default:
					log.Println(string(e.Name()))
				}
			} else if ctrl && !alt {
				switch e.Key() {
				case tcell.KeyLeft:
					v.MoveWordLeft()
				case tcell.KeyRight:
					v.MoveWordRight()
				case tcell.KeyCtrlS:
					v.Save()
				case tcell.KeyCtrlU:
					v.Undo()
				case tcell.KeyCtrlR:
					v.Redo()
				case tcell.KeyCtrlD:
					v.DuplicateLine()
				}
			} else {
				switch e.Key() {
				case tcell.KeyBackspace2, tcell.KeyBackspace:
					v.DeleteBackward()
				case tcell.KeyTAB:
					v.Tab()
				case tcell.KeyEnter:
					v.Newline()
				case tcell.KeyLeft:
					v.MoveLeft()
				case tcell.KeyUp:
					v.MoveUp()
				case tcell.KeyRight:
					v.MoveRight()
				case tcell.KeyDown:
					v.MoveDown()
				case tcell.KeyDelete:
					v.DeleteForward()
				}
			}
		}
	}
}
<commit_msg>ctrl-z as undo<commit_after>package editor

import (
	"github.com/jantb/olive/rpc"
	"log"
	"strconv"

	"github.com/gdamore/tcell"
)

const tabSize = 4

// TODO: Move this to RPC
type requestLines struct {
	Method string `json:"method"`
	Params []int  `json:"params"`
	ViewID string `json:"view_id"`
}

type View struct {
	*LineCache
	*InputHandler

	ID        string
	view      *Viewport
	gutter    *Viewport
	xi        *rpc.Connection
	ViewID    string
	lineStart int
	lineEnd   int
}

func ralign(str string, width int) string {
	diff := width - len(str)
	res := ""
	for i := 0; i < diff; i++ {
		res += " "
	}

	res += str
	return res
}

func NewView(path string, vp *Viewport, xi *rpc.Connection) (*View, error) {
	view := &View{}
	view.view = NewViewport(vp, 3, 0)
	view.gutter = NewViewport(vp, 0, 0)
	view.xi = xi
	view.LineCache = NewLineCache()

	msg, err := xi.Request(&rpc.Request{
		Method: "new_view",
		Params: &rpc.Object{"file_path": path},
	})
	if err != nil {
		return view, err
	}

	view.ID = msg.Value.(string)
	view.InputHandler = &InputHandler{view.ID, path, xi}

	// Set scroll window size
	_, height := vp.Size()
	xi.Notify(&rpc.Request{
		Method: "edit",
		Params: &rpc.Object{
			"method":  "scroll",
			"params":  &rpc.Array{0, height - 2},
			"view_id": view.ID,
		},
	})

	return view, nil
}

func (v *View) Draw() {
	if len(v.lines) == 0 {
		return
	}

	// render line numbers
	// TODO: improve, alot... :-)
	style := defaultStyle.Foreground(tcell.ColorLightCyan)
	width := len(strconv.Itoa(len(v.lines) + v.LineCache.invalidBefore))

	v.gutter.SetWidth(width + 1)
	v.view.SetOffsetX(width + 2)
	for i := 0; i < len(v.lines); i++ {
		nLine := i + v.invalidBefore
		txt := ralign(strconv.Itoa(nLine+1), width)
		width := len(txt)
		for x := 0; x < width; x++ {
			v.gutter.SetContent(1+x, nLine, rune(txt[x]), nil, style)
		}
	}

	// TODO: Line numbers in a separate viewport
	for y, line := range v.lines {
		if line == nil {
			continue
		}
		nLine := y + v.invalidBefore
		visualX := 0
		for x, char := range []rune(line.Text) {
			// TODO: Do this somewhere else
			var style = defaultStyle
			// TODO: Reserved??
			if line.StyleIds[x] >= 2 {
				fg, _, _ := styles[line.StyleIds[x]].Decompose()
				style = style.Foreground(fg)
			}

			if char == '\t' {
				ts := tabSize - (visualX % tabSize)
				for i := 0; i < ts; i++ {
					v.view.SetContent(visualX+i, nLine, ' ', nil, style)
				}
				visualX += ts
			} else if char != '\n' {
				// TODO: Trim newline in a better way?
				v.view.SetContent(visualX, nLine, char, nil, style)
				visualX++
			}
		}
		if len(line.Cursors) != 0 {
			// TODO: Verify if xi-core will take care of tabs for us
			cX := GetCursorVisualX(line.Cursors[0], line.Text)
			// TODO: Multiple cursor support
			v.view.ShowCursor(cX, nLine)
		}
	}
	lineStart, lineEnd := v.view.GetViewport()
	if lineStart != v.lineStart || lineEnd != v.lineEnd {
		v.Scroll(lineStart, lineEnd)
		v.lineStart = lineStart
		v.lineEnd = lineEnd
	}
}

func (v *View) MakeLineVisible(line int) {
	v.view.MakeVisibleY(line)
	v.gutter.MakeVisibleY(line)
}

// HandleEvent handles tcell events
func (v *View) HandleEvent(ev tcell.Event) {
	switch e := ev.(type) {
	case *tcell.EventKey:
		ctrl := e.Modifiers()&tcell.ModCtrl != 0
		alt := e.Modifiers()&tcell.ModAlt != 0

		if e.Key() == tcell.KeyRune && !ctrl && !alt {
			v.Insert(string(e.Rune()))
		} else {
			if ctrl && alt {
				switch e.Name() {
				case "Alt+Ctrl+L":
					//	log.Println(goPlugin.Format(path))

				default:
					log.Println(string(e.Name()))
				}
			} else if ctrl && !alt {
				switch e.Key() {
				case tcell.KeyLeft:
					v.MoveWordLeft()
				case tcell.KeyRight:
					v.MoveWordRight()
				case tcell.KeyCtrlS:
					v.Save()
				case tcell.KeyCtrlZ:
					v.Undo()
				case tcell.KeyCtrlR:
					v.Redo()
				case tcell.KeyCtrlD:
					v.DuplicateLine()
				default:
					log.Println(string(e.Name()))
				}
			} else {
				switch e.Key() {
				case tcell.KeyBackspace2, tcell.KeyBackspace:
					v.DeleteBackward()
				case tcell.KeyTAB:
					v.Tab()
				case tcell.KeyEnter:
					v.Newline()
				case tcell.KeyLeft:
					v.MoveLeft()
				case tcell.KeyUp:
					v.MoveUp()
				case tcell.KeyRight:
					v.MoveRight()
				case tcell.KeyDown:
					v.MoveDown()
				case tcell.KeyDelete:
					v.DeleteForward()
				default:
					log.Println(string(e.Name()))

				}
			}
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2013 Julien Schmidt. All rights reserved.
// Based on the path package, Copyright 2009 The Go Authors.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.

package httprouter

// CleanPath is the URL version of path.Clean, it returns a canonical URL path
// for p, eliminating . and .. elements.
//
// The following rules are applied iteratively until no further processing can
// be done:
//	1. Replace multiple slashes with a single slash.
//	2. Eliminate each . path name element (the current directory).
//	3. Eliminate each inner .. path name element (the parent directory)
//	   along with the non-.. element that precedes it.
//	4. Eliminate .. elements that begin a rooted path:
//	   that is, replace "/.." by "/" at the beginning of a path.
//
// If the result of this process is an empty string, "/" is returned
func CleanPath(p string) string {
	// Turn empty string into "/"
	if p == "" {
		return "/"
	}

	n := len(p)
	var buf []byte

	// Invariants:
	//      reading from path; r is index of next byte to process.
	//      writing to buf; w is index of next byte to write.

	// path must start with '/'
	r := 1
	w := 1

	if p[0] != '/' {
		r = 0
		buf = make([]byte, n+1)
		buf[0] = '/'
	}

	trailing := n > 1 && p[n-1] == '/'

	// A bit more clunky without a 'lazybuf' like the path package, but the loop
	// gets completely inlined (bufApp). So in contrast to the path package this
	// loop has no expensive function calls (except 1x make)

	for r < n {
		switch {
		case p[r] == '/':
			// empty path element, trailing slash is added after the end
			r++

		case p[r] == '.' && r+1 == n:
			trailing = true
			r++

		case p[r] == '.' && p[r+1] == '/':
			// . element
			r++

		case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'):
			// .. element: remove to last /
			r += 2

			if w > 1 {
				// can backtrack
				w--

				if buf == nil {
					for w > 1 && p[w] != '/' {
						w--
					}
				} else {
					for w > 1 && buf[w] != '/' {
						w--
					}
				}
			}

		default:
			// real path element.
			// add slash if needed
			if w > 1 {
				bufApp(&buf, p, w, '/')
				w++
			}

			// copy element
			for r < n && p[r] != '/' {
				bufApp(&buf, p, w, p[r])
				w++
				r++
			}
		}
	}

	// re-append trailing slash
	if trailing && w > 1 {
		bufApp(&buf, p, w, '/')
		w++
	}

	if buf == nil {
		return p[:w]
	}
	return string(buf[:w])
}

// internal helper to lazily create a buffer if necessary
func bufApp(buf *[]byte, s string, w int, c byte) {
	if *buf == nil {
		if s[w] == c {
			return
		}

		*buf = make([]byte, len(s))
		copy(*buf, s[:w])
	}
	(*buf)[w] = c
}
<commit_msg>small enhance at CleanPath (#243)<commit_after>// Copyright 2013 Julien Schmidt. All rights reserved.
// Based on the path package, Copyright 2009 The Go Authors.
// Use of this source code is governed by a BSD-style license that can be found
// in the LICENSE file.

package httprouter

// CleanPath is the URL version of path.Clean, it returns a canonical URL path
// for p, eliminating . and .. elements.
//
// The following rules are applied iteratively until no further processing can
// be done:
//	1. Replace multiple slashes with a single slash.
//	2. Eliminate each . path name element (the current directory).
//	3. Eliminate each inner .. path name element (the parent directory)
//	   along with the non-.. element that precedes it.
//	4. Eliminate .. elements that begin a rooted path:
//	   that is, replace "/.." by "/" at the beginning of a path.
//
// If the result of this process is an empty string, "/" is returned
func CleanPath(p string) string {
	// Turn empty string into "/"
	if p == "" {
		return "/"
	}

	n := len(p)
	var buf []byte

	// Invariants:
	//      reading from path; r is index of next byte to process.
	//      writing to buf; w is index of next byte to write.

	// path must start with '/'
	r := 1
	w := 1

	if p[0] != '/' {
		r = 0
		buf = make([]byte, n+1)
		buf[0] = '/'
	}

	trailing := n > 1 && p[n-1] == '/'

	// A bit more clunky without a 'lazybuf' like the path package, but the loop
	// gets completely inlined (bufApp). So in contrast to the path package this
	// loop has no expensive function calls (except 1x make)

	for r < n {
		switch {
		case p[r] == '/':
			// empty path element, trailing slash is added after the end
			r++

		case p[r] == '.' && r+1 == n:
			trailing = true
			r++

		case p[r] == '.' && p[r+1] == '/':
			// . element
			r += 2

		case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'):
			// .. element: remove to last /
			r += 3

			if w > 1 {
				// can backtrack
				w--

				if buf == nil {
					for w > 1 && p[w] != '/' {
						w--
					}
				} else {
					for w > 1 && buf[w] != '/' {
						w--
					}
				}
			}

		default:
			// real path element.
			// add slash if needed
			if w > 1 {
				bufApp(&buf, p, w, '/')
				w++
			}

			// copy element
			for r < n && p[r] != '/' {
				bufApp(&buf, p, w, p[r])
				w++
				r++
			}
		}
	}

	// re-append trailing slash
	if trailing && w > 1 {
		bufApp(&buf, p, w, '/')
		w++
	}

	if buf == nil {
		return p[:w]
	}
	return string(buf[:w])
}

// internal helper to lazily create a buffer if necessary
func bufApp(buf *[]byte, s string, w int, c byte) {
	if *buf == nil {
		if s[w] == c {
			return
		}

		*buf = make([]byte, len(s))
		copy(*buf, s[:w])
	}
	(*buf)[w] = c
}
<|endoftext|>