<commit_before>// EVH is designed to be a single-use file transfer system.  Its purpose is to replace
// aging methods of sharing files such as FTP.  With the advent of services like
// DropBox, Box, Google Drive and the like, this type of service is becoming more
// commonplace EVH has some differentiating features that make it an especially
// good tool for corporations and/or home use.
//
// EVH runs in two modes: server and client.  Server hosts a web server interface for
// uploading and downloading files.  The Client is for uploading only and runs
// in a terminal.  This app is designed to run on all platforms that Go supports.
package main

import (
	"flag"
	"html/template"
	"log"
	"net/http"
	"os"
)

// Flags
var ConfigFileFlag string
var DstEmailFlag string
var ExpirationFlag string
var FileDescrFlag string
var FilesFieldFlag string
var ProgressFlag bool
var ServerFlag bool
var SrcEmailFlag string
var UrlFlag string
var Evh1ImportFlag bool
var ProxyUrlFlag string

// Global Variables
var UploadUrlPath = "/upload/"
var DownloadUrlPath = "/download/"
var AdminUrlPath = "/admin/"
var Files []string
var HttpProto = "http"
var SiteDown bool
var Templates *template.Template

// Constants
const VERSION = "2.5.8"

func init() {
	flag.StringVar(&ConfigFileFlag, "c", "", "Location of the Configuration file")
	flag.BoolVar(&ServerFlag, "server", false, "Listen for incoming file uploads")

	// Client flags
	flag.StringVar(&UrlFlag, "url", "", "Remote server URL to send files to (client only)")
	flag.StringVar(&FilesFieldFlag, "field", "", "Field name of the form (client only)")
	flag.StringVar(&SrcEmailFlag, "from", "", "Email address of uploader (client only)")
	flag.StringVar(&DstEmailFlag, "to", "", "Comma separated set of email address(es) of file recipient(s) (client only)")
	flag.StringVar(&FileDescrFlag, "description", "", "File desription (use quotes) (client only)")
	flag.BoolVar(&ProgressFlag, "progress", true, "Show progress bar during upload (client only)")
	flag.StringVar(&ExpirationFlag, "expires", "", "Example 1:d for 1 day (client only)")
	flag.BoolVar(&Evh1ImportFlag, "import", false, "Import data from EVH1 instance (client only)")
	flag.StringVar(&ProxyUrlFlag, "proxy", "", "URL/Address for proxy (env=use environment proxy, other=use as defined")
}

func main() {
	flag.Parse()

	// Load in our Config
	Config = NewConfig(ConfigFileFlag)
	Config.ImportFlags()

	if ServerFlag {
		// Final sanity check
		if Config.Server.Assets == "" {
			log.Fatal("ERROR: Cannot continue without specifying assets path")
		}
		if Config.Server.Templates == "" {
			log.Fatal("ERROR: Cannot continue without specifying templates path")
		}
		if Config.Server.ListenAddr == "" {
			log.Fatal("ERROR: Cannot continue without specifying listenaddr value")
		}
		if Config.Server.Mailserver == "" {
			log.Println("WARNING: cannot send emails, mailserver not set")
		}

		// Set so all generated URLs use https if enabled
		if Config.Server.Ssl {
			HttpProto = "https"
		}

		// Setup our assets dir (if it don't already exist)
		err := os.MkdirAll(Config.Server.Assets, 0700)
		if err != nil {
			log.Fatal("Cannot setup assetdir as needed: " + err.Error())
		}

		// Parse our html templates
		go RefreshTemplates()
		go ScrubDownloads()

		// Register our handler functions
		http.HandleFunc(UploadUrlPath, SSLCheck(UploadHandler))
		http.HandleFunc(DownloadUrlPath, SSLCheck(AssetHandler))
		http.HandleFunc(AdminUrlPath, BasicAuth(SSLCheck(AdminHandler)))
		http.HandleFunc("/", Evh1Intercept(SSLCheck(HomeHandler)))

		// Listen
		log.Println("Listening...")

		// Spawn HTTPS listener in another thread
		go func() {
			if Config.Server.Ssl == false || Config.Server.SslPort == "" {
				return
			}
			var addrSsl = Config.Server.ListenAddr + ":" + Config.Server.SslPort
			listenErrSsl := http.ListenAndServeTLS(addrSsl, Config.Server.CertFile, Config.Server.KeyFile, nil)
			if listenErrSsl != nil {
				log.Fatal("ERROR: ssl listen problem: " + listenErrSsl.Error())
			}
		}()

		// Start non-SSL listener
		var addrNonSsl = Config.Server.ListenAddr + ":" + Config.Server.NonSslPort
		listenErr := http.ListenAndServe(addrNonSsl, nil)
		if listenErr != nil {
			log.Fatal("ERROR: non-ssl listen problem: " + listenErr.Error())
		}
	} else {
		// Run import if requested
		if Evh1ImportFlag {
			SpitSlurp()
			return
		}

		// Final sanity check
		if Config.Client.DestEmail == "" {
			log.Println("WARNING: no -destemail value set, cannot send reciever an email")
		}
		if Config.Client.Email == "" {
			log.Println("WARNING: no -email value set, cannot send email to uploader")
		}
		if Config.Client.Field == "" {
			log.Println("WARNING: no -field value set, using \"file\" instead")
			Config.Client.Field = "file"
		}
		if Config.Client.Url == "" {
			log.Fatal("ERROR: Cannot continue without specifying -url value")
		}

		// All filenames are unflagged arguments, loop through them and uplod the file(s)
		for _, fname := range flag.Args() {
			fi, err := os.Stat(fname)
			if err != nil {
				log.Println("WARNING: Cannot read file, skipping ", fname, ": ", err.Error())
			} else {
				if fi.Mode().IsRegular() {
					Files = append(Files, fname)
				}
			}
		}

		Upload(Files)
	}
}
<commit_msg>Version bump to 2.5.9<commit_after>// EVH is designed to be a single-use file transfer system.  Its purpose is to replace
// aging methods of sharing files such as FTP.  With the advent of services like
// DropBox, Box, Google Drive and the like, this type of service is becoming more
// commonplace EVH has some differentiating features that make it an especially
// good tool for corporations and/or home use.
//
// EVH runs in two modes: server and client.  Server hosts a web server interface for
// uploading and downloading files.  The Client is for uploading only and runs
// in a terminal.  This app is designed to run on all platforms that Go supports.
package main

import (
	"flag"
	"html/template"
	"log"
	"net/http"
	"os"
)

// Flags
var ConfigFileFlag string
var DstEmailFlag string
var ExpirationFlag string
var FileDescrFlag string
var FilesFieldFlag string
var ProgressFlag bool
var ServerFlag bool
var SrcEmailFlag string
var UrlFlag string
var Evh1ImportFlag bool
var ProxyUrlFlag string

// Global Variables
var UploadUrlPath = "/upload/"
var DownloadUrlPath = "/download/"
var AdminUrlPath = "/admin/"
var Files []string
var HttpProto = "http"
var SiteDown bool
var Templates *template.Template

// Constants
const VERSION = "2.5.9"

func init() {
	flag.StringVar(&ConfigFileFlag, "c", "", "Location of the Configuration file")
	flag.BoolVar(&ServerFlag, "server", false, "Listen for incoming file uploads")

	// Client flags
	flag.StringVar(&UrlFlag, "url", "", "Remote server URL to send files to (client only)")
	flag.StringVar(&FilesFieldFlag, "field", "", "Field name of the form (client only)")
	flag.StringVar(&SrcEmailFlag, "from", "", "Email address of uploader (client only)")
	flag.StringVar(&DstEmailFlag, "to", "", "Comma separated set of email address(es) of file recipient(s) (client only)")
	flag.StringVar(&FileDescrFlag, "description", "", "File desription (use quotes) (client only)")
	flag.BoolVar(&ProgressFlag, "progress", true, "Show progress bar during upload (client only)")
	flag.StringVar(&ExpirationFlag, "expires", "", "Example 1:d for 1 day (client only)")
	flag.BoolVar(&Evh1ImportFlag, "import", false, "Import data from EVH1 instance (client only)")
	flag.StringVar(&ProxyUrlFlag, "proxy", "", "URL/Address for proxy (env=use environment proxy, other=use as defined")
}

func main() {
	flag.Parse()

	// Load in our Config
	Config = NewConfig(ConfigFileFlag)
	Config.ImportFlags()

	if ServerFlag {
		// Final sanity check
		if Config.Server.Assets == "" {
			log.Fatal("ERROR: Cannot continue without specifying assets path")
		}
		if Config.Server.Templates == "" {
			log.Fatal("ERROR: Cannot continue without specifying templates path")
		}
		if Config.Server.ListenAddr == "" {
			log.Fatal("ERROR: Cannot continue without specifying listenaddr value")
		}
		if Config.Server.Mailserver == "" {
			log.Println("WARNING: cannot send emails, mailserver not set")
		}

		// Set so all generated URLs use https if enabled
		if Config.Server.Ssl {
			HttpProto = "https"
		}

		// Setup our assets dir (if it don't already exist)
		err := os.MkdirAll(Config.Server.Assets, 0700)
		if err != nil {
			log.Fatal("Cannot setup assetdir as needed: " + err.Error())
		}

		// Parse our html templates
		go RefreshTemplates()
		go ScrubDownloads()

		// Register our handler functions
		http.HandleFunc(UploadUrlPath, SSLCheck(UploadHandler))
		http.HandleFunc(DownloadUrlPath, SSLCheck(AssetHandler))
		http.HandleFunc(AdminUrlPath, BasicAuth(SSLCheck(AdminHandler)))
		http.HandleFunc("/", Evh1Intercept(SSLCheck(HomeHandler)))

		// Listen
		log.Println("Listening...")

		// Spawn HTTPS listener in another thread
		go func() {
			if Config.Server.Ssl == false || Config.Server.SslPort == "" {
				return
			}
			var addrSsl = Config.Server.ListenAddr + ":" + Config.Server.SslPort
			listenErrSsl := http.ListenAndServeTLS(addrSsl, Config.Server.CertFile, Config.Server.KeyFile, nil)
			if listenErrSsl != nil {
				log.Fatal("ERROR: ssl listen problem: " + listenErrSsl.Error())
			}
		}()

		// Start non-SSL listener
		var addrNonSsl = Config.Server.ListenAddr + ":" + Config.Server.NonSslPort
		listenErr := http.ListenAndServe(addrNonSsl, nil)
		if listenErr != nil {
			log.Fatal("ERROR: non-ssl listen problem: " + listenErr.Error())
		}
	} else {
		// Run import if requested
		if Evh1ImportFlag {
			SpitSlurp()
			return
		}

		// Final sanity check
		if Config.Client.DestEmail == "" {
			log.Println("WARNING: no -destemail value set, cannot send reciever an email")
		}
		if Config.Client.Email == "" {
			log.Println("WARNING: no -email value set, cannot send email to uploader")
		}
		if Config.Client.Field == "" {
			log.Println("WARNING: no -field value set, using \"file\" instead")
			Config.Client.Field = "file"
		}
		if Config.Client.Url == "" {
			log.Fatal("ERROR: Cannot continue without specifying -url value")
		}

		// All filenames are unflagged arguments, loop through them and uplod the file(s)
		for _, fname := range flag.Args() {
			fi, err := os.Stat(fname)
			if err != nil {
				log.Println("WARNING: Cannot read file, skipping ", fname, ": ", err.Error())
			} else {
				if fi.Mode().IsRegular() {
					Files = append(Files, fname)
				}
			}
		}

		Upload(Files)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package efh

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"strconv"
	"time"

	"my/errs"

	"my/ev/packet"
)

type ReplayConfig struct {
	InputFileName   string
	OutputInterface string
	Pps             int
	Limit           int
	Loop            int

	EfhLoglevel  int
	EfhIgnoreGap bool
	EfhDump      string
	EfhSubscribe []string
	EfhChannel   []string
	EfhProf      bool

	TestEfh string
	Local   bool
}

type EfhReplay interface {
	Run() (err error)
}

type efhReplay struct {
	ReplayConfig
	testEfhCmd    *exec.Cmd
	testEfhDump   string
	testEfhArgs   []string
	testEfhExit   error
	testEfhDoneCh chan struct{}
	replay        *packet.Replay
}

func NewEfhReplay(conf ReplayConfig) EfhReplay {
	return &efhReplay{
		ReplayConfig: conf,
	}
}

var DumpsDifferError = errors.New("dumps differ")

func (e *efhReplay) Run() (err error) {
	defer errs.PassE(&err)
	if e.EfhDump != "" {
		e.testEfhDump = "test_efh.dump"
	}
	if e.Local {
		e.TestEfh = os.ExpandEnv("$HOME/efh-install/bin/test_efh")
		e.testEfhArgs = append(e.testEfhArgs, "--load-fw", "/usr/share/efh/firmware/fw.bin")
	}
	errs.CheckE(e.startTestEfh())
	errs.CheckE(e.startDumpReplay())
	func() {
		ticker := time.NewTicker(time.Second / 10)
		defer ticker.Stop()
		for {
			select {
			case <-e.testEfhDoneCh:
				fmt.Println()
				return
			case <-e.replay.DoneCh:
				fmt.Printf("\rdone: 100%%   \n")
				return
			case <-ticker.C:
				select {
				case done, ok := <-e.replay.ProgressCh:
					if !ok {
						done = 1
					}
					fmt.Printf("\rdone: %.1f%%", done*100)
				default:
				}
			}
		}
	}()
	errs.CheckE(e.stopDumpReplay())
	errs.CheckE(e.stopTestEfh())
	if e.testEfhDump != "" {
		var same bool
		same, err = e.diffAppDump()
		errs.CheckE(err)
		if !same {
			log.Printf("dumps differ")
			err = DumpsDifferError
		}
	}
	return
}

func (e *efhReplay) startTestEfh() (err error) {
	defer errs.PassE(&err)
	e.testEfhArgs = append(e.testEfhArgs,
		"--loglevel", strconv.Itoa(e.EfhLoglevel),
		"--logfile", "test_efh.log",
	)
	if e.EfhProf {
		e.testEfhArgs = append(e.testEfhArgs, "--prof")
	}
	for _, ch := range e.EfhChannel {
		e.testEfhArgs = append(e.testEfhArgs, "--channel", ch)
	}
	if len(e.EfhSubscribe) == 0 {
		e.testEfhArgs = append(e.testEfhArgs, "--debug-assume-subscribed")
	} else {
		for _, s := range e.EfhSubscribe {
			e.testEfhArgs = append(e.testEfhArgs, "--subscribe", s)
		}
	}
	e.testEfhArgs = append(e.testEfhArgs,
		"--debug-stop-on-status", "STATUS_RX_QUEUE_FULL",
		"--debug-stop-on-status", "STATUS_DESTINATION_IP_UNKNOWN",
		"--debug-stop-on-status", "STATUS_BAD_FRAME",
	)
	if e.EfhIgnoreGap {
		e.testEfhArgs = append(e.testEfhArgs, "--debug-disable-gap")
	}
	if e.testEfhDump != "" {
		e.testEfhArgs = append(e.testEfhArgs, "--dump-file", e.testEfhDump)
	}
	readyFile := "ready"
	e.testEfhArgs = append(e.testEfhArgs, "--readycmd", fmt.Sprintf("{ sleep 5; touch %s;}&", readyFile))

	log.Printf("starting %s %s", e.TestEfh, e.testEfhArgs)
	e.testEfhCmd = exec.Command(e.TestEfh, e.testEfhArgs...)
	out, err := os.Create("test_efh.out")
	errs.CheckE(err)
	e.testEfhCmd.Stdout = out
	e.testEfhCmd.Stderr = out

	errs.CheckE(e.testEfhCmd.Start())

	func() {
		for {
			select {
			case <-time.After(time.Second / 100):
				if _, err := os.Stat(readyFile); err == nil {
					os.Remove(readyFile)
					log.Printf("test_efh ready")
					return
				}
			case <-time.After(30 * time.Second):
				err = errors.New("timeout starting test_efh")
				log.Printf("timeout starting test_efh")
				return
			}
		}
	}()

	e.testEfhDoneCh = make(chan struct{})
	go func() {
		e.testEfhExit = e.testEfhCmd.Wait()
		close(e.testEfhDoneCh)
	}()
	return
}

func (e *efhReplay) stopTestEfh() (err error) {
	log.Printf("stopping test_efh\n")
	e.testEfhCmd.Process.Signal(os.Interrupt)
	time.AfterFunc(10*time.Second, func() { e.testEfhCmd.Process.Kill() })
	<-e.testEfhDoneCh
	log.Printf("test_efh wait: %s\n", e.testEfhExit)
	return
}

func (e *efhReplay) startDumpReplay() (err error) {
	e.replay = &packet.Replay{
		IfaceName:  e.OutputInterface,
		DumpName:   e.InputFileName,
		Limit:      e.Limit,
		Pps:        e.Pps,
		Loop:       e.Loop,
		StopCh:     make(chan struct{}),
		DoneCh:     make(chan struct{}),
		ProgressCh: make(chan float64, 1),
	}
	log.Printf("starting replay %v", e.replay)
	go func() {
		errs.CheckE(e.replay.Run())
	}()
	return
}

func (e *efhReplay) stopDumpReplay() (err error) {
	log.Printf("stopping replay\n")
	close(e.replay.StopCh)
	<-e.replay.DoneCh
	return
}

func (e *efhReplay) diffAppDump() (same bool, err error) {
	if e.testEfhDump == "" {
		return
	}
	log.Printf("compare output dumps [ %s, %s ]\n", e.EfhDump, e.testEfhDump)
	defer errs.PassE(&err)

	expFile, err := os.Open(e.EfhDump)
	errs.CheckE(err)
	defer expFile.Close()
	actFile, err := os.Open(e.testEfhDump)
	errs.CheckE(err)
	defer actFile.Close()

	expFi, err := expFile.Stat()
	errs.CheckE(err)
	actFi, err := actFile.Stat()
	errs.CheckE(err)
	if expFi.Size() != actFi.Size() {
		log.Printf("dump size differ: exp %d act %d", expFi.Size(), actFi.Size())
		return
	}

	expBytes := make([]byte, 1<<20)
	actBytes := make([]byte, 1<<20)
	pos := 0
	for {
		n1, err1 := io.ReadFull(expFile, expBytes)
		n2, err2 := io.ReadFull(actFile, actBytes)
		if n1 != n2 {
			log.Printf("dump read differ at pos %d", pos)
			return
		}
		if !bytes.Equal(expBytes[:n1], actBytes[:n1]) {
			log.Printf("dump bytes differ at pos >= %d", pos)
			return
		}
		if err1 == io.ErrUnexpectedEOF && err2 == io.ErrUnexpectedEOF || err1 == io.EOF && err2 == io.EOF {
			break
		}
		errs.CheckE(err1)
		errs.CheckE(err2)
		pos += n1
	}
	same = true
	log.Printf("dumps are the same")
	return
}
<commit_msg>efh: fix case of test_efh exiting too soon<commit_after>// Copyright (c) Ilia Kravets, 2015. All rights reserved. PROVIDED "AS IS"
// WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. See LICENSE file for details.

package efh

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"strconv"
	"time"

	"my/errs"

	"my/ev/packet"
)

type ReplayConfig struct {
	InputFileName   string
	OutputInterface string
	Pps             int
	Limit           int
	Loop            int

	EfhLoglevel  int
	EfhIgnoreGap bool
	EfhDump      string
	EfhSubscribe []string
	EfhChannel   []string
	EfhProf      bool

	TestEfh string
	Local   bool
}

type EfhReplay interface {
	Run() (err error)
}

type efhReplay struct {
	ReplayConfig
	testEfhCmd    *exec.Cmd
	testEfhDump   string
	testEfhArgs   []string
	testEfhExit   error
	testEfhDoneCh chan struct{}
	replay        *packet.Replay
}

func NewEfhReplay(conf ReplayConfig) EfhReplay {
	return &efhReplay{
		ReplayConfig: conf,
	}
}

var DumpsDifferError = errors.New("dumps differ")

func (e *efhReplay) Run() (err error) {
	defer errs.PassE(&err)
	if e.EfhDump != "" {
		e.testEfhDump = "test_efh.dump"
	}
	if e.Local {
		e.TestEfh = os.ExpandEnv("$HOME/efh-install/bin/test_efh")
		e.testEfhArgs = append(e.testEfhArgs, "--load-fw", "/usr/share/efh/firmware/fw.bin")
	}
	errs.CheckE(e.startTestEfh())
	errs.CheckE(e.startDumpReplay())
	func() {
		ticker := time.NewTicker(time.Second / 10)
		defer ticker.Stop()
		for {
			select {
			case <-e.testEfhDoneCh:
				fmt.Println()
				return
			case <-e.replay.DoneCh:
				fmt.Printf("\rdone: 100%%   \n")
				return
			case <-ticker.C:
				select {
				case done, ok := <-e.replay.ProgressCh:
					if !ok {
						done = 1
					}
					fmt.Printf("\rdone: %.1f%%", done*100)
				default:
				}
			}
		}
	}()
	errs.CheckE(e.stopDumpReplay())
	errs.CheckE(e.stopTestEfh())
	if e.testEfhDump != "" {
		var same bool
		same, err = e.diffAppDump()
		errs.CheckE(err)
		if !same {
			log.Printf("dumps differ")
			err = DumpsDifferError
		}
	}
	return
}

func (e *efhReplay) startTestEfh() (err error) {
	defer errs.PassE(&err)
	e.testEfhArgs = append(e.testEfhArgs,
		"--loglevel", strconv.Itoa(e.EfhLoglevel),
		"--logfile", "test_efh.log",
	)
	if e.EfhProf {
		e.testEfhArgs = append(e.testEfhArgs, "--prof")
	}
	for _, ch := range e.EfhChannel {
		e.testEfhArgs = append(e.testEfhArgs, "--channel", ch)
	}
	if len(e.EfhSubscribe) == 0 {
		e.testEfhArgs = append(e.testEfhArgs, "--debug-assume-subscribed")
	} else {
		for _, s := range e.EfhSubscribe {
			e.testEfhArgs = append(e.testEfhArgs, "--subscribe", s)
		}
	}
	e.testEfhArgs = append(e.testEfhArgs,
		"--debug-stop-on-status", "STATUS_RX_QUEUE_FULL",
		"--debug-stop-on-status", "STATUS_DESTINATION_IP_UNKNOWN",
		"--debug-stop-on-status", "STATUS_BAD_FRAME",
	)
	if e.EfhIgnoreGap {
		e.testEfhArgs = append(e.testEfhArgs, "--debug-disable-gap")
	}
	if e.testEfhDump != "" {
		e.testEfhArgs = append(e.testEfhArgs, "--dump-file", e.testEfhDump)
	}
	readyFile := "ready"
	e.testEfhArgs = append(e.testEfhArgs, "--readycmd", fmt.Sprintf("{ sleep 5; touch %s;}&", readyFile))

	log.Printf("starting %s %s", e.TestEfh, e.testEfhArgs)
	e.testEfhCmd = exec.Command(e.TestEfh, e.testEfhArgs...)
	out, err := os.Create("test_efh.out")
	errs.CheckE(err)
	e.testEfhCmd.Stdout = out
	e.testEfhCmd.Stderr = out

	errs.CheckE(e.testEfhCmd.Start())
	e.testEfhDoneCh = make(chan struct{})
	go func() {
		e.testEfhExit = e.testEfhCmd.Wait()
		close(e.testEfhDoneCh)
	}()

	func() {
		for {
			select {
			case <-time.After(time.Second / 100):
				if _, err := os.Stat(readyFile); err == nil {
					os.Remove(readyFile)
					log.Printf("test_efh ready")
					return
				}
			case <-time.After(30 * time.Second):
				err = errors.New("timeout starting test_efh")
				return
			case <-e.testEfhDoneCh:
				err = errors.New("test_efh exited too soon")
				return
			}
		}
	}()
	return
}

func (e *efhReplay) stopTestEfh() (err error) {
	log.Printf("stopping test_efh\n")
	e.testEfhCmd.Process.Signal(os.Interrupt)
	time.AfterFunc(10*time.Second, func() { e.testEfhCmd.Process.Kill() })
	<-e.testEfhDoneCh
	if e.testEfhExit != nil {
		log.Printf("test_efh wait: %s\n", e.testEfhExit)
	}
	return
}

func (e *efhReplay) startDumpReplay() (err error) {
	e.replay = &packet.Replay{
		IfaceName:  e.OutputInterface,
		DumpName:   e.InputFileName,
		Limit:      e.Limit,
		Pps:        e.Pps,
		Loop:       e.Loop,
		StopCh:     make(chan struct{}),
		DoneCh:     make(chan struct{}),
		ProgressCh: make(chan float64, 1),
	}
	log.Printf("starting replay %v", e.replay)
	go func() {
		errs.CheckE(e.replay.Run())
	}()
	return
}

func (e *efhReplay) stopDumpReplay() (err error) {
	log.Printf("stopping replay\n")
	close(e.replay.StopCh)
	<-e.replay.DoneCh
	return
}

func (e *efhReplay) diffAppDump() (same bool, err error) {
	if e.testEfhDump == "" {
		return
	}
	log.Printf("compare output dumps [ %s, %s ]\n", e.EfhDump, e.testEfhDump)
	defer errs.PassE(&err)

	expFile, err := os.Open(e.EfhDump)
	errs.CheckE(err)
	defer expFile.Close()
	actFile, err := os.Open(e.testEfhDump)
	errs.CheckE(err)
	defer actFile.Close()

	expFi, err := expFile.Stat()
	errs.CheckE(err)
	actFi, err := actFile.Stat()
	errs.CheckE(err)
	if expFi.Size() != actFi.Size() {
		log.Printf("dump size differ: exp %d act %d", expFi.Size(), actFi.Size())
		return
	}

	expBytes := make([]byte, 1<<20)
	actBytes := make([]byte, 1<<20)
	pos := 0
	for {
		n1, err1 := io.ReadFull(expFile, expBytes)
		n2, err2 := io.ReadFull(actFile, actBytes)
		if n1 != n2 {
			log.Printf("dump read differ at pos %d", pos)
			return
		}
		if !bytes.Equal(expBytes[:n1], actBytes[:n1]) {
			log.Printf("dump bytes differ at pos >= %d", pos)
			return
		}
		if err1 == io.ErrUnexpectedEOF && err2 == io.ErrUnexpectedEOF || err1 == io.EOF && err2 == io.EOF {
			break
		}
		errs.CheckE(err1)
		errs.CheckE(err2)
		pos += n1
	}
	same = true
	log.Printf("dumps are the same")
	return
}
<|endoftext|>


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

// Package pprof serves via its HTTP server runtime profiling data
// in the format expected by the pprof visualization tool.
// For more information about pprof, see
// http://code.google.com/p/google-perftools/.
//
// The package is typically only imported for the side effect of
// registering its HTTP handlers.
// The handled paths all begin with /debug/pprof/.
//
// To use pprof, link this package into your program:
//	import _ "net/http/pprof"
//
// If your application is not already running an http server, you
// need to start one. Add "net/http" and "log" to your imports and
// the following code to your main function:
//
// 	go func() {
// 		log.Println(http.ListenAndServe("localhost:6060", nil))
// 	}()
//
// Then use the pprof tool to look at the heap profile:
//
//	go tool pprof http://localhost:6060/debug/pprof/heap
//
// Or to look at a 30-second CPU profile:
//
//	go tool pprof http://localhost:6060/debug/pprof/profile
//
// Or to look at the goroutine blocking profile, after calling
// runtime.SetBlockProfileRate in your program:
//
//	go tool pprof http://localhost:6060/debug/pprof/block
//
// Or to collect a 5-second execution trace:
//
//	wget http://localhost:6060/debug/pprof/trace?seconds=5
//
// To view all available profiles, open http://localhost:6060/debug/pprof/
// in your browser.
//
// For a study of the facility in action, visit
//
//	https://blog.golang.org/2011/06/profiling-go-programs.html
//
package pprof

import (
	"bufio"
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"runtime"
	"runtime/pprof"
	"runtime/trace"
	"strconv"
	"strings"
	"time"
)

func init() {
	http.Handle("/debug/pprof/", http.HandlerFunc(Index))
	http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
	http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
	http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
	http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace))
}

// Cmdline responds with the running program's
// command line, with arguments separated by NUL bytes.
// The package initialization registers it as /debug/pprof/cmdline.
func Cmdline(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
}

func sleep(w http.ResponseWriter, d time.Duration) {
	var clientGone <-chan bool
	if cn, ok := w.(http.CloseNotifier); ok {
		clientGone = cn.CloseNotify()
	}
	select {
	case <-time.After(d):
	case <-clientGone:
	}
}

// Profile responds with the pprof-formatted cpu profile.
// The package initialization registers it as /debug/pprof/profile.
func Profile(w http.ResponseWriter, r *http.Request) {
	sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
	if sec == 0 {
		sec = 30
	}

	// Set Content Type assuming StartCPUProfile will work,
	// because if it does it starts writing.
	w.Header().Set("Content-Type", "application/octet-stream")
	if err := pprof.StartCPUProfile(w); err != nil {
		// StartCPUProfile failed, so no writes yet.
		// Can change header back to text content
		// and send error code.
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
		return
	}
	sleep(w, time.Duration(sec)*time.Second)
	pprof.StopCPUProfile()
}

// Trace responds with the execution trace in binary form.
// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.
// The package initialization registers it as /debug/pprof/trace.
func Trace(w http.ResponseWriter, r *http.Request) {
	sec, err := strconv.ParseFloat(r.FormValue("seconds"), 64)
	if sec <= 0 || err != nil {
		sec = 1
	}

	// Set Content Type assuming trace.Start will work,
	// because if it does it starts writing.
	w.Header().Set("Content-Type", "application/octet-stream")
	if err := trace.Start(w); err != nil {
		// trace.Start failed, so no writes yet.
		// Can change header back to text content and send error code.
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
		return
	}
	sleep(w, time.Duration(sec*float64(time.Second)))
	trace.Stop()
}

// Symbol looks up the program counters listed in the request,
// responding with a table mapping program counters to function names.
// The package initialization registers it as /debug/pprof/symbol.
func Symbol(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")

	// We have to read the whole POST body before
	// writing any output. Buffer the output here.
	var buf bytes.Buffer

	// We don't know how many symbols we have, but we
	// do have symbol information. Pprof only cares whether
	// this number is 0 (no symbols available) or > 0.
	fmt.Fprintf(&buf, "num_symbols: 1\n")

	var b *bufio.Reader
	if r.Method == "POST" {
		b = bufio.NewReader(r.Body)
	} else {
		b = bufio.NewReader(strings.NewReader(r.URL.RawQuery))
	}

	for {
		word, err := b.ReadSlice('+')
		if err == nil {
			word = word[0 : len(word)-1] // trim +
		}
		pc, _ := strconv.ParseUint(string(word), 0, 64)
		if pc != 0 {
			f := runtime.FuncForPC(uintptr(pc))
			if f != nil {
				fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name())
			}
		}

		// Wait until here to check for err; the last
		// symbol will have an err because it doesn't end in +.
		if err != nil {
			if err != io.EOF {
				fmt.Fprintf(&buf, "reading request: %v\n", err)
			}
			break
		}
	}

	w.Write(buf.Bytes())
}

// Handler returns an HTTP handler that serves the named profile.
func Handler(name string) http.Handler {
	return handler(name)
}

type handler string

func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	debug, _ := strconv.Atoi(r.FormValue("debug"))
	p := pprof.Lookup(string(name))
	if p == nil {
		w.WriteHeader(404)
		fmt.Fprintf(w, "Unknown profile: %s\n", name)
		return
	}
	gc, _ := strconv.Atoi(r.FormValue("gc"))
	if name == "heap" && gc > 0 {
		runtime.GC()
	}
	p.WriteTo(w, debug)
	return
}

// Index responds with the pprof-formatted profile named by the request.
// For example, "/debug/pprof/heap" serves the "heap" profile.
// Index responds to a request for "/debug/pprof/" with an HTML page
// listing the available profiles.
func Index(w http.ResponseWriter, r *http.Request) {
	if strings.HasPrefix(r.URL.Path, "/debug/pprof/") {
		name := strings.TrimPrefix(r.URL.Path, "/debug/pprof/")
		if name != "" {
			handler(name).ServeHTTP(w, r)
			return
		}
	}

	profiles := pprof.Profiles()
	if err := indexTmpl.Execute(w, profiles); err != nil {
		log.Print(err)
	}
}

var indexTmpl = template.Must(template.New("index").Parse(`

<title>/debug/pprof/</title>

/debug/pprof/

profiles:

{{range .}}

{{.Count}}{{.Name}}
{{end}}

full goroutine stack dump

`))
<commit_msg>net/http/pprof: remove comments pointing to gperftools<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package pprof serves via its HTTP server runtime profiling data
// in the format expected by the pprof visualization tool.
//
// The package is typically only imported for the side effect of
// registering its HTTP handlers.
// The handled paths all begin with /debug/pprof/.
//
// To use pprof, link this package into your program:
//	import _ "net/http/pprof"
//
// If your application is not already running an http server, you
// need to start one. Add "net/http" and "log" to your imports and
// the following code to your main function:
//
// 	go func() {
// 		log.Println(http.ListenAndServe("localhost:6060", nil))
// 	}()
//
// Then use the pprof tool to look at the heap profile:
//
//	go tool pprof http://localhost:6060/debug/pprof/heap
//
// Or to look at a 30-second CPU profile:
//
//	go tool pprof http://localhost:6060/debug/pprof/profile
//
// Or to look at the goroutine blocking profile, after calling
// runtime.SetBlockProfileRate in your program:
//
//	go tool pprof http://localhost:6060/debug/pprof/block
//
// Or to collect a 5-second execution trace:
//
//	wget http://localhost:6060/debug/pprof/trace?seconds=5
//
// To view all available profiles, open http://localhost:6060/debug/pprof/
// in your browser.
//
// For a study of the facility in action, visit
//
//	https://blog.golang.org/2011/06/profiling-go-programs.html
//
package pprof

import (
	"bufio"
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"runtime"
	"runtime/pprof"
	"runtime/trace"
	"strconv"
	"strings"
	"time"
)

func init() {
	http.Handle("/debug/pprof/", http.HandlerFunc(Index))
	http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
	http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
	http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
	http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace))
}

// Cmdline responds with the running program's
// command line, with arguments separated by NUL bytes.
// The package initialization registers it as /debug/pprof/cmdline.
func Cmdline(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
}

func sleep(w http.ResponseWriter, d time.Duration) {
	var clientGone <-chan bool
	if cn, ok := w.(http.CloseNotifier); ok {
		clientGone = cn.CloseNotify()
	}
	select {
	case <-time.After(d):
	case <-clientGone:
	}
}

// Profile responds with the pprof-formatted cpu profile.
// The package initialization registers it as /debug/pprof/profile.
func Profile(w http.ResponseWriter, r *http.Request) {
	sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
	if sec == 0 {
		sec = 30
	}

	// Set Content Type assuming StartCPUProfile will work,
	// because if it does it starts writing.
	w.Header().Set("Content-Type", "application/octet-stream")
	if err := pprof.StartCPUProfile(w); err != nil {
		// StartCPUProfile failed, so no writes yet.
		// Can change header back to text content
		// and send error code.
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
		return
	}
	sleep(w, time.Duration(sec)*time.Second)
	pprof.StopCPUProfile()
}

// Trace responds with the execution trace in binary form.
// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.
// The package initialization registers it as /debug/pprof/trace.
func Trace(w http.ResponseWriter, r *http.Request) {
	sec, err := strconv.ParseFloat(r.FormValue("seconds"), 64)
	if sec <= 0 || err != nil {
		sec = 1
	}

	// Set Content Type assuming trace.Start will work,
	// because if it does it starts writing.
	w.Header().Set("Content-Type", "application/octet-stream")
	if err := trace.Start(w); err != nil {
		// trace.Start failed, so no writes yet.
		// Can change header back to text content and send error code.
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
		return
	}
	sleep(w, time.Duration(sec*float64(time.Second)))
	trace.Stop()
}

// Symbol looks up the program counters listed in the request,
// responding with a table mapping program counters to function names.
// The package initialization registers it as /debug/pprof/symbol.
func Symbol(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")

	// We have to read the whole POST body before
	// writing any output. Buffer the output here.
	var buf bytes.Buffer

	// We don't know how many symbols we have, but we
	// do have symbol information. Pprof only cares whether
	// this number is 0 (no symbols available) or > 0.
	fmt.Fprintf(&buf, "num_symbols: 1\n")

	var b *bufio.Reader
	if r.Method == "POST" {
		b = bufio.NewReader(r.Body)
	} else {
		b = bufio.NewReader(strings.NewReader(r.URL.RawQuery))
	}

	for {
		word, err := b.ReadSlice('+')
		if err == nil {
			word = word[0 : len(word)-1] // trim +
		}
		pc, _ := strconv.ParseUint(string(word), 0, 64)
		if pc != 0 {
			f := runtime.FuncForPC(uintptr(pc))
			if f != nil {
				fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name())
			}
		}

		// Wait until here to check for err; the last
		// symbol will have an err because it doesn't end in +.
		if err != nil {
			if err != io.EOF {
				fmt.Fprintf(&buf, "reading request: %v\n", err)
			}
			break
		}
	}

	w.Write(buf.Bytes())
}

// Handler returns an HTTP handler that serves the named profile.
func Handler(name string) http.Handler {
	return handler(name)
}

type handler string

func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	debug, _ := strconv.Atoi(r.FormValue("debug"))
	p := pprof.Lookup(string(name))
	if p == nil {
		w.WriteHeader(404)
		fmt.Fprintf(w, "Unknown profile: %s\n", name)
		return
	}
	gc, _ := strconv.Atoi(r.FormValue("gc"))
	if name == "heap" && gc > 0 {
		runtime.GC()
	}
	p.WriteTo(w, debug)
	return
}

// Index responds with the pprof-formatted profile named by the request.
// For example, "/debug/pprof/heap" serves the "heap" profile.
// Index responds to a request for "/debug/pprof/" with an HTML page
// listing the available profiles.
func Index(w http.ResponseWriter, r *http.Request) {
	if strings.HasPrefix(r.URL.Path, "/debug/pprof/") {
		name := strings.TrimPrefix(r.URL.Path, "/debug/pprof/")
		if name != "" {
			handler(name).ServeHTTP(w, r)
			return
		}
	}

	profiles := pprof.Profiles()
	if err := indexTmpl.Execute(w, profiles); err != nil {
		log.Print(err)
	}
}

var indexTmpl = template.Must(template.New("index").Parse(`

<title>/debug/pprof/</title>

/debug/pprof/

profiles:

{{range .}}

{{.Count}}{{.Name}}
{{end}}

full goroutine stack dump

`))
<|endoftext|>


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

// This file contains support functionality for godoc.

package main

import (
	"io"
	"io/ioutil"
	"os"
	pathutil "path"
	"sort"
	"strings"
	"sync"
	"time"
	"utf8"
)

// An RWValue wraps a value and permits mutually exclusive
// access to it and records the time the value was last set.
//
type RWValue struct {
	mutex     sync.RWMutex
	value     interface{}
	timestamp int64 // time of last set(), in seconds since epoch
}

func (v *RWValue) set(value interface{}) {
	v.mutex.Lock()
	v.value = value
	v.timestamp = time.Seconds()
	v.mutex.Unlock()
}

func (v *RWValue) get() (interface{}, int64) {
	v.mutex.RLock()
	defer v.mutex.RUnlock()
	return v.value, v.timestamp
}

var cwd, _ = os.Getwd() // ignore errors

// canonicalizePaths takes a list of (directory/file) paths and returns
// the list of corresponding absolute paths in sorted (increasing) order.
// Relative paths are assumed to be relative to the current directory,
// empty and duplicate paths as well as paths for which filter(path) is
// false are discarded. filter may be nil in which case it is not used.
//
func canonicalizePaths(list []string, filter func(path string) bool) []string {
	i := 0
	for _, path := range list {
		path = strings.TrimSpace(path)
		if len(path) == 0 {
			continue // ignore empty paths (don't assume ".")
		}
		// len(path) > 0: normalize path
		if path[0] != '/' {
			path = pathutil.Join(cwd, path)
		} else {
			path = pathutil.Clean(path)
		}
		// we have a non-empty absolute path
		if filter != nil && !filter(path) {
			continue
		}
		// keep the path
		list[i] = path
		i++
	}
	list = list[0:i]

	// sort the list and remove duplicate entries
	sort.SortStrings(list)
	i = 0
	prev := ""
	for _, path := range list {
		if path != prev {
			list[i] = path
			i++
			prev = path
		}
	}

	return list[0:i]
}

// writeFileAtomically writes data to a temporary file and then
// atomically renames that file to the file named by filename.
//
func writeFileAtomically(filename string, data []byte) os.Error {
	f, err := ioutil.TempFile(cwd, filename)
	if err != nil {
		return err
	}
	n, err := f.Write(data)
	f.Close()
	if err != nil {
		return err
	}
	if n < len(data) {
		return io.ErrShortWrite
	}
	return os.Rename(f.Name(), filename)
}

// isText returns true if a significant prefix of s looks like correct UTF-8;
// that is, if it is likely that s is human-readable text.
//
func isText(s []byte) bool {
	const max = 1024 // at least utf8.UTFMax
	if len(s) > max {
		s = s[0:max]
	}
	for i, c := range string(s) {
		if i+utf8.UTFMax > len(s) {
			// last char may be incomplete - ignore
			break
		}
		if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' {
			// decoding error or control character - not a text file
			return false
		}
	}
	return true
}

// TODO(gri): Should have a mapping from extension to handler, eventually.

// textExt[x] is true if the extension x indicates a text file, and false otherwise.
var textExt = map[string]bool{
	".css": false, // must be served raw
	".js":  false, // must be served raw
}

// isTextFile returns true if the file has a known extension indicating
// a text file, or if a significant chunk of the specified file looks like
// correct UTF-8; that is, if it is likely that the file contains human-
// readable text.
//
func isTextFile(filename string) bool {
	// if the extension is known, use it for decision making
	if isText, found := textExt[pathutil.Ext(filename)]; found {
		return isText
	}

	// the extension is not known; read an initial chunk
	// of the file and check if it looks like text
	f, err := os.Open(filename, os.O_RDONLY, 0)
	if err != nil {
		return false
	}
	defer f.Close()

	var buf [1024]byte
	n, err := f.Read(buf[0:])
	if err != nil {
		return false
	}

	return isText(buf[0:n])
}
<commit_msg>godoc: godoc: Use IsAbs to test for absolute paths (fix for win32).<commit_after>// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file contains support functionality for godoc.

package main

import (
	"io"
	"io/ioutil"
	"os"
	pathutil "path"
	"sort"
	"strings"
	"sync"
	"time"
	"utf8"
)

// An RWValue wraps a value and permits mutually exclusive
// access to it and records the time the value was last set.
//
type RWValue struct {
	mutex     sync.RWMutex
	value     interface{}
	timestamp int64 // time of last set(), in seconds since epoch
}

func (v *RWValue) set(value interface{}) {
	v.mutex.Lock()
	v.value = value
	v.timestamp = time.Seconds()
	v.mutex.Unlock()
}

func (v *RWValue) get() (interface{}, int64) {
	v.mutex.RLock()
	defer v.mutex.RUnlock()
	return v.value, v.timestamp
}

var cwd, _ = os.Getwd() // ignore errors

// canonicalizePaths takes a list of (directory/file) paths and returns
// the list of corresponding absolute paths in sorted (increasing) order.
// Relative paths are assumed to be relative to the current directory,
// empty and duplicate paths as well as paths for which filter(path) is
// false are discarded. filter may be nil in which case it is not used.
//
func canonicalizePaths(list []string, filter func(path string) bool) []string {
	i := 0
	for _, path := range list {
		path = strings.TrimSpace(path)
		if len(path) == 0 {
			continue // ignore empty paths (don't assume ".")
		}
		// len(path) > 0: normalize path
		if pathutil.IsAbs(path) {
			path = pathutil.Clean(path)
		} else {
			path = pathutil.Join(cwd, path)
		}
		// we have a non-empty absolute path
		if filter != nil && !filter(path) {
			continue
		}
		// keep the path
		list[i] = path
		i++
	}
	list = list[0:i]

	// sort the list and remove duplicate entries
	sort.SortStrings(list)
	i = 0
	prev := ""
	for _, path := range list {
		if path != prev {
			list[i] = path
			i++
			prev = path
		}
	}

	return list[0:i]
}

// writeFileAtomically writes data to a temporary file and then
// atomically renames that file to the file named by filename.
//
func writeFileAtomically(filename string, data []byte) os.Error {
	f, err := ioutil.TempFile(cwd, filename)
	if err != nil {
		return err
	}
	n, err := f.Write(data)
	f.Close()
	if err != nil {
		return err
	}
	if n < len(data) {
		return io.ErrShortWrite
	}
	return os.Rename(f.Name(), filename)
}

// isText returns true if a significant prefix of s looks like correct UTF-8;
// that is, if it is likely that s is human-readable text.
//
func isText(s []byte) bool {
	const max = 1024 // at least utf8.UTFMax
	if len(s) > max {
		s = s[0:max]
	}
	for i, c := range string(s) {
		if i+utf8.UTFMax > len(s) {
			// last char may be incomplete - ignore
			break
		}
		if c == 0xFFFD || c < ' ' && c != '\n' && c != '\t' {
			// decoding error or control character - not a text file
			return false
		}
	}
	return true
}

// TODO(gri): Should have a mapping from extension to handler, eventually.

// textExt[x] is true if the extension x indicates a text file, and false otherwise.
var textExt = map[string]bool{
	".css": false, // must be served raw
	".js":  false, // must be served raw
}

// isTextFile returns true if the file has a known extension indicating
// a text file, or if a significant chunk of the specified file looks like
// correct UTF-8; that is, if it is likely that the file contains human-
// readable text.
//
func isTextFile(filename string) bool {
	// if the extension is known, use it for decision making
	if isText, found := textExt[pathutil.Ext(filename)]; found {
		return isText
	}

	// the extension is not known; read an initial chunk
	// of the file and check if it looks like text
	f, err := os.Open(filename, os.O_RDONLY, 0)
	if err != nil {
		return false
	}
	defer f.Close()

	var buf [1024]byte
	n, err := f.Read(buf[0:])
	if err != nil {
		return false
	}

	return isText(buf[0:n])
}
<|endoftext|>


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

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime/pprof"
	"strings"
)

var (
	// main operation modes
	list        = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
	write       = flag.Bool("w", false, "write result to (source) file instead of stdout")
	rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')")
	simplifyAST = flag.Bool("s", false, "simplify code")
	doDiff      = flag.Bool("d", false, "display diffs instead of rewriting files")
	allErrors   = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)")

	// debugging
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
)

const (
	tabWidth    = 8
	printerMode = printer.UseSpaces | printer.TabIndent
)

var (
	fileSet    = token.NewFileSet() // per process FileSet
	exitCode   = 0
	rewrite    func(*ast.File) *ast.File
	parserMode parser.Mode
)

func report(err error) {
	scanner.PrintError(os.Stderr, err)
	exitCode = 2
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
	flag.PrintDefaults()
}

func initParserMode() {
	parserMode = parser.ParseComments
	if *allErrors {
		parserMode |= parser.AllErrors
	}
}

func isGoFile(f os.FileInfo) bool {
	// ignore non-Go files
	name := f.Name()
	return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}

// If in == nil, the source is the contents of the file with the given filename.
func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
	if in == nil {
		f, err := os.Open(filename)
		if err != nil {
			return err
		}
		defer f.Close()
		in = f
	}

	src, err := ioutil.ReadAll(in)
	if err != nil {
		return err
	}

	file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin)
	if err != nil {
		return err
	}

	if rewrite != nil {
		if sourceAdj == nil {
			file = rewrite(file)
		} else {
			fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n")
		}
	}

	ast.SortImports(fileSet, file)

	if *simplifyAST {
		simplify(file)
	}

	res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
	if err != nil {
		return err
	}

	if !bytes.Equal(src, res) {
		// formatting has changed
		if *list {
			fmt.Fprintln(out, filename)
		}
		if *write {
			err = ioutil.WriteFile(filename, res, 0644)
			if err != nil {
				return err
			}
		}
		if *doDiff {
			data, err := diff(src, res)
			if err != nil {
				return fmt.Errorf("computing diff: %s", err)
			}
			fmt.Printf("diff %s gofmt/%s\n", filename, filename)
			out.Write(data)
		}
	}

	if !*list && !*write && !*doDiff {
		_, err = out.Write(res)
	}

	return err
}

func visitFile(path string, f os.FileInfo, err error) error {
	if err == nil && isGoFile(f) {
		err = processFile(path, nil, os.Stdout, false)
	}
	// Don't complain if a file was deleted in the meantime (i.e.
	// the directory changed concurrently while running gofmt).
	if err != nil && !os.IsNotExist(err) {
		report(err)
	}
	return nil
}

func walkDir(path string) {
	filepath.Walk(path, visitFile)
}

func main() {
	// call gofmtMain in a separate function
	// so that it can use defer and have them
	// run before the exit.
	gofmtMain()
	os.Exit(exitCode)
}

func gofmtMain() {
	flag.Usage = usage
	flag.Parse()

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err)
			exitCode = 2
			return
		}
		defer f.Close()
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	initParserMode()
	initRewrite()

	if flag.NArg() == 0 {
		if *write {
			fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input")
			exitCode = 2
			return
		}
		if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
			report(err)
		}
		return
	}

	for i := 0; i < flag.NArg(); i++ {
		path := flag.Arg(i)
		switch dir, err := os.Stat(path); {
		case err != nil:
			report(err)
		case dir.IsDir():
			walkDir(path)
		default:
			if err := processFile(path, nil, os.Stdout, false); err != nil {
				report(err)
			}
		}
	}
}

func diff(b1, b2 []byte) (data []byte, err error) {
	f1, err := ioutil.TempFile("", "gofmt")
	if err != nil {
		return
	}
	defer os.Remove(f1.Name())
	defer f1.Close()

	f2, err := ioutil.TempFile("", "gofmt")
	if err != nil {
		return
	}
	defer os.Remove(f2.Name())
	defer f2.Close()

	f1.Write(b1)
	f2.Write(b2)

	data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
	if len(data) > 0 {
		// diff exits with a non-zero status when the files don't match.
		// Ignore that failure as long as we get output.
		err = nil
	}
	return

}
<commit_msg>cmd/gofmt: don't eat source if -w fails<commit_after>// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/parser"
	"go/printer"
	"go/scanner"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime/pprof"
	"strings"
)

var (
	// main operation modes
	list        = flag.Bool("l", false, "list files whose formatting differs from gofmt's")
	write       = flag.Bool("w", false, "write result to (source) file instead of stdout")
	rewriteRule = flag.String("r", "", "rewrite rule (e.g., 'a[b:len(a)] -> a[b:]')")
	simplifyAST = flag.Bool("s", false, "simplify code")
	doDiff      = flag.Bool("d", false, "display diffs instead of rewriting files")
	allErrors   = flag.Bool("e", false, "report all errors (not just the first 10 on different lines)")

	// debugging
	cpuprofile = flag.String("cpuprofile", "", "write cpu profile to this file")
)

const (
	tabWidth    = 8
	printerMode = printer.UseSpaces | printer.TabIndent
)

var (
	fileSet    = token.NewFileSet() // per process FileSet
	exitCode   = 0
	rewrite    func(*ast.File) *ast.File
	parserMode parser.Mode
)

func report(err error) {
	scanner.PrintError(os.Stderr, err)
	exitCode = 2
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
	flag.PrintDefaults()
}

func initParserMode() {
	parserMode = parser.ParseComments
	if *allErrors {
		parserMode |= parser.AllErrors
	}
}

func isGoFile(f os.FileInfo) bool {
	// ignore non-Go files
	name := f.Name()
	return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}

// If in == nil, the source is the contents of the file with the given filename.
func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error {
	if in == nil {
		f, err := os.Open(filename)
		if err != nil {
			return err
		}
		defer f.Close()
		in = f
	}

	src, err := ioutil.ReadAll(in)
	if err != nil {
		return err
	}

	file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin)
	if err != nil {
		return err
	}

	if rewrite != nil {
		if sourceAdj == nil {
			file = rewrite(file)
		} else {
			fmt.Fprintf(os.Stderr, "warning: rewrite ignored for incomplete programs\n")
		}
	}

	ast.SortImports(fileSet, file)

	if *simplifyAST {
		simplify(file)
	}

	res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth})
	if err != nil {
		return err
	}

	if !bytes.Equal(src, res) {
		// formatting has changed
		if *list {
			fmt.Fprintln(out, filename)
		}
		if *write {
			err = writeFile(filename, res, 0644)
			if err != nil {
				return err
			}
		}
		if *doDiff {
			data, err := diff(src, res)
			if err != nil {
				return fmt.Errorf("computing diff: %s", err)
			}
			fmt.Printf("diff %s gofmt/%s\n", filename, filename)
			out.Write(data)
		}
	}

	if !*list && !*write && !*doDiff {
		_, err = out.Write(res)
	}

	return err
}

func visitFile(path string, f os.FileInfo, err error) error {
	if err == nil && isGoFile(f) {
		err = processFile(path, nil, os.Stdout, false)
	}
	// Don't complain if a file was deleted in the meantime (i.e.
	// the directory changed concurrently while running gofmt).
	if err != nil && !os.IsNotExist(err) {
		report(err)
	}
	return nil
}

func walkDir(path string) {
	filepath.Walk(path, visitFile)
}

func main() {
	// call gofmtMain in a separate function
	// so that it can use defer and have them
	// run before the exit.
	gofmtMain()
	os.Exit(exitCode)
}

func gofmtMain() {
	flag.Usage = usage
	flag.Parse()

	if *cpuprofile != "" {
		f, err := os.Create(*cpuprofile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "creating cpu profile: %s\n", err)
			exitCode = 2
			return
		}
		defer f.Close()
		pprof.StartCPUProfile(f)
		defer pprof.StopCPUProfile()
	}

	initParserMode()
	initRewrite()

	if flag.NArg() == 0 {
		if *write {
			fmt.Fprintln(os.Stderr, "error: cannot use -w with standard input")
			exitCode = 2
			return
		}
		if err := processFile("<standard input>", os.Stdin, os.Stdout, true); err != nil {
			report(err)
		}
		return
	}

	for i := 0; i < flag.NArg(); i++ {
		path := flag.Arg(i)
		switch dir, err := os.Stat(path); {
		case err != nil:
			report(err)
		case dir.IsDir():
			walkDir(path)
		default:
			if err := processFile(path, nil, os.Stdout, false); err != nil {
				report(err)
			}
		}
	}
}

func diff(b1, b2 []byte) (data []byte, err error) {
	f1, err := ioutil.TempFile("", "gofmt")
	if err != nil {
		return
	}
	defer os.Remove(f1.Name())
	defer f1.Close()

	f2, err := ioutil.TempFile("", "gofmt")
	if err != nil {
		return
	}
	defer os.Remove(f2.Name())
	defer f2.Close()

	f1.Write(b1)
	f2.Write(b2)

	data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
	if len(data) > 0 {
		// diff exits with a non-zero status when the files don't match.
		// Ignore that failure as long as we get output.
		err = nil
	}
	return

}

// writeFile is a drop-in replacement for ioutil.WriteFile;
// but writeFile writes data to a temporary file first and
// only upon success renames that file to filename.
// TODO(gri) This can be removed if #17869 is accepted and
// implemented.
func writeFile(filename string, data []byte, perm os.FileMode) error {
	// open temp file
	f, err := ioutil.TempFile(filepath.Dir(filename), "tmp")
	if err != nil {
		return err
	}
	err = f.Chmod(perm)
	if err != nil {
		return err
	}
	tmpname := f.Name()

	// write data to temp file
	n, err := f.Write(data)
	if err == nil && n < len(data) {
		err = io.ErrShortWrite
	}
	if err1 := f.Close(); err == nil {
		err = err1
	}
	if err != nil {
		return err
	}

	return os.Rename(tmpname, filename)
}
<|endoftext|>


<commit_before>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
// Author: arnej

package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/vespa-engine/vespa/client/go/cmd/clusterstate"
	"github.com/vespa-engine/vespa/client/go/cmd/deploy"
	"github.com/vespa-engine/vespa/client/go/cmd/logfmt"
	"github.com/vespa-engine/vespa/client/go/jvm"
	"github.com/vespa-engine/vespa/client/go/script-utils/configserver"
	"github.com/vespa-engine/vespa/client/go/script-utils/startcbinary"
	"github.com/vespa-engine/vespa/client/go/util"
	"github.com/vespa-engine/vespa/client/go/vespa"
)

func basename(s string) string {
	parts := strings.Split(s, "/")
	return parts[len(parts)-1]
}

func main() {
	defer handleSimplePanic()
	_ = vespa.FindAndVerifyVespaHome()
	action := basename(os.Args[0])
	if action == "script-utils" && len(os.Args) > 1 {
		action = os.Args[1]
		os.Args = os.Args[1:]
	}
	switch action {
	case "vespa-start-configserver":
		os.Exit(configserver.StartConfigserverEtc())
	case "just-start-configserver":
		os.Exit(configserver.JustStartConfigserver())
	case "vespa-start-container-daemon":
		os.Exit(jvm.RunApplicationContainer(os.Args[1:]))
	case "start-c-binary":
		os.Exit(startcbinary.Run(os.Args[1:]))
	case "export-env":
		vespa.ExportDefaultEnvToSh()
	case "security-env", "vespa-security-env":
		vespa.ExportSecurityEnvToSh()
	case "ipv6-only":
		if vespa.HasOnlyIpV6() {
			os.Exit(0)
		} else {
			os.Exit(1)
		}
	case "vespa-deploy":
		cobra := deploy.NewDeployCmd()
		cobra.Execute()
	case "vespa-logfmt":
		cobra := logfmt.NewLogfmtCmd()
		cobra.Execute()
	case "vespa-get-cluster-state":
		cobra := clusterstate.NewGetClusterStateCmd()
		cobra.Execute()
	case "vespa-get-node-state":
		cobra := clusterstate.NewGetNodeStateCmd()
		cobra.Execute()
	case "vespa-set-node-state":
		cobra := clusterstate.NewSetNodeStateCmd()
		cobra.Execute()
	default:
		if startcbinary.IsCandidate(os.Args[0]) {
			os.Exit(startcbinary.Run(os.Args))
		}
		fmt.Fprintf(os.Stderr, "unknown action '%s'\n", action)
		fmt.Fprintln(os.Stderr, "actions: export-env, ipv6-only, security-env")
		fmt.Fprintln(os.Stderr, "(also: vespa-deploy, vespa-logfmt)")
	}
}

func handleSimplePanic() {
	if r := recover(); r != nil {
		if jee, ok := r.(*util.JustExitError); ok {
			fmt.Fprintln(os.Stderr, jee)
			os.Exit(1)
		} else {
			panic(r)
		}
	}
}
<commit_msg>add "detect-hostname" mode<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
// Author: arnej

package main

import (
	"fmt"
	"os"
	"strings"

	"github.com/vespa-engine/vespa/client/go/cmd/clusterstate"
	"github.com/vespa-engine/vespa/client/go/cmd/deploy"
	"github.com/vespa-engine/vespa/client/go/cmd/logfmt"
	"github.com/vespa-engine/vespa/client/go/jvm"
	"github.com/vespa-engine/vespa/client/go/script-utils/configserver"
	"github.com/vespa-engine/vespa/client/go/script-utils/startcbinary"
	"github.com/vespa-engine/vespa/client/go/util"
	"github.com/vespa-engine/vespa/client/go/vespa"
)

func basename(s string) string {
	parts := strings.Split(s, "/")
	return parts[len(parts)-1]
}

func main() {
	defer handleSimplePanic()
	_ = vespa.FindAndVerifyVespaHome()
	action := basename(os.Args[0])
	if action == "script-utils" && len(os.Args) > 1 {
		action = os.Args[1]
		os.Args = os.Args[1:]
	}
	switch action {
	case "vespa-start-configserver":
		os.Exit(configserver.StartConfigserverEtc())
	case "just-start-configserver":
		os.Exit(configserver.JustStartConfigserver())
	case "vespa-start-container-daemon":
		os.Exit(jvm.RunApplicationContainer(os.Args[1:]))
	case "start-c-binary":
		os.Exit(startcbinary.Run(os.Args[1:]))
	case "export-env":
		vespa.ExportDefaultEnvToSh()
	case "security-env", "vespa-security-env":
		vespa.ExportSecurityEnvToSh()
	case "ipv6-only":
		if vespa.HasOnlyIpV6() {
			os.Exit(0)
		} else {
			os.Exit(1)
		}
	case "detect-hostname":
		myName, err := vespa.FindOurHostname()
		fmt.Println(myName)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	case "vespa-deploy":
		cobra := deploy.NewDeployCmd()
		cobra.Execute()
	case "vespa-logfmt":
		cobra := logfmt.NewLogfmtCmd()
		cobra.Execute()
	case "vespa-get-cluster-state":
		cobra := clusterstate.NewGetClusterStateCmd()
		cobra.Execute()
	case "vespa-get-node-state":
		cobra := clusterstate.NewGetNodeStateCmd()
		cobra.Execute()
	case "vespa-set-node-state":
		cobra := clusterstate.NewSetNodeStateCmd()
		cobra.Execute()
	default:
		if startcbinary.IsCandidate(os.Args[0]) {
			os.Exit(startcbinary.Run(os.Args))
		}
		fmt.Fprintf(os.Stderr, "unknown action '%s'\n", action)
		fmt.Fprintln(os.Stderr, "actions: export-env, ipv6-only, security-env, detect-hostname")
		fmt.Fprintln(os.Stderr, "(also: vespa-deploy, vespa-logfmt)")
	}
}

func handleSimplePanic() {
	if r := recover(); r != nil {
		if jee, ok := r.(*util.JustExitError); ok {
			fmt.Fprintln(os.Stderr, jee)
			os.Exit(1)
		} else {
			panic(r)
		}
	}
}
<|endoftext|>


<commit_before>/*
renamer.go

Renaming files script on various patterns

Author: Gianluca Fiore <forod.g@gmail.com> © 2013
*/

package main

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

var usageMessage string = `
renamer.go (-p <prefix>|-s <suffix>|-i <indexname> -I <num>|-l|-u) [-x <regexp>] [-t <target_dir>] -[cnr]

renamer.go will rename all files matching a regexp or all files in the
given directory (and optionally in all its subdirectories) by the flag
chosen. It can add a prefix/suffix, rename according to a
<name><numeric_index> pattern, make all low/uppercase and copy files
somewhere else leaving the originals untouched.

Arguments:

	-prefix|-p <prefix>
		Renames matching files by adding a prefix

	-suffix|-s <suffix>
		Renames matching files by adding a suffix

	-index|-i <name>
		Renames matching files to <name><num>. Requires '-I'

	-startnumber|-I <num>
		The <num> to start renaming in index mode. Requires '-i'

	-regexp|-x <regexp>
		The regular expression for matching files. Use double quotes
		around it

	-target-dir|-t <path>
		The directory where to rename/copy the files. Default is the
		current directory

	-copy|-c
		Copy instead of renaming

	-lowercase|-l
		Lowercase the new filename. It is mutually exclusive with
		'-u'

	-uppercase|-u
		Uppercase the new filename. It is mutually exclusive with
		'-l'

	-dry-run|-n
		List files but don't actually perform any action

	-force|-f
		Overwrite existing files. The default is to not copy/rename
		if the target file already exists

	-recursive|-r
		Operate recursively on all subdirectories of target-dir
`

var regexpArg string // the regexp argument
var fileRegex *regexp.Regexp // the files matching the regexp
var prefixArg string // the prefix
var suffixArg string // the suffix
var indexArg string  // the <name> in the <name><num> pattern
var numArg int // the <num> in the <name><num> pattern
var targetArg string // the target directory
var lowerArg bool // the lowercase switch
var upperArg bool // the uppercase switch
var copyArg bool // the copy switch
var dryrunArg bool // the dry-run switch
var forceArg bool  // the force switch
var recursiveArg bool // the recursive switch

var operationSuccessful int // numeric flag to keep trace of what went
			// wrong during the renaming

// Print a message and the usage instructions
func printUsage(msg string) {
	fmt.Fprintf(os.Stderr, msg + "\n")
	fmt.Fprintf(os.Stderr, usageMessage)
	os.Exit(2)
}

// Parse flags ("arguments")
func flagsInit() {
	// Use our custom usageMessage to print usage instructions
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usageMessage)
	}

	const (
		def_regexp		= ""
		def_prefix		= ""
		def_suffix		= ""
		def_index		= ""
		def_num			= 1
		def_target		= ""
		def_lowercase	= false
		def_uppercase	= false
		def_copy		= false
		def_dryrun		= false
		def_force		= false
		def_recursive	= false
	)

	flag.StringVar(&regexpArg, "regexp", def_regexp, "")
	flag.StringVar(&regexpArg, "x", def_regexp, "")
	flag.StringVar(&prefixArg, "prefix", def_prefix, "")
	flag.StringVar(&prefixArg, "p", def_prefix, "")
	flag.StringVar(&suffixArg, "suffix", def_suffix, "")
	flag.StringVar(&suffixArg, "s", def_suffix, "")
	flag.StringVar(&indexArg, "index", def_index, "")
	flag.StringVar(&indexArg, "i", def_index, "")
	flag.IntVar(&numArg, "startnumber", def_num, "")
	flag.IntVar(&numArg, "I", def_num, "")
	flag.StringVar(&targetArg, "target", def_target, "")
	flag.StringVar(&targetArg, "t", def_target, "")
	flag.BoolVar(&lowerArg, "lowercase", def_lowercase, "")
	flag.BoolVar(&lowerArg, "l", def_lowercase, "")
	flag.BoolVar(&upperArg, "uppercase", def_uppercase, "")
	flag.BoolVar(&upperArg, "u", def_uppercase, "")
	flag.BoolVar(&copyArg, "copy", def_copy, "")
	flag.BoolVar(&copyArg, "c", def_copy, "")
	flag.BoolVar(&dryrunArg, "dry-run", def_dryrun, "")
	flag.BoolVar(&dryrunArg, "n", def_dryrun, "")
	flag.BoolVar(&forceArg, "force", def_force, "")
	flag.BoolVar(&forceArg, "f", def_force, "")
	flag.BoolVar(&recursiveArg, "recursive", def_recursive, "")
	flag.BoolVar(&recursiveArg, "r", def_recursive, "")

	flag.Parse()

	if regexpArg == "" && prefixArg == "" && suffixArg == "" && indexArg == "" && lowerArg == false && upperArg == false {
		printUsage("At least one of the mandatory actions must be given, nothing to do...")
	}
}

// Write a renamed or a copy of a file to disk
func writeFile(oldname, newname string) {
/*	newname = filepath.Join(targetArg, newname)
/*	oldname = filepath.Join(targetArg, oldname) */
	// check if the new filename is already present
	_, lstat_err := os.Lstat(newname)
	if lstat_err == nil && forceArg == false {
		fmt.Fprintf(os.Stderr, "File %s already exist! Use -force to override it\n", newname)
		operationSuccessful = operationSuccessful + 1
	}
	if dryrunArg {
		// if dry-run was given, just output the renaming operation
		fmt.Fprintf(os.Stdout, "Renaming %s to %s (dry-run)\n", oldname, newname)
		operationSuccessful = operationSuccessful + 0
	} else {
		if copyArg {
			copyf, create_err := os.Create(newname)
			if create_err != nil {
				fmt.Fprintf(os.Stderr, create_err.Error())
				operationSuccessful = operationSuccessful + 1
			}
			originalf, open_err := os.Open(oldname)
			if open_err != nil {
				fmt.Fprintf(os.Stderr, open_err.Error())
				operationSuccessful = operationSuccessful + 1
			}
			_, copy_err := io.Copy(copyf, originalf)
			if copy_err != nil {
				fmt.Fprintf(os.Stderr, "An error occurred during the copy of %s to %s\n", oldname, newname)
				fmt.Fprintf(os.Stderr, copy_err.Error())
				operationSuccessful = operationSuccessful + 1
			} else {
				fmt.Fprintf(os.Stdout, "Copying %s to %s\n", oldname, newname)
			}
		} else {
			rename_err := os.Rename(oldname, newname)
			if rename_err != nil {
				fmt.Fprintf(os.Stderr, "An error occurred during the renaming of %s to %s\n", oldname, newname)
				fmt.Fprintf(os.Stderr, rename_err.Error())
				operationSuccessful = operationSuccessful + 1
			} else {
				fmt.Fprintf(os.Stdout, "Renaming %s to %s\n", oldname, newname)
			}
		}
	}
}

// Add a prefix string to a name
func addPrefix(names []string, prefix string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f) + "/"
		finalname = dirname + prefix + filepath.Base(f)
		writeFile(f, finalname)
	}
	return 0
}

// Add a suffix string to a name
func addSuffix(names []string, suffix string) int {
	var finalname, dirname, justname, ext string
	for _, f := range names {
		ext = filepath.Ext(f)
		dirname = filepath.Dir(f) + "/"
		justname = strings.TrimSuffix(filepath.Base(f), ext)
		finalname = dirname + justname + suffix + ext
		writeFile(f, finalname)
	}
	return 0
}

// Rename a slice of filenames to <newname><count>.<extension>
func indexName(names []string, newname string, count int) int {
	var finalname, dirname, ext string
	for _, f := range names {
		ext = filepath.Ext(f)
		dirname = filepath.Dir(f) + "/"
		finalname = fmt.Sprintf("%s%s%03d%s", dirname, newname, count, ext)
		writeFile(f, finalname)
		count++
	}
	return 0
}

// Make filenames all lowercase
func lowercaseFiles(names []string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f) + "/"
		finalname = dirname + strings.ToLower(filepath.Base(f))
		writeFile(f, finalname)
	}
	return 0
}

// Make filenames all uppercase
func uppercaseFiles(names []string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f) + "/"
		finalname = dirname + strings.ToUpper(filepath.Base(f))
		writeFile(f, finalname)
	}
	return 0
}

// Get all files and directories
func getFilesFromDir(dirname string) ([]string, []string) {
	var complete_path string // final, absolute, path
	var filesindir = make([]os.FileInfo, 0) // files & directories found in path
	var allfiles = make([]string, 0)
	var alldirectories = make([]string, 0)

	dirinfo, lerr := os.Lstat(dirname)
	if lerr != nil {
		fmt.Fprintf(os.Stderr, lerr.Error())
		return alldirectories, allfiles
	}

	// check whether targetArg is an absolute path AND a directory
	if filepath.IsAbs(dirname) && dirinfo.IsDir() {
		complete_path = dirname
	} else {
		abs_path, err := filepath.Abs(dirname)
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
		}
		complete_path = abs_path
	}
	dir, err := os.Open(complete_path)
	defer dir.Close()
	if err != nil {
		err = errors.New(fmt.Sprintf("Target directory %s is not a directory or can't be accessed\n", complete_path))
		fmt.Fprintf(os.Stderr, err.Error())
		return alldirectories, allfiles
	}

	// scan for files/directories in path
	filesindir, read_err := dir.Readdir(0)
	if read_err != nil {
		fmt.Fprintf(os.Stderr, read_err.Error())
		return alldirectories, allfiles
	}

	// check in filesindir slice and separate directories from files in
	// 2 different slices
	for _, f := range filesindir {
		if f.IsDir() {
			alldirectories = append(alldirectories, filepath.Join(complete_path, f.Name()))
		} else {
			allfiles = append(allfiles, filepath.Join(complete_path, f.Name()))
		}
	}

	return alldirectories, allfiles
}

func renameFiles(dir, files []string) int {
	var basename string
	var matchingfiles []string // a slice containing only the files
					// matching the regexp passed as argument (if)
	var result int // the integer returned by each functions, signaling
					// success or failure

	// recursively search on every directory in dir for other
	// files/directories if recursiveArg switch has been enabled
	if dir != nil && recursiveArg == true {
		for _, d := range dir {
			nd, nf := getFilesFromDir(d)
			// if it's a dir, append to []dir
			if len(nd) > 0 {
				for _, i := range nd {
					dir = append(dir, i)
				}
			}
			// if it's a file, append to []files
			if len(nf) > 0 {
				for _, i := range nf {
					files = append(files, i)
				}
			}
		}
	}

	// check if the files should match a given regexp
	if regexpArg != "" {
		for _, f := range files {
		basename = filepath.Base(f)
			// Compile and check if the regexp is a valid one
			compRegexp, err := regexp.Compile(regexpArg)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Invalid regexp: %s\n", regexpArg)
				printUsage("You must give a valid regexp (or none, to operate on all files). Alternatively, add -force to force renaming all files, whether they match the regexp or not")
				return 1
			} else {
				if compRegexp.MatchString(basename) == false {
					continue
				} else {
					matchingfiles = append(matchingfiles, f)
				}
			}
		}
	}

	// if matchingfiles contains something, iterate over it.
	// Otherwise, we simply use the generic files slice
	if len(matchingfiles) >= 1 {
		files = matchingfiles
	} else {
		// different messages whether we have forceArg == true or false
		if regexpArg != "" {
			if forceArg {
				fmt.Fprintf(os.Stdout, "No files matched, including all files anyway (-force enabled)\n")
			} else {
				fmt.Fprintf(os.Stderr, "No files matched, check the correctness of your regexp\n")
				return 1
			}
		}
	}

	if prefixArg != "" {
		result = addPrefix(files, prefixArg)
	}
	if suffixArg != "" {
		result = addSuffix(files, suffixArg)
	}
	if indexArg != "" {
		result = indexName(files, indexArg, numArg)
	}
	if lowerArg == true && upperArg == true {
		// can't use both
		printUsage("Can't use both lowercase and uppercase, choose one only!")
		return 1
	}
	if lowerArg == true {
		result = lowercaseFiles(files)
	}
	if upperArg == true {
		result = uppercaseFiles(files)
	}

	return result
}

func main() {
	var success_rename int
	var directories, files []string

	flagsInit()

	directories, files = getFilesFromDir(targetArg)

	success_rename = renameFiles(directories, files)

	// check that everything went smoothly
	if success_rename == 0  && operationSuccessful == 0 {
		fmt.Fprintf(os.Stdout, "\nRenaming complete\n")
	} else {
		fmt.Fprintf(os.Stdout, "\nNot all files were correctly renamed, check the previous error messages")
	}
}
<commit_msg>Substitute path string concatenations with filepath.Join()<commit_after>/*
renamer.go

Renaming files script on various patterns

Author: Gianluca Fiore <forod.g@gmail.com> © 2013
*/

package main

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

var usageMessage string = `
renamer.go (-p <prefix>|-s <suffix>|-i <indexname> -I <num>|-l|-u) [-x <regexp>] [-t <target_dir>] -[cnr]

renamer.go will rename all files matching a regexp or all files in the
given directory (and optionally in all its subdirectories) by the flag
chosen. It can add a prefix/suffix, rename according to a
<name><numeric_index> pattern, make all low/uppercase and copy files
somewhere else leaving the originals untouched.

Arguments:

	-prefix|-p <prefix>
		Renames matching files by adding a prefix

	-suffix|-s <suffix>
		Renames matching files by adding a suffix

	-index|-i <name>
		Renames matching files to <name><num>. Requires '-I'

	-startnumber|-I <num>
		The <num> to start renaming in index mode. Requires '-i'

	-regexp|-x <regexp>
		The regular expression for matching files. Use double quotes
		around it

	-target-dir|-t <path>
		The directory where to rename/copy the files. Default is the
		current directory

	-copy|-c
		Copy instead of renaming

	-lowercase|-l
		Lowercase the new filename. It is mutually exclusive with
		'-u'

	-uppercase|-u
		Uppercase the new filename. It is mutually exclusive with
		'-l'

	-dry-run|-n
		List files but don't actually perform any action

	-force|-f
		Overwrite existing files. The default is to not copy/rename
		if the target file already exists

	-recursive|-r
		Operate recursively on all subdirectories of target-dir
`

var regexpArg string // the regexp argument
var fileRegex *regexp.Regexp // the files matching the regexp
var prefixArg string // the prefix
var suffixArg string // the suffix
var indexArg string  // the <name> in the <name><num> pattern
var numArg int // the <num> in the <name><num> pattern
var targetArg string // the target directory
var lowerArg bool // the lowercase switch
var upperArg bool // the uppercase switch
var copyArg bool // the copy switch
var dryrunArg bool // the dry-run switch
var forceArg bool  // the force switch
var recursiveArg bool // the recursive switch

var operationSuccessful int // numeric flag to keep trace of what went
			// wrong during the renaming

// Print a message and the usage instructions
func printUsage(msg string) {
	fmt.Fprintf(os.Stderr, msg + "\n")
	fmt.Fprintf(os.Stderr, usageMessage)
	os.Exit(2)
}

// Parse flags ("arguments")
func flagsInit() {
	// Use our custom usageMessage to print usage instructions
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usageMessage)
	}

	const (
		def_regexp		= ""
		def_prefix		= ""
		def_suffix		= ""
		def_index		= ""
		def_num			= 1
		def_target		= ""
		def_lowercase	= false
		def_uppercase	= false
		def_copy		= false
		def_dryrun		= false
		def_force		= false
		def_recursive	= false
	)

	flag.StringVar(&regexpArg, "regexp", def_regexp, "")
	flag.StringVar(&regexpArg, "x", def_regexp, "")
	flag.StringVar(&prefixArg, "prefix", def_prefix, "")
	flag.StringVar(&prefixArg, "p", def_prefix, "")
	flag.StringVar(&suffixArg, "suffix", def_suffix, "")
	flag.StringVar(&suffixArg, "s", def_suffix, "")
	flag.StringVar(&indexArg, "index", def_index, "")
	flag.StringVar(&indexArg, "i", def_index, "")
	flag.IntVar(&numArg, "startnumber", def_num, "")
	flag.IntVar(&numArg, "I", def_num, "")
	flag.StringVar(&targetArg, "target", def_target, "")
	flag.StringVar(&targetArg, "t", def_target, "")
	flag.BoolVar(&lowerArg, "lowercase", def_lowercase, "")
	flag.BoolVar(&lowerArg, "l", def_lowercase, "")
	flag.BoolVar(&upperArg, "uppercase", def_uppercase, "")
	flag.BoolVar(&upperArg, "u", def_uppercase, "")
	flag.BoolVar(&copyArg, "copy", def_copy, "")
	flag.BoolVar(&copyArg, "c", def_copy, "")
	flag.BoolVar(&dryrunArg, "dry-run", def_dryrun, "")
	flag.BoolVar(&dryrunArg, "n", def_dryrun, "")
	flag.BoolVar(&forceArg, "force", def_force, "")
	flag.BoolVar(&forceArg, "f", def_force, "")
	flag.BoolVar(&recursiveArg, "recursive", def_recursive, "")
	flag.BoolVar(&recursiveArg, "r", def_recursive, "")

	flag.Parse()

	if regexpArg == "" && prefixArg == "" && suffixArg == "" && indexArg == "" && lowerArg == false && upperArg == false {
		printUsage("At least one of the mandatory actions must be given, nothing to do...")
	}
}

// Write a renamed or a copy of a file to disk
func writeFile(oldname, newname string) {
/*	newname = filepath.Join(targetArg, newname)
/*	oldname = filepath.Join(targetArg, oldname) */
	// check if the new filename is already present
	_, lstat_err := os.Lstat(newname)
	if lstat_err == nil && forceArg == false {
		fmt.Fprintf(os.Stderr, "File %s already exist! Use -force to override it\n", newname)
		operationSuccessful = operationSuccessful + 1
	}
	if dryrunArg {
		// if dry-run was given, just output the renaming operation
		fmt.Fprintf(os.Stdout, "Renaming %s to %s (dry-run)\n", oldname, newname)
		operationSuccessful = operationSuccessful + 0
	} else {
		if copyArg {
			copyf, create_err := os.Create(newname)
			if create_err != nil {
				fmt.Fprintf(os.Stderr, create_err.Error())
				operationSuccessful = operationSuccessful + 1
			}
			originalf, open_err := os.Open(oldname)
			if open_err != nil {
				fmt.Fprintf(os.Stderr, open_err.Error())
				operationSuccessful = operationSuccessful + 1
			}
			_, copy_err := io.Copy(copyf, originalf)
			if copy_err != nil {
				fmt.Fprintf(os.Stderr, "An error occurred during the copy of %s to %s\n", oldname, newname)
				fmt.Fprintf(os.Stderr, copy_err.Error())
				operationSuccessful = operationSuccessful + 1
			} else {
				fmt.Fprintf(os.Stdout, "Copying %s to %s\n", oldname, newname)
			}
		} else {
			rename_err := os.Rename(oldname, newname)
			if rename_err != nil {
				fmt.Fprintf(os.Stderr, "An error occurred during the renaming of %s to %s\n", oldname, newname)
				fmt.Fprintf(os.Stderr, rename_err.Error())
				operationSuccessful = operationSuccessful + 1
			} else {
				fmt.Fprintf(os.Stdout, "Renaming %s to %s\n", oldname, newname)
			}
		}
	}
}

// Add a prefix string to a name
func addPrefix(names []string, prefix string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f)
		finalname = filepath.Join(dirname, prefix + filepath.Base(f))
		writeFile(f, finalname)
	}
	return 0
}

// Add a suffix string to a name
func addSuffix(names []string, suffix string) int {
	var finalname, dirname, justname, ext string
	for _, f := range names {
		ext = filepath.Ext(f)
		dirname = filepath.Dir(f)
		justname = strings.TrimSuffix(filepath.Base(f), ext)
		finalname = filepath.Join(dirname, justname + suffix + ext)
		writeFile(f, finalname)
	}
	return 0
}

// Rename a slice of filenames to <newname><count>.<extension>
func indexName(names []string, newname string, count int) int {
	var finalname, dirname, ext string
	for _, f := range names {
		ext = filepath.Ext(f)
		dirname = filepath.Dir(f)
		finalname = fmt.Sprintf("%s/%s%03d%s", dirname, newname, count, ext)
		writeFile(f, finalname)
		count++
	}
	return 0
}

// Make filenames all lowercase
func lowercaseFiles(names []string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f)
		finalname = filepath.Join(dirname, strings.ToLower(filepath.Base(f)))
		writeFile(f, finalname)
	}
	return 0
}

// Make filenames all uppercase
func uppercaseFiles(names []string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f)
		finalname = filepath.Join(dirname, strings.ToUpper(filepath.Base(f)))
		writeFile(f, finalname)
	}
	return 0
}

// Get all files and directories
func getFilesFromDir(dirname string) ([]string, []string) {
	var complete_path string // final, absolute, path
	var filesindir = make([]os.FileInfo, 0) // files & directories found in path
	var allfiles = make([]string, 0)
	var alldirectories = make([]string, 0)

	dirinfo, lerr := os.Lstat(dirname)
	if lerr != nil {
		fmt.Fprintf(os.Stderr, lerr.Error())
		return alldirectories, allfiles
	}

	// check whether targetArg is an absolute path AND a directory
	if filepath.IsAbs(dirname) && dirinfo.IsDir() {
		complete_path = dirname
	} else {
		abs_path, err := filepath.Abs(dirname)
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
		}
		complete_path = abs_path
	}
	dir, err := os.Open(complete_path)
	defer dir.Close()
	if err != nil {
		err = errors.New(fmt.Sprintf("Target directory %s is not a directory or can't be accessed\n", complete_path))
		fmt.Fprintf(os.Stderr, err.Error())
		return alldirectories, allfiles
	}

	// scan for files/directories in path
	filesindir, read_err := dir.Readdir(0)
	if read_err != nil {
		fmt.Fprintf(os.Stderr, read_err.Error())
		return alldirectories, allfiles
	}

	// check in filesindir slice and separate directories from files in
	// 2 different slices
	for _, f := range filesindir {
		if f.IsDir() {
			alldirectories = append(alldirectories, filepath.Join(complete_path, f.Name()))
		} else {
			allfiles = append(allfiles, filepath.Join(complete_path, f.Name()))
		}
	}

	return alldirectories, allfiles
}

func renameFiles(dir, files []string) int {
	var basename string
	var matchingfiles []string // a slice containing only the files
					// matching the regexp passed as argument (if)
	var result int // the integer returned by each functions, signaling
					// success or failure

	// recursively search on every directory in dir for other
	// files/directories if recursiveArg switch has been enabled
	if dir != nil && recursiveArg == true {
		for _, d := range dir {
			nd, nf := getFilesFromDir(d)
			// if it's a dir, append to []dir
			if len(nd) > 0 {
				for _, i := range nd {
					dir = append(dir, i)
				}
			}
			// if it's a file, append to []files
			if len(nf) > 0 {
				for _, i := range nf {
					files = append(files, i)
				}
			}
		}
	}

	// check if the files should match a given regexp
	if regexpArg != "" {
		for _, f := range files {
		basename = filepath.Base(f)
			// Compile and check if the regexp is a valid one
			compRegexp, err := regexp.Compile(regexpArg)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Invalid regexp: %s\n", regexpArg)
				printUsage("You must give a valid regexp (or none, to operate on all files). Alternatively, add -force to force renaming all files, whether they match the regexp or not")
				return 1
			} else {
				if compRegexp.MatchString(basename) == false {
					continue
				} else {
					matchingfiles = append(matchingfiles, f)
				}
			}
		}
	}

	// if matchingfiles contains something, iterate over it.
	// Otherwise, we simply use the generic files slice
	if len(matchingfiles) >= 1 {
		files = matchingfiles
	} else {
		// different messages whether we have forceArg == true or false
		if regexpArg != "" {
			if forceArg {
				fmt.Fprintf(os.Stdout, "No files matched, including all files anyway (-force enabled)\n")
			} else {
				fmt.Fprintf(os.Stderr, "No files matched, check the correctness of your regexp\n")
				return 1
			}
		}
	}

	if prefixArg != "" {
		result = addPrefix(files, prefixArg)
	}
	if suffixArg != "" {
		result = addSuffix(files, suffixArg)
	}
	if indexArg != "" {
		result = indexName(files, indexArg, numArg)
	}
	if lowerArg == true && upperArg == true {
		// can't use both
		printUsage("Can't use both lowercase and uppercase, choose one only!")
		return 1
	}
	if lowerArg == true {
		result = lowercaseFiles(files)
	}
	if upperArg == true {
		result = uppercaseFiles(files)
	}

	return result
}

func main() {
	var success_rename int
	var directories, files []string

	flagsInit()

	directories, files = getFilesFromDir(targetArg)

	success_rename = renameFiles(directories, files)

	// check that everything went smoothly
	if success_rename == 0  && operationSuccessful == 0 {
		fmt.Fprintf(os.Stdout, "\nRenaming complete\n")
	} else {
		fmt.Fprintf(os.Stdout, "\nNot all files were correctly renamed, check the previous error messages")
	}
}
<|endoftext|>