<commit_before>package main

import (
	"flag"
	"fmt"
	ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
	"io"
	"math"
	"net"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"
)

var config struct {
	server string
	port   int
	passwd string
	method string
	core   int
	nconn  int
	nreq   int
	// nsec   int
}

var debug ss.DebugLog

func doOneRequest(client *http.Client, uri string, buf []byte) (err error) {
	resp, err := client.Get(uri)
	if err != nil {
		fmt.Printf("GET %s error: %v\n", uri, err)
		return err
	}
	for err == nil {
		_, err = resp.Body.Read(buf)
		if debug {
			debug.Println(string(buf))
		}
	}
	if err != io.EOF {
		fmt.Printf("Read %s response error: %v\n", uri, err)
	} else {
		err = nil
	}
	return
}

func get(connid int, uri, serverAddr string, rawAddr []byte, cipher ss.Cipher, done chan []time.Duration) {
	reqDone := 0
	reqTime := make([]time.Duration, config.nreq)
	defer func() {
		done <- reqTime[:reqDone]
	}()
	tr := &http.Transport{
		Dial: func(_, _ string) (net.Conn, error) {
			return ss.DialWithRawAddr(rawAddr, serverAddr, cipher.Copy())
		},
	}

	buf := make([]byte, 8192)
	client := &http.Client{Transport: tr}
	for ; reqDone < config.nreq; reqDone++ {
		start := time.Now()
		if err := doOneRequest(client, uri, buf); err != nil {
			return
		}
		reqTime[reqDone] = time.Now().Sub(start)

		if (reqDone+1)%1000 == 0 {
			fmt.Printf("conn %d finished %d get requests\n", connid, reqDone+1)
		}
	}
}

func main() {
	flag.StringVar(&config.server, "s", "127.0.0.1", "server:port")
	flag.IntVar(&config.port, "p", 0, "server:port")
	flag.IntVar(&config.core, "core", 1, "number of CPU cores to use")
	flag.StringVar(&config.passwd, "k", "", "password")
	flag.StringVar(&config.method, "m", "", "encryption method, use empty string or rc4")
	flag.IntVar(&config.nconn, "nc", 1, "number of connection to server")
	flag.IntVar(&config.nreq, "nr", 1, "number of request for each connection")
	// flag.IntVar(&config.nsec, "ns", 0, "run how many seconds for each connection")
	flag.BoolVar((*bool)(&debug), "d", false, "print http response body for debugging")

	flag.Parse()

	if config.server == "" || config.port == 0 || config.passwd == "" || len(flag.Args()) != 1 {
		fmt.Printf("Usage: %s -s <server> -p <port> -k <password> <url>\n", os.Args[0])
		os.Exit(1)
	}
	if err := ss.SetDefaultCipher(config.method); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	runtime.GOMAXPROCS(config.core)
	uri := flag.Arg(0)
	if !strings.HasPrefix(uri, "http://") {
		uri = "http://" + uri
	}

	cipher, err := ss.NewCipher(config.passwd)
	if err != nil {
		fmt.Println("Error creating cipher:", err)
		os.Exit(1)
	}
	serverAddr := net.JoinHostPort(config.server, strconv.Itoa(config.port))

	parsedURL, err := url.Parse(uri)
	if err != nil {
		fmt.Println("Error parsing url:", err)
		os.Exit(1)
	}
	host, _, err := net.SplitHostPort(parsedURL.Host)
	if err != nil {
		host = net.JoinHostPort(parsedURL.Host, "80")
	} else {
		host = parsedURL.Host
	}
	// fmt.Println(host)
	rawAddr, err := ss.RawAddr(host)
	if err != nil {
		panic("Error getting raw address.")
		return
	}

	done := make(chan []time.Duration)
	for i := 1; i <= config.nconn; i++ {
		go get(i, uri, serverAddr, rawAddr, cipher, done)
	}

	// collect request finish time
	reqTime := make([]int64, config.nconn*config.nreq)
	reqDone := 0
	for i := 1; i <= config.nconn; i++ {
		rt := <-done
		for _, t := range rt {
			reqTime[reqDone] = int64(t)
			reqDone++
		}
	}

	fmt.Println("number of total requests:", config.nconn*config.nreq)
	fmt.Println("number of finished requests:", reqDone)
	if reqDone == 0 {
		return
	}

	// calculate average an standard deviation
	reqTime = reqTime[:reqDone]
	var sum int64
	for _, d := range reqTime {
		sum += d
	}
	avg := float64(sum) / float64(reqDone)

	varSum := float64(0)
	for _, d := range reqTime {
		di := math.Abs(float64(d) - avg)
		di *= di
		varSum += di
	}
	stddev := math.Sqrt(varSum / float64(reqDone))
	fmt.Println("\naverage time per request:", time.Duration(avg))
	fmt.Println("standard deviation:", time.Duration(stddev))
}
<commit_msg>Fix shadowsocks-httpget for new cipher API.<commit_after>package main

import (
	"flag"
	"fmt"
	ss "github.com/shadowsocks/shadowsocks-go/shadowsocks"
	"io"
	"math"
	"net"
	"net/http"
	"net/url"
	"os"
	"runtime"
	"strconv"
	"strings"
	"time"
)

var config struct {
	server string
	port   int
	passwd string
	method string
	core   int
	nconn  int
	nreq   int
	// nsec   int
}

var debug ss.DebugLog

func doOneRequest(client *http.Client, uri string, buf []byte) (err error) {
	resp, err := client.Get(uri)
	if err != nil {
		fmt.Printf("GET %s error: %v\n", uri, err)
		return err
	}
	for err == nil {
		_, err = resp.Body.Read(buf)
		if debug {
			debug.Println(string(buf))
		}
	}
	if err != io.EOF {
		fmt.Printf("Read %s response error: %v\n", uri, err)
	} else {
		err = nil
	}
	return
}

func get(connid int, uri, serverAddr string, rawAddr []byte, cipher ss.Cipher, done chan []time.Duration) {
	reqDone := 0
	reqTime := make([]time.Duration, config.nreq)
	defer func() {
		done <- reqTime[:reqDone]
	}()
	tr := &http.Transport{
		Dial: func(_, _ string) (net.Conn, error) {
			return ss.DialWithRawAddr(rawAddr, serverAddr, cipher.Copy())
		},
	}

	buf := make([]byte, 8192)
	client := &http.Client{Transport: tr}
	for ; reqDone < config.nreq; reqDone++ {
		start := time.Now()
		if err := doOneRequest(client, uri, buf); err != nil {
			return
		}
		reqTime[reqDone] = time.Now().Sub(start)

		if (reqDone+1)%1000 == 0 {
			fmt.Printf("conn %d finished %d get requests\n", connid, reqDone+1)
		}
	}
}

func main() {
	flag.StringVar(&config.server, "s", "127.0.0.1", "server:port")
	flag.IntVar(&config.port, "p", 0, "server:port")
	flag.IntVar(&config.core, "core", 1, "number of CPU cores to use")
	flag.StringVar(&config.passwd, "k", "", "password")
	flag.StringVar(&config.method, "m", "", "encryption method, use empty string or rc4")
	flag.IntVar(&config.nconn, "nc", 1, "number of connection to server")
	flag.IntVar(&config.nreq, "nr", 1, "number of request for each connection")
	// flag.IntVar(&config.nsec, "ns", 0, "run how many seconds for each connection")
	flag.BoolVar((*bool)(&debug), "d", false, "print http response body for debugging")

	flag.Parse()

	if config.server == "" || config.port == 0 || config.passwd == "" || len(flag.Args()) != 1 {
		fmt.Printf("Usage: %s -s <server> -p <port> -k <password> <url>\n", os.Args[0])
		os.Exit(1)
	}

	runtime.GOMAXPROCS(config.core)
	uri := flag.Arg(0)
	if !strings.HasPrefix(uri, "http://") {
		uri = "http://" + uri
	}

	cipher, err := ss.NewCipher(config.method, config.passwd)
	if err != nil {
		fmt.Println("Error creating cipher:", err)
		os.Exit(1)
	}
	serverAddr := net.JoinHostPort(config.server, strconv.Itoa(config.port))

	parsedURL, err := url.Parse(uri)
	if err != nil {
		fmt.Println("Error parsing url:", err)
		os.Exit(1)
	}
	host, _, err := net.SplitHostPort(parsedURL.Host)
	if err != nil {
		host = net.JoinHostPort(parsedURL.Host, "80")
	} else {
		host = parsedURL.Host
	}
	// fmt.Println(host)
	rawAddr, err := ss.RawAddr(host)
	if err != nil {
		panic("Error getting raw address.")
		return
	}

	done := make(chan []time.Duration)
	for i := 1; i <= config.nconn; i++ {
		go get(i, uri, serverAddr, rawAddr, cipher, done)
	}

	// collect request finish time
	reqTime := make([]int64, config.nconn*config.nreq)
	reqDone := 0
	for i := 1; i <= config.nconn; i++ {
		rt := <-done
		for _, t := range rt {
			reqTime[reqDone] = int64(t)
			reqDone++
		}
	}

	fmt.Println("number of total requests:", config.nconn*config.nreq)
	fmt.Println("number of finished requests:", reqDone)
	if reqDone == 0 {
		return
	}

	// calculate average an standard deviation
	reqTime = reqTime[:reqDone]
	var sum int64
	for _, d := range reqTime {
		sum += d
	}
	avg := float64(sum) / float64(reqDone)

	varSum := float64(0)
	for _, d := range reqTime {
		di := math.Abs(float64(d) - avg)
		di *= di
		varSum += di
	}
	stddev := math.Sqrt(varSum / float64(reqDone))
	fmt.Println("\naverage time per request:", time.Duration(avg))
	fmt.Println("standard deviation:", time.Duration(stddev))
}
<|endoftext|>


<commit_before>package logs

var logger *Logger

func init() {
	logger = NewLogger(1024)
	logger.SetLogFuncCallDepth(4)
}

/*
// set file logger with json config.
// jsonconfig like:
//	{
//	"filename":"logs/beego.log",
//	"maxlines":10000,
//	"maxsize":1<<30,
//	"daily":true,
//	"maxdays":15,
//	"rotate":true
//	}
*/
func SetFileLogger(file string) {
	logger = NewFileLogger(file)
}
func Error(v ...interface{}) {
	logger.Error(v...)
}
func Warn(v ...interface{}) {
	logger.Warn(v...)
}
func Info(v ...interface{}) {
	logger.Info(v...)
}
func Debug(v ...interface{}) {
	logger.Debug(v...)
}
func Pretty(v interface{}, message string) {
	logger.Pretty(v, message)
}
<commit_msg>add setLevel<commit_after>package logs

var logger *Logger

func init() {
	logger = NewLogger(1024)
	logger.SetLogFuncCallDepth(4)
}

/*
// set file logger with json config.
// jsonconfig like:
//	{
//	"filename":"logs/beego.log",
//	"maxlines":10000,
//	"maxsize":1<<30,
//	"daily":true,
//	"maxdays":15,
//	"rotate":true
//	}
*/
func SetFileLogger(file string) {
	logger = NewFileLogger(file)
}
func Error(v ...interface{}) {
	logger.Error(v...)
}
func Warn(v ...interface{}) {
	logger.Warn(v...)
}
func Info(v ...interface{}) {
	logger.Info(v...)
}
func Debug(v ...interface{}) {
	logger.Debug(v...)
}
func Pretty(v interface{}, message string) {
	logger.Pretty(v, message)
}
func SetLoggerLevel(l int) {
	logger.SetLevel(l)
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
)

func in_slice(a string, list []string) bool {
	for b := range list {
		if list[b] == a {
			return true
		}
	}
	return false
}

// Shamelessly ripped off of Simon Budig's woof
// http://www.home.unix-ag.org/simon/woof
func find_ip() string {
	ips := [3]string{"192.168.2.0", "198.51.100.0", "203.0.113.0"}
	ip_addr := []string{}
	for ip := range ips {
		serverAddr, _ := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:80", ips[ip]))
		con, _ := net.DialUDP("udp", nil, serverAddr)
		new_ip := con.LocalAddr().String()
		new_host, _, _ := net.SplitHostPort(new_ip)
		// If new_host already in ip_addr, return new_host
		if in_slice(new_host, ip_addr) {
			return new_host
		}
		ip_addr = append(ip_addr, new_host)
	}
	return ip_addr[0]
}

func main() {
	port_i := flag.Int("port", 4242, "port number")
	flag.Parse()
	port := fmt.Sprintf(":%d", *port_i)

	args := flag.Args()

	if len(args) == 0 {
		log.Printf("Nothing to serve.")
		return
	} else if len(args) > 1 {
		log.Printf("We can only serve one element at a time.")
		return
	}

	file_name := filepath.Base(flag.Args()[0])
	file_path, err := filepath.Abs(flag.Args()[0])
	if err != nil {
		log.Printf("Error getting absolute path for %s: %v", file_path, err)
		return
	}

	file_info, err := os.Stat(file_path)
	if err != nil {
		log.Printf("%v", err)
		return
	}

	ip_addr := find_ip()
	url := fmt.Sprintf("http://%s%s/%s", ip_addr, port, file_name)
	log.Printf("Serving %s at %s", file_path, url)
	cmd := exec.Command("xclip", "-i", "-selection", "clipboard")
	if runtime.GOOS == "darwin" {
		cmd = exec.Command("pbcopy")
	}
	cmd.Stdin = strings.NewReader(url)
	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	handler := http.FileServer(http.Dir(file_path))
	if !file_info.IsDir() {
		handler = nil
		// Easier to use a closure func since we use local variables
		serveFile := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Description", "File Transfer")
			w.Header().Set("Content-Type", "application/octet-stream")
			w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", file_name))
			w.Header().Set("Content-Transfer-Encoding", "binary")
			w.Header().Set("Expires", "0")
			w.Header().Set("Cache-Control", "private")
			w.Header().Set("Pragma", "private")
			w.Header().Set("Expires", "Mon, 26 Jul 1997 05:00:00 GMT")
			s_size := strconv.FormatInt(file_info.Size(), 10)
			w.Header().Set("Content-Length", s_size)
			http.ServeFile(w, r, file_path)
			os.Exit(0)
		})
		http.HandleFunc("/", serveFile)
	}

	err = http.ListenAndServe(port, handler)
	if err != nil {
		log.Printf("Error running web server for static assets: %v", err)
	}
}
<commit_msg>Fix xclip error when using SSH<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"net/http"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
)

func in_slice(a string, list []string) bool {
	for b := range list {
		if list[b] == a {
			return true
		}
	}
	return false
}

// Shamelessly ripped off of Simon Budig's woof
// http://www.home.unix-ag.org/simon/woof
func find_ip() string {
	ips := [3]string{"192.168.2.0", "198.51.100.0", "203.0.113.0"}
	ip_addr := []string{}
	for ip := range ips {
		serverAddr, _ := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:80", ips[ip]))
		con, _ := net.DialUDP("udp", nil, serverAddr)
		new_ip := con.LocalAddr().String()
		new_host, _, _ := net.SplitHostPort(new_ip)
		// If new_host already in ip_addr, return new_host
		if in_slice(new_host, ip_addr) {
			return new_host
		}
		ip_addr = append(ip_addr, new_host)
	}
	return ip_addr[0]
}

func main() {
	port_i := flag.Int("port", 4242, "port number")
	flag.Parse()
	port := fmt.Sprintf(":%d", *port_i)

	args := flag.Args()

	if len(args) == 0 {
		log.Printf("Nothing to serve.")
		return
	} else if len(args) > 1 {
		log.Printf("We can only serve one element at a time.")
		return
	}

	file_name := filepath.Base(flag.Args()[0])
	file_path, err := filepath.Abs(flag.Args()[0])
	if err != nil {
		log.Printf("Error getting absolute path for %s: %v", file_path, err)
		return
	}

	file_info, err := os.Stat(file_path)
	if err != nil {
		log.Printf("%v", err)
		return
	}

	ip_addr := find_ip()
	url := fmt.Sprintf("http://%s%s/%s", ip_addr, port, file_name)
	log.Printf("Serving %s at %s", file_path, url)
	cmd := exec.Command("xclip", "-i", "-selection", "clipboard")
	cmd.Env = append(cmd.Env, "DISPLAY=:0")
	if runtime.GOOS == "darwin" {
		cmd = exec.Command("pbcopy")
	}
	cmd.Stdin = strings.NewReader(url)
	err = cmd.Run()
	if err != nil {
		log.Fatal(err)
	}

	handler := http.FileServer(http.Dir(file_path))
	if !file_info.IsDir() {
		handler = nil
		// Easier to use a closure func since we use local variables
		serveFile := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			w.Header().Set("Content-Description", "File Transfer")
			w.Header().Set("Content-Type", "application/octet-stream")
			w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", file_name))
			w.Header().Set("Content-Transfer-Encoding", "binary")
			w.Header().Set("Expires", "0")
			w.Header().Set("Cache-Control", "private")
			w.Header().Set("Pragma", "private")
			w.Header().Set("Expires", "Mon, 26 Jul 1997 05:00:00 GMT")
			s_size := strconv.FormatInt(file_info.Size(), 10)
			w.Header().Set("Content-Length", s_size)
			http.ServeFile(w, r, file_path)
			os.Exit(0)
		})
		http.HandleFunc("/", serveFile)
	}

	err = http.ListenAndServe(port, handler)
	if err != nil {
		log.Printf("Error running web server for static assets: %v", err)
	}
}
<|endoftext|>


<commit_before>package torrent

import (
	"github.com/anacrolix/missinggo/pubsub"

	"github.com/anacrolix/torrent/metainfo"
)

// The torrent's infohash. This is fixed and cannot change. It uniquely
// identifies a torrent.
func (t *Torrent) InfoHash() metainfo.Hash {
	return t.infoHash
}

// Returns a channel that is closed when the info (.Info()) for the torrent
// has become available.
func (t *Torrent) GotInfo() <-chan struct{} {
	return t.gotMetainfo
}

// Returns the metainfo info dictionary, or nil if it's not yet available.
func (t *Torrent) Info() *metainfo.InfoEx {
	return t.info
}

// Returns a Reader bound to the torrent's data. All read calls block until
// the data requested is actually available.
func (t *Torrent) NewReader() (ret *Reader) {
	ret = &Reader{
		t:         t,
		readahead: 5 * 1024 * 1024,
	}
	t.addReader(ret)
	return
}

// Returns the state of pieces of the torrent. They are grouped into runs of
// same state. The sum of the state run lengths is the number of pieces
// in the torrent.
func (t *Torrent) PieceStateRuns() []PieceStateRun {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	return t.pieceStateRuns()
}

func (t *Torrent) PieceState(piece int) PieceState {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	return t.pieceState(piece)
}

// The number of pieces in the torrent. This requires that the info has been
// obtained first.
func (t *Torrent) NumPieces() int {
	return t.numPieces()
}

// Drop the torrent from the client, and close it. It's always safe to do
// this. No data corruption can, or should occur to either the torrent's data,
// or connected peers.
func (t *Torrent) Drop() {
	t.cl.mu.Lock()
	t.cl.dropTorrent(t.infoHash)
	t.cl.mu.Unlock()
}

// Number of bytes of the entire torrent we have completed.
func (t *Torrent) BytesCompleted() int64 {
	t.cl.mu.RLock()
	defer t.cl.mu.RUnlock()
	return t.bytesCompleted()
}

// The subscription emits as (int) the index of pieces as their state changes.
// A state change is when the PieceState for a piece alters in value.
func (t *Torrent) SubscribePieceStateChanges() *pubsub.Subscription {
	return t.pieceStateChanges.Subscribe()
}

// Returns true if the torrent is currently being seeded. This occurs when the
// client is willing to upload without wanting anything in return.
func (t *Torrent) Seeding() bool {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	return t.cl.seeding(t)
}

// Clobbers the torrent display name. The display name is used as the torrent
// name if the metainfo is not available.
func (t *Torrent) SetDisplayName(dn string) {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	t.setDisplayName(dn)
}

// The current working name for the torrent. Either the name in the info dict,
// or a display name given such as by the dn value in a magnet link, or "".
func (t *Torrent) Name() string {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	return t.name()
}

// The completed length of all the torrent data, in all its files. This is
// derived from the torrent info, when it is available.
func (t *Torrent) Length() int64 {
	select {
	case <-t.GotInfo():
		return t.length
	default:
		return -1
	}
}

// Returns a run-time generated metainfo for the torrent that includes the
// info bytes and announce-list as currently known to the client.
func (t *Torrent) Metainfo() *metainfo.MetaInfo {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	return t.metainfo()
}

func (t *Torrent) addReader(r *Reader) {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	if t.readers == nil {
		t.readers = make(map[*Reader]struct{})
	}
	t.readers[r] = struct{}{}
	t.readersChanged()
}

func (t *Torrent) deleteReader(r *Reader) {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	delete(t.readers, r)
	t.readersChanged()
}

func (t *Torrent) DownloadPieces(begin, end int) {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	t.pendPieceRange(begin, end)
}

func (t *Torrent) CancelPieces(begin, end int) {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	t.unpendPieceRange(begin, end)
}
<commit_msg>Change the behaviour of Torrent.Length with when info isn't available<commit_after>package torrent

import (
	"github.com/anacrolix/missinggo/pubsub"

	"github.com/anacrolix/torrent/metainfo"
)

// The torrent's infohash. This is fixed and cannot change. It uniquely
// identifies a torrent.
func (t *Torrent) InfoHash() metainfo.Hash {
	return t.infoHash
}

// Returns a channel that is closed when the info (.Info()) for the torrent
// has become available.
func (t *Torrent) GotInfo() <-chan struct{} {
	return t.gotMetainfo
}

// Returns the metainfo info dictionary, or nil if it's not yet available.
func (t *Torrent) Info() *metainfo.InfoEx {
	return t.info
}

// Returns a Reader bound to the torrent's data. All read calls block until
// the data requested is actually available.
func (t *Torrent) NewReader() (ret *Reader) {
	ret = &Reader{
		t:         t,
		readahead: 5 * 1024 * 1024,
	}
	t.addReader(ret)
	return
}

// Returns the state of pieces of the torrent. They are grouped into runs of
// same state. The sum of the state run lengths is the number of pieces
// in the torrent.
func (t *Torrent) PieceStateRuns() []PieceStateRun {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	return t.pieceStateRuns()
}

func (t *Torrent) PieceState(piece int) PieceState {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	return t.pieceState(piece)
}

// The number of pieces in the torrent. This requires that the info has been
// obtained first.
func (t *Torrent) NumPieces() int {
	return t.numPieces()
}

// Drop the torrent from the client, and close it. It's always safe to do
// this. No data corruption can, or should occur to either the torrent's data,
// or connected peers.
func (t *Torrent) Drop() {
	t.cl.mu.Lock()
	t.cl.dropTorrent(t.infoHash)
	t.cl.mu.Unlock()
}

// Number of bytes of the entire torrent we have completed.
func (t *Torrent) BytesCompleted() int64 {
	t.cl.mu.RLock()
	defer t.cl.mu.RUnlock()
	return t.bytesCompleted()
}

// The subscription emits as (int) the index of pieces as their state changes.
// A state change is when the PieceState for a piece alters in value.
func (t *Torrent) SubscribePieceStateChanges() *pubsub.Subscription {
	return t.pieceStateChanges.Subscribe()
}

// Returns true if the torrent is currently being seeded. This occurs when the
// client is willing to upload without wanting anything in return.
func (t *Torrent) Seeding() bool {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	return t.cl.seeding(t)
}

// Clobbers the torrent display name. The display name is used as the torrent
// name if the metainfo is not available.
func (t *Torrent) SetDisplayName(dn string) {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	t.setDisplayName(dn)
}

// The current working name for the torrent. Either the name in the info dict,
// or a display name given such as by the dn value in a magnet link, or "".
func (t *Torrent) Name() string {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	return t.name()
}

// The completed length of all the torrent data, in all its files. This is
// derived from the torrent info, when it is available.
func (t *Torrent) Length() int64 {
	if t.info == nil {
		panic("not valid until info obtained")
	}
	return t.length
}

// Returns a run-time generated metainfo for the torrent that includes the
// info bytes and announce-list as currently known to the client.
func (t *Torrent) Metainfo() *metainfo.MetaInfo {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	return t.metainfo()
}

func (t *Torrent) addReader(r *Reader) {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	if t.readers == nil {
		t.readers = make(map[*Reader]struct{})
	}
	t.readers[r] = struct{}{}
	t.readersChanged()
}

func (t *Torrent) deleteReader(r *Reader) {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	delete(t.readers, r)
	t.readersChanged()
}

func (t *Torrent) DownloadPieces(begin, end int) {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	t.pendPieceRange(begin, end)
}

func (t *Torrent) CancelPieces(begin, end int) {
	t.cl.mu.Lock()
	defer t.cl.mu.Unlock()
	t.unpendPieceRange(begin, end)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/user"
	"path"
	"path/filepath"
	"regexp"

	"gopkg.in/alecthomas/kingpin.v1"

	"./app"
)

const (
	APP_DESCRIPTION          = "ah - A Better history."
	SHELL_FLAVOUR_DESRIPTION = "A shell flavour you are using." +
		" Vaild options are \"bash\" and \"zsh\"." +
		" By default ah tries to sniff what shell you are using and if you" +
		" have a nonstandard setup, bash would be used."
	HISTFILE_DESCRIPTION = "The path to your shell history file. " +
		"No worries if you are not sure or just do not want to set it, " +
		"ah will try to sniff. But it costs 1 interpreter start."
	HISTTIMEFORMAT_DESCRIPTION = "If you want to set different time format " +
		"of the history file, the best way to do it here"
	APP_DIR_DESCRIPTION = "An ah's directory for own storage"

	SHOW_CMD_DESCRIPTION       = "Shows an enhanced history of your commands."
	SHOW_CMD_GREP_DESCRIPTION  = "Filter output by given regular expression."
	SHOW_CMD_FUZZY_DESCRIPTION = "Interpret grep expression as fuzzy search " +
		"string instead of regular expression."
	SHOW_CMD_SLICE_DESCRIPTION = "Basically it could be a single argument " +
		"or a slice. Let's say it is 20. Then ah will show you 20 latest " +
		"records. So it is an equialent of :-20. What does negative number " +
		"means? It is rather simple: n commands from the end so it is a " +
		"shortcut of \"len(history)-20\". By default whole history would " +
		"be shown."
)

const (
	APP_DIR = "~/.ah"
)

var (
	HISTFILE_BASH = ".bash_history"
	HISTFILE_ZSH  = ".zsh_history"
)

var (
	application = kingpin.New("ah", APP_DESCRIPTION)
	histfile    = application.Flag("histfile", HISTFILE_DESCRIPTION).
			Short('f').
			String()
	histtimeformat = application.Flag("histtimeformat", HISTTIMEFORMAT_DESCRIPTION).
			Short('t').
			String()
	shell_flavour = application.Flag("shell", SHELL_FLAVOUR_DESRIPTION).
			Short('s').
			String()
	app_path = application.Flag("dir", APP_DIR_DESCRIPTION).
			Default(APP_DIR).
			String()

	show      = application.Command("s", SHOW_CMD_DESCRIPTION)
	show_grep = show.Flag("grep", SHOW_CMD_GREP_DESCRIPTION).
			Short('g').
			String()
	show_fuzzy = show.Flag("fuzzy", SHOW_CMD_FUZZY_DESCRIPTION).
			Short('f').Bool()
	show_arg = show.Arg("slice", SHOW_CMD_SLICE_DESCRIPTION).
			String()
)

func init() {
	currentUser, err := user.Current()
	if err != nil {
		os.Stderr.WriteString(fmt.Sprintf("Impossible to detect current user\n"))
		os.Exit(1)
	}

	HISTFILE_BASH = filepath.Join(currentUser.HomeDir, HISTFILE_BASH)
	HISTFILE_ZSH = filepath.Join(currentUser.HomeDir, HISTFILE_ZSH)
}

func main() {
	defer func() {
		if exc := recover(); exc != nil {
			os.Stderr.WriteString(fmt.Sprintf("%v\n", exc))
			os.Exit(1)
		}
	}()

	command := kingpin.MustParse(application.Parse(os.Args[1:]))
	env := app.Environment{}

	env.Shell = *shell_flavour
	if env.Shell == "" {
		env.Shell = os.Getenv("SHELL")
	}
	env.Shell = path.Base(env.Shell)
	if env.Shell != "zsh" && env.Shell != "bash" {
		panic("Sorry, ah supports only bash and zsh")
	}

	env.HistFile = *histfile
	if env.HistFile == "" {
		env.HistFile = os.Getenv("HISTFILE")
	}
	if env.HistFile == "" {
		if env.Shell == "bash" {
			env.HistFile = HISTFILE_BASH
		} else {
			env.HistFile = HISTFILE_ZSH
		}
	}

	env.HistTimeFormat = *histtimeformat
	if env.HistTimeFormat == "" {
		env.HistTimeFormat = os.Getenv("HISTTIMEFORMAT")
	}

	env.AppDir = *app_path

	switch command {
	case "s":
		slice, err := app.ExtractSlice(*show_arg)
		if err != nil {
			panic(err)
		}

		var filter *regexp.Regexp = nil
		if *show_grep != "" {
			filter = regexp.MustCompile(*show_grep)
		}

		app.CommandShow(slice, filter, &env)
	default:
		panic("Unknown command. Please specify at least one.")
	}
}
<commit_msg>Fuzzy search<commit_after>package main

import (
	"fmt"
	"os"
	"os/user"
	"path"
	"path/filepath"
	"regexp"

	"gopkg.in/alecthomas/kingpin.v1"

	"./app"
)

const (
	APP_DESCRIPTION          = "ah - A Better history."
	SHELL_FLAVOUR_DESRIPTION = "A shell flavour you are using." +
		" Vaild options are \"bash\" and \"zsh\"." +
		" By default ah tries to sniff what shell you are using and if you" +
		" have a nonstandard setup, bash would be used."
	HISTFILE_DESCRIPTION = "The path to your shell history file. " +
		"No worries if you are not sure or just do not want to set it, " +
		"ah will try to sniff. But it costs 1 interpreter start."
	HISTTIMEFORMAT_DESCRIPTION = "If you want to set different time format " +
		"of the history file, the best way to do it here"
	APP_DIR_DESCRIPTION = "An ah's directory for own storage"

	SHOW_CMD_DESCRIPTION       = "Shows an enhanced history of your commands."
	SHOW_CMD_GREP_DESCRIPTION  = "Filter output by given regular expression."
	SHOW_CMD_FUZZY_DESCRIPTION = "Interpret grep expression as fuzzy search " +
		"string instead of regular expression."
	SHOW_CMD_SLICE_DESCRIPTION = "Basically it could be a single argument " +
		"or a slice. Let's say it is 20. Then ah will show you 20 latest " +
		"records. So it is an equialent of :-20. What does negative number " +
		"means? It is rather simple: n commands from the end so it is a " +
		"shortcut of \"len(history)-20\". By default whole history would " +
		"be shown."
)

const (
	APP_DIR = "~/.ah"
)

var (
	HISTFILE_BASH = ".bash_history"
	HISTFILE_ZSH  = ".zsh_history"
)

var (
	application = kingpin.New("ah", APP_DESCRIPTION)
	histfile    = application.Flag("histfile", HISTFILE_DESCRIPTION).
			Short('f').
			String()
	histtimeformat = application.Flag("histtimeformat", HISTTIMEFORMAT_DESCRIPTION).
			Short('t').
			String()
	shell_flavour = application.Flag("shell", SHELL_FLAVOUR_DESRIPTION).
			Short('s').
			String()
	app_path = application.Flag("dir", APP_DIR_DESCRIPTION).
			Default(APP_DIR).
			String()

	show      = application.Command("s", SHOW_CMD_DESCRIPTION)
	show_grep = show.Flag("grep", SHOW_CMD_GREP_DESCRIPTION).
			Short('g').
			String()
	show_fuzzy = show.Flag("fuzzy", SHOW_CMD_FUZZY_DESCRIPTION).
			Short('f').Bool()
	show_arg = show.Arg("slice", SHOW_CMD_SLICE_DESCRIPTION).
			String()
)

func init() {
	currentUser, err := user.Current()
	if err != nil {
		os.Stderr.WriteString(fmt.Sprintf("Impossible to detect current user\n"))
		os.Exit(1)
	}

	HISTFILE_BASH = filepath.Join(currentUser.HomeDir, HISTFILE_BASH)
	HISTFILE_ZSH = filepath.Join(currentUser.HomeDir, HISTFILE_ZSH)
}

func main() {
	defer func() {
		if exc := recover(); exc != nil {
			os.Stderr.WriteString(fmt.Sprintf("%v\n", exc))
			os.Exit(1)
		}
	}()

	command := kingpin.MustParse(application.Parse(os.Args[1:]))
	env := app.Environment{}

	env.Shell = *shell_flavour
	if env.Shell == "" {
		env.Shell = os.Getenv("SHELL")
	}
	env.Shell = path.Base(env.Shell)
	if env.Shell != "zsh" && env.Shell != "bash" {
		panic("Sorry, ah supports only bash and zsh")
	}

	env.HistFile = *histfile
	if env.HistFile == "" {
		env.HistFile = os.Getenv("HISTFILE")
	}
	if env.HistFile == "" {
		if env.Shell == "bash" {
			env.HistFile = HISTFILE_BASH
		} else {
			env.HistFile = HISTFILE_ZSH
		}
	}

	env.HistTimeFormat = *histtimeformat
	if env.HistTimeFormat == "" {
		env.HistTimeFormat = os.Getenv("HISTTIMEFORMAT")
	}

	env.AppDir = *app_path

	switch command {
	case "s":
		slice, err := app.ExtractSlice(*show_arg)
		if err != nil {
			panic(err)
		}

		var filter *regexp.Regexp = nil
		if *show_grep != "" {
			query := *show_grep
			if *show_fuzzy {
				regex := ""
				for idx := 0; idx < len(query); idx++ {
					regex += ".*?" + regexp.QuoteMeta(string(query[idx]))
				}
				query = regex + ".*?"
			}
			filter = regexp.MustCompile(query)
		}

		app.CommandShow(slice, filter, &env)
	default:
		panic("Unknown command. Please specify at least one.")
	}
}
<|endoftext|>


<commit_before>package expect

import (
	"errors"
	"fmt"
	"reflect"
)

type Be struct {
	Else   *Else
	And    *Be
	t      T
	actual interface{}
	assert bool
}

func newBe(t T, e *Else, actual interface{}, assert bool) *Be {
	be := &Be{
		Else:   e,
		t:      t,
		actual: actual,
		assert: assert,
	}
	be.And = be
	return be
}

// Assert numeric value above the given value (> n)
func (b *Be) Above(e float64) *Be {
	msg := b.msg(fmt.Sprintf("above %v", e))
	if b.Num() > e != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert numeric value below the given value (< n)
func (b *Be) Below(e float64) *Be {
	msg := b.msg(fmt.Sprintf("below %v", e))
	if b.Num() < e != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert inclusive numeric range (<= to and >= from)
func (b *Be) Within(from, to float64) *Be {
	msg := b.msg(fmt.Sprintf("between range %v <= x <= %v", from, to))
	x := b.Num()
	if x <= to && x >= from != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is empty, Array, Slice, Map or String
func (b *Be) Empty() *Be {
	msg := b.msg("empty")
	if i, ok := length(b.actual); ok {
		if i == 0 != b.assert {
			b.fail(2, msg)
		}
	} else {
		b.t.Fatal(invMsg("Array, Slice, Map or String"))
	}
	return b
}

// Assert if the given value is truthy(i.e: not "", nil, 0, false)
func (b *Be) Ok() *Be {
	msg := b.msg("ok")
	var exp bool
	switch b.actual.(type) {
	case int, int8, int32, int64, uint, uint8, uint32, uint64, float32, float64:
		exp = b.actual != 0
	case string:
		exp = b.actual != ""
	case bool:
		exp = b.actual != false // TODO(Ariel): without the `!= false`, it's ask for type assertion
	default:
		exp = b.actual != nil
	}
	if exp != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of string
func (b *Be) String() *Be {
	msg := b.msg("string")
	if _, ok := b.actual.(string); ok != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of int
func (b *Be) Int() *Be {
	msg := b.msg("int")
	if _, ok := b.actual.(int); ok != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of float32/64
func (b *Be) Float() *Be {
	msg := b.msg("float")
	exp := false
	switch b.actual.(type) {
	case float32, float64:
		exp = true
	}
	if exp != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of boolean
func (b *Be) Bool() *Be {
	msg := b.msg("boolean")
	if _, ok := b.actual.(bool); ok != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of map
func (b *Be) Map() *Be {
	msg := b.msg("map")
	if reflect.TypeOf(b.actual).Kind() == reflect.Map != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of array
func (b *Be) Array() *Be {
	msg := b.msg("array")
	if reflect.TypeOf(b.actual).Kind() == reflect.Array != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of slice
func (b *Be) Slice() *Be {
	msg := b.msg("slice")
	if reflect.TypeOf(b.actual).Kind() == reflect.Slice != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of channel
func (b *Be) Chan() *Be {
	msg := b.msg("channel")
	if reflect.TypeOf(b.actual).Kind() == reflect.Chan != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of struct
func (b *Be) Struct() *Be {
	msg := b.msg("struct")
	if reflect.TypeOf(b.actual).Kind() == reflect.Struct != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of pointer
func (b *Be) Ptr() *Be {
	msg := b.msg("pointer")
	if reflect.TypeOf(b.actual).Kind() == reflect.Ptr != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is nil
func (b *Be) Nil() *Be {
	msg := b.msg("nil")
	if b.actual == nil != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of the given string
func (b *Be) Type(s string) *Be {
	msg := b.msg(fmt.Sprintf("type %v", s))
	if reflect.TypeOf(b.actual).Name() == s != b.assert {
		b.fail(2, msg)
	}
	return b
}

func (b *Be) fail(callers int, msg string) {
	b.Else.failed = true
	fail(b.t, callers, msg)
}

func (b *Be) msg(s string) string {
	return errMsg("to be")(b.actual, s, b.assert)
}

func (b *Be) Num() float64 {
	rv := reflect.ValueOf(b.actual)
	switch rv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return float64(rv.Int())
	case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return float64(rv.Uint())
	case reflect.Float32, reflect.Float64:
		return float64(rv.Float())
	default:
		b.t.Fatal(invMsg("numeric"))
		return 0
	}
}

func (b *Be) True() bool {
	v, err := b.bool()
	if err != nil {
		b.t.Fatal(invMsg("bool"))
		return false
	}
	if !v {
		b.fail(2, b.msg("true"))
	}
	return v
}

func (b *Be) False() bool {
	v, err := b.bool()
	if err != nil {
		b.t.Fatal(invMsg("bool"))
		return false
	}
	if v {
		b.fail(2, b.msg("false"))
	}
	return v
}

func (b *Be) bool() (bool, error) {
	rv := reflect.ValueOf(b.actual)
	switch rv.Kind() {
	case reflect.Bool:
		return rv.Bool(), nil
	default:
	}
	return false, errors.New("not a bool")
}
<commit_msg>Modify True and False methods of Be to return the receiver<commit_after>package expect

import (
	"errors"
	"fmt"
	"reflect"
)

type Be struct {
	Else   *Else
	And    *Be
	t      T
	actual interface{}
	assert bool
}

func newBe(t T, e *Else, actual interface{}, assert bool) *Be {
	be := &Be{
		Else:   e,
		t:      t,
		actual: actual,
		assert: assert,
	}
	be.And = be
	return be
}

// Assert numeric value above the given value (> n)
func (b *Be) Above(e float64) *Be {
	msg := b.msg(fmt.Sprintf("above %v", e))
	if b.Num() > e != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert numeric value below the given value (< n)
func (b *Be) Below(e float64) *Be {
	msg := b.msg(fmt.Sprintf("below %v", e))
	if b.Num() < e != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert inclusive numeric range (<= to and >= from)
func (b *Be) Within(from, to float64) *Be {
	msg := b.msg(fmt.Sprintf("between range %v <= x <= %v", from, to))
	x := b.Num()
	if x <= to && x >= from != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is empty, Array, Slice, Map or String
func (b *Be) Empty() *Be {
	msg := b.msg("empty")
	if i, ok := length(b.actual); ok {
		if i == 0 != b.assert {
			b.fail(2, msg)
		}
	} else {
		b.t.Fatal(invMsg("Array, Slice, Map or String"))
	}
	return b
}

// Assert if the given value is truthy(i.e: not "", nil, 0, false)
func (b *Be) Ok() *Be {
	msg := b.msg("ok")
	var exp bool
	switch b.actual.(type) {
	case int, int8, int32, int64, uint, uint8, uint32, uint64, float32, float64:
		exp = b.actual != 0
	case string:
		exp = b.actual != ""
	case bool:
		exp = b.actual != false // TODO(Ariel): without the `!= false`, it's ask for type assertion
	default:
		exp = b.actual != nil
	}
	if exp != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of string
func (b *Be) String() *Be {
	msg := b.msg("string")
	if _, ok := b.actual.(string); ok != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of int
func (b *Be) Int() *Be {
	msg := b.msg("int")
	if _, ok := b.actual.(int); ok != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of float32/64
func (b *Be) Float() *Be {
	msg := b.msg("float")
	exp := false
	switch b.actual.(type) {
	case float32, float64:
		exp = true
	}
	if exp != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of boolean
func (b *Be) Bool() *Be {
	msg := b.msg("boolean")
	if _, ok := b.actual.(bool); ok != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of map
func (b *Be) Map() *Be {
	msg := b.msg("map")
	if reflect.TypeOf(b.actual).Kind() == reflect.Map != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of array
func (b *Be) Array() *Be {
	msg := b.msg("array")
	if reflect.TypeOf(b.actual).Kind() == reflect.Array != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of slice
func (b *Be) Slice() *Be {
	msg := b.msg("slice")
	if reflect.TypeOf(b.actual).Kind() == reflect.Slice != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of channel
func (b *Be) Chan() *Be {
	msg := b.msg("channel")
	if reflect.TypeOf(b.actual).Kind() == reflect.Chan != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of struct
func (b *Be) Struct() *Be {
	msg := b.msg("struct")
	if reflect.TypeOf(b.actual).Kind() == reflect.Struct != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of pointer
func (b *Be) Ptr() *Be {
	msg := b.msg("pointer")
	if reflect.TypeOf(b.actual).Kind() == reflect.Ptr != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is nil
func (b *Be) Nil() *Be {
	msg := b.msg("nil")
	if b.actual == nil != b.assert {
		b.fail(2, msg)
	}
	return b
}

// Assert given value is type of the given string
func (b *Be) Type(s string) *Be {
	msg := b.msg(fmt.Sprintf("type %v", s))
	if reflect.TypeOf(b.actual).Name() == s != b.assert {
		b.fail(2, msg)
	}
	return b
}

func (b *Be) fail(callers int, msg string) {
	b.Else.failed = true
	fail(b.t, callers, msg)
}

func (b *Be) msg(s string) string {
	return errMsg("to be")(b.actual, s, b.assert)
}

func (b *Be) Num() float64 {
	rv := reflect.ValueOf(b.actual)
	switch rv.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return float64(rv.Int())
	case reflect.Uint, reflect.Uintptr, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return float64(rv.Uint())
	case reflect.Float32, reflect.Float64:
		return float64(rv.Float())
	default:
		b.t.Fatal(invMsg("numeric"))
		return 0
	}
}

func (b *Be) True() *Be {
	v, err := b.bool()
	if err != nil {
		b.t.Fatal(invMsg("bool"))
		return b
	}
	if !v {
		b.fail(2, b.msg("true"))
	}
	return b
}

func (b *Be) False() *Be {
	v, err := b.bool()
	if err != nil {
		b.t.Fatal(invMsg("bool"))
		return b
	}
	if v {
		b.fail(2, b.msg("false"))
	}
	return b
}

func (b *Be) bool() (bool, error) {
	rv := reflect.ValueOf(b.actual)
	switch rv.Kind() {
	case reflect.Bool:
		return rv.Bool(), nil
	default:
	}
	return false, errors.New("not a bool")
}
<|endoftext|>


<commit_before>package gist

import (
	"crypto/rand"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"

	"github.com/boltdb/bolt"
)

// DB represents the application-level database.
type DB struct {
	*bolt.DB
	secret []byte

	// GistPath to the root of the gist data.
	GistPath string
}

// Open opens and initializes the database.
func (db *DB) Open(path string, mode os.FileMode) error {
	d, err := bolt.Open(path, mode, nil)
	if err != nil {
		return err
	}
	db.DB = d

	return db.Update(func(tx *Tx) error {
		// Initialize the top-level buckets.
		_, _ = tx.CreateBucketIfNotExists([]byte("meta"))
		_, _ = tx.CreateBucketIfNotExists([]byte("users"))
		_, _ = tx.CreateBucketIfNotExists([]byte("gists"))

		// Initialize secret.
		if err := tx.GenerateSecretIfNotExists(); err != nil {
			return err
		}
		db.secret = tx.Secret()

		return nil
	})
}

// View executes a function in the context of a read-only transaction.
func (db *DB) View(fn func(*Tx) error) error {
	return db.DB.View(func(tx *bolt.Tx) error {
		return fn(&Tx{tx})
	})
}

// Update executes a function in the context of a writable transaction.
func (db *DB) Update(fn func(*Tx) error) error {
	return db.DB.Update(func(tx *bolt.Tx) error {
		return fn(&Tx{tx})
	})
}

// Secret returns the secure secret key.
func (db *DB) Secret() []byte {
	return db.secret
}

// LoadGist retrieves the latest gist files from GitHub.
func (db *DB) LoadGist(userID int, gistID string) error {
	return db.Update(func(tx *Tx) error {
		// Retrieve user.
		u, err := tx.User(userID)
		if err != nil {
			return fmt.Errorf("user: %s", err)
		} else if u == nil {
			return fmt.Errorf("user not found: %d", userID)
		}

		// Create GitHub client.
		client := NewGitHubClient(u.AccessToken)

		// Retrieve gist data.
		gist, err := client.Gist(gistID)
		if err != nil {
			return fmt.Errorf("gist: %s", err)
		} else if gist == nil {
			return fmt.Errorf("gist not found: %s", gistID)
		}

		// Download all files over HTTP.
		ch := make(chan error)
		for _, file := range gist.Files {
			go func() {
				defer autonotify()
				var err error
				if err = download(file.RawURL, db.GistFilePath(gistID, file.Filename)); err != nil {
					err = fmt.Errorf("download: %s: %s", file.RawURL, err)
				}
				ch <- err
			}()
		}

		// Check for download errors.
		for i := 0; i < len(gist.Files); i++ {
			if err := <-ch; err != nil {
				return err
			}
		}

		// Save to the database.
		if err := tx.SaveGist(gist); err != nil {
			return fmt.Errorf("save gist: %s", err)
		}
		fmt.Println("save:", gist.ID)

		return nil
	})
}

// GistFilePath returns the path for a given gist file.
func (db *DB) GistFilePath(gistID, filename string) string {
	return filepath.Join(db.GistPath, gistID, filename)
}

// Tx represents an application-level transaction.
type Tx struct {
	*bolt.Tx
}

func (tx *Tx) meta() *bolt.Bucket  { return tx.Bucket([]byte("meta")) }
func (tx *Tx) gists() *bolt.Bucket { return tx.Bucket([]byte("gists")) }
func (tx *Tx) users() *bolt.Bucket { return tx.Bucket([]byte("users")) }

// Gist retrieves a gist from the database by ID.
func (tx *Tx) Gist(id string) (g *Gist, err error) {
	if v := tx.gists().Get([]byte(id)); v != nil {
		err = json.Unmarshal(v, &g)
	}
	return
}

// SaveGist stores a gist in the database.
func (tx *Tx) SaveGist(g *Gist) error {
	assert(g != nil, "nil gist")
	assert(g.ID != "", "gist id required")
	b, err := json.Marshal(g)
	if err != nil {
		return fmt.Errorf("marshal gist: %s", err)
	}
	return tx.gists().Put([]byte(g.ID), b)
}

// User retrieves an user from the database by ID.
func (tx *Tx) User(id int) (u *User, err error) {
	if v := tx.users().Get(i64tob(int64(id))); v != nil {
		err = json.Unmarshal(v, &u)
	}
	return
}

// SaveUser stores an user in the database.
func (tx *Tx) SaveUser(u *User) error {
	assert(u != nil, "nil user")
	assert(u.ID != 0, "user id required")
	b, err := json.Marshal(u)
	if err != nil {
		return fmt.Errorf("marshal user: %s", err)
	}
	return tx.users().Put(i64tob(int64(u.ID)), b)
}

// Secret returns the 64-byte secret key.
func (tx *Tx) Secret() []byte {
	return tx.meta().Get([]byte("secret"))
}

// GenerateSecretIfNotExists generates a 64-byte secret key.
func (tx *Tx) GenerateSecretIfNotExists() error {
	// Ignore if a secret is already set.
	if tx.Secret() != nil {
		return nil
	}

	// Otherwise generate one.
	value := make([]byte, 64)
	if _, err := rand.Read(value); err != nil {
		return err
	}
	return tx.meta().Put([]byte("secret"), value)
}

// download retrieves a URL over HTTP GET and writes the response to the path.
func download(url, path string) error {
	// Create the parent directory.
	if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
		return err
	}

	// Retrieve the file over HTTP.
	resp, err := http.Get(url)
	if err != nil {
		return fmt.Errorf("get: %s", err)
	}
	defer func() { _ = resp.Body.Close() }()

	// Check the response code.
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("invalid HTTP status: %d", resp.StatusCode)
	}

	// Open the file to write to.
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("create: %s", err)
	}
	defer func() { _ = f.Close() }()

	// Copy from the response to the file.
	// Note: This is not perfect as a partial file can be read but this is
	// not the record of authority so we can always retry if there's a problem.
	if _, err := io.Copy(f, resp.Body); err != nil {
		return err
	}

	return nil
}

// Converts an integer to a big-endian encoded byte slice.
func i64tob(v int64) []byte {
	var b = make([]byte, 8)
	binary.BigEndian.PutUint64(b, uint64(v))
	return b
}
<commit_msg>go vet<commit_after>package gist

import (
	"crypto/rand"
	"encoding/binary"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"

	"github.com/boltdb/bolt"
)

// DB represents the application-level database.
type DB struct {
	*bolt.DB
	secret []byte

	// GistPath to the root of the gist data.
	GistPath string
}

// Open opens and initializes the database.
func (db *DB) Open(path string, mode os.FileMode) error {
	d, err := bolt.Open(path, mode, nil)
	if err != nil {
		return err
	}
	db.DB = d

	return db.Update(func(tx *Tx) error {
		// Initialize the top-level buckets.
		_, _ = tx.CreateBucketIfNotExists([]byte("meta"))
		_, _ = tx.CreateBucketIfNotExists([]byte("users"))
		_, _ = tx.CreateBucketIfNotExists([]byte("gists"))

		// Initialize secret.
		if err := tx.GenerateSecretIfNotExists(); err != nil {
			return err
		}
		db.secret = tx.Secret()

		return nil
	})
}

// View executes a function in the context of a read-only transaction.
func (db *DB) View(fn func(*Tx) error) error {
	return db.DB.View(func(tx *bolt.Tx) error {
		return fn(&Tx{tx})
	})
}

// Update executes a function in the context of a writable transaction.
func (db *DB) Update(fn func(*Tx) error) error {
	return db.DB.Update(func(tx *bolt.Tx) error {
		return fn(&Tx{tx})
	})
}

// Secret returns the secure secret key.
func (db *DB) Secret() []byte {
	return db.secret
}

// LoadGist retrieves the latest gist files from GitHub.
func (db *DB) LoadGist(userID int, gistID string) error {
	return db.Update(func(tx *Tx) error {
		// Retrieve user.
		u, err := tx.User(userID)
		if err != nil {
			return fmt.Errorf("user: %s", err)
		} else if u == nil {
			return fmt.Errorf("user not found: %d", userID)
		}

		// Create GitHub client.
		client := NewGitHubClient(u.AccessToken)

		// Retrieve gist data.
		gist, err := client.Gist(gistID)
		if err != nil {
			return fmt.Errorf("gist: %s", err)
		} else if gist == nil {
			return fmt.Errorf("gist not found: %s", gistID)
		}

		// Download all files over HTTP.
		ch := make(chan error)
		for _, file := range gist.Files {
			go func(file *GistFile) {
				defer autonotify()
				var err error
				if err = download(file.RawURL, db.GistFilePath(gistID, file.Filename)); err != nil {
					err = fmt.Errorf("download: %s: %s", file.RawURL, err)
				}
				ch <- err
			}(file)
		}

		// Check for download errors.
		for i := 0; i < len(gist.Files); i++ {
			if err := <-ch; err != nil {
				return err
			}
		}

		// Save to the database.
		if err := tx.SaveGist(gist); err != nil {
			return fmt.Errorf("save gist: %s", err)
		}
		fmt.Println("save:", gist.ID)

		return nil
	})
}

// GistFilePath returns the path for a given gist file.
func (db *DB) GistFilePath(gistID, filename string) string {
	return filepath.Join(db.GistPath, gistID, filename)
}

// Tx represents an application-level transaction.
type Tx struct {
	*bolt.Tx
}

func (tx *Tx) meta() *bolt.Bucket  { return tx.Bucket([]byte("meta")) }
func (tx *Tx) gists() *bolt.Bucket { return tx.Bucket([]byte("gists")) }
func (tx *Tx) users() *bolt.Bucket { return tx.Bucket([]byte("users")) }

// Gist retrieves a gist from the database by ID.
func (tx *Tx) Gist(id string) (g *Gist, err error) {
	if v := tx.gists().Get([]byte(id)); v != nil {
		err = json.Unmarshal(v, &g)
	}
	return
}

// SaveGist stores a gist in the database.
func (tx *Tx) SaveGist(g *Gist) error {
	assert(g != nil, "nil gist")
	assert(g.ID != "", "gist id required")
	b, err := json.Marshal(g)
	if err != nil {
		return fmt.Errorf("marshal gist: %s", err)
	}
	return tx.gists().Put([]byte(g.ID), b)
}

// User retrieves an user from the database by ID.
func (tx *Tx) User(id int) (u *User, err error) {
	if v := tx.users().Get(i64tob(int64(id))); v != nil {
		err = json.Unmarshal(v, &u)
	}
	return
}

// SaveUser stores an user in the database.
func (tx *Tx) SaveUser(u *User) error {
	assert(u != nil, "nil user")
	assert(u.ID != 0, "user id required")
	b, err := json.Marshal(u)
	if err != nil {
		return fmt.Errorf("marshal user: %s", err)
	}
	return tx.users().Put(i64tob(int64(u.ID)), b)
}

// Secret returns the 64-byte secret key.
func (tx *Tx) Secret() []byte {
	return tx.meta().Get([]byte("secret"))
}

// GenerateSecretIfNotExists generates a 64-byte secret key.
func (tx *Tx) GenerateSecretIfNotExists() error {
	// Ignore if a secret is already set.
	if tx.Secret() != nil {
		return nil
	}

	// Otherwise generate one.
	value := make([]byte, 64)
	if _, err := rand.Read(value); err != nil {
		return err
	}
	return tx.meta().Put([]byte("secret"), value)
}

// download retrieves a URL over HTTP GET and writes the response to the path.
func download(url, path string) error {
	// Create the parent directory.
	if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
		return err
	}

	// Retrieve the file over HTTP.
	resp, err := http.Get(url)
	if err != nil {
		return fmt.Errorf("get: %s", err)
	}
	defer func() { _ = resp.Body.Close() }()

	// Check the response code.
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("invalid HTTP status: %d", resp.StatusCode)
	}

	// Open the file to write to.
	f, err := os.Create(path)
	if err != nil {
		return fmt.Errorf("create: %s", err)
	}
	defer func() { _ = f.Close() }()

	// Copy from the response to the file.
	// Note: This is not perfect as a partial file can be read but this is
	// not the record of authority so we can always retry if there's a problem.
	if _, err := io.Copy(f, resp.Body); err != nil {
		return err
	}

	return nil
}

// Converts an integer to a big-endian encoded byte slice.
func i64tob(v int64) []byte {
	var b = make([]byte, 8)
	binary.BigEndian.PutUint64(b, uint64(v))
	return b
}
<|endoftext|>


<commit_before>package aspect

import (
	"database/sql"
)

// TODO The db should be able to determine if a stmt should be used with
// either Exec() or Query()

// TODO How to distiguish between full statements and fragments?
type Executable interface {
	Compiles
}

// TODO dialect
type DB struct {
	conn    *sql.DB
	dialect Dialect
}

func (db *DB) Close() error {
	return db.conn.Close()
}

func (db *DB) Dialect() Dialect {
	return db.dialect
}

func (db *DB) Query(stmt Executable, args ...interface{}) (*Result, error) {
	// Initialize a list of empty parameters
	params := Params()

	// TODO Columns are needed for name return types, tag matching, etc...
	s, err := stmt.Compile(db.dialect, params)
	if err != nil {
		return nil, err
	}

	// TODO When to use the given arguments?
	// TODO If args are structs, maps, or slices, unpack them
	// Use any arguments given to Query() over compiled arguments
	if len(args) == 0 {
		args = params.args
	}

	rows, err := db.conn.Query(s, args...)
	if err != nil {
		return nil, err
	}
	// Wrap the sql rows in a result
	return &Result{rows: rows, stmt: s}, nil
}

// Query the statement and populate the interface with all results
func (db *DB) QueryAll(s Executable, i interface{}) error {
	result, err := db.Query(s)
	if err != nil {
		return err
	}
	return result.All(i)
}

// Query the statement and populate the interface with one result
// TODO Return an error if there is more than one result?
func (db *DB) QueryOne(s Executable, i interface{}) error {
	result, err := db.Query(s)
	// Close the result rows or sqlite3 will open another connection
	defer result.rows.Close()
	if err != nil {
		return err
	}
	return result.One(i)
}

// Execute the statement
// Execute should be used when no results are expected
// TODO What should the return type be?
func (db *DB) Execute(stmt Executable, args ...interface{}) (sql.Result, error) {
	// Initialize a list of empty parameters
	params := Params()

	// TODO Columns are needed for name return types, tag matching, etc...
	s, err := stmt.Compile(db.dialect, params)
	if err != nil {
		return nil, err
	}

	// TODO When to use the given arguments?
	// TODO If args are structs, maps, or slices, unpack them
	// Use any arguments given to Query() over compiled arguments
	if len(args) == 0 {
		args = params.args
	}
	return db.conn.Exec(s, args...)
}

func Connect(driver, credentials string) (*DB, error) {
	// Connect to the database using the given credentials
	db, err := sql.Open(driver, credentials)
	if err != nil {
		return nil, err
	}

	// Get the dialect
	dialect, err := GetDialect(driver)
	if err != nil {
		return nil, err
	}
	return &DB{conn: db, dialect: dialect}, nil
}
<commit_msg>Added a transaction wrapper with query and execute methods<commit_after>package aspect

import (
	"database/sql"
)

// TODO The db should be able to determine if a stmt should be used with
// either Exec() or Query()

// TODO How to distiguish between full statements and fragments?
type Executable interface {
	Compiles
}

// DB includes the current sql.DB connection and the associated Dialect
type DB struct {
	conn    *sql.DB
	dialect Dialect
}

func (db *DB) Begin() (*TX, error) {
	tx, err := db.conn.Begin()
	return &TX{tx, db}, err
}

func (db *DB) Close() error {
	return db.conn.Close()
}

func (db *DB) Dialect() Dialect {
	return db.dialect
}

func (db *DB) Query(stmt Executable, args ...interface{}) (*Result, error) {
	// Initialize a list of empty parameters
	params := Params()

	// TODO Columns are needed for name return types, tag matching, etc...
	s, err := stmt.Compile(db.dialect, params)
	if err != nil {
		return nil, err
	}

	// TODO When to use the given arguments?
	// TODO If args are structs, maps, or slices, unpack them
	// Use any arguments given to Query() over compiled arguments
	if len(args) == 0 {
		args = params.args
	}

	rows, err := db.conn.Query(s, args...)
	if err != nil {
		return nil, err
	}
	// Wrap the sql rows in a result
	return &Result{rows: rows, stmt: s}, nil
}

// QueryAll will query the statement and populate the interface with all
// results
func (db *DB) QueryAll(s Executable, i interface{}) error {
	result, err := db.Query(s)
	if err != nil {
		return err
	}
	return result.All(i)
}

// QueryOne will query the statement and populate the interface with one result
func (db *DB) QueryOne(s Executable, i interface{}) error {
	result, err := db.Query(s)
	// Close the result rows or sqlite3 will open another connection
	defer result.rows.Close()
	if err != nil {
		return err
	}
	return result.One(i)
}

// Execute the statement
// Execute should be used when no results are expected
// TODO What should the return type be?
func (db *DB) Execute(stmt Executable, args ...interface{}) (sql.Result, error) {
	// Initialize a list of empty parameters
	params := Params()

	// TODO Columns are needed for name return types, tag matching, etc...
	s, err := stmt.Compile(db.dialect, params)
	if err != nil {
		return nil, err
	}

	// TODO When to use the given arguments?
	// TODO If args are structs, maps, or slices, unpack them
	// Use any arguments given to Query() over compiled arguments
	if len(args) == 0 {
		args = params.args
	}
	return db.conn.Exec(s, args...)
}

func Connect(driver, credentials string) (*DB, error) {
	// Connect to the database using the given credentials
	db, err := sql.Open(driver, credentials)
	if err != nil {
		return nil, err
	}

	// Get the dialect
	dialect, err := GetDialect(driver)
	if err != nil {
		return nil, err
	}
	return &DB{conn: db, dialect: dialect}, nil
}

type TX struct {
	*sql.Tx
	db *DB
}

func (tx *TX) Query(stmt Executable, args ...interface{}) (*Result, error) {
	// Initialize a list of empty parameters
	params := Params()

	// TODO Columns are needed for name return types, tag matching, etc...
	s, err := stmt.Compile(tx.db.dialect, params)
	if err != nil {
		return nil, err
	}

	// TODO When to use the given arguments?
	// TODO If args are structs, maps, or slices, unpack them
	// Use any arguments given to Query() over compiled arguments
	if len(args) == 0 {
		args = params.args
	}

	rows, err := tx.Tx.Query(s, args...)
	if err != nil {
		return nil, err
	}
	// Wrap the sql rows in a result
	return &Result{rows: rows, stmt: s}, nil
}

// QueryAll will query the statement and populate the interface with all
// results
func (tx *TX) QueryAll(s Executable, i interface{}) error {
	result, err := tx.Query(s)
	if err != nil {
		return err
	}
	return result.All(i)
}

// QueryOne will query the statement and populate the interface with one result
func (tx *TX) QueryOne(s Executable, i interface{}) error {
	result, err := tx.Query(s)
	// Close the result rows or sqlite3 will open another connection
	defer result.rows.Close()
	if err != nil {
		return err
	}
	return result.One(i)
}

// Execute the statement
// Execute should be used when no results are expected
// TODO What should the return type be?
func (tx *TX) Execute(stmt Executable, args ...interface{}) (sql.Result, error) {
	// Initialize a list of empty parameters
	params := Params()

	// TODO Columns are needed for name return types, tag matching, etc...
	s, err := stmt.Compile(tx.db.dialect, params)
	if err != nil {
		return nil, err
	}

	// TODO When to use the given arguments?
	// TODO If args are structs, maps, or slices, unpack them
	// Use any arguments given to Query() over compiled arguments
	if len(args) == 0 {
		args = params.args
	}
	return tx.Exec(s, args...)
}
<|endoftext|>


<commit_before>package yorm

import (
	"database/sql"
	"reflect"
)

type Query struct {
	query   string
	dests   []interface{}
	where   string
	table   string
	columns []column
}
type Where string

func (q *Query) String() string {
	if q.where == "" {
		return q.query
	}
	return q.query + " where " + q.where
}

func (q *Query) Where(w string) *Query {
	q.where = w
	return q
}

func newQuery(i interface{}) *Query {
	ri := reflect.ValueOf(i)
	if ri.Kind() != reflect.Ptr || ri.IsNil() {
		return nil
	}
	q := new(Query)
	table, cs := structToTable(reflect.Indirect(ri).Interface())
	q.table = table
	q.columns = cs
	q.query = query(table, cs)
	q.dests = make([]interface{}, len(cs))
	for k, v := range cs {
		if v.typ.Kind() == reflect.Int {
			q.dests[k] = new(int)
		}
	}
	return q
}

func convertAssign(i interface{}, rows *sql.Rows, q *Query) error {
	berforeAssign(rows, q)
	st := reflect.ValueOf(i).Elem()
	for idx, c := range q.columns {
		st.Field(c.fieldNum).SetInt(int64(*(q.dests[idx].(*int))))
	}
	return nil
}
func berforeAssign(rows *sql.Rows, q *Query) error {
	for rows.Next() {
		err := rows.Scan(q.dests...)
		if err != nil {
			return err
		}
	}
	return nil
}

func query(table string, cs []column) string {
	s := "select "
	for k, v := range cs {
		s += v.name
		if k != len(cs)-1 {
			s += ","
		}
	}
	s += " from " + table
	return s
}
<commit_msg>add toto<commit_after>package yorm

import (
	"database/sql"
	"reflect"
)

type Query struct {
	query   string
	dests   []interface{}
	where   string
	table   string
	columns []column
}
type Where string

func (q *Query) String() string {
	if q.where == "" {
		return q.query
	}
	return q.query + " where " + q.where
}

func (q *Query) Where(w string) *Query {
	q.where = w
	return q
}

func newQuery(i interface{}) *Query {
	ri := reflect.ValueOf(i)
	if ri.Kind() != reflect.Ptr || ri.IsNil() {
		return nil
	}
	q := new(Query)
	table, cs := structToTable(reflect.Indirect(ri).Interface())
	q.table = table
	q.columns = cs
	q.query = query(table, cs)
	q.dests = make([]interface{}, len(cs))
	for k, v := range cs {
		if v.typ.Kind() == reflect.Int {
			q.dests[k] = new(int)
		}
	}
	return q
}

func convertAssign(i interface{}, rows *sql.Rows, q *Query) error {
	berforeAssign(rows, q)
	st := reflect.ValueOf(i).Elem()
	for idx, c := range q.columns {
		// different assign func here
		st.Field(c.fieldNum).SetInt(int64(*(q.dests[idx].(*int))))
	}
	return nil
}
func berforeAssign(rows *sql.Rows, q *Query) error {
	for rows.Next() {
		err := rows.Scan(q.dests...)
		if err != nil {
			return err
		}
	}
	return nil
}

func query(table string, cs []column) string {
	s := "select "
	for k, v := range cs {
		s += v.name
		if k != len(cs)-1 {
			s += ","
		}
	}
	s += " from " + table
	return s
}
<|endoftext|>


<commit_before>// Copyright 2012 Google Inc. 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

/* TODO

- symlinks.
- expose md5 as xattr.

*/

import (
	"crypto"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/hanwen/go-fuse/fuse"

	_ "crypto/md5"
	"p4fuse/p4"
)

type P4Fs struct {
	fuse.DefaultNodeFileSystem
	backingDir string
	root       *p4Root
	p4         *p4.Conn
}

// Creates a new P4FS
func NewP4Fs(conn *p4.Conn, backingDir string) *P4Fs {
	fs := &P4Fs{
		p4: conn,
	}

	fs.backingDir = backingDir
	fs.root = &p4Root{fs: fs}
	return fs
}

func (fs *P4Fs) Root() fuse.FsNode {
	return fs.root
}

func (fs *P4Fs) OnMount(conn *fuse.FileSystemConnector) {
	fs.root.Inode().AddChild("head", fs.root.Inode().New(false, &p4Link{fs: fs}))
}

func (fs *P4Fs) newFolder(path string, change int) *p4Folder {
	f := &p4Folder{fs: fs, path: path, change: change}
	return f
}

func (fs *P4Fs) newFile(st *p4.Stat) *p4File {
	f := &p4File{fs: fs, stat: *st}
	return f
}

////////////////
type p4Link struct {
	fuse.DefaultFsNode
	fs *P4Fs
}

func (f *p4Link) Deletable() bool {
	return false
}

func (f *p4Link) GetAttr(out *fuse.Attr, file fuse.File, c *fuse.Context) (fuse.Status) {
	out.Mode = fuse.S_IFLNK
	return fuse.OK
}

func (f *p4Link) Readlink(c *fuse.Context) ([]byte, fuse.Status) {
	r, err := f.fs.p4.Changes([]string{"-s", "submitted", "-m1"})
	if err != nil {
		log.Printf("p4.Changes: %v", err)
		return nil, fuse.EIO
	}

	ch := r[0].(*p4.Change)
	return []byte(fmt.Sprintf("%d", ch.Change)), fuse.OK
}

type p4Root struct {
	fuse.DefaultFsNode
	fs *P4Fs

	link *p4Link
}

func (f *p4Root) OpenDir(context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
	return []fuse.DirEntry{{Name: "head", Mode: fuse.S_IFLNK}}, fuse.OK
}

func (r *p4Root) Lookup(out *fuse.Attr, name string, context *fuse.Context) (node fuse.FsNode, code fuse.Status) {
	cl, err := strconv.ParseInt(name, 10, 64)
	if err != nil {
		return nil, fuse.ENOENT
	}

	node = r.fs.newFolder("", int(cl))
	r.Inode().AddChild(name, r.Inode().New(true, node))
	node.GetAttr(out, nil, context)
	return node, fuse.OK
}

////////////////

type p4Folder struct {
	fuse.DefaultFsNode
	change int
	path   string
	fs     *P4Fs

	// nil means they haven't been fetched yet.
	files   map[string]*p4.Stat
	folders map[string]bool
}

func (f *p4Folder) OpenDir(context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
	if !f.fetch() {
		return nil, fuse.EIO
	}
	stream = make([]fuse.DirEntry, 0, len(f.files)+len(f.folders))

	for n, _ := range f.files {
		mode := fuse.S_IFREG | 0644
		stream = append(stream,  fuse.DirEntry{Name: n, Mode: uint32(mode)})
	}
	for n, _ := range f.folders {
		mode := fuse.S_IFDIR | 0755
 		stream = append(stream,fuse.DirEntry{Name: n, Mode: uint32(mode)})
	}
	return stream, fuse.OK
}

func (f *p4Folder) GetAttr(out *fuse.Attr, file fuse.File, c *fuse.Context) (fuse.Status) {
	out.Mode = fuse.S_IFDIR | 0755
	return fuse.OK
}

func (f *p4Folder) Deletable() bool {
	return false
}

func (f *p4Folder) fetch() bool {
	if f.files != nil {
		return true
	}

	var err error
	path := "//" + f.path
	if !strings.HasSuffix(path, "/") {
		path += "/"
	}
	path += fmt.Sprintf("*@%d", f.change)

	folders, err := f.fs.p4.Dirs([]string{path})
	if err != nil {
		log.Printf("fetch: %v", err)
		return false
	}
	files, err := f.fs.p4.Fstat([]string{path})
	if err != nil {
		log.Printf("fetch: %v", err)
		return false
	}

	f.files = map[string]*p4.Stat{}
	for _, r := range files {
		if stat, ok := r.(*p4.Stat); ok && stat.HeadAction != "delete" {
			_, base := filepath.Split(stat.DepotFile)
			f.files[base] = stat
		}
	}

	f.folders = map[string]bool{}
	for _, r := range folders {
		if dir, ok := r.(*p4.Dir); ok {
			_, base := filepath.Split(dir.Dir)
			f.folders[base] = true
		}
	}

	return true
}

func (f *p4Folder) Lookup(out *fuse.Attr, name string, context *fuse.Context) (node fuse.FsNode, code fuse.Status) {
	f.fetch()

	if st := f.files[name]; st != nil {
		node = f.fs.newFile(st)
	} else if f.folders[name] {
		node = f.fs.newFolder(filepath.Join(f.path, name), f.change)
	} else {
		return nil, fuse.ENOENT
	}

	f.Inode().AddChild(name, f.Inode().New(true, node))

	node.GetAttr(out, nil, context)
	return node, fuse.OK
}

////////////////

type p4File struct {
	fuse.DefaultFsNode
	stat    p4.Stat
	fs      *P4Fs
	backing string
}

func (f *p4File) GetAttr(out *fuse.Attr, file fuse.File, c *fuse.Context) (fuse.Status) {
	out.Mode = fuse.S_IFREG | 0644
	out.Mtime = uint64(f.stat.HeadTime)
	out.Size = uint64(f.stat.FileSize)
	return fuse.OK
}

func (f *p4File) fetch() bool {
	if f.backing != "" {
		return true
	}
	id := fmt.Sprintf("%s#%d", f.stat.DepotFile, f.stat.HeadRev)
	content, err := f.fs.p4.Print(id)
	if err != nil {
		log.Printf("p4 print error: %v", err)
		return false
	}

	tmp, err := ioutil.TempFile(f.fs.backingDir, "")
	if err != nil {
		log.Printf("TempFile: %v", err)
		return false
	}

	tmp.Write(content)
	tmp.Close()

	h := crypto.MD5.New()
	h.Write([]byte(id))
	dest := fmt.Sprintf("%s/%x", f.fs.backingDir, h.Sum(nil))
	os.Rename(tmp.Name(), dest)
	f.backing = dest
	return true
}

func (f *p4File) Deletable() bool {
	return false
}

func (n *p4File) Open(flags uint32, context *fuse.Context) (file fuse.File, code fuse.Status) {
	if flags&fuse.O_ANYWRITE != 0 {
		return nil, fuse.EROFS
	}

	n.fetch()
	f, err := os.OpenFile(n.backing, int(flags), 0644)
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	return &fuse.LoopbackFile{File: f}, fuse.OK
}
<commit_msg>Fetch each filerev only once<commit_after>// Copyright 2012 Google Inc. 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

/* TODO

- symlinks.
- expose md5 as xattr.

*/

import (
	"crypto"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/hanwen/go-fuse/fuse"

	_ "crypto/md5"
	"p4fuse/p4"
)

type P4Fs struct {
	fuse.DefaultNodeFileSystem
	backingDir string
	root       *p4Root
	p4         *p4.Conn
}

// Creates a new P4FS
func NewP4Fs(conn *p4.Conn, backingDir string) *P4Fs {
	fs := &P4Fs{
		p4: conn,
	}

	fs.backingDir = backingDir
	fs.root = &p4Root{fs: fs}
	return fs
}

func (fs *P4Fs) Root() fuse.FsNode {
	return fs.root
}

func (fs *P4Fs) OnMount(conn *fuse.FileSystemConnector) {
	fs.root.Inode().AddChild("head", fs.root.Inode().New(false, &p4Link{fs: fs}))
}

func (fs *P4Fs) newFolder(path string, change int) *p4Folder {
	f := &p4Folder{fs: fs, path: path, change: change}
	return f
}

func (fs *P4Fs) newFile(st *p4.Stat) *p4File {
	f := &p4File{fs: fs, stat: *st}
	return f
}

////////////////
type p4Link struct {
	fuse.DefaultFsNode
	fs *P4Fs
}

func (f *p4Link) Deletable() bool {
	return false
}

func (f *p4Link) GetAttr(out *fuse.Attr, file fuse.File, c *fuse.Context) (fuse.Status) {
	out.Mode = fuse.S_IFLNK
	return fuse.OK
}

func (f *p4Link) Readlink(c *fuse.Context) ([]byte, fuse.Status) {
	r, err := f.fs.p4.Changes([]string{"-s", "submitted", "-m1"})
	if err != nil {
		log.Printf("p4.Changes: %v", err)
		return nil, fuse.EIO
	}

	ch := r[0].(*p4.Change)
	return []byte(fmt.Sprintf("%d", ch.Change)), fuse.OK
}

type p4Root struct {
	fuse.DefaultFsNode
	fs *P4Fs

	link *p4Link
}

func (f *p4Root) OpenDir(context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
	return []fuse.DirEntry{{Name: "head", Mode: fuse.S_IFLNK}}, fuse.OK
}

func (r *p4Root) Lookup(out *fuse.Attr, name string, context *fuse.Context) (node fuse.FsNode, code fuse.Status) {
	cl, err := strconv.ParseInt(name, 10, 64)
	if err != nil {
		return nil, fuse.ENOENT
	}

	node = r.fs.newFolder("", int(cl))
	r.Inode().AddChild(name, r.Inode().New(true, node))
	node.GetAttr(out, nil, context)
	return node, fuse.OK
}

////////////////

type p4Folder struct {
	fuse.DefaultFsNode
	change int
	path   string
	fs     *P4Fs

	// nil means they haven't been fetched yet.
	files   map[string]*p4.Stat
	folders map[string]bool
}

func (f *p4Folder) OpenDir(context *fuse.Context) (stream []fuse.DirEntry, status fuse.Status) {
	if !f.fetch() {
		return nil, fuse.EIO
	}
	stream = make([]fuse.DirEntry, 0, len(f.files)+len(f.folders))

	for n, _ := range f.files {
		mode := fuse.S_IFREG | 0644
		stream = append(stream,  fuse.DirEntry{Name: n, Mode: uint32(mode)})
	}
	for n, _ := range f.folders {
		mode := fuse.S_IFDIR | 0755
 		stream = append(stream,fuse.DirEntry{Name: n, Mode: uint32(mode)})
	}
	return stream, fuse.OK
}

func (f *p4Folder) GetAttr(out *fuse.Attr, file fuse.File, c *fuse.Context) (fuse.Status) {
	out.Mode = fuse.S_IFDIR | 0755
	return fuse.OK
}

func (f *p4Folder) Deletable() bool {
	return false
}

func (f *p4Folder) fetch() bool {
	if f.files != nil {
		return true
	}

	var err error
	path := "//" + f.path
	if !strings.HasSuffix(path, "/") {
		path += "/"
	}
	path += fmt.Sprintf("*@%d", f.change)

	folders, err := f.fs.p4.Dirs([]string{path})
	if err != nil {
		log.Printf("fetch: %v", err)
		return false
	}
	files, err := f.fs.p4.Fstat([]string{path})
	if err != nil {
		log.Printf("fetch: %v", err)
		return false
	}

	f.files = map[string]*p4.Stat{}
	for _, r := range files {
		if stat, ok := r.(*p4.Stat); ok && stat.HeadAction != "delete" {
			_, base := filepath.Split(stat.DepotFile)
			f.files[base] = stat
		}
	}

	f.folders = map[string]bool{}
	for _, r := range folders {
		if dir, ok := r.(*p4.Dir); ok {
			_, base := filepath.Split(dir.Dir)
			f.folders[base] = true
		}
	}

	return true
}

func (f *p4Folder) Lookup(out *fuse.Attr, name string, context *fuse.Context) (node fuse.FsNode, code fuse.Status) {
	f.fetch()

	if st := f.files[name]; st != nil {
		node = f.fs.newFile(st)
	} else if f.folders[name] {
		node = f.fs.newFolder(filepath.Join(f.path, name), f.change)
	} else {
		return nil, fuse.ENOENT
	}

	f.Inode().AddChild(name, f.Inode().New(true, node))

	node.GetAttr(out, nil, context)
	return node, fuse.OK
}

////////////////

type p4File struct {
	fuse.DefaultFsNode
	stat    p4.Stat
	fs      *P4Fs
	backing string
}

func (f *p4File) GetAttr(out *fuse.Attr, file fuse.File, c *fuse.Context) (fuse.Status) {
	out.Mode = fuse.S_IFREG | 0644
	out.Mtime = uint64(f.stat.HeadTime)
	out.Size = uint64(f.stat.FileSize)
	return fuse.OK
}

func (f *p4File) fetch() bool {
	if f.backing != "" {
		return true
	}
	id := fmt.Sprintf("%s#%d", f.stat.DepotFile, f.stat.HeadRev)
	h := crypto.MD5.New()
	h.Write([]byte(id))
	dest := fmt.Sprintf("%s/%x", f.fs.backingDir, h.Sum(nil))

	if _, err := os.Lstat(dest); err == nil {
		f.backing = dest
		return true
	}
	content, err := f.fs.p4.Print(id)
	if err != nil {
		log.Printf("p4 print error: %v", err)
		return false
	}

	tmp, err := ioutil.TempFile(f.fs.backingDir, "")
	if err != nil {
		log.Printf("TempFile: %v", err)
		return false
	}

	tmp.Write(content)
	tmp.Close()

	os.Rename(tmp.Name(), dest)
	f.backing = dest
	return true
}

func (f *p4File) Deletable() bool {
	return false
}

func (n *p4File) Open(flags uint32, context *fuse.Context) (file fuse.File, code fuse.Status) {
	if flags&fuse.O_ANYWRITE != 0 {
		return nil, fuse.EROFS
	}

	n.fetch()
	f, err := os.OpenFile(n.backing, int(flags), 0644)
	if err != nil {
		return nil, fuse.ToStatus(err)
	}
	return &fuse.LoopbackFile{File: f}, fuse.OK
}
<|endoftext|>


<commit_before>/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package runc

import (
	"io"
	"os"
	"os/exec"
)

type IO interface {
	io.Closer
	Stdin() io.WriteCloser
	Stdout() io.ReadCloser
	Stderr() io.ReadCloser
	Set(*exec.Cmd)
}

type StartCloser interface {
	CloseAfterStart() error
}

func newPipe() (*pipe, error) {
	r, w, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	return &pipe{
		r: r,
		w: w,
	}, nil
}

type pipe struct {
	r *os.File
	w *os.File
}

func (p *pipe) Close() error {
	err := p.r.Close()
	if werr := p.w.Close(); err == nil {
		err = werr
	}
	return err
}

type pipeIO struct {
	in  *pipe
	out *pipe
	err *pipe
}

func (i *pipeIO) Stdin() io.WriteCloser {
	return i.in.w
}

func (i *pipeIO) Stdout() io.ReadCloser {
	return i.out.r
}

func (i *pipeIO) Stderr() io.ReadCloser {
	return i.err.r
}

func (i *pipeIO) Close() error {
	var err error
	for _, v := range []*pipe{
		i.in,
		i.out,
		i.err,
	} {
		if cerr := v.Close(); err == nil {
			err = cerr
		}
	}
	return err
}

func (i *pipeIO) CloseAfterStart() error {
	for _, f := range []*os.File{
		i.out.w,
		i.err.w,
	} {
		f.Close()
	}
	return nil
}

// Set sets the io to the exec.Cmd
func (i *pipeIO) Set(cmd *exec.Cmd) {
	cmd.Stdin = i.in.r
	cmd.Stdout = i.out.w
	cmd.Stderr = i.err.w
}

func NewSTDIO() (IO, error) {
	return &stdio{}, nil
}

type stdio struct {
}

func (s *stdio) Close() error {
	return nil
}

func (s *stdio) Set(cmd *exec.Cmd) {
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
}

func (s *stdio) Stdin() io.WriteCloser {
	return os.Stdin
}

func (s *stdio) Stdout() io.ReadCloser {
	return os.Stdout
}

func (s *stdio) Stderr() io.ReadCloser {
	return os.Stderr
}

// NewNullIO returns IO setup for /dev/null use with runc
func NewNullIO() (IO, error) {
	f, err := os.Open(os.DevNull)
	if err != nil {
		return nil, err
	}
	return &nullIO{
		devNull: f,
	}, nil
}

type nullIO struct {
	devNull *os.File
}

func (n *nullIO) Close() error {
	// this should be closed after start but if not
	// make sure we close the file but don't return the error
	n.devNull.Close()
	return nil
}

func (n *nullIO) Stdin() io.WriteCloser {
	return nil
}

func (n *nullIO) Stdout() io.ReadCloser {
	return nil
}

func (n *nullIO) Stderr() io.ReadCloser {
	return nil
}

func (n *nullIO) Set(c *exec.Cmd) {
	// don't set STDIN here
	c.Stdout = n.devNull
	c.Stderr = n.devNull
}

func (n *nullIO) CloseAfterStart() error {
	return n.devNull.Close()
}
<commit_msg>Reorder pipe close to be write/read<commit_after>/*
   Copyright The containerd Authors.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

package runc

import (
	"io"
	"os"
	"os/exec"
)

type IO interface {
	io.Closer
	Stdin() io.WriteCloser
	Stdout() io.ReadCloser
	Stderr() io.ReadCloser
	Set(*exec.Cmd)
}

type StartCloser interface {
	CloseAfterStart() error
}

func newPipe() (*pipe, error) {
	r, w, err := os.Pipe()
	if err != nil {
		return nil, err
	}
	return &pipe{
		r: r,
		w: w,
	}, nil
}

type pipe struct {
	r *os.File
	w *os.File
}

func (p *pipe) Close() error {
	err := p.w.Close()
	if rerr := p.r.Close(); err == nil {
		err = rerr
	}
	return err
}

type pipeIO struct {
	in  *pipe
	out *pipe
	err *pipe
}

func (i *pipeIO) Stdin() io.WriteCloser {
	return i.in.w
}

func (i *pipeIO) Stdout() io.ReadCloser {
	return i.out.r
}

func (i *pipeIO) Stderr() io.ReadCloser {
	return i.err.r
}

func (i *pipeIO) Close() error {
	var err error
	for _, v := range []*pipe{
		i.in,
		i.out,
		i.err,
	} {
		if cerr := v.Close(); err == nil {
			err = cerr
		}
	}
	return err
}

func (i *pipeIO) CloseAfterStart() error {
	for _, f := range []*os.File{
		i.out.w,
		i.err.w,
	} {
		f.Close()
	}
	return nil
}

// Set sets the io to the exec.Cmd
func (i *pipeIO) Set(cmd *exec.Cmd) {
	cmd.Stdin = i.in.r
	cmd.Stdout = i.out.w
	cmd.Stderr = i.err.w
}

func NewSTDIO() (IO, error) {
	return &stdio{}, nil
}

type stdio struct {
}

func (s *stdio) Close() error {
	return nil
}

func (s *stdio) Set(cmd *exec.Cmd) {
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
}

func (s *stdio) Stdin() io.WriteCloser {
	return os.Stdin
}

func (s *stdio) Stdout() io.ReadCloser {
	return os.Stdout
}

func (s *stdio) Stderr() io.ReadCloser {
	return os.Stderr
}

// NewNullIO returns IO setup for /dev/null use with runc
func NewNullIO() (IO, error) {
	f, err := os.Open(os.DevNull)
	if err != nil {
		return nil, err
	}
	return &nullIO{
		devNull: f,
	}, nil
}

type nullIO struct {
	devNull *os.File
}

func (n *nullIO) Close() error {
	// this should be closed after start but if not
	// make sure we close the file but don't return the error
	n.devNull.Close()
	return nil
}

func (n *nullIO) Stdin() io.WriteCloser {
	return nil
}

func (n *nullIO) Stdout() io.ReadCloser {
	return nil
}

func (n *nullIO) Stderr() io.ReadCloser {
	return nil
}

func (n *nullIO) Set(c *exec.Cmd) {
	// don't set STDIN here
	c.Stdout = n.devNull
	c.Stderr = n.devNull
}

func (n *nullIO) CloseAfterStart() error {
	return n.devNull.Close()
}
<|endoftext|>


<commit_before>package scipipe

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"os"
	"os/exec"
	"sync"
	"time"
)

// ======= InformationPacket ========

// InformationPacket contains information and helper methods for a physical file on a
// normal disk.
type InformationPacket struct {
	path      string
	buffer    *bytes.Buffer
	doStream  bool
	lock      *sync.Mutex
	auditInfo *AuditInfo
	SubStream *FilePort
}

// Create new InformationPacket "object"
func NewInformationPacket(path string) *InformationPacket {
	ip := new(InformationPacket)
	ip.path = path
	ip.lock = new(sync.Mutex)
	ip.SubStream = NewFilePort()
	//Don't init buffer if not needed?
	//buf := make([]byte, 0, 128)
	//ip.buffer = bytes.NewBuffer(buf)
	return ip
}

// Get the (final) path of the physical file
func (ip *InformationPacket) GetPath() string {
	return ip.path
}

// Get the temporary path of the physical file
func (ip *InformationPacket) GetTempPath() string {
	return ip.path + ".tmp"
}

// Get the path to use when a FIFO file is used instead of a normal file
func (ip *InformationPacket) GetFifoPath() string {
	return ip.path + ".fifo"
}

// Get the size of an existing file, in bytes
func (ip *InformationPacket) GetSize() int64 {
	fi, err := os.Stat(ip.path)
	CheckErr(err)
	return fi.Size()
}

// Open the file and return a file handle (*os.File)
func (ip *InformationPacket) Open() *os.File {
	f, err := os.Open(ip.GetPath())
	Check(err, "Could not open file: "+ip.GetPath())
	return f
}

// Open the temp file and return a file handle (*os.File)
func (ip *InformationPacket) OpenTemp() *os.File {
	f, err := os.Open(ip.GetTempPath())
	Check(err, "Could not open temp file: "+ip.GetTempPath())
	return f
}

// Open the file for writing return a file handle (*os.File)
func (ip *InformationPacket) OpenWriteTemp() *os.File {
	f, err := os.Create(ip.GetTempPath())
	Check(err, "Could not open temp file for writing: "+ip.GetTempPath())
	return f
}

// Read the whole content of the file and return as a byte array ([]byte)
func (ip *InformationPacket) Read() []byte {
	dat, err := ioutil.ReadFile(ip.GetPath())
	Check(err, "Could not open file for reading: "+ip.GetPath())
	return dat
}

// Read the whole content of the file and return as a byte array ([]byte)
func (ip *InformationPacket) ReadAuditFile() []byte {
	dat, err := ioutil.ReadFile(ip.GetAuditFilePath())
	Check(err, "Could not open file for reading: "+ip.GetAuditFilePath())
	return dat
}

// Write a byte array ([]byte) to the file (first to its temp path, and then atomize)
func (ip *InformationPacket) WriteTempFile(dat []byte) {
	err := ioutil.WriteFile(ip.GetTempPath(), dat, 0644)
	Check(err, "Could not write to temp file: "+ip.GetTempPath())
}

const (
	sleepDurationSec = 1
)

// Change from the temporary file name to the final file name
func (ip *InformationPacket) Atomize() {
	Debug.Println("InformationPacket: Atomizing", ip.GetTempPath(), "->", ip.GetPath())
	doneAtomizing := false
	for !doneAtomizing {
		if ip.TempFileExists() {
			ip.lock.Lock()
			err := os.Rename(ip.GetTempPath(), ip.path)
			Check(err, "Could not rename file: "+ip.GetTempPath())
			ip.lock.Unlock()
			doneAtomizing = true
			Debug.Println("InformationPacket: Done atomizing", ip.GetTempPath(), "->", ip.GetPath())
		} else {
			Debug.Printf("Sleeping for %d seconds before atomizing ...\n", sleepDurationSec)
			time.Sleep(time.Duration(sleepDurationSec) * time.Second)
		}
	}
}

// Create FIFO file for the InformationPacket
func (ip *InformationPacket) CreateFifo() {
	ip.lock.Lock()
	cmd := "mkfifo " + ip.GetFifoPath()
	Debug.Println("Now creating FIFO with command:", cmd)

	if _, err := os.Stat(ip.GetFifoPath()); err == nil {
		Warning.Println("FIFO already exists, so not creating a new one:", ip.GetFifoPath())
	} else {
		_, err := exec.Command("bash", "-c", cmd).Output()
		Check(err, "Could not execute command: "+cmd)
	}

	ip.lock.Unlock()
}

// Remove the FIFO file, if it exists
func (ip *InformationPacket) RemoveFifo() {
	// FIXME: Shouldn't we check first whether the fifo exists?
	ip.lock.Lock()
	output, err := exec.Command("bash", "-c", "rm "+ip.GetFifoPath()).Output()
	Check(err, "Could not delete fifo file: "+ip.GetFifoPath())
	Debug.Println("Removed FIFO output: ", output)
	ip.lock.Unlock()
}

// Check if the file exists (at its final file name)
func (ip *InformationPacket) Exists() bool {
	exists := false
	ip.lock.Lock()
	if _, err := os.Stat(ip.GetPath()); err == nil {
		exists = true
	}
	ip.lock.Unlock()
	return exists
}

// Check if the temp-file exists
func (ip *InformationPacket) TempFileExists() bool {
	tempFileExists := false
	ip.lock.Lock()
	if _, err := os.Stat(ip.GetTempPath()); err == nil {
		tempFileExists = true
	}
	ip.lock.Unlock()
	return tempFileExists
}

func (ip *InformationPacket) GetAuditInfo() *AuditInfo {
	auditInfo := &AuditInfo{}
	if ip.auditInfo != nil {
		defer ip.lock.Unlock()
		ip.lock.Lock()
		auditInfo = ip.auditInfo
	} else {
		auditFileData, err := ioutil.ReadFile(ip.GetAuditFilePath())
		if err == nil {
			unmarshalErr := json.Unmarshal(auditFileData, auditInfo)
			Check(unmarshalErr, "Could not unmarchal audit log file content: "+ip.GetAuditFilePath())
		}
	}
	return auditInfo
}

func (ip *InformationPacket) SetAuditInfo(ai *AuditInfo) {
	ip.lock.Lock()
	ip.auditInfo = ai
	ip.lock.Unlock()
}

func (ip *InformationPacket) GetAuditFilePath() string {
	return ip.GetPath() + ".audit.json"
}

func (ip *InformationPacket) WriteAuditLogToFile() {
	auditInfo := ip.GetAuditInfo()
	auditInfoJson, jsonErr := json.MarshalIndent(auditInfo, "", "    ")
	Check(jsonErr, "Could not marshall JSON")
	writeErr := ioutil.WriteFile(ip.GetAuditFilePath(), auditInfoJson, 0644)
	Check(writeErr, "Could not write audit file: "+ip.GetPath())
}

// ======= IPGen=======

// IPGen is initialized by a set of strings with file paths, and from that will
// return instantiated (generated) InformationPacket on its Out-port, when run.
type IPGen struct {
	Process
	name      string
	Out       *FilePort
	FilePaths []string
}

// Initialize a new IPGen component from a list of file paths
func NewIPGen(workflow *Workflow, name string, filePaths ...string) (fq *IPGen) {
	fq = &IPGen{
		name:      name,
		Out:       NewFilePort(),
		FilePaths: filePaths,
	}
	workflow.AddProc(fq)
	return
}

// Execute the IPGen, returning instantiated InformationPacket
func (ipg *IPGen) Run() {
	defer ipg.Out.Close()
	for _, fp := range ipg.FilePaths {
		ipg.Out.Send(NewInformationPacket(fp))
	}
}

func (ipg *IPGen) Name() string {
	return ipg.name
}

// Check if the IPGen outport is connected
func (ipg *IPGen) IsConnected() bool {
	return ipg.Out.IsConnected()
}
<commit_msg>Implement GetParam() function in ip<commit_after>package scipipe

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"os"
	"os/exec"
	"sync"
	"time"
)

// ======= InformationPacket ========

// InformationPacket contains information and helper methods for a physical file on a
// normal disk.
type InformationPacket struct {
	path      string
	buffer    *bytes.Buffer
	doStream  bool
	lock      *sync.Mutex
	auditInfo *AuditInfo
	SubStream *FilePort
}

// Create new InformationPacket "object"
func NewInformationPacket(path string) *InformationPacket {
	ip := new(InformationPacket)
	ip.path = path
	ip.lock = new(sync.Mutex)
	ip.SubStream = NewFilePort()
	//Don't init buffer if not needed?
	//buf := make([]byte, 0, 128)
	//ip.buffer = bytes.NewBuffer(buf)
	return ip
}

// Get the (final) path of the physical file
func (ip *InformationPacket) GetPath() string {
	return ip.path
}

// Get the temporary path of the physical file
func (ip *InformationPacket) GetTempPath() string {
	return ip.path + ".tmp"
}

// Get the path to use when a FIFO file is used instead of a normal file
func (ip *InformationPacket) GetFifoPath() string {
	return ip.path + ".fifo"
}

// Get the size of an existing file, in bytes
func (ip *InformationPacket) GetSize() int64 {
	fi, err := os.Stat(ip.path)
	CheckErr(err)
	return fi.Size()
}

// Open the file and return a file handle (*os.File)
func (ip *InformationPacket) Open() *os.File {
	f, err := os.Open(ip.GetPath())
	Check(err, "Could not open file: "+ip.GetPath())
	return f
}

// Open the temp file and return a file handle (*os.File)
func (ip *InformationPacket) OpenTemp() *os.File {
	f, err := os.Open(ip.GetTempPath())
	Check(err, "Could not open temp file: "+ip.GetTempPath())
	return f
}

// Open the file for writing return a file handle (*os.File)
func (ip *InformationPacket) OpenWriteTemp() *os.File {
	f, err := os.Create(ip.GetTempPath())
	Check(err, "Could not open temp file for writing: "+ip.GetTempPath())
	return f
}

// Read the whole content of the file and return as a byte array ([]byte)
func (ip *InformationPacket) Read() []byte {
	dat, err := ioutil.ReadFile(ip.GetPath())
	Check(err, "Could not open file for reading: "+ip.GetPath())
	return dat
}

// Read the whole content of the file and return as a byte array ([]byte)
func (ip *InformationPacket) ReadAuditFile() []byte {
	dat, err := ioutil.ReadFile(ip.GetAuditFilePath())
	Check(err, "Could not open file for reading: "+ip.GetAuditFilePath())
	return dat
}

// Write a byte array ([]byte) to the file (first to its temp path, and then atomize)
func (ip *InformationPacket) WriteTempFile(dat []byte) {
	err := ioutil.WriteFile(ip.GetTempPath(), dat, 0644)
	Check(err, "Could not write to temp file: "+ip.GetTempPath())
}

const (
	sleepDurationSec = 1
)

// Change from the temporary file name to the final file name
func (ip *InformationPacket) Atomize() {
	Debug.Println("InformationPacket: Atomizing", ip.GetTempPath(), "->", ip.GetPath())
	doneAtomizing := false
	for !doneAtomizing {
		if ip.TempFileExists() {
			ip.lock.Lock()
			err := os.Rename(ip.GetTempPath(), ip.path)
			Check(err, "Could not rename file: "+ip.GetTempPath())
			ip.lock.Unlock()
			doneAtomizing = true
			Debug.Println("InformationPacket: Done atomizing", ip.GetTempPath(), "->", ip.GetPath())
		} else {
			Debug.Printf("Sleeping for %d seconds before atomizing ...\n", sleepDurationSec)
			time.Sleep(time.Duration(sleepDurationSec) * time.Second)
		}
	}
}

// Create FIFO file for the InformationPacket
func (ip *InformationPacket) CreateFifo() {
	ip.lock.Lock()
	cmd := "mkfifo " + ip.GetFifoPath()
	Debug.Println("Now creating FIFO with command:", cmd)

	if _, err := os.Stat(ip.GetFifoPath()); err == nil {
		Warning.Println("FIFO already exists, so not creating a new one:", ip.GetFifoPath())
	} else {
		_, err := exec.Command("bash", "-c", cmd).Output()
		Check(err, "Could not execute command: "+cmd)
	}

	ip.lock.Unlock()
}

// Remove the FIFO file, if it exists
func (ip *InformationPacket) RemoveFifo() {
	// FIXME: Shouldn't we check first whether the fifo exists?
	ip.lock.Lock()
	output, err := exec.Command("bash", "-c", "rm "+ip.GetFifoPath()).Output()
	Check(err, "Could not delete fifo file: "+ip.GetFifoPath())
	Debug.Println("Removed FIFO output: ", output)
	ip.lock.Unlock()
}

// Check if the file exists (at its final file name)
func (ip *InformationPacket) Exists() bool {
	exists := false
	ip.lock.Lock()
	if _, err := os.Stat(ip.GetPath()); err == nil {
		exists = true
	}
	ip.lock.Unlock()
	return exists
}

// Check if the temp-file exists
func (ip *InformationPacket) TempFileExists() bool {
	tempFileExists := false
	ip.lock.Lock()
	if _, err := os.Stat(ip.GetTempPath()); err == nil {
		tempFileExists = true
	}
	ip.lock.Unlock()
	return tempFileExists
}

func (ip *InformationPacket) GetParam(key string) string {
	ai := ip.GetAuditInfo()
	val, ok := ai.Params[key]
	if !ok {
		Error.Fatalf("Could not find parameter %s in ip with path: %s\n", key, ip.GetPath())
	}
	return val
}

func (ip *InformationPacket) GetAuditInfo() *AuditInfo {
	defer ip.lock.Unlock()
	ip.lock.Lock()
	if ip.auditInfo == nil {
		ip.auditInfo = NewAuditInfo()
		auditFileData, err := ioutil.ReadFile(ip.GetAuditFilePath())
		if err == nil {
			unmarshalErr := json.Unmarshal(auditFileData, ip.auditInfo)
			Check(unmarshalErr, "Could not unmarshal audit log file content: "+ip.GetAuditFilePath())
		}
	}
	return ip.auditInfo
}

func (ip *InformationPacket) SetAuditInfo(ai *AuditInfo) {
	ip.lock.Lock()
	ip.auditInfo = ai
	ip.lock.Unlock()
}

func (ip *InformationPacket) GetAuditFilePath() string {
	return ip.GetPath() + ".audit.json"
}

func (ip *InformationPacket) WriteAuditLogToFile() {
	auditInfo := ip.GetAuditInfo()
	auditInfoJson, jsonErr := json.MarshalIndent(auditInfo, "", "    ")
	Check(jsonErr, "Could not marshall JSON")
	writeErr := ioutil.WriteFile(ip.GetAuditFilePath(), auditInfoJson, 0644)
	Check(writeErr, "Could not write audit file: "+ip.GetPath())
}

// ======= IPGen=======

// IPGen is initialized by a set of strings with file paths, and from that will
// return instantiated (generated) InformationPacket on its Out-port, when run.
type IPGen struct {
	Process
	name      string
	Out       *FilePort
	FilePaths []string
}

// Initialize a new IPGen component from a list of file paths
func NewIPGen(workflow *Workflow, name string, filePaths ...string) (fq *IPGen) {
	fq = &IPGen{
		name:      name,
		Out:       NewFilePort(),
		FilePaths: filePaths,
	}
	workflow.AddProc(fq)
	return
}

// Execute the IPGen, returning instantiated InformationPacket
func (ipg *IPGen) Run() {
	defer ipg.Out.Close()
	for _, fp := range ipg.FilePaths {
		ipg.Out.Send(NewInformationPacket(fp))
	}
}

func (ipg *IPGen) Name() string {
	return ipg.name
}

// Check if the IPGen outport is connected
func (ipg *IPGen) IsConnected() bool {
	return ipg.Out.IsConnected()
}
<|endoftext|>