<commit_before>package main

import (
	"bytes"
	"encoding/gob"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"
)

// Buffer stores the text for files that are loaded into the text editor
// It uses a rope to efficiently store the string and contains some
// simple functions for saving and wrapper functions for modifying the rope
type Buffer struct {
	// The eventhandler for undo/redo
	*EventHandler
	// This stores all the text in the buffer as an array of lines
	*LineArray

	Cursor Cursor

	// Path to the file on disk
	Path string
	// Absolute path to the file on disk
	AbsPath string
	// Name of the buffer on the status line
	name string

	// Whether or not the buffer has been modified since it was opened
	IsModified bool

	// Stores the last modification time of the file the buffer is pointing to
	ModTime time.Time

	NumLines int

	// Syntax highlighting rules
	rules []SyntaxRule

	// Buffer local settings
	Settings map[string]interface{}
}

// The SerializedBuffer holds the types that get serialized when a buffer is saved
// These are used for the savecursor and saveundo options
type SerializedBuffer struct {
	EventHandler *EventHandler
	Cursor       Cursor
	ModTime      time.Time
}

func NewBufferFromString(text, path string) *Buffer {
	return NewBuffer(strings.NewReader(text), path)
}

// NewBuffer creates a new buffer from a given reader with a given path
func NewBuffer(reader io.Reader, path string) *Buffer {
	if path != "" {
		for _, tab := range tabs {
			for _, view := range tab.views {
				if view.Buf.Path == path {
					return view.Buf
				}
			}
		}
	}

	b := new(Buffer)
	b.LineArray = NewLineArray(reader)

	b.Settings = DefaultLocalSettings()
	for k, v := range globalSettings {
		if _, ok := b.Settings[k]; ok {
			b.Settings[k] = v
		}
	}

	absPath, _ := filepath.Abs(path)

	b.Path = path
	b.AbsPath = absPath

	// The last time this file was modified
	b.ModTime, _ = GetModTime(b.Path)

	b.EventHandler = NewEventHandler(b)

	b.Update()
	b.FindFileType()
	b.UpdateRules()

	if _, err := os.Stat(configDir + "/buffers/"); os.IsNotExist(err) {
		os.Mkdir(configDir+"/buffers/", os.ModePerm)
	}

	// Put the cursor at the first spot
	cursorStartX := 0
	cursorStartY := 0
	// If -startpos LINE,COL was passed, use start position LINE,COL
	if len(*flagStartPos) > 0 {
		positions := strings.Split(*flagStartPos, ",")
		if len(positions) == 2 {
			lineNum, errPos1 := strconv.Atoi(positions[0])
			colNum, errPos2 := strconv.Atoi(positions[1])
			if errPos1 == nil && errPos2 == nil {
				cursorStartX = colNum
				cursorStartY = lineNum - 1
				// Check to avoid line overflow
				if cursorStartY > b.NumLines {
					cursorStartY = b.NumLines - 1
				} else if cursorStartY < 0 {
					cursorStartY = 0
				}
				// Check to avoid column overflow
				if cursorStartX > len(b.Line(cursorStartY)) {
					cursorStartX = len(b.Line(cursorStartY))
				} else if cursorStartX < 0 {
					cursorStartX = 0
				}
			}
		}
	}
	b.Cursor = Cursor{
		Loc: Loc{
			X: cursorStartX,
			Y: cursorStartY,
		},
		buf: b,
	}

	InitLocalSettings(b)

	if b.Settings["savecursor"].(bool) || b.Settings["saveundo"].(bool) {
		// If either savecursor or saveundo is turned on, we need to load the serialized information
		// from ~/.config/micro/buffers
		file, err := os.Open(configDir + "/buffers/" + EscapePath(b.AbsPath))
		if err == nil {
			var buffer SerializedBuffer
			decoder := gob.NewDecoder(file)
			gob.Register(TextEvent{})
			err = decoder.Decode(&buffer)
			if err != nil {
				TermMessage(err.Error(), "\n", "You may want to remove the files in ~/.config/micro/buffers (these files store the information for the 'saveundo' and 'savecursor' options) if this problem persists.")
			}
			if b.Settings["savecursor"].(bool) {
				b.Cursor = buffer.Cursor
				b.Cursor.buf = b
				b.Cursor.Relocate()
			}

			if b.Settings["saveundo"].(bool) {
				// We should only use last time's eventhandler if the file wasn't by someone else in the meantime
				if b.ModTime == buffer.ModTime {
					b.EventHandler = buffer.EventHandler
					b.EventHandler.buf = b
				}
			}
		}
		file.Close()
	}

	return b
}

func (b *Buffer) GetName() string {
	if b.name == "" {
		if b.Path == "" {
			return "No name"
		}
		return b.Path
	}
	return b.name
}

// UpdateRules updates the syntax rules and filetype for this buffer
// This is called when the colorscheme changes
func (b *Buffer) UpdateRules() {
	b.rules = GetRules(b)
}

// FindFileType identifies this buffer's filetype based on the extension or header
func (b *Buffer) FindFileType() {
	b.Settings["filetype"] = FindFileType(b)
}

// FileType returns the buffer's filetype
func (b *Buffer) FileType() string {
	return b.Settings["filetype"].(string)
}

// IndentString returns a string representing one level of indentation
func (b *Buffer) IndentString() string {
	if b.Settings["tabstospaces"].(bool) {
		return Spaces(int(b.Settings["tabsize"].(float64)))
	}
	return "\t"
}

// CheckModTime makes sure that the file this buffer points to hasn't been updated
// by an external program since it was last read
// If it has, we ask the user if they would like to reload the file
func (b *Buffer) CheckModTime() {
	modTime, ok := GetModTime(b.Path)
	if ok {
		if modTime != b.ModTime {
			choice, canceled := messenger.YesNoPrompt("The file has changed since it was last read. Reload file? (y,n)")
			messenger.Reset()
			messenger.Clear()
			if !choice || canceled {
				// Don't load new changes -- do nothing
				b.ModTime, _ = GetModTime(b.Path)
			} else {
				// Load new changes
				b.ReOpen()
			}
		}
	}
}

// ReOpen reloads the current buffer from disk
func (b *Buffer) ReOpen() {
	data, err := ioutil.ReadFile(b.Path)
	txt := string(data)

	if err != nil {
		messenger.Error(err.Error())
		return
	}
	b.EventHandler.ApplyDiff(txt)

	b.ModTime, _ = GetModTime(b.Path)
	b.IsModified = false
	b.Update()
	b.Cursor.Relocate()
}

// Update fetches the string from the rope and updates the `text` and `lines` in the buffer
func (b *Buffer) Update() {
	b.NumLines = len(b.lines)
}

// Save saves the buffer to its default path
func (b *Buffer) Save() error {
	return b.SaveAs(b.Path)
}

// SaveWithSudo saves the buffer to the default path with sudo
func (b *Buffer) SaveWithSudo() error {
	return b.SaveAsWithSudo(b.Path)
}

// Serialize serializes the buffer to configDir/buffers
func (b *Buffer) Serialize() error {
	if b.Settings["savecursor"].(bool) || b.Settings["saveundo"].(bool) {
		file, err := os.Create(configDir + "/buffers/" + EscapePath(b.AbsPath))
		if err == nil {
			enc := gob.NewEncoder(file)
			gob.Register(TextEvent{})
			err = enc.Encode(SerializedBuffer{
				b.EventHandler,
				b.Cursor,
				b.ModTime,
			})
		}
		file.Close()
		return err
	}
	return nil
}

// SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist
func (b *Buffer) SaveAs(filename string) error {
	b.FindFileType()
	b.UpdateRules()
	b.Path = filename
	str := b.String()
	if b.Settings["eofnewline"].(bool) {
		end := b.End()
		if b.RuneAt(Loc{end.X - 1, end.Y}) != '\n' {
			b.Insert(end, "\n")
		}
	}
	data := []byte(str)
	err := ioutil.WriteFile(filename, data, 0644)
	if err == nil {
		b.IsModified = false
		b.ModTime, _ = GetModTime(filename)
		return b.Serialize()
	}
	b.ModTime, _ = GetModTime(filename)
	return err
}

// SaveAsWithSudo is the same as SaveAs except it uses a neat trick
// with tee to use sudo so the user doesn't have to reopen micro with sudo
func (b *Buffer) SaveAsWithSudo(filename string) error {
	b.FindFileType()
	b.UpdateRules()
	b.Path = filename

	// The user may have already used sudo in which case we won't need the password
	// It's a bit nicer for them if they don't have to enter the password every time
	_, err := RunShellCommand("sudo -v")
	needPassword := err != nil

	// If we need the password, we have to close the screen and ask using the shell
	if needPassword {
		// Shut down the screen because we're going to interact directly with the shell
		screen.Fini()
		screen = nil
	}

	// Set up everything for the command
	cmd := exec.Command("sudo", "tee", filename)
	cmd.Stdin = bytes.NewBufferString(b.String())

	// This is a trap for Ctrl-C so that it doesn't kill micro
	// Instead we trap Ctrl-C to kill the program we're running
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for range c {
			cmd.Process.Kill()
		}
	}()

	// Start the command
	cmd.Start()
	err = cmd.Wait()

	// If we needed the password, we closed the screen, so we have to initialize it again
	if needPassword {
		// Start the screen back up
		InitScreen()
	}
	if err == nil {
		b.IsModified = false
		b.ModTime, _ = GetModTime(filename)
		b.Serialize()
	}
	return err
}

func (b *Buffer) insert(pos Loc, value []byte) {
	b.IsModified = true
	b.LineArray.insert(pos, value)
	b.Update()
}
func (b *Buffer) remove(start, end Loc) string {
	b.IsModified = true
	sub := b.LineArray.remove(start, end)
	b.Update()
	return sub
}

// Start returns the location of the first character in the buffer
func (b *Buffer) Start() Loc {
	return Loc{0, 0}
}

// End returns the location of the last character in the buffer
func (b *Buffer) End() Loc {
	return Loc{utf8.RuneCount(b.lines[b.NumLines-1]), b.NumLines - 1}
}

// RuneAt returns the rune at a given location in the buffer
func (b *Buffer) RuneAt(loc Loc) rune {
	line := []rune(b.Line(loc.Y))
	if len(line) > 0 {
		return line[loc.X]
	}
	return '\n'
}

// Line returns a single line
func (b *Buffer) Line(n int) string {
	if n >= len(b.lines) {
		return ""
	}
	return string(b.lines[n])
}

// Lines returns an array of strings containing the lines from start to end
func (b *Buffer) Lines(start, end int) []string {
	lines := b.lines[start:end]
	var slice []string
	for _, line := range lines {
		slice = append(slice, string(line))
	}
	return slice
}

// Len gives the length of the buffer
func (b *Buffer) Len() int {
	return Count(b.String())
}

// MoveLinesUp moves the range of lines up one row
func (b *Buffer) MoveLinesUp(start int, end int) {
	// 0 < start < end <= len(b.lines)
	if start < 1 || start >= end || end > len(b.lines) {
		return // what to do? FIXME
	}
	if end == len(b.lines) {
		b.Insert(
			Loc{
				utf8.RuneCount(b.lines[end-1]),
				end - 1,
			},
			"\n"+b.Line(start-1),
		)
	} else {
		b.Insert(
			Loc{0, end},
			b.Line(start-1)+"\n",
		)
	}
	b.Remove(
		Loc{0, start - 1},
		Loc{0, start},
	)
}

// MoveLinesDown moves the range of lines down one row
func (b *Buffer) MoveLinesDown(start int, end int) {
	// 0 <= start < end < len(b.lines)
	// if end == len(b.lines), we can't do anything here because the
	// last line is unaccessible, FIXME
	if start < 0 || start >= end || end >= len(b.lines)-1 {
		return // what to do? FIXME
	}
	b.Insert(
		Loc{0, start},
		b.Line(end)+"\n",
	)
	end++
	b.Remove(
		Loc{0, end},
		Loc{0, end + 1},
	)
}
<commit_msg>Expand '~' in SaveAs<commit_after>package main

import (
	"bytes"
	"encoding/gob"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/signal"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"unicode/utf8"

	"github.com/mitchellh/go-homedir"
)

// Buffer stores the text for files that are loaded into the text editor
// It uses a rope to efficiently store the string and contains some
// simple functions for saving and wrapper functions for modifying the rope
type Buffer struct {
	// The eventhandler for undo/redo
	*EventHandler
	// This stores all the text in the buffer as an array of lines
	*LineArray

	Cursor Cursor

	// Path to the file on disk
	Path string
	// Absolute path to the file on disk
	AbsPath string
	// Name of the buffer on the status line
	name string

	// Whether or not the buffer has been modified since it was opened
	IsModified bool

	// Stores the last modification time of the file the buffer is pointing to
	ModTime time.Time

	NumLines int

	// Syntax highlighting rules
	rules []SyntaxRule

	// Buffer local settings
	Settings map[string]interface{}
}

// The SerializedBuffer holds the types that get serialized when a buffer is saved
// These are used for the savecursor and saveundo options
type SerializedBuffer struct {
	EventHandler *EventHandler
	Cursor       Cursor
	ModTime      time.Time
}

func NewBufferFromString(text, path string) *Buffer {
	return NewBuffer(strings.NewReader(text), path)
}

// NewBuffer creates a new buffer from a given reader with a given path
func NewBuffer(reader io.Reader, path string) *Buffer {
	if path != "" {
		for _, tab := range tabs {
			for _, view := range tab.views {
				if view.Buf.Path == path {
					return view.Buf
				}
			}
		}
	}

	b := new(Buffer)
	b.LineArray = NewLineArray(reader)

	b.Settings = DefaultLocalSettings()
	for k, v := range globalSettings {
		if _, ok := b.Settings[k]; ok {
			b.Settings[k] = v
		}
	}

	absPath, _ := filepath.Abs(path)

	b.Path = path
	b.AbsPath = absPath

	// The last time this file was modified
	b.ModTime, _ = GetModTime(b.Path)

	b.EventHandler = NewEventHandler(b)

	b.Update()
	b.FindFileType()
	b.UpdateRules()

	if _, err := os.Stat(configDir + "/buffers/"); os.IsNotExist(err) {
		os.Mkdir(configDir+"/buffers/", os.ModePerm)
	}

	// Put the cursor at the first spot
	cursorStartX := 0
	cursorStartY := 0
	// If -startpos LINE,COL was passed, use start position LINE,COL
	if len(*flagStartPos) > 0 {
		positions := strings.Split(*flagStartPos, ",")
		if len(positions) == 2 {
			lineNum, errPos1 := strconv.Atoi(positions[0])
			colNum, errPos2 := strconv.Atoi(positions[1])
			if errPos1 == nil && errPos2 == nil {
				cursorStartX = colNum
				cursorStartY = lineNum - 1
				// Check to avoid line overflow
				if cursorStartY > b.NumLines {
					cursorStartY = b.NumLines - 1
				} else if cursorStartY < 0 {
					cursorStartY = 0
				}
				// Check to avoid column overflow
				if cursorStartX > len(b.Line(cursorStartY)) {
					cursorStartX = len(b.Line(cursorStartY))
				} else if cursorStartX < 0 {
					cursorStartX = 0
				}
			}
		}
	}
	b.Cursor = Cursor{
		Loc: Loc{
			X: cursorStartX,
			Y: cursorStartY,
		},
		buf: b,
	}

	InitLocalSettings(b)

	if b.Settings["savecursor"].(bool) || b.Settings["saveundo"].(bool) {
		// If either savecursor or saveundo is turned on, we need to load the serialized information
		// from ~/.config/micro/buffers
		file, err := os.Open(configDir + "/buffers/" + EscapePath(b.AbsPath))
		if err == nil {
			var buffer SerializedBuffer
			decoder := gob.NewDecoder(file)
			gob.Register(TextEvent{})
			err = decoder.Decode(&buffer)
			if err != nil {
				TermMessage(err.Error(), "\n", "You may want to remove the files in ~/.config/micro/buffers (these files store the information for the 'saveundo' and 'savecursor' options) if this problem persists.")
			}
			if b.Settings["savecursor"].(bool) {
				b.Cursor = buffer.Cursor
				b.Cursor.buf = b
				b.Cursor.Relocate()
			}

			if b.Settings["saveundo"].(bool) {
				// We should only use last time's eventhandler if the file wasn't by someone else in the meantime
				if b.ModTime == buffer.ModTime {
					b.EventHandler = buffer.EventHandler
					b.EventHandler.buf = b
				}
			}
		}
		file.Close()
	}

	return b
}

func (b *Buffer) GetName() string {
	if b.name == "" {
		if b.Path == "" {
			return "No name"
		}
		return b.Path
	}
	return b.name
}

// UpdateRules updates the syntax rules and filetype for this buffer
// This is called when the colorscheme changes
func (b *Buffer) UpdateRules() {
	b.rules = GetRules(b)
}

// FindFileType identifies this buffer's filetype based on the extension or header
func (b *Buffer) FindFileType() {
	b.Settings["filetype"] = FindFileType(b)
}

// FileType returns the buffer's filetype
func (b *Buffer) FileType() string {
	return b.Settings["filetype"].(string)
}

// IndentString returns a string representing one level of indentation
func (b *Buffer) IndentString() string {
	if b.Settings["tabstospaces"].(bool) {
		return Spaces(int(b.Settings["tabsize"].(float64)))
	}
	return "\t"
}

// CheckModTime makes sure that the file this buffer points to hasn't been updated
// by an external program since it was last read
// If it has, we ask the user if they would like to reload the file
func (b *Buffer) CheckModTime() {
	modTime, ok := GetModTime(b.Path)
	if ok {
		if modTime != b.ModTime {
			choice, canceled := messenger.YesNoPrompt("The file has changed since it was last read. Reload file? (y,n)")
			messenger.Reset()
			messenger.Clear()
			if !choice || canceled {
				// Don't load new changes -- do nothing
				b.ModTime, _ = GetModTime(b.Path)
			} else {
				// Load new changes
				b.ReOpen()
			}
		}
	}
}

// ReOpen reloads the current buffer from disk
func (b *Buffer) ReOpen() {
	data, err := ioutil.ReadFile(b.Path)
	txt := string(data)

	if err != nil {
		messenger.Error(err.Error())
		return
	}
	b.EventHandler.ApplyDiff(txt)

	b.ModTime, _ = GetModTime(b.Path)
	b.IsModified = false
	b.Update()
	b.Cursor.Relocate()
}

// Update fetches the string from the rope and updates the `text` and `lines` in the buffer
func (b *Buffer) Update() {
	b.NumLines = len(b.lines)
}

// Save saves the buffer to its default path
func (b *Buffer) Save() error {
	return b.SaveAs(b.Path)
}

// SaveWithSudo saves the buffer to the default path with sudo
func (b *Buffer) SaveWithSudo() error {
	return b.SaveAsWithSudo(b.Path)
}

// Serialize serializes the buffer to configDir/buffers
func (b *Buffer) Serialize() error {
	if b.Settings["savecursor"].(bool) || b.Settings["saveundo"].(bool) {
		file, err := os.Create(configDir + "/buffers/" + EscapePath(b.AbsPath))
		if err == nil {
			enc := gob.NewEncoder(file)
			gob.Register(TextEvent{})
			err = enc.Encode(SerializedBuffer{
				b.EventHandler,
				b.Cursor,
				b.ModTime,
			})
		}
		file.Close()
		return err
	}
	return nil
}

// SaveAs saves the buffer to a specified path (filename), creating the file if it does not exist
func (b *Buffer) SaveAs(filename string) error {
	b.FindFileType()
	b.UpdateRules()
	dir, _ := homedir.Dir()
	b.Path = strings.Replace(filename, "~", dir, 1)
	str := b.String()
	if b.Settings["eofnewline"].(bool) {
		end := b.End()
		if b.RuneAt(Loc{end.X - 1, end.Y}) != '\n' {
			b.Insert(end, "\n")
		}
	}
	data := []byte(str)
	err := ioutil.WriteFile(filename, data, 0644)
	if err == nil {
		b.IsModified = false
		b.ModTime, _ = GetModTime(filename)
		return b.Serialize()
	}
	b.ModTime, _ = GetModTime(filename)
	return err
}

// SaveAsWithSudo is the same as SaveAs except it uses a neat trick
// with tee to use sudo so the user doesn't have to reopen micro with sudo
func (b *Buffer) SaveAsWithSudo(filename string) error {
	b.FindFileType()
	b.UpdateRules()
	b.Path = filename

	// The user may have already used sudo in which case we won't need the password
	// It's a bit nicer for them if they don't have to enter the password every time
	_, err := RunShellCommand("sudo -v")
	needPassword := err != nil

	// If we need the password, we have to close the screen and ask using the shell
	if needPassword {
		// Shut down the screen because we're going to interact directly with the shell
		screen.Fini()
		screen = nil
	}

	// Set up everything for the command
	cmd := exec.Command("sudo", "tee", filename)
	cmd.Stdin = bytes.NewBufferString(b.String())

	// This is a trap for Ctrl-C so that it doesn't kill micro
	// Instead we trap Ctrl-C to kill the program we're running
	c := make(chan os.Signal, 1)
	signal.Notify(c, os.Interrupt)
	go func() {
		for range c {
			cmd.Process.Kill()
		}
	}()

	// Start the command
	cmd.Start()
	err = cmd.Wait()

	// If we needed the password, we closed the screen, so we have to initialize it again
	if needPassword {
		// Start the screen back up
		InitScreen()
	}
	if err == nil {
		b.IsModified = false
		b.ModTime, _ = GetModTime(filename)
		b.Serialize()
	}
	return err
}

func (b *Buffer) insert(pos Loc, value []byte) {
	b.IsModified = true
	b.LineArray.insert(pos, value)
	b.Update()
}
func (b *Buffer) remove(start, end Loc) string {
	b.IsModified = true
	sub := b.LineArray.remove(start, end)
	b.Update()
	return sub
}

// Start returns the location of the first character in the buffer
func (b *Buffer) Start() Loc {
	return Loc{0, 0}
}

// End returns the location of the last character in the buffer
func (b *Buffer) End() Loc {
	return Loc{utf8.RuneCount(b.lines[b.NumLines-1]), b.NumLines - 1}
}

// RuneAt returns the rune at a given location in the buffer
func (b *Buffer) RuneAt(loc Loc) rune {
	line := []rune(b.Line(loc.Y))
	if len(line) > 0 {
		return line[loc.X]
	}
	return '\n'
}

// Line returns a single line
func (b *Buffer) Line(n int) string {
	if n >= len(b.lines) {
		return ""
	}
	return string(b.lines[n])
}

// Lines returns an array of strings containing the lines from start to end
func (b *Buffer) Lines(start, end int) []string {
	lines := b.lines[start:end]
	var slice []string
	for _, line := range lines {
		slice = append(slice, string(line))
	}
	return slice
}

// Len gives the length of the buffer
func (b *Buffer) Len() int {
	return Count(b.String())
}

// MoveLinesUp moves the range of lines up one row
func (b *Buffer) MoveLinesUp(start int, end int) {
	// 0 < start < end <= len(b.lines)
	if start < 1 || start >= end || end > len(b.lines) {
		return // what to do? FIXME
	}
	if end == len(b.lines) {
		b.Insert(
			Loc{
				utf8.RuneCount(b.lines[end-1]),
				end - 1,
			},
			"\n"+b.Line(start-1),
		)
	} else {
		b.Insert(
			Loc{0, end},
			b.Line(start-1)+"\n",
		)
	}
	b.Remove(
		Loc{0, start - 1},
		Loc{0, start},
	)
}

// MoveLinesDown moves the range of lines down one row
func (b *Buffer) MoveLinesDown(start int, end int) {
	// 0 <= start < end < len(b.lines)
	// if end == len(b.lines), we can't do anything here because the
	// last line is unaccessible, FIXME
	if start < 0 || start >= end || end >= len(b.lines)-1 {
		return // what to do? FIXME
	}
	b.Insert(
		Loc{0, start},
		b.Line(end)+"\n",
	)
	end++
	b.Remove(
		Loc{0, end},
		Loc{0, end + 1},
	)
}
<|endoftext|>


<commit_before>// Command prepend inserts data read from stdin or an input file at the begining
// of the given file.
//
// If data to prepend is passed both via stdin and input file, first the given
// file is prepended with data read from stdin, then from input file.
//
// The prepend command does not load the files contents to the memory, making
// it suitable for large files. Writes issued by the prepend command are atomic,
// meaning if reading from stdin or input file fails the original file is left
// untouched.
//
// Example
//
//  ~ $ head -4 license.go | prepend package.go
//
package main

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
)

const usage = `prepend - inserts data at the begining of the file

USAGE:

	prepend [-f INPUT_FILE] FILE

EXAMPLE:

	~ $ head -4 license.go | prepend package.go`

var src string
var dst string

func nonil(err ...error) error {
	for _, err := range err {
		if err != nil {
			return err
		}
	}
	return nil
}

func die(v ...interface{}) {
	fmt.Fprintln(os.Stderr, v...)
	os.Exit(1)
}

func isfile(s string) error {
	if fi, err := os.Stat(dst); err != nil && fi.IsDir() {
		return nonil(err, errors.New(dst+" is a directory"))
	}
	return nil
}

func init() {
	flag.CommandLine.Usage = func() {
		fmt.Println(usage)
		os.Exit(0)
	}
	help := false
	flag.StringVar(&src, "f", "", "")
	flag.BoolVar(&help, "help", false, "")
	flag.Parse()
	if help {
		flag.CommandLine.Usage()
	}
	if flag.NArg() != 1 {
		die(usage)
	}
	dst = flag.Arg(0)
	// Early validate paths provided by the user.
	if err := isfile(dst); err != nil {
		die(err)
	}
	if src != "" {
		if err := isfile(src); err != nil {
			die(err)
		}
	}
}

func main() {
	tmp, err := ioutil.TempFile(filepath.Split(dst))
	if err != nil {
		die(err)
	}
	rdst, err := os.Open(dst)
	if err != nil {
		die(nonil(err, tmp.Close(), os.Remove(tmp.Name())))
	}
	var errCleanup error
	defer func() {
		switch errCleanup {
		case nil:
			if err = nonil(tmp.Close(), rdst.Close()); err != nil {
				os.Remove(tmp.Name())
				die(err)
			}
			// os.Renamve fails under Windows if destination file exists.
			if err = os.Remove(dst); err != nil {
				os.Remove(tmp.Name())
				die(err)
			}
			if err = os.Rename(tmp.Name(), dst); err != nil {
				die(err, "Prepended content is safe under ", tmp.Name())
			}
		default:
			die(nonil(errCleanup, tmp.Close(), rdst.Close(), os.Remove(tmp.Name())))
		}
	}()
	r := io.MultiReader(os.Stdin, rdst)
	if src != "" {
		f, err := os.Open(src)
		if err != nil {
			errCleanup = err
			return
		}
		defer f.Close()
		r = io.MultiReader(os.Stdin, f, rdst)
	}
	_, errCleanup = io.Copy(tmp, r)
}
<commit_msg>cmd/prepend: don't hang if no data is piped to stdin<commit_after>// Command prepend inserts data read from stdin or an input file at the begining
// of the given file.
//
// If data to prepend is passed both via stdin and input file, first the given
// file is prepended with data read from stdin, then from input file.
//
// The prepend command does not load the files contents to the memory, making
// it suitable for large files. Writes issued by the prepend command are atomic,
// meaning if reading from stdin or input file fails the original file is left
// untouched.
//
// Example
//
//  ~ $ head -4 license.go | prepend package.go
//
package main

import (
	"errors"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
)

const usage = `prepend - inserts data at the begining of the file

USAGE:

	prepend [-f INPUT_FILE] FILE

EXAMPLE:

	~ $ head -4 license.go | prepend package.go`

var src string
var dst string

func nonil(err ...error) error {
	for _, err := range err {
		if err != nil {
			return err
		}
	}
	return nil
}

func die(v ...interface{}) {
	fmt.Fprintln(os.Stderr, v...)
	os.Exit(1)
}

func isfile(s string) error {
	if fi, err := os.Stat(dst); err != nil && fi.IsDir() {
		return nonil(err, errors.New(dst+" is a directory"))
	}
	return nil
}

func init() {
	flag.CommandLine.Usage = func() {
		fmt.Println(usage)
		os.Exit(0)
	}
	help := false
	flag.StringVar(&src, "f", "", "")
	flag.BoolVar(&help, "help", false, "")
	flag.Parse()
	if help {
		flag.CommandLine.Usage()
	}
	if flag.NArg() != 1 {
		die(usage)
	}
	dst = flag.Arg(0)
	// Early validate paths provided by the user.
	if err := isfile(dst); err != nil {
		die(err)
	}
	if src != "" {
		if err := isfile(src); err != nil {
			die(err)
		}
	}
}

func main() {
	tmp, err := ioutil.TempFile(filepath.Split(dst))
	if err != nil {
		die(err)
	}
	rdst, err := os.Open(dst)
	if err != nil {
		die(nonil(err, tmp.Close(), os.Remove(tmp.Name())))
	}
	var errCleanup error
	defer func() {
		switch errCleanup {
		case nil:
			if err = nonil(tmp.Close(), rdst.Close()); err != nil {
				os.Remove(tmp.Name())
				die(err)
			}
			// os.Renamve fails under Windows if destination file exists.
			if err = os.Remove(dst); err != nil {
				os.Remove(tmp.Name())
				die(err)
			}
			if err = os.Rename(tmp.Name(), dst); err != nil {
				die(err, "Prepended content is safe under ", tmp.Name())
			}
		default:
			die(nonil(errCleanup, tmp.Close(), rdst.Close(), os.Remove(tmp.Name())))
		}
	}()
	var r io.Reader = rdst
	if src != "" {
		f, err := os.Open(src)
		if err != nil {
			errCleanup = err
			return
		}
		defer f.Close()
		r = io.MultiReader(f, r)
	}
	// stackoverflow.com/questions/22744443
	fi, err := os.Stdin.Stat()
	if err != nil {
		errCleanup = err
		return
	}
	if (fi.Mode() & os.ModeCharDevice) == 0 {
		r = io.MultiReader(os.Stdin, r)
	}
	_, errCleanup = io.Copy(tmp, r)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/pkg/errors"
	"github.com/scipipe/scipipe"
)

var (
	Info *log.Logger
)

func main() {
	flag.Parse()
	err := parseFlags(flag.Args())
	if err != nil {
		log.Fatalln(err.Error())
		os.Exit(1)
	}
}

func parseFlags(args []string) error {
	scipipe.InitLogError()
	if len(args) < 1 {
		printHelp()
		return nil
	}
	cmd := args[0]
	switch cmd {
	case "new":
		if len(args) < 2 {
			return errors.New("No infile specified")
		}
		writeNewWorkflowFile(args[1])
	case "audit2html":
		if len(args) < 2 {
			return errors.New("No infile specified")
		}
		inFile := args[1]
		if len(inFile) < 12 || (inFile[len(inFile)-11:] != ".audit.json") {
			return errors.New("Infile does not look like an audit file (does not end with .audit.json): " + inFile)
		}
		if len(args) < 3 {
			return errors.New("No outfile specified")
		}
		outFile := args[2]
		err := errors.New("")
		err = auditInfoToHTML(inFile, outFile, true)
		if err != nil {
			return errors.Wrap(err, "Could not convert Audit file to HTML")
		}
	default:
		return errors.New("Unknown command: " + cmd)
	}
	return nil
}

func printNewUsage() {
	Info.Println(`
Usage:
$ scipipe new <filename.go>`)
}
func printAudit2HTMLUsage() {
	Info.Print(`
Usage:
$ scipipe audit2html <infile.audit.json> [<outfile.html>]
`)
}

func printHelp() {
	Info.Printf(`________________________________________________________________________

SciPipe (http://scipipe.org)
Version: %s
________________________________________________________________________

Usage:
$ scipipe <command> [command options]

Available commands:
$ scipipe new <filename.go>
$ scipipe audit2html <infile.audit.json> [<outfile.html>]
________________________________________________________________________
`, scipipe.Version)
}

func writeNewWorkflowFile(fileName string) {
	f, err := os.Create(fileName)
	if err != nil {
		scipipe.Fail("Could not create file:", fileName)
	}
	defer f.Close()
	_, err = f.Write([]byte(workflowStub))
	if err != nil {
		scipipe.Fail("Could not write to file:", fileName)
	}
	Info.Println("Successfully wrote new workflow file to:", fileName, "\n\nNow you can run it with:\ngo run ", fileName)
}

func auditInfoToHTML(inFilePath string, outFilePath string, flatten bool) error {
	ip := scipipe.NewFileIP(strings.Replace(inFilePath, ".audit.json", "", 1))
	auditInfo := ip.AuditInfo()

	outHTML := fmt.Sprintf(headHTMLPattern, ip.Path())
	if flatten {
		auditInfosByID := extractAuditInfosByID(auditInfo)
		auditInfosByStartTime := sortAuditInfosByStartTime(auditInfosByID)
		for _, ai := range auditInfosByStartTime {
			ai.Upstream = nil
			outHTML += formatTaskHTML(ai.ProcessName, ai)
		}
	} else {
		outHTML += formatTaskHTML(ip.Path(), auditInfo)
	}
	outHTML += bottomHTML

	if _, err := os.Stat(outFilePath); os.IsExist(err) {
		return errors.Wrap(err, "File already exists:"+outFilePath)
	}
	outFile, err := os.Create(outFilePath)
	if err != nil {
		return errors.Wrap(err, "Could not create file:"+outFilePath)
	}
	outFile.WriteString(outHTML)
	outFile.Close()
	return nil
}

func formatTaskHTML(fileName string, auditInfo *scipipe.AuditInfo) (outHTML string) {
	outHTML = "
\n"
	outHTML += fmt.Sprintf("
%s / %s
\n", auditInfo.ProcessName, auditInfo.ID, auditInfo.ID, auditInfo.ID)
	outHTML += fmt.Sprintf("

%s

\n", auditInfo.Command)

	params := []string{}
	for pname, p := range auditInfo.Params {
		params = append(params, fmt.Sprintf("%s: %s", pname, p))
	}
	outHTML += fmt.Sprintf("
Parameters:	%s
\n", strings.Join(params, ", "))
	tags := []string{}
	for pname, p := range auditInfo.Tags {
		tags = append(tags, fmt.Sprintf("%s: %s", pname, p))
	}
	outHTML += fmt.Sprintf("
Tags:
%v

\n", strings.Join(tags, ", "))

	outHTML += fmt.Sprintf("
Start time:	%s
\n", auditInfo.StartTime.Format(`2006-01-02 15:04:05<span class="greyout">.000 -0700 MST</span>`))
	outHTML += fmt.Sprintf("
Finish time:	%s
\n", auditInfo.FinishTime.Format(`2006-01-02 15:04:05<span class="greyout">.000 -0700 MST</span>`))
	et := auditInfo.ExecTimeNS
	outHTML += fmt.Sprintf("
Execution time:	%s
\n", et.Truncate(time.Millisecond).String())
	//upStreamHTML := ""
	//for filePath, uai := range auditInfo.Upstream {
	//	upStreamHTML += formatTaskHTML(filePath, uai)
	//}
	//if outHTML != "" {
	//	outHTML += "
Upstreams:	" + upStreamHTML + "
\n"
	//}
	outHTML += "
\n"
	return
}

func extractAuditInfosByID(auditInfo *scipipe.AuditInfo) (auditInfosByID map[string]*scipipe.AuditInfo) {
	auditInfosByID = make(map[string]*scipipe.AuditInfo)
	auditInfosByID[auditInfo.ID] = auditInfo
	for _, ai := range auditInfo.Upstream {
		auditInfosByID = mergeStringAuditInfoMaps(auditInfosByID, extractAuditInfosByID(ai))
	}
	return auditInfosByID
}

func mergeStringAuditInfoMaps(ms ...map[string]*scipipe.AuditInfo) (merged map[string]*scipipe.AuditInfo) {
	merged = make(map[string]*scipipe.AuditInfo)
	for _, m := range ms {
		for k, v := range m {
			merged[k] = v
		}
	}
	return merged
}

func sortAuditInfosByStartTime(auditInfosByID map[string]*scipipe.AuditInfo) []*scipipe.AuditInfo {
	sorted := []*scipipe.AuditInfo{}

	auditInfosByStartTime := map[time.Time]*scipipe.AuditInfo{}
	startTimes := []time.Time{}
	for _, ai := range auditInfosByID {
		auditInfosByStartTime[ai.StartTime] = ai
		startTimes = append(startTimes, ai.StartTime)
	}
	sort.Slice(startTimes, func(i, j int) bool { return startTimes[i].Before(startTimes[j]) })
	for _, t := range startTimes {
		sorted = append(sorted, auditInfosByStartTime[t])
	}
	return sorted
}
func initLogs() {
	Info = log.New(os.Stdout, "", 0)
}

func initLogsTest() {
	Info = log.New(ioutil.Discard, "", 0)
}

const (
	workflowStub = `// Workflow written in SciPipe.
// For more information about SciPipe, see: http://scipipe.org
package main

import sp "github.com/scipipe/scipipe"

func main() {
	// Create a workflow, using 4 cpu cores
	wf := sp.NewWorkflow("my_workflow", 4)

	// Initialize processes
	foo := wf.NewProc("fooer", "echo foo > {o:foo}")
	foo.SetPathStatic("foo", "foo.txt")

	f2b := wf.NewProc("foo2bar", "sed 's/foo/bar/g' {i:foo} > {o:bar}")
	f2b.SetPathExtend("foo", "bar", ".bar.txt")

	// From workflow dependency network
	f2b.In("foo").From(foo.Out("foo"))

	// Run the workflow
	wf.Run()
}`
	headHTMLPattern = `

<title>Audit info for: %s</title>

`
	bottomHTML = `
`
)
<commit_msg>Don't require output filename<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"sort"
	"strings"
	"time"

	"github.com/pkg/errors"
	"github.com/scipipe/scipipe"
)

var (
	Info *log.Logger
)

func main() {
	flag.Parse()
	err := parseFlags(flag.Args())
	if err != nil {
		log.Fatalln(err.Error())
		os.Exit(1)
	}
}

func parseFlags(args []string) error {
	scipipe.InitLogError()
	if len(args) < 1 {
		printHelp()
		return nil
	}
	cmd := args[0]
	switch cmd {
	case "new":
		if len(args) < 2 {
			return errors.New("No infile specified")
		}
		writeNewWorkflowFile(args[1])
	case "audit2html":
		if len(args) < 2 {
			return errors.New("No infile specified")
		}
		inFile := args[1]
		if len(inFile) < 12 || (inFile[len(inFile)-11:] != ".audit.json") {
			return errors.New("Infile does not look like an audit file (does not end with .audit.json): " + inFile)
		}
		outFile := strings.Replace(inFile, ".audit.json", ".audit.html", 1)
		if len(args) > 3 {
			return errors.New("Extra arguments found: " + args[3])
		}
		if len(args) == 3 {
			outFile = args[2]
		}
		err := errors.New("")
		err = auditInfoToHTML(inFile, outFile, true)
		if err != nil {
			return errors.Wrap(err, "Could not convert Audit file to HTML")
		}
	default:
		return errors.New("Unknown command: " + cmd)
	}
	return nil
}

func printNewUsage() {
	Info.Println(`
Usage:
$ scipipe new <filename.go>`)
}
func printAudit2HTMLUsage() {
	Info.Print(`
Usage:
$ scipipe audit2html <infile.audit.json> [<outfile.html>]
`)
}

func printHelp() {
	Info.Printf(`________________________________________________________________________

SciPipe (http://scipipe.org)
Version: %s
________________________________________________________________________

Usage:
$ scipipe <command> [command options]

Available commands:
$ scipipe new <filename.go>
$ scipipe audit2html <infile.audit.json> [<outfile.html>]
________________________________________________________________________
`, scipipe.Version)
}

func writeNewWorkflowFile(fileName string) {
	f, err := os.Create(fileName)
	if err != nil {
		scipipe.Fail("Could not create file:", fileName)
	}
	defer f.Close()
	_, err = f.Write([]byte(workflowStub))
	if err != nil {
		scipipe.Fail("Could not write to file:", fileName)
	}
	Info.Println("Successfully wrote new workflow file to:", fileName, "\n\nNow you can run it with:\ngo run ", fileName)
}

func auditInfoToHTML(inFilePath string, outFilePath string, flatten bool) error {
	ip := scipipe.NewFileIP(strings.Replace(inFilePath, ".audit.json", "", 1))
	auditInfo := ip.AuditInfo()

	outHTML := fmt.Sprintf(headHTMLPattern, ip.Path())
	if flatten {
		auditInfosByID := extractAuditInfosByID(auditInfo)
		auditInfosByStartTime := sortAuditInfosByStartTime(auditInfosByID)
		for _, ai := range auditInfosByStartTime {
			ai.Upstream = nil
			outHTML += formatTaskHTML(ai.ProcessName, ai)
		}
	} else {
		outHTML += formatTaskHTML(ip.Path(), auditInfo)
	}
	outHTML += bottomHTML

	if _, err := os.Stat(outFilePath); os.IsExist(err) {
		return errors.Wrap(err, "File already exists:"+outFilePath)
	}
	outFile, err := os.Create(outFilePath)
	if err != nil {
		return errors.Wrap(err, "Could not create file:"+outFilePath)
	}
	outFile.WriteString(outHTML)
	outFile.Close()
	return nil
}

func formatTaskHTML(fileName string, auditInfo *scipipe.AuditInfo) (outHTML string) {
	outHTML = "
\n"
	outHTML += fmt.Sprintf("
%s / %s
\n", auditInfo.ProcessName, auditInfo.ID, auditInfo.ID, auditInfo.ID)
	outHTML += fmt.Sprintf("

%s

\n", auditInfo.Command)

	params := []string{}
	for pname, p := range auditInfo.Params {
		params = append(params, fmt.Sprintf("%s: %s", pname, p))
	}
	outHTML += fmt.Sprintf("
Parameters:	%s
\n", strings.Join(params, ", "))
	tags := []string{}
	for pname, p := range auditInfo.Tags {
		tags = append(tags, fmt.Sprintf("%s: %s", pname, p))
	}
	outHTML += fmt.Sprintf("
Tags:
%v

\n", strings.Join(tags, ", "))

	outHTML += fmt.Sprintf("
Start time:	%s
\n", auditInfo.StartTime.Format(`2006-01-02 15:04:05<span class="greyout">.000 -0700 MST</span>`))
	outHTML += fmt.Sprintf("
Finish time:	%s
\n", auditInfo.FinishTime.Format(`2006-01-02 15:04:05<span class="greyout">.000 -0700 MST</span>`))
	et := auditInfo.ExecTimeNS
	outHTML += fmt.Sprintf("
Execution time:	%s
\n", et.Truncate(time.Millisecond).String())
	//upStreamHTML := ""
	//for filePath, uai := range auditInfo.Upstream {
	//	upStreamHTML += formatTaskHTML(filePath, uai)
	//}
	//if outHTML != "" {
	//	outHTML += "
Upstreams:	" + upStreamHTML + "
\n"
	//}
	outHTML += "
\n"
	return
}

func extractAuditInfosByID(auditInfo *scipipe.AuditInfo) (auditInfosByID map[string]*scipipe.AuditInfo) {
	auditInfosByID = make(map[string]*scipipe.AuditInfo)
	auditInfosByID[auditInfo.ID] = auditInfo
	for _, ai := range auditInfo.Upstream {
		auditInfosByID = mergeStringAuditInfoMaps(auditInfosByID, extractAuditInfosByID(ai))
	}
	return auditInfosByID
}

func mergeStringAuditInfoMaps(ms ...map[string]*scipipe.AuditInfo) (merged map[string]*scipipe.AuditInfo) {
	merged = make(map[string]*scipipe.AuditInfo)
	for _, m := range ms {
		for k, v := range m {
			merged[k] = v
		}
	}
	return merged
}

func sortAuditInfosByStartTime(auditInfosByID map[string]*scipipe.AuditInfo) []*scipipe.AuditInfo {
	sorted := []*scipipe.AuditInfo{}

	auditInfosByStartTime := map[time.Time]*scipipe.AuditInfo{}
	startTimes := []time.Time{}
	for _, ai := range auditInfosByID {
		auditInfosByStartTime[ai.StartTime] = ai
		startTimes = append(startTimes, ai.StartTime)
	}
	sort.Slice(startTimes, func(i, j int) bool { return startTimes[i].Before(startTimes[j]) })
	for _, t := range startTimes {
		sorted = append(sorted, auditInfosByStartTime[t])
	}
	return sorted
}
func initLogs() {
	Info = log.New(os.Stdout, "", 0)
}

func initLogsTest() {
	Info = log.New(ioutil.Discard, "", 0)
}

const (
	workflowStub = `// Workflow written in SciPipe.
// For more information about SciPipe, see: http://scipipe.org
package main

import sp "github.com/scipipe/scipipe"

func main() {
	// Create a workflow, using 4 cpu cores
	wf := sp.NewWorkflow("my_workflow", 4)

	// Initialize processes
	foo := wf.NewProc("fooer", "echo foo > {o:foo}")
	foo.SetPathStatic("foo", "foo.txt")

	f2b := wf.NewProc("foo2bar", "sed 's/foo/bar/g' {i:foo} > {o:bar}")
	f2b.SetPathExtend("foo", "bar", ".bar.txt")

	// From workflow dependency network
	f2b.In("foo").From(foo.Out("foo"))

	// Run the workflow
	wf.Run()
}`
	headHTMLPattern = `

<title>Audit info for: %s</title>

`
	bottomHTML = `
`
)
<|endoftext|>


<commit_before>package main

import (
  "database/sql"
  _ "github.com/mattn/go-sqlite3"
  "scan"
  "flag"
  "fmt"
  "os"
)

var artist = flag.String("artist", "", "Artist search criteria")
var album = flag.String("album", "", "Album search criteria")
var title = flag.String("title", "", "Title search criteria")
var dbflag = flag.String("db", "mp3db", "database containing mp3 info")
var field = flag.String("field", "", "Only output the specified field (album, artist, or title)")
var page = flag.Int("page", -1, "The page in results to return")
var pageSize = flag.Int("pageSize", 10, "Size of a page")

func output(db scan.Mp3Db, filt map[string]string) {
  quit := make(chan bool)
  ch := make(chan map[string]string)

  var paging *scan.Paging

  if *page >= 0 {
    paging = &scan.Paging{PageSize: *pageSize, Page: *page}
  }

  fields := []string{"artist","album","title","path"}
  if len(*field) > 0 {
    fields = []string{*field}
  }

  go scan.FindMp3sInDb(
    db,
    fields,
    filt,
    []string{"artist","album","title"},
    ch,
    paging,
    quit)

  for meta := range(ch) {
    if _, ok := meta["eof"]; ok {
      fmt.Println("<final page>")
      break
    } else {
      if len(*field) > 0 {
        fmt.Println(meta[*field])
      } else {
        fmt.Printf("    {artist: \"%s\", album: \"%s\", title: \"%s\", path: \"%s\"},\n",
          meta["artist"], meta["album"], meta["title"], meta["path"])
      }
    }
  }
}
/*
func outputField(db scan.Mp3Db, c scan.Criteria, field scan.DbField) {
  quit := make(chan bool)
  ch := make(chan string)

  go scan.FindMp3FieldInDb(db, c, field, ch, quit)

  i := 0
  for s := range(ch) {
    fmt.Println(s)
    i++
    if *max >= 0 && i >= *max {
      quit <- true
      // On the next iteration the channel will be closed so the loop will exit
    }
  }
}
*/
func main() {
  flag.Parse()

/*
  var dbField scan.DbField = -1
  if len(*field) > 0 {
    var err error
    dbField, err = scan.GetDbField(*field)
    if err != nil {
      fmt.Println("Unknown field type",*field)
      os.Exit(1)
    }
  }
*/

  c := map[string]string {
    "artist": *artist,
    "album": *album,
    "title": *title,
  }

  db, err := sql.Open("sqlite3",*dbflag)
  if err != nil {
    return
  }

  mp3db, err := scan.OpenMp3Db(db)
  if err != nil {
    fmt.Println("Error opening database:", err)
    os.Exit(1)
  }
  defer mp3db.Close()

  output(mp3db, c)

/*
  quit := make(chan bool)
  ch := make(chan scan.Metadata)

  go scan.FindMp3sInDb(db, c, ch, quit)

  i := 0
  for meta := range(ch) {
    fmt.Printf("    {artist: \"%s\", album: \"%s\", title: \"%s\", path: \"%s\"},\n",
      meta.Artist, meta.Album, meta.Title, meta.Path)
    i++
    if *max >= 0 && i >= *max {
      quit <- true
      // On the next iteration the channel will be closed so the loop will exit
    }
  }
*/
}
<commit_msg>Fixed import path<commit_after>package main

import (
  "database/sql"
  _ "github.com/mattn/go-sqlite3"
  "github.com/jeffwilliams/wwwmp3/scan"
  "flag"
  "fmt"
  "os"
)

var artist = flag.String("artist", "", "Artist search criteria")
var album = flag.String("album", "", "Album search criteria")
var title = flag.String("title", "", "Title search criteria")
var dbflag = flag.String("db", "mp3db", "database containing mp3 info")
var field = flag.String("field", "", "Only output the specified field (album, artist, or title)")
var page = flag.Int("page", -1, "The page in results to return")
var pageSize = flag.Int("pageSize", 10, "Size of a page")

func output(db scan.Mp3Db, filt map[string]string) {
  quit := make(chan bool)
  ch := make(chan map[string]string)

  var paging *scan.Paging

  if *page >= 0 {
    paging = &scan.Paging{PageSize: *pageSize, Page: *page}
  }

  fields := []string{"artist","album","title","path"}
  if len(*field) > 0 {
    fields = []string{*field}
  }

  go scan.FindMp3sInDb(
    db,
    fields,
    filt,
    []string{"artist","album","title"},
    ch,
    paging,
    quit)

  for meta := range(ch) {
    if _, ok := meta["eof"]; ok {
      fmt.Println("<final page>")
      break
    } else {
      if len(*field) > 0 {
        fmt.Println(meta[*field])
      } else {
        fmt.Printf("    {artist: \"%s\", album: \"%s\", title: \"%s\", path: \"%s\"},\n",
          meta["artist"], meta["album"], meta["title"], meta["path"])
      }
    }
  }
}
/*
func outputField(db scan.Mp3Db, c scan.Criteria, field scan.DbField) {
  quit := make(chan bool)
  ch := make(chan string)

  go scan.FindMp3FieldInDb(db, c, field, ch, quit)

  i := 0
  for s := range(ch) {
    fmt.Println(s)
    i++
    if *max >= 0 && i >= *max {
      quit <- true
      // On the next iteration the channel will be closed so the loop will exit
    }
  }
}
*/
func main() {
  flag.Parse()

/*
  var dbField scan.DbField = -1
  if len(*field) > 0 {
    var err error
    dbField, err = scan.GetDbField(*field)
    if err != nil {
      fmt.Println("Unknown field type",*field)
      os.Exit(1)
    }
  }
*/

  c := map[string]string {
    "artist": *artist,
    "album": *album,
    "title": *title,
  }

  db, err := sql.Open("sqlite3",*dbflag)
  if err != nil {
    return
  }

  mp3db, err := scan.OpenMp3Db(db)
  if err != nil {
    fmt.Println("Error opening database:", err)
    os.Exit(1)
  }
  defer mp3db.Close()

  output(mp3db, c)

/*
  quit := make(chan bool)
  ch := make(chan scan.Metadata)

  go scan.FindMp3sInDb(db, c, ch, quit)

  i := 0
  for meta := range(ch) {
    fmt.Printf("    {artist: \"%s\", album: \"%s\", title: \"%s\", path: \"%s\"},\n",
      meta.Artist, meta.Album, meta.Title, meta.Path)
    i++
    if *max >= 0 && i >= *max {
      quit <- true
      // On the next iteration the channel will be closed so the loop will exit
    }
  }
*/
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"time"
)

var (
	tczPackages = []string{
		"aterm",
		"bash",
		"fltk-1.3",
		"flwm",
		"freetype",
		"glib2",
		"harfbuzz",
		"imlib2-bin",
		"imlib2",
		"libffi",
		"libfontenc",
		"libICE",
		"libjpeg-turbo",
		"libpng",
		"libSM",
		"libX11",
		"libXau",
		"libxcb",
		"libXdmcp",
		"libXext",
		"libXfont",
		"libXi",
		"libXmu",
		"libXpm",
		"libXrandr",
		"libXrender",
		"libXt",
		"pcre",
		"wbar",
		"Xfbdev",
		"Xlibs",
		"Xorg-fonts",
		"Xprogs",
		"Xorg-7.7",
		"links",
		"opera-12",
	}
	sshdCommands = []string{
		"Protocol 2",
		"AcceptEnv LANG LC_*",
		"UsePAM no",
		"ChallengeResponseAuthentication no",
		"passwordauthentication no",
		"AuthorizedKeysFile ~/.ssh/authorized_keys",
		"PermitRootLogin without-password",
		"X11Forwarding yes",
		"RSAAuthentication yes",
		"PubkeyAuthentication yes",
		"X11DisplayOffset 10",
		"X11UseLocalhost yes",
	}
	ssh = flag.Bool("ssh", false, "Ssh default set to false")
)

func setup() error {
	var errors error
	if err := os.Symlink("/usr/local/bin/bash", "/bin/bash"); err != nil {
		errors = fmt.Errorf("bash symlink: %v", err)
	}
	if err := os.Symlink("/lib/ld-linux-x86-64.so.2", "/lib64/ld-linux-x86-64.so.2"); err != nil {
		errors = fmt.Errorf("%v. ld-linux symlink: %v", errors, err)
	}
	return errors
}

func sshSetup() error {
	sshdLoc := "/etc/ssh/sshd_config"
	cmd := exec.Command("tcz", "openssh")
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	//This block of code does cp /etc/ssh/sshd_config /etc/ssh/sshd_config_backup
	if _, err := os.Stat(sshdLoc); err != nil {
		return err
	}
	fileContent, err := ioutil.ReadFile(sshdLoc)
	if err != nil {
		return err
	}
	if err := ioutil.WriteFile(sshdLoc+"_backup", fileContent, 0777); err != nil {
		return nil
	}
	// This writes the new sshd file
	var buffer bytes.Buffer
	byteFile := []byte{}
	for arg := range sshdCommands {
		buffer.WriteString(fmt.Sprintf("%v\n", arg))
	}
	fmt.Printf("SSHD file is : %s", string(byteFile))
	if err := ioutil.WriteFile(sshdLoc, byteFile, 0777); err != nil {
		return nil
	}

	if err := ioutil.WriteFile("/etc/passwd", []byte("root:x:0:0:root:/root:/bin/bash\nnobody::27:27:nobody privsep:/var/empty:/sbin/nologin"), 0777); err != nil {
		return err
	}
	if err := ioutil.WriteFile("/etc/group", []byte("nobody::27:"), 0777); err != nil {
		return err
	}

	//this does scp yourname@iplink:~/.ssh/id_rsa.pub /root/.ssh
	locationKeys := "yourname@iplink:~/.ssh/id_rsa.pub"
	for true {
		fmt.Printf("Where are your public keys located? ex:%s They will be copied to /root/.ssh and be called id_rsa.pub. \n", locationKeys)
		_, err := fmt.Scanf("%s", &locationKeys)
		if err != nil {
			return err
		}
		cmd := exec.Command("scp", locationKeys, "/root/.ssh/id_rsa.pub")
		cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
		if err := cmd.Run(); err != nil {
			fmt.Printf("tried to scp your public key. Failed because error: %v", err)
		}
		break
	}
	//this does cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys
	rsaKey, err := ioutil.ReadFile("/root/.ssh/id_rsa.pub")
	if err != nil {
		return err
	}
	ioutil.WriteFile("/root/.ssh/authorized_keys", rsaKey, os.ModeAppend)

	cmd = exec.Command("usr/sbin/sshd", "-d", "-d", "-d", "-D", "-e")
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func tczSetup() error {
	get := []string{"-v", "8.x"}
	get = append(get, tczPackages...)
	cmd := exec.Command("tcz", get...)
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func xSetup() error {
	go func() {
		cmd := exec.Command("Xfbdev")
		cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
		if err := cmd.Run(); err != nil {
			log.Fatalf("X11 startup: %v", err)
		}
	}()
	time.Sleep(5 * time.Second)
	for _, f := range []string{"flwm", "opera-12"} {
		log.Printf("Run %v", f)
		go func(n string) {
			cmd := exec.Command(n, "-display", ":0")
			cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
			if err := cmd.Run(); err != nil {
				log.Printf("%v: %v", n, err)
			}
		}(f)
	}
	cmd := exec.Command("aterm", "-display", ":0")
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func main() {
	if err := setup(); err != nil {
		log.Printf("Error is %v", err)
	}
	if err := tczSetup(); err != nil {
		log.Printf("Error is %v", err)
	}
	if false {
		if err := sshSetup(); err != nil {
			log.Printf("Error is %v", err)
		}
	}
	if err := xSetup(); err != nil {
		log.Printf("Error is %v", err)
	}
}
<commit_msg>add wifi to the list of packages xinit installs<commit_after>package main

import (
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"time"
)

var (
	tczPackages = []string{
		"aterm",
		"bash",
		"fltk-1.3",
		"flwm",
		"freetype",
		"glib2",
		"harfbuzz",
		"imlib2-bin",
		"imlib2",
		"libffi",
		"libfontenc",
		"libICE",
		"libjpeg-turbo",
		"libpng",
		"libSM",
		"libX11",
		"libXau",
		"libxcb",
		"libXdmcp",
		"libXext",
		"libXfont",
		"libXi",
		"libXmu",
		"libXpm",
		"libXrandr",
		"libXrender",
		"libXt",
		"pcre",
		"wbar",
		"Xfbdev",
		"Xlibs",
		"Xorg-fonts",
		"Xprogs",
		"Xorg-7.7",
		"links",
		"opera-12",
		"wifi",
	}
	sshdCommands = []string{
		"Protocol 2",
		"AcceptEnv LANG LC_*",
		"UsePAM no",
		"ChallengeResponseAuthentication no",
		"passwordauthentication no",
		"AuthorizedKeysFile ~/.ssh/authorized_keys",
		"PermitRootLogin without-password",
		"X11Forwarding yes",
		"RSAAuthentication yes",
		"PubkeyAuthentication yes",
		"X11DisplayOffset 10",
		"X11UseLocalhost yes",
	}
	ssh = flag.Bool("ssh", false, "Ssh default set to false")
)

func setup() error {
	var errors error
	if err := os.Symlink("/usr/local/bin/bash", "/bin/bash"); err != nil {
		errors = fmt.Errorf("bash symlink: %v", err)
	}
	if err := os.Symlink("/lib/ld-linux-x86-64.so.2", "/lib64/ld-linux-x86-64.so.2"); err != nil {
		errors = fmt.Errorf("%v. ld-linux symlink: %v", errors, err)
	}
	return errors
}

func sshSetup() error {
	sshdLoc := "/etc/ssh/sshd_config"
	cmd := exec.Command("tcz", "openssh")
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	//This block of code does cp /etc/ssh/sshd_config /etc/ssh/sshd_config_backup
	if _, err := os.Stat(sshdLoc); err != nil {
		return err
	}
	fileContent, err := ioutil.ReadFile(sshdLoc)
	if err != nil {
		return err
	}
	if err := ioutil.WriteFile(sshdLoc+"_backup", fileContent, 0777); err != nil {
		return nil
	}
	// This writes the new sshd file
	var buffer bytes.Buffer
	byteFile := []byte{}
	for arg := range sshdCommands {
		buffer.WriteString(fmt.Sprintf("%v\n", arg))
	}
	fmt.Printf("SSHD file is : %s", string(byteFile))
	if err := ioutil.WriteFile(sshdLoc, byteFile, 0777); err != nil {
		return nil
	}

	if err := ioutil.WriteFile("/etc/passwd", []byte("root:x:0:0:root:/root:/bin/bash\nnobody::27:27:nobody privsep:/var/empty:/sbin/nologin"), 0777); err != nil {
		return err
	}
	if err := ioutil.WriteFile("/etc/group", []byte("nobody::27:"), 0777); err != nil {
		return err
	}

	//this does scp yourname@iplink:~/.ssh/id_rsa.pub /root/.ssh
	locationKeys := "yourname@iplink:~/.ssh/id_rsa.pub"
	for true {
		fmt.Printf("Where are your public keys located? ex:%s They will be copied to /root/.ssh and be called id_rsa.pub. \n", locationKeys)
		_, err := fmt.Scanf("%s", &locationKeys)
		if err != nil {
			return err
		}
		cmd := exec.Command("scp", locationKeys, "/root/.ssh/id_rsa.pub")
		cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
		if err := cmd.Run(); err != nil {
			fmt.Printf("tried to scp your public key. Failed because error: %v", err)
		}
		break
	}
	//this does cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys
	rsaKey, err := ioutil.ReadFile("/root/.ssh/id_rsa.pub")
	if err != nil {
		return err
	}
	ioutil.WriteFile("/root/.ssh/authorized_keys", rsaKey, os.ModeAppend)

	cmd = exec.Command("usr/sbin/sshd", "-d", "-d", "-d", "-D", "-e")
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func tczSetup() error {
	get := []string{"-v", "8.x"}
	get = append(get, tczPackages...)
	cmd := exec.Command("tcz", get...)
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func xSetup() error {
	go func() {
		cmd := exec.Command("Xfbdev")
		cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
		if err := cmd.Run(); err != nil {
			log.Fatalf("X11 startup: %v", err)
		}
	}()
	time.Sleep(5 * time.Second)
	for _, f := range []string{"flwm", "opera-12"} {
		log.Printf("Run %v", f)
		go func(n string) {
			cmd := exec.Command(n, "-display", ":0")
			cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
			if err := cmd.Run(); err != nil {
				log.Printf("%v: %v", n, err)
			}
		}(f)
	}
	cmd := exec.Command("aterm", "-display", ":0")
	cmd.Stdin, cmd.Stdout, cmd.Stderr = os.Stdin, os.Stdout, os.Stderr
	if err := cmd.Run(); err != nil {
		return err
	}
	return nil
}

func main() {
	if err := setup(); err != nil {
		log.Printf("Error is %v", err)
	}
	if err := tczSetup(); err != nil {
		log.Printf("Error is %v", err)
	}
	if false {
		if err := sshSetup(); err != nil {
			log.Printf("Error is %v", err)
		}
	}
	if err := xSetup(); err != nil {
		log.Printf("Error is %v", err)
	}
}
<|endoftext|>


<commit_before>package git

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
)

// CheckoutOptions represents the options that may be passed to
// "git checkout"
type CheckoutOptions struct {
	// Not implemented
	Quiet bool
	// Not implemented
	Progress bool
	// Not implemented
	Force bool

	// Check out the named stage for unnamed paths.
	// Stage2 is equivalent to --ours, Stage3 to --theirs
	// Not implemented
	Stage Stage

	Branch string // -b

	// Not implemented
	ForceBranch bool // use branch as -B
	// Not implemented
	OrphanBranch bool // use branch as --orphan

	// Not implemented
	Track string
	// Not implemented
	CreateReflog bool // -l

	// Not implemented
	Detach bool

	IgnoreSkipWorktreeBits bool

	// Not implemented
	Merge bool

	// Not implemented.
	ConflictStyle string

	Patch bool

	// Not implemented
	IgnoreOtherWorktrees bool
}

// Implements the "git checkout" subcommand of git. Variations in the man-page
// are:
//
//     git checkout [-q] [-f] [-m] [<branch>]
//     git checkout [-q] [-f] [-m] --detach [<branch>]
//     git checkout [-q] [-f] [-m] [--detach] <commit>
//     git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
//     git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
//     git checkout [-p|--patch] [<tree-ish>] [--] [<paths>...]
//
// This will just check the options and call the appropriate variation. You
// can avoid the overhead by calling the proper variation directly.
//
// "thing" is the thing that the user entered on the command line to be checked out. It
// might be a branch, a commit, or a treeish, depending on the variation above.
func Checkout(c *Client, opts CheckoutOptions, thing string, files []File) error {
	if thing == "" {
		thing = "HEAD"
	}

	if opts.Patch {
		diffs, err := DiffFiles(c, DiffFilesOptions{}, files)
		if err != nil {
			return err
		}
		var patchbuf bytes.Buffer
		if err := GeneratePatch(c, DiffCommonOptions{Patch: true}, diffs, &patchbuf); err != nil {
			return err
		}
		hunks, err := splitPatch(patchbuf.String(), false)
		if err != nil {
			return err
		}
		hunks, err = filterHunks("discard this hunk from the work tree", hunks)
		if err == userAborted {
			return nil
		} else if err != nil {
			return err
		}

		patch, err := ioutil.TempFile("", "checkoutpatch")
		if err != nil {
			return err
		}
		defer os.Remove(patch.Name())
		recombinePatch(patch, hunks)

		return Apply(c, ApplyOptions{Reverse: true}, []File{File(patch.Name())})
	}

	if len(files) == 0 {
		cmt, err := RevParseCommitish(c, &RevParseOptions{}, thing)
		if err != nil {
			return err
		}
		return CheckoutCommit(c, opts, cmt)
	}

	b, err := RevParseTreeish(c, &RevParseOptions{}, thing)
	if err != nil {
		return err
	}
	return CheckoutFiles(c, opts, b, files)
}

// Implements the "git checkout" subcommand of git for variations:
//     git checkout [-q] [-f] [-m] [<branch>]
//     git checkout [-q] [-f] [-m] --detach [<branch>]
//     git checkout [-q] [-f] [-m] [--detach] <commit>
//     git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
func CheckoutCommit(c *Client, opts CheckoutOptions, commit Commitish) error {
	// RefSpec for new branch with -b/-B variety
	var newRefspec RefSpec
	if opts.Branch != "" {
		// Handle the -b/-B variety.
		// commit is the startpoint in the last variation, otherwise
		// Checkout() already set it to the commit of "HEAD"
		newRefspec = RefSpec("refs/heads/" + opts.Branch)
		refspecfile := newRefspec.File(c)
		if refspecfile.Exists() && !opts.ForceBranch {
			return fmt.Errorf("Branch %s already exists.", opts.Branch)
		}
	}
	// Get the original HEAD for the reflog
	var head Commitish
	head, err := SymbolicRefGet(c, SymbolicRefOptions{}, "HEAD")
	switch err {
	case DetachedHead:
		head, err = c.GetHeadCommit()
		if err != nil {
			return err
		}
	case nil:
	default:
		return err
	}

	// Convert from Commitish to Treeish for ReadTree and LsTree
	cid, err := commit.CommitID(c)
	if err != nil {
		return err
	}

	// Check that nothing would be lost
	lstree, err := LsTree(c, LsTreeOptions{Recurse: true}, cid, nil)
	if err != nil {
		return err
	}
	newfiles := make([]File, 0, len(lstree))
	for _, entry := range lstree {
		f, err := entry.PathName.FilePath(c)
		if err != nil {
			return err
		}
		newfiles = append(newfiles, f)
	}
	untracked, err := LsFiles(c, LsFilesOptions{Others: true}, newfiles)
	if err != nil {
		return err
	}
	if len(untracked) > 0 {
		err := "error: The following untracked working tree files would be overwritten by checkout:\n"
		for _, f := range untracked {
			err += "\t" + f.IndexEntry.PathName.String() + "\n"
		}
		err += "Please move or remove them before you switch branches.\nAborting"
		return fmt.Errorf("%v", err)
	}

	// Now actually read the tree into the index
	readtreeopts := ReadTreeOptions{Update: true, Merge: true}
	if opts.Force {
		readtreeopts.Merge = false
		readtreeopts.Reset = true
	}
	if opts.IgnoreSkipWorktreeBits {
		readtreeopts.NoSparseCheckout = true
	}
	if _, err := ReadTree(c, readtreeopts, cid); err != nil {
		return err
	}

	var origB string
	// Get the original HEAD branchname for the reflog
	//origB = Branch(head).BranchName()
	switch h := head.(type) {
	case RefSpec:
		origB = Branch(h).BranchName()
	default:
		if h, err := head.CommitID(c); err == nil {
			origB = h.String()
		}
	}

	if opts.Branch != "" {
		if err := c.CreateBranch(opts.Branch, cid); err != nil {
			return err
		}
		refmsg := fmt.Sprintf("checkout: moving from %s to %s (dgit)", origB, opts.Branch)
		return SymbolicRefUpdate(c, SymbolicRefOptions{}, "HEAD", RefSpec("refs/heads/"+opts.Branch), refmsg)
	}
	if b, ok := commit.(Branch); ok && !opts.Detach {
		// We're checking out a branch, first read the new tree, and
		// then update the SymbolicRef for HEAD, if that succeeds.
		refmsg := fmt.Sprintf("checkout: moving from %s to %s (dgit)", origB, b.BranchName())
		return SymbolicRefUpdate(c, SymbolicRefOptions{}, "HEAD", RefSpec(b), refmsg)
	}
	refmsg := fmt.Sprintf("checkout: moving from %s to %s (dgit)", origB, cid)
	if err := UpdateRef(c, UpdateRefOptions{NoDeref: true, OldValue: head}, "HEAD", cid, refmsg); err != nil {
		return err
	}
	return nil
}

// Implements "git checkout" subcommand of git for variations:
//     git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
//     git checkout [-p|--patch] [<tree-ish>] [--] [<paths>...]
func CheckoutFiles(c *Client, opts CheckoutOptions, tree Treeish, files []File) error {
	// If files were specified, we don't want ReadTree to update the workdir,
	// because we only want to (force) update the specified files.
	//
	// If they weren't, we want to checkout a treeish, so let ReadTree update
	// the workdir so that we don't lose any changes.
	updateAll := (len(files) == 0)
	i, err := ReadTree(c, ReadTreeOptions{Update: updateAll, Merge: updateAll, NoSparseCheckout: opts.IgnoreSkipWorktreeBits}, tree)
	if err != nil {
		return err
	}
	// ReadTree wrote the index to disk, but since we already have a copy in
	// memory we use the Uncommited variation.
	return CheckoutIndexUncommited(c, i, CheckoutIndexOptions{Force: true, UpdateStat: true}, files)
}
<commit_msg>Only check for untracked files if --force isn't set on checkout<commit_after>package git

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
)

// CheckoutOptions represents the options that may be passed to
// "git checkout"
type CheckoutOptions struct {
	// Not implemented
	Quiet bool
	// Not implemented
	Progress bool
	// Not implemented
	Force bool

	// Check out the named stage for unnamed paths.
	// Stage2 is equivalent to --ours, Stage3 to --theirs
	// Not implemented
	Stage Stage

	Branch string // -b

	// Not implemented
	ForceBranch bool // use branch as -B
	// Not implemented
	OrphanBranch bool // use branch as --orphan

	// Not implemented
	Track string
	// Not implemented
	CreateReflog bool // -l

	// Not implemented
	Detach bool

	IgnoreSkipWorktreeBits bool

	// Not implemented
	Merge bool

	// Not implemented.
	ConflictStyle string

	Patch bool

	// Not implemented
	IgnoreOtherWorktrees bool
}

// Implements the "git checkout" subcommand of git. Variations in the man-page
// are:
//
//     git checkout [-q] [-f] [-m] [<branch>]
//     git checkout [-q] [-f] [-m] --detach [<branch>]
//     git checkout [-q] [-f] [-m] [--detach] <commit>
//     git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
//     git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
//     git checkout [-p|--patch] [<tree-ish>] [--] [<paths>...]
//
// This will just check the options and call the appropriate variation. You
// can avoid the overhead by calling the proper variation directly.
//
// "thing" is the thing that the user entered on the command line to be checked out. It
// might be a branch, a commit, or a treeish, depending on the variation above.
func Checkout(c *Client, opts CheckoutOptions, thing string, files []File) error {
	if thing == "" {
		thing = "HEAD"
	}

	if opts.Patch {
		diffs, err := DiffFiles(c, DiffFilesOptions{}, files)
		if err != nil {
			return err
		}
		var patchbuf bytes.Buffer
		if err := GeneratePatch(c, DiffCommonOptions{Patch: true}, diffs, &patchbuf); err != nil {
			return err
		}
		hunks, err := splitPatch(patchbuf.String(), false)
		if err != nil {
			return err
		}
		hunks, err = filterHunks("discard this hunk from the work tree", hunks)
		if err == userAborted {
			return nil
		} else if err != nil {
			return err
		}

		patch, err := ioutil.TempFile("", "checkoutpatch")
		if err != nil {
			return err
		}
		defer os.Remove(patch.Name())
		recombinePatch(patch, hunks)

		return Apply(c, ApplyOptions{Reverse: true}, []File{File(patch.Name())})
	}

	if len(files) == 0 {
		cmt, err := RevParseCommitish(c, &RevParseOptions{}, thing)
		if err != nil {
			return err
		}
		return CheckoutCommit(c, opts, cmt)
	}

	b, err := RevParseTreeish(c, &RevParseOptions{}, thing)
	if err != nil {
		return err
	}
	return CheckoutFiles(c, opts, b, files)
}

// Implements the "git checkout" subcommand of git for variations:
//     git checkout [-q] [-f] [-m] [<branch>]
//     git checkout [-q] [-f] [-m] --detach [<branch>]
//     git checkout [-q] [-f] [-m] [--detach] <commit>
//     git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
func CheckoutCommit(c *Client, opts CheckoutOptions, commit Commitish) error {
	// RefSpec for new branch with -b/-B variety
	var newRefspec RefSpec
	if opts.Branch != "" {
		// Handle the -b/-B variety.
		// commit is the startpoint in the last variation, otherwise
		// Checkout() already set it to the commit of "HEAD"
		newRefspec = RefSpec("refs/heads/" + opts.Branch)
		refspecfile := newRefspec.File(c)
		if refspecfile.Exists() && !opts.ForceBranch {
			return fmt.Errorf("Branch %s already exists.", opts.Branch)
		}
	}
	// Get the original HEAD for the reflog
	var head Commitish
	head, err := SymbolicRefGet(c, SymbolicRefOptions{}, "HEAD")
	switch err {
	case DetachedHead:
		head, err = c.GetHeadCommit()
		if err != nil {
			return err
		}
	case nil:
	default:
		return err
	}

	// Convert from Commitish to Treeish for ReadTree and LsTree
	cid, err := commit.CommitID(c)
	if err != nil {
		return err
	}

	if !opts.Force {
		// Check that nothing would be lost
		lstree, err := LsTree(c, LsTreeOptions{Recurse: true}, cid, nil)
		if err != nil {
			return err
		}
		newfiles := make([]File, 0, len(lstree))
		for _, entry := range lstree {
			f, err := entry.PathName.FilePath(c)
			if err != nil {
				return err
			}
			newfiles = append(newfiles, f)
		}
		untracked, err := LsFiles(c, LsFilesOptions{Others: true}, newfiles)
		if err != nil {
			return err
		}
		if len(untracked) > 0 {
			err := "error: The following untracked working tree files would be overwritten by checkout:\n"
			for _, f := range untracked {
				err += "\t" + f.IndexEntry.PathName.String() + "\n"
			}
			err += "Please move or remove them before you switch branches.\nAborting"
			return fmt.Errorf("%v", err)
		}
	}

	// Now actually read the tree into the index
	readtreeopts := ReadTreeOptions{Update: true, Merge: true}
	if opts.Force {
		readtreeopts.Merge = false
		readtreeopts.Reset = true
	}
	if opts.IgnoreSkipWorktreeBits {
		readtreeopts.NoSparseCheckout = true
	}
	if _, err := ReadTree(c, readtreeopts, cid); err != nil {
		return err
	}

	var origB string
	// Get the original HEAD branchname for the reflog
	//origB = Branch(head).BranchName()
	switch h := head.(type) {
	case RefSpec:
		origB = Branch(h).BranchName()
	default:
		if h, err := head.CommitID(c); err == nil {
			origB = h.String()
		}
	}

	if opts.Branch != "" {
		if err := c.CreateBranch(opts.Branch, cid); err != nil {
			return err
		}
		refmsg := fmt.Sprintf("checkout: moving from %s to %s (dgit)", origB, opts.Branch)
		return SymbolicRefUpdate(c, SymbolicRefOptions{}, "HEAD", RefSpec("refs/heads/"+opts.Branch), refmsg)
	}
	if b, ok := commit.(Branch); ok && !opts.Detach {
		// We're checking out a branch, first read the new tree, and
		// then update the SymbolicRef for HEAD, if that succeeds.
		refmsg := fmt.Sprintf("checkout: moving from %s to %s (dgit)", origB, b.BranchName())
		return SymbolicRefUpdate(c, SymbolicRefOptions{}, "HEAD", RefSpec(b), refmsg)
	}
	refmsg := fmt.Sprintf("checkout: moving from %s to %s (dgit)", origB, cid)
	if err := UpdateRef(c, UpdateRefOptions{NoDeref: true, OldValue: head}, "HEAD", cid, refmsg); err != nil {
		return err
	}
	return nil
}

// Implements "git checkout" subcommand of git for variations:
//     git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
//     git checkout [-p|--patch] [<tree-ish>] [--] [<paths>...]
func CheckoutFiles(c *Client, opts CheckoutOptions, tree Treeish, files []File) error {
	// If files were specified, we don't want ReadTree to update the workdir,
	// because we only want to (force) update the specified files.
	//
	// If they weren't, we want to checkout a treeish, so let ReadTree update
	// the workdir so that we don't lose any changes.
	updateAll := (len(files) == 0)
	i, err := ReadTree(c, ReadTreeOptions{Update: updateAll, Merge: updateAll, NoSparseCheckout: opts.IgnoreSkipWorktreeBits}, tree)
	if err != nil {
		return err
	}
	// ReadTree wrote the index to disk, but since we already have a copy in
	// memory we use the Uncommited variation.
	return CheckoutIndexUncommited(c, i, CheckoutIndexOptions{Force: true, UpdateStat: true}, files)
}
<|endoftext|>


<commit_before>package options

import (
	"shadowss/pkg/config"

	"github.com/golang/glog"
	"github.com/spf13/pflag"
)

type ServerOption struct {
	ConfigFile         string
	CpuCoreNum         int
	EnableUDPRelay     bool
	URL                string
	MaxTCPConnPerPort  int
	APIProxyListenPort int
	APIProxyPassword   string
	APIServerToken     string
}

func NewServerOption() *ServerOption {
	return &ServerOption{
		ConfigFile:     string(""),
		CpuCoreNum:     1,
		EnableUDPRelay: false,
	}
}

func (s *ServerOption) LoadConfigFile() error {
	glog.V(5).Infof("Parse %s file\r\n", s.ConfigFile)
	err := config.ServerCfg.Parse(s.ConfigFile)
	if err != nil {
		glog.Errorf("error reading %s: %v\n", s.ConfigFile, err)
		return err
	}

	return nil
}

func (s *ServerOption) AddFlags(fs *pflag.FlagSet) {

	fs.StringVar(&s.ConfigFile, "config-file", s.ConfigFile, ""+
		"specify a configure file for server run. ")

	fs.IntVar(&s.CpuCoreNum, "cpu-core-num", s.CpuCoreNum, ""+
		"specify how many cpu core will be alloc for program")

	fs.BoolVar(&s.EnableUDPRelay, "enable-udp-relay", s.EnableUDPRelay, ""+
		"enable udp relay")

	fs.StringVar(&s.URL, "apiserver-url", s.URL, ""+
		"specify a api server url. ")

	fs.IntVar(&s.MaxTCPConnPerPort, "max-tcp-conn-per-port", 300, ""+
		"specify how many tcp connection per port")

	fs.IntVar(&s.APIProxyListenPort, "api-proxy-port", 48888, ""+
		"specify a port for api proxy")

	fs.StringVar(&s.APIProxyPassword, "api-proxy-password", s.APIProxyPassword, ""+
		"specify password for api proxy. ")

	fs.StringVar(&s.APIServerToken, "apiserver-token", s.APIServerToken, ""+
		"specify a api server token. ")

}
<commit_msg>change default api proxy port<commit_after>package options

import (
	"shadowss/pkg/config"

	"github.com/golang/glog"
	"github.com/spf13/pflag"
)

type ServerOption struct {
	ConfigFile         string
	CpuCoreNum         int
	EnableUDPRelay     bool
	URL                string
	MaxTCPConnPerPort  int
	APIProxyListenPort int
	APIProxyPassword   string
	APIServerToken     string
}

func NewServerOption() *ServerOption {
	return &ServerOption{
		ConfigFile:     string(""),
		CpuCoreNum:     1,
		EnableUDPRelay: false,
	}
}

func (s *ServerOption) LoadConfigFile() error {
	glog.V(5).Infof("Parse %s file\r\n", s.ConfigFile)
	err := config.ServerCfg.Parse(s.ConfigFile)
	if err != nil {
		glog.Errorf("error reading %s: %v\n", s.ConfigFile, err)
		return err
	}

	return nil
}

func (s *ServerOption) AddFlags(fs *pflag.FlagSet) {

	fs.StringVar(&s.ConfigFile, "config-file", s.ConfigFile, ""+
		"specify a configure file for server run. ")

	fs.IntVar(&s.CpuCoreNum, "cpu-core-num", s.CpuCoreNum, ""+
		"specify how many cpu core will be alloc for program")

	fs.BoolVar(&s.EnableUDPRelay, "enable-udp-relay", s.EnableUDPRelay, ""+
		"enable udp relay")

	fs.StringVar(&s.URL, "apiserver-url", s.URL, ""+
		"specify a api server url. ")

	fs.IntVar(&s.MaxTCPConnPerPort, "max-tcp-conn-per-port", 300, ""+
		"specify how many tcp connection per port")

	fs.IntVar(&s.APIProxyListenPort, "api-proxy-port", 12345, ""+
		"specify a port for api proxy")

	fs.StringVar(&s.APIProxyPassword, "api-proxy-password", s.APIProxyPassword, ""+
		"specify password for api proxy. ")

	fs.StringVar(&s.APIServerToken, "apiserver-token", s.APIServerToken, ""+
		"specify a api server token. ")

}
<|endoftext|>


<commit_before>package application

import (
	"context"

	"github.com/google/uuid"
	auth_proto "github.com/vardius/go-api-boilerplate/cmd/auth/infrastructure/proto"
	user_persistance "github.com/vardius/go-api-boilerplate/cmd/user/infrastructure/persistence"
	http_authenticator "github.com/vardius/go-api-boilerplate/pkg/http/security/authenticator"
	"github.com/vardius/go-api-boilerplate/pkg/identity"
	"github.com/vardius/golog"
)

// TokenAuthHandler provides token auth function
func TokenAuthHandler(grpAuthClient auth_proto.AuthenticationServiceClient, repository user_persistance.UserRepository, logger golog.Logger) http_authenticator.TokenAuthFunc {
	fn := func(token string) (identity.Identity, error) {
		tokenInfo, err := grpAuthClient.VerifyToken(context.Background(), &auth_proto.VerifyTokenRequest{
			Token: token,
		})
		if err != nil {
			logger.Error(context.Background(), "TokenAuthHandler Error: %v\n", err)
			return identity.NullIdentity, err
		}

		user, err := repository.Get(context.Background(), tokenInfo.GetUserId())
		if err != nil {
			logger.Error(context.Background(), "TokenAuthHandler Error: %v\n", err)
			return identity.NullIdentity, err
		}

		i := identity.Identity{
			ID:    uuid.MustParse(user.GetID()),
			Token: token,
			Email: user.GetEmail(),
			Roles: []string{"USER"},
		}

		return i, nil
	}

	return http_authenticator.TokenAuthFunc(fn)
}
<commit_msg>Remove logger, wrap errors<commit_after>package application

import (
	"context"

	"github.com/google/uuid"
	auth_proto "github.com/vardius/go-api-boilerplate/cmd/auth/infrastructure/proto"
	user_persistance "github.com/vardius/go-api-boilerplate/cmd/user/infrastructure/persistence"
	"github.com/vardius/go-api-boilerplate/pkg/errors"
	http_authenticator "github.com/vardius/go-api-boilerplate/pkg/http/security/authenticator"
	"github.com/vardius/go-api-boilerplate/pkg/identity"
)

// TokenAuthHandler provides token auth function
func TokenAuthHandler(grpAuthClient auth_proto.AuthenticationServiceClient, repository user_persistance.UserRepository) http_authenticator.TokenAuthFunc {
	fn := func(token string) (identity.Identity, error) {
		tokenInfo, err := grpAuthClient.VerifyToken(context.Background(), &auth_proto.VerifyTokenRequest{
			Token: token,
		})
		if err != nil {
			return identity.NullIdentity, errors.Wrap(err, errors.UNAUTHORIZED, "Could not verify token")
		}

		user, err := repository.Get(context.Background(), tokenInfo.GetUserId())
		if err != nil {
			return identity.NullIdentity, errors.Wrap(err, errors.INTERNAL, "Could not find user for token")
		}

		i := identity.Identity{
			ID:    uuid.MustParse(user.GetID()),
			Token: token,
			Email: user.GetEmail(),
			Roles: []string{"USER"},
		}

		return i, nil
	}

	return http_authenticator.TokenAuthFunc(fn)
}
<|endoftext|>


<commit_before>package backend

import (
	"atlantis/router/testutils"
	"net/http"
	"testing"
	"time"
)

func TestNewServerStatus(t *testing.T) {
	tstart := time.Now()

	status := NewServerStatus()
	if status.Current != StatusMaintenance {
		t.Errorf("should set status to maintenance")
	}

	if status.checked.UnixNano() < tstart.UnixNano() ||
		status.changed.UnixNano() < tstart.UnixNano() {
		t.Errorf("should set checked and changed")
	}
}

func TestSet(t *testing.T) {
	status := NewServerStatus()
	tcreate := status.changed

	status.Set(StatusCritical)
	if status.checked.UnixNano() <= tcreate.UnixNano() ||
		status.changed.UnixNano() <= tcreate.UnixNano() {
		t.Errorf("should set checked and changed when changes")
	}
	tmodify := status.checked

	status.Set(StatusCritical)
	if status.checked.UnixNano() <= tmodify.UnixNano() {
		t.Errorf("should set checked when unchanged")
	}
	if status.changed.UnixNano() != tmodify.UnixNano() {
		t.Errorf("should not set changed when unchanged")
	}
}

func TestStatusWeight(t *testing.T) {
	if StatusWeight(StatusOk) > StatusWeight(StatusDegraded) {
		t.Errorf("ok costs less than degraded")
	}

	if StatusWeight(StatusDegraded) > StatusWeight(StatusCritical) {
		t.Errorf("degraded costs less than critical")
	}

	if StatusWeight(StatusCritical) != StatusWeight("Po-taa-tooo") {
		t.Errorf("should default to cost of critical")
	}
}

func TestIsValidStatus(t *testing.T) {
	valids := []string{StatusOk, StatusDegraded, StatusCritical}
	for _, status := range valids {
		if !IsValidStatus(status) {
			t.Errorf("%s is valid status", status)
		}
	}

	if IsValidStatus("Po-taa-tooo") {
		t.Errorf("Po-ta-tooo is not a valid status")
	}
}

func TestParseAndSet(t *testing.T) {
	status := NewServerStatus()

	backend := testutils.NewBackend(0, false)
	defer backend.Shutdown()

	client := &http.Client{}
	req, _ := http.NewRequest("GET", backend.URL()+"/healthz", nil)

	backend.SetStatus(http.StatusOK, "DEGRADED")
	res, _ := client.Do(req)

	status.ParseAndSet(res)
	if status.Current != StatusDegraded {
		t.Errorf("should set status to degraded from header")
	}

	backend.SetStatus(http.StatusInternalServerError, "OK")
	res, _ = client.Do(req)

	status.ParseAndSet(res)
	if status.Current != StatusMaintenance {
		t.Errorf("should set status to maintenance when not ok")
	}
}

func TestCostMasking(t *testing.T) {
	status0 := NewServerStatus()
	status0.Set(StatusDegraded)

	status1 := NewServerStatus()
	status1.Set(StatusCritical)

	if status0.Cost(StatusDegraded) != status1.Cost(StatusCritical) {
		t.Errorf("should mask accepting status")
	}
}

func TestSlowStartFactor(t *testing.T) {
	status := NewServerStatus()

	status.Set(StatusCritical)
	if status.SlowStartFactor() == 0 {
		t.Errorf("should affect critical servers")
	}

	status.Set(StatusDegraded)
	if status.SlowStartFactor() == 0 {
		t.Errorf("should affect degraded servers")
	}

	status.Set(StatusOk)
	fact := status.SlowStartFactor()
	if fact != Kstartup {
		t.Errorf("should be Kstartup")
	}

	time.Sleep(1 * time.Second)
	fact = status.SlowStartFactor()
	if fact >= Kstartup {
		t.Errorf("should decrease monotonically")
	}

	status.changed, _ = time.Parse("1970-Jan-01", "1970-Jan-01")
	fact = status.SlowStartFactor()
	if fact != 0 {
		t.Errorf("should be zero after Kstartup")
	}
}

func TestSlowStartShape(t *testing.T) {
	if !testing.Verbose() {
		t.Skipf("skipping shape test, use verbose to run")
	}

	status := NewServerStatus()
	status.Set(StatusOk)

	t.Logf("Tdelta, SlowStartFactor")
	fact := status.SlowStartFactor()
	for i := 0; i < Tstartup; i++ {
		time.Sleep(1 * time.Second)
		fact_ := status.SlowStartFactor()
		t.Logf("%2d, %d", i, fact_)
		if fact_ < 1 || fact < fact_ {
			t.Errorf("should decrease monotonically to 0")
		}
		fact = fact_
	}

	time.Sleep(100 * time.Millisecond)
	if status.SlowStartFactor() != 0 {
		t.Errorf("should be 0 after Tstartup")
	}
}
<commit_msg>Fix status_test: Changed and Checked changed.<commit_after>package backend

import (
	"atlantis/router/testutils"
	"net/http"
	"testing"
	"time"
)

func TestNewServerStatus(t *testing.T) {
	tstart := time.Now()

	status := NewServerStatus()
	if status.Current != StatusMaintenance {
		t.Errorf("should set status to maintenance")
	}

	if status.Checked.UnixNano() < tstart.UnixNano() ||
		status.Changed.UnixNano() < tstart.UnixNano() {
		t.Errorf("should set checked and changed")
	}
}

func TestSet(t *testing.T) {
	status := NewServerStatus()
	tcreate := status.Changed

	status.Set(StatusCritical)
	if status.Checked.UnixNano() <= tcreate.UnixNano() ||
		status.Changed.UnixNano() <= tcreate.UnixNano() {
		t.Errorf("should set checked and changed when changes")
	}
	tmodify := status.Checked

	status.Set(StatusCritical)
	if status.Checked.UnixNano() <= tmodify.UnixNano() {
		t.Errorf("should set checked when unchanged")
	}
	if status.Changed.UnixNano() != tmodify.UnixNano() {
		t.Errorf("should not set changed when unchanged")
	}
}

func TestStatusWeight(t *testing.T) {
	if StatusWeight(StatusOk) > StatusWeight(StatusDegraded) {
		t.Errorf("ok costs less than degraded")
	}

	if StatusWeight(StatusDegraded) > StatusWeight(StatusCritical) {
		t.Errorf("degraded costs less than critical")
	}

	if StatusWeight(StatusCritical) != StatusWeight("Po-taa-tooo") {
		t.Errorf("should default to cost of critical")
	}
}

func TestIsValidStatus(t *testing.T) {
	valids := []string{StatusOk, StatusDegraded, StatusCritical}
	for _, status := range valids {
		if !IsValidStatus(status) {
			t.Errorf("%s is valid status", status)
		}
	}

	if IsValidStatus("Po-taa-tooo") {
		t.Errorf("Po-ta-tooo is not a valid status")
	}
}

func TestParseAndSet(t *testing.T) {
	status := NewServerStatus()

	backend := testutils.NewBackend(0, false)
	defer backend.Shutdown()

	client := &http.Client{}
	req, _ := http.NewRequest("GET", backend.URL()+"/healthz", nil)

	backend.SetStatus(http.StatusOK, "DEGRADED")
	res, _ := client.Do(req)

	status.ParseAndSet(res)
	if status.Current != StatusDegraded {
		t.Errorf("should set status to degraded from header")
	}

	backend.SetStatus(http.StatusInternalServerError, "OK")
	res, _ = client.Do(req)

	status.ParseAndSet(res)
	if status.Current != StatusMaintenance {
		t.Errorf("should set status to maintenance when not ok")
	}
}

func TestCostMasking(t *testing.T) {
	status0 := NewServerStatus()
	status0.Set(StatusDegraded)

	status1 := NewServerStatus()
	status1.Set(StatusCritical)

	if status0.Cost(StatusDegraded) != status1.Cost(StatusCritical) {
		t.Errorf("should mask accepting status")
	}
}

func TestSlowStartFactor(t *testing.T) {
	status := NewServerStatus()

	status.Set(StatusCritical)
	if status.SlowStartFactor() == 0 {
		t.Errorf("should affect critical servers")
	}

	status.Set(StatusDegraded)
	if status.SlowStartFactor() == 0 {
		t.Errorf("should affect degraded servers")
	}

	status.Set(StatusOk)
	fact := status.SlowStartFactor()
	if fact != Kstartup {
		t.Errorf("should be Kstartup")
	}

	time.Sleep(1 * time.Second)
	fact = status.SlowStartFactor()
	if fact >= Kstartup {
		t.Errorf("should decrease monotonically")
	}

	status.Changed, _ = time.Parse("1970-Jan-01", "1970-Jan-01")
	fact = status.SlowStartFactor()
	if fact != 0 {
		t.Errorf("should be zero after Kstartup")
	}
}

func TestSlowStartShape(t *testing.T) {
	if !testing.Verbose() {
		t.Skipf("skipping shape test, use verbose to run")
	}

	status := NewServerStatus()
	status.Set(StatusOk)

	t.Logf("Tdelta, SlowStartFactor")
	fact := status.SlowStartFactor()
	for i := 0; i < Tstartup; i++ {
		time.Sleep(1 * time.Second)
		fact_ := status.SlowStartFactor()
		t.Logf("%2d, %d", i, fact_)
		if fact_ < 1 || fact < fact_ {
			t.Errorf("should decrease monotonically to 0")
		}
		fact = fact_
	}

	time.Sleep(100 * time.Millisecond)
	if status.SlowStartFactor() != 0 {
		t.Errorf("should be 0 after Tstartup")
	}
}
<|endoftext|>


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

package codegen

import (
	"bytes"
	"encoding/json"
	"io"
	"os"
	"path/filepath"
	"strings"
	tmpl "text/template"

	"github.com/pkg/errors"
	"github.com/uber/zanzibar/codegen/template_bundle"
)

// AssetProvider provides access to template assets
type AssetProvider interface {
	// AssetNames returns a list of named assets available
	AssetNames() []string
	// Asset returns the bytes for a provided asset name
	Asset(string) ([]byte, error)
}

type defaultAssetCollection struct{}

func (*defaultAssetCollection) AssetNames() []string {
	return templates.AssetNames()
}

func (*defaultAssetCollection) Asset(assetName string) ([]byte, error) {
	return templates.Asset(assetName)
}

var defaultFuncMap = tmpl.FuncMap{
	"lower":         strings.ToLower,
	"title":         strings.Title,
	"fullTypeName":  fullTypeName,
	"camel":         CamelCase,
	"split":         strings.Split,
	"dec":           decrement,
	"basePath":      filepath.Base,
	"pascal":        PascalCase,
	"jsonMarshal":   jsonMarshal,
	"isPointerType": IsPointerType,
	"unref":         Unref,
	"lintAcronym":   LintAcronym,
	"args":          args,
}

func fullTypeName(typeName, packageName string) string {
	if typeName == "" || strings.Contains(typeName, ".") {
		return typeName
	}
	return packageName + "." + typeName
}

func decrement(num int) int {
	return num - 1
}

func jsonMarshal(jsonObj map[string]interface{}) (string, error) {
	str, err := json.Marshal(jsonObj)
	return string(str), err
}

func IsPointerType(t string) bool {
	return strings.HasPrefix(t, "*")
}

func Unref(t string) string {
	if strings.HasPrefix(t, "*") {
		return strings.TrimLeft(t, "*")
	}
	return t
}

func args(v ...interface{}) []interface{} {
	return v
}

// Template generates code for edge gateway clients and edgegateway endpoints.
type Template struct {
	template *tmpl.Template
}

// NewDefaultTemplate creates a bundle of templates.
func NewDefaultTemplate() (*Template, error) {
	return NewTemplate(
		&defaultAssetCollection{},
		defaultFuncMap,
	)
}

// NewTemplate returns a template helper for the provided asset collection
func NewTemplate(
	assetProvider AssetProvider,
	functionMap tmpl.FuncMap,
) (*Template, error) {
	t := tmpl.New("main").Funcs(functionMap)
	for _, file := range assetProvider.AssetNames() {
		fileContent, err := assetProvider.Asset(file)
		if err != nil {
			return nil, errors.Wrapf(
				err,
				"Could not read bin data for template %s",
				file,
			)
		}
		if _, err := t.New(file).Parse(string(fileContent)); err != nil {
			return nil, errors.Wrapf(err, "Could not parse template %s", file)
		}
	}
	return &Template{
		template: t,
	}, nil
}

// ExecTemplate executes the named templated, returning the generated bytes
func (t *Template) ExecTemplate(
	tplName string,
	tplData interface{},
	pkgHelper *PackageHelper,
	buildTags ...string,
) (ret []byte, rErr error) {
	defer func() {
		if r := recover(); r != nil {
			rErr = errors.Errorf(
				"panic when generating %s template in %s: %+v",
				tplName, pkgHelper.packageRoot, r,
			)
		}
	}()
	tplBuffer := bytes.NewBuffer(nil)
	if _, err := io.WriteString(tplBuffer, "// Code generated by zanzibar \n"+
		"// @generated \n \n"); err != nil {
		rErr = errors.Wrapf(err, "failed to write to file: %s", err)
		return
	}
	buildTagsLine := strings.Join(buildTags, " ")
	if buildTagsLine != "" {
		if _, err := io.WriteString(tplBuffer, "// +build "+buildTagsLine+"\n\n"); err != nil {
			rErr = errors.Wrapf(err, "failed to write to file: %s", err)
			return
		}

	}
	if _, err := io.WriteString(tplBuffer, pkgHelper.copyrightHeader); err != nil {
		rErr = errors.Wrapf(err, "failed to write to file: %s", err)
		return
	}
	if _, err := io.WriteString(tplBuffer, "\n\n"); err != nil {
		rErr = errors.Wrapf(err, "failed to write to file: %s", err)
		return
	}
	if err := t.template.ExecuteTemplate(
		tplBuffer,
		tplName,
		tplData,
	); err != nil {
		rErr = errors.Wrapf(
			err,
			"Error generating template %s",
			tplName,
		)
	}
	ret = tplBuffer.Bytes()
	return
}

func openFileOrCreate(file string) (*os.File, error) {
	if _, err := os.Stat(file); os.IsNotExist(err) {
		if err := os.MkdirAll(filepath.Dir(file), os.ModePerm); err != nil {
			return nil, errors.Wrapf(
				err, "could not make directory: %s", file,
			)
		}
	}
	return os.OpenFile(file, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
}
<commit_msg>add comments<commit_after>// Copyright (c) 2018 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package codegen

import (
	"bytes"
	"encoding/json"
	"io"
	"os"
	"path/filepath"
	"strings"
	tmpl "text/template"

	"github.com/pkg/errors"
	"github.com/uber/zanzibar/codegen/template_bundle"
)

// AssetProvider provides access to template assets
type AssetProvider interface {
	// AssetNames returns a list of named assets available
	AssetNames() []string
	// Asset returns the bytes for a provided asset name
	Asset(string) ([]byte, error)
}

type defaultAssetCollection struct{}

func (*defaultAssetCollection) AssetNames() []string {
	return templates.AssetNames()
}

func (*defaultAssetCollection) Asset(assetName string) ([]byte, error) {
	return templates.Asset(assetName)
}

var defaultFuncMap = tmpl.FuncMap{
	"lower":         strings.ToLower,
	"title":         strings.Title,
	"fullTypeName":  fullTypeName,
	"camel":         CamelCase,
	"split":         strings.Split,
	"dec":           decrement,
	"basePath":      filepath.Base,
	"pascal":        PascalCase,
	"jsonMarshal":   jsonMarshal,
	"isPointerType": IsPointerType,
	"unref":         Unref,
	"lintAcronym":   LintAcronym,
	"args":          args,
}

func fullTypeName(typeName, packageName string) string {
	if typeName == "" || strings.Contains(typeName, ".") {
		return typeName
	}
	return packageName + "." + typeName
}

func decrement(num int) int {
	return num - 1
}

func jsonMarshal(jsonObj map[string]interface{}) (string, error) {
	str, err := json.Marshal(jsonObj)
	return string(str), err
}

// IsPointerType determines if the passed in string is a string for a pointer
func IsPointerType(t string) bool {
	return strings.HasPrefix(t, "*")
}

//  Unref unrefs a pointer reference
func Unref(t string) string {
	if strings.HasPrefix(t, "*") {
		return strings.TrimLeft(t, "*")
	}
	return t
}

func args(v ...interface{}) []interface{} {
	return v
}

// Template generates code for edge gateway clients and edgegateway endpoints.
type Template struct {
	template *tmpl.Template
}

// NewDefaultTemplate creates a bundle of templates.
func NewDefaultTemplate() (*Template, error) {
	return NewTemplate(
		&defaultAssetCollection{},
		defaultFuncMap,
	)
}

// NewTemplate returns a template helper for the provided asset collection
func NewTemplate(
	assetProvider AssetProvider,
	functionMap tmpl.FuncMap,
) (*Template, error) {
	t := tmpl.New("main").Funcs(functionMap)
	for _, file := range assetProvider.AssetNames() {
		fileContent, err := assetProvider.Asset(file)
		if err != nil {
			return nil, errors.Wrapf(
				err,
				"Could not read bin data for template %s",
				file,
			)
		}
		if _, err := t.New(file).Parse(string(fileContent)); err != nil {
			return nil, errors.Wrapf(err, "Could not parse template %s", file)
		}
	}
	return &Template{
		template: t,
	}, nil
}

// ExecTemplate executes the named templated, returning the generated bytes
func (t *Template) ExecTemplate(
	tplName string,
	tplData interface{},
	pkgHelper *PackageHelper,
	buildTags ...string,
) (ret []byte, rErr error) {
	defer func() {
		if r := recover(); r != nil {
			rErr = errors.Errorf(
				"panic when generating %s template in %s: %+v",
				tplName, pkgHelper.packageRoot, r,
			)
		}
	}()
	tplBuffer := bytes.NewBuffer(nil)
	if _, err := io.WriteString(tplBuffer, "// Code generated by zanzibar \n"+
		"// @generated \n \n"); err != nil {
		rErr = errors.Wrapf(err, "failed to write to file: %s", err)
		return
	}
	buildTagsLine := strings.Join(buildTags, " ")
	if buildTagsLine != "" {
		if _, err := io.WriteString(tplBuffer, "// +build "+buildTagsLine+"\n\n"); err != nil {
			rErr = errors.Wrapf(err, "failed to write to file: %s", err)
			return
		}

	}
	if _, err := io.WriteString(tplBuffer, pkgHelper.copyrightHeader); err != nil {
		rErr = errors.Wrapf(err, "failed to write to file: %s", err)
		return
	}
	if _, err := io.WriteString(tplBuffer, "\n\n"); err != nil {
		rErr = errors.Wrapf(err, "failed to write to file: %s", err)
		return
	}
	if err := t.template.ExecuteTemplate(
		tplBuffer,
		tplName,
		tplData,
	); err != nil {
		rErr = errors.Wrapf(
			err,
			"Error generating template %s",
			tplName,
		)
	}
	ret = tplBuffer.Bytes()
	return
}

func openFileOrCreate(file string) (*os.File, error) {
	if _, err := os.Stat(file); os.IsNotExist(err) {
		if err := os.MkdirAll(filepath.Dir(file), os.ModePerm); err != nil {
			return nil, errors.Wrapf(
				err, "could not make directory: %s", file,
			)
		}
	}
	return os.OpenFile(file, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
}
<|endoftext|>