<commit_before>package solidserver

import (
  "github.com/hashicorp/terraform/helper/schema"
  "encoding/json"
  "net/url"
  "strings"
  "fmt"
  "log"
)

func resourceipalias() *schema.Resource {
  return &schema.Resource{
    Create: resourceipaliasCreate,
    Read:   resourceipaliasRead,
    //Update: resourceipaliasUpdate,
    Delete: resourceipaliasDelete,

    Schema: map[string]*schema.Schema{
      "space": &schema.Schema{
        Type:     schema.TypeString,
        Description: "The name of the space to which the address belong to.",
        Required: true,
        ForceNew: true,
      },
      "address": &schema.Schema{
        Type:     schema.TypeString,
        Description: "The IP address for which the alias will be associated to.",
        Required: true,
        ForceNew: true,
      },
      "name": &schema.Schema{
        Type:     schema.TypeString,
        Description: "The FQDN of the IP address alias to create.",
        Required: true,
        ForceNew: true,
      },
      "type": &schema.Schema{
        Type:         schema.TypeString,
        Description:  "The type of the Alias to create (Supported: A, CNAME; Default: CNAME).",
        ValidateFunc: resourcealiasvalidatetype,
        Default:      "CNAME",
        Optional:     true,
        ForceNew:     true,
      },
    },
  }
}

func resourcealiasvalidatetype(v interface{}, _ string) ([]string, []error) {
  switch strings.ToUpper(v.(string)){
    case "A":
      return nil, nil
    case "CNAME":
      return nil, nil
    default:
      return nil, []error{fmt.Errorf("Unsupported Alias type.")}
  }
}

func resourceipaliasCreate(d *schema.ResourceData, meta interface{}) error {
  s := meta.(*SOLIDserver)

  var site_id    string = ipsiteidbyname(d.Get("space").(string), meta)
  var address_id  string = ipaddressidbyip(site_id, d.Get("address").(string), meta)

  // Building parameters
  parameters := url.Values{}
  parameters.Add("ip_id", address_id)
  parameters.Add("ip_name", d.Get("name").(string))
  parameters.Add("ip_name_type", d.Get("type").(string))

  // Sending the creation request
  http_resp, body, _ := s.Request("post", "rest/ip_alias_add", &parameters)

  var buf [](map[string]interface{})
  json.Unmarshal([]byte(body), &buf)

  // Checking the answer
  if ((http_resp.StatusCode == 200 || http_resp.StatusCode == 201) && len(buf) > 0) {
    if oid, oid_exist := buf[0]["ret_oid"].(string); (oid_exist) {
      //ip_name_id := ipaliasidbyinfo(oid, d.Get("name").(string), d.Get("type").(string), meta)

      log.Printf("[DEBUG] SOLIDServer - Created IP alias (oid): %s", oid)

      d.SetId(oid)

      return nil
    }
  }

  // Reporting a failure
  return fmt.Errorf("SOLIDServer - Unable to create IP alias: %s - %s (associated to IP address with ID: %s)", d.Get("name").(string), d.Get("type"), address_id)
}

//func resourceipaliasUpdate(d *schema.ResourceData, meta interface{}) error {
  // Not necessary
//  return nil
//}

func resourceipaliasDelete(d *schema.ResourceData, meta interface{}) error {
  s := meta.(*SOLIDserver)

  // Building parameters
  parameters := url.Values{}
  parameters.Add("ip_name_id", d.Id())

  // Sending the deletion request
  http_resp, body, _ := s.Request("delete", "rest/ip_alias_delete", &parameters)

  var buf [](map[string]interface{})
  json.Unmarshal([]byte(body), &buf)

  // Checking the answer
  if (http_resp.StatusCode != 204 && len(buf) > 0) {
    if errmsg, err_exist := buf[0]["errmsg"].(string); (err_exist) {
      log.Printf("[DEBUG] SOLIDServer - Unable to delete IP alias : %s - %s (%s)", d.Get("name"), d.Get("type"), errmsg)
    }
  }

  // Log deletion
  log.Printf("[DEBUG] SOLIDServer - Deleted IP alias with oid: %s", d.Id())

  // Unset local ID
  d.SetId("")

  return nil
}

func resourceipaliasRead(d *schema.ResourceData, meta interface{}) error {
  s := meta.(*SOLIDserver)

  var site_id    string = ipsiteidbyname(d.Get("space").(string), meta)
  var address_id  string = ipaddressidbyip(site_id, d.Get("address").(string), meta)

  // Building parameters
  parameters := url.Values{}
  parameters.Add("ip_id", address_id)
  // Bug - Ticket 18653
  //parameters.Add("WHERE", "ip_name_id='" + d.Id() + "'")

  // Sending the read request
  http_resp, body, _ := s.Request("get", "rest/ip_alias_list", &parameters)

  var buf [](map[string]interface{})
  json.Unmarshal([]byte(body), &buf)

  // Shall be removed once Ticket 18653 is closed
  // Checking the answer
  if (http_resp.StatusCode == 200 && len(buf) > 0) {
    for i := 0; i < len(buf); i++ {
      r_ip_name_id, r_ip_name_id_exist := buf[i]["ip_name_id"].(string)
      r_ip_name_type, r_ip_name_type_exist := buf[i]["ip_name_type"].(string)
      r_alias_name, r_alias_name_exist := buf[i]["alias_name"].(string)

      if (r_ip_name_id_exist && strings.Compare(d.Id(), r_ip_name_id) == 0) {
        if (r_alias_name_exist) {
          d.Set("name", r_alias_name)
        }
        if (r_ip_name_type_exist) {
          d.Set("type", r_ip_name_type)
        }

        return nil
      }
    }
  }

  // Shall be restored once Ticket 18653 is closed
  // Checking the answer
  //if (http_resp.StatusCode == 200 && len(buf) > 0) {
  //  d.Set("name", buf[0]["alias_name"].(string))
  //  d.Set("type", buf[0]["ip_name_type"].(string))
  //
  //  return nil
  //}

  if (len(buf) > 0) {
    if errmsg, err_exist := buf[0]["errmsg"].(string); (err_exist) {
      // Log the error
      log.Printf("[DEBUG] SOLIDServer - Unable to find IP alias: %s (%s)", d.Get("name"), errmsg)
    }
  } else {
    // Log the error
    log.Printf("[DEBUG] SOLIDServer - Unable to find IP alias (oid): %s", d.Id())
  }

  // Do not unset the local ID to avoid inconsistency

  // Reporting a failure
  return fmt.Errorf("SOLIDServer - Unable to find IP alias: %s", d.Get("name").(string))
}<commit_msg>Small update for better error handling<commit_after>package solidserver

import (
  "github.com/hashicorp/terraform/helper/schema"
  "encoding/json"
  "net/url"
  "strings"
  "fmt"
  "log"
)

func resourceipalias() *schema.Resource {
  return &schema.Resource{
    Create: resourceipaliasCreate,
    Read:   resourceipaliasRead,
    //Update: resourceipaliasUpdate,
    Delete: resourceipaliasDelete,

    Schema: map[string]*schema.Schema{
      "space": &schema.Schema{
        Type:     schema.TypeString,
        Description: "The name of the space to which the address belong to.",
        Required: true,
        ForceNew: true,
      },
      "address": &schema.Schema{
        Type:     schema.TypeString,
        Description: "The IP address for which the alias will be associated to.",
        Required: true,
        ForceNew: true,
      },
      "name": &schema.Schema{
        Type:     schema.TypeString,
        Description: "The FQDN of the IP address alias to create.",
        Required: true,
        ForceNew: true,
      },
      "type": &schema.Schema{
        Type:         schema.TypeString,
        Description:  "The type of the Alias to create (Supported: A, CNAME; Default: CNAME).",
        ValidateFunc: resourcealiasvalidatetype,
        Default:      "CNAME",
        Optional:     true,
        ForceNew:     true,
      },
    },
  }
}

func resourcealiasvalidatetype(v interface{}, _ string) ([]string, []error) {
  switch strings.ToUpper(v.(string)){
    case "A":
      return nil, nil
    case "CNAME":
      return nil, nil
    default:
      return nil, []error{fmt.Errorf("Unsupported Alias type.")}
  }
}

func resourceipaliasCreate(d *schema.ResourceData, meta interface{}) error {
  s := meta.(*SOLIDserver)

  // FIXME - Replace following line by the one following
  var site_id string = ipsiteidbyname(d.Get("space").(string), meta)
  var address_id string = ipaddressidbyip(site_id, d.Get("address").(string), meta)

  // Gather required ID(s) from provided information
  // if site_id, err := ipsiteidbyname(d.Get("space").(string), meta); (err != nil) {
  //   return err
  // }
  // if address_id, err := ipaddressidbyip(site_id, d.Get("address").(string), meta); (err != nil) {
  //   return err
  // }

  // Building parameters
  parameters := url.Values{}
  parameters.Add("ip_id", address_id)
  parameters.Add("ip_name", d.Get("name").(string))
  parameters.Add("ip_name_type", d.Get("type").(string))

  // Sending the creation request
  http_resp, body, err := s.Request("post", "rest/ip_alias_add", &parameters)

  if (err == nil) {
    var buf [](map[string]interface{})
    json.Unmarshal([]byte(body), &buf)

    // Checking the answer
    if ((http_resp.StatusCode == 200 || http_resp.StatusCode == 201) && len(buf) > 0) {
      if oid, oid_exist := buf[0]["ret_oid"].(string); (oid_exist) {
        log.Printf("[DEBUG] SOLIDServer - Created IP alias (oid): %s", oid)
        d.SetId(oid)

        return nil
      }
    }

    // Reporting a failure
    return fmt.Errorf("SOLIDServer - Unable to create IP alias: %s - %s (associated to IP address with ID: %s)", d.Get("name").(string), d.Get("type"), address_id)
  }

  // Reporting a failure
  return err
}

func resourceipaliasDelete(d *schema.ResourceData, meta interface{}) error {
  s := meta.(*SOLIDserver)

  // Building parameters
  parameters := url.Values{}
  parameters.Add("ip_name_id", d.Id())

  // Sending the deletion request
  http_resp, body, err := s.Request("delete", "rest/ip_alias_delete", &parameters)

  if (err == nil) {
    var buf [](map[string]interface{})
    json.Unmarshal([]byte(body), &buf)

    // Checking the answer
    if (http_resp.StatusCode != 204 && len(buf) > 0) {
      if errmsg, err_exist := buf[0]["errmsg"].(string); (err_exist) {
        log.Printf("[DEBUG] SOLIDServer - Unable to delete IP alias : %s - %s (%s)", d.Get("name"), d.Get("type"), errmsg)
      }
    }

    // Log deletion
    log.Printf("[DEBUG] SOLIDServer - Deleted IP alias with oid: %s", d.Id())

    // Unset local ID
    d.SetId("")

    // Reporting a success
    return nil
  }

  // Reporting a failure
  return err
}

func resourceipaliasRead(d *schema.ResourceData, meta interface{}) error {
  s := meta.(*SOLIDserver)

  // FIXME - Replace following line by the one following
  var site_id    string = ipsiteidbyname(d.Get("space").(string), meta)
  var address_id  string = ipaddressidbyip(site_id, d.Get("address").(string), meta)

  // Gather required ID(s) from provided information
  // if site_id, err := ipsiteidbyname(d.Get("space").(string), meta); (err != nil) {
  //   return err
  // }
  // if address_id, err := ipaddressidbyip(site_id, d.Get("address").(string), meta); (err != nil) {
  //   return err
  // }

  // Building parameters
  parameters := url.Values{}
  parameters.Add("ip_id", address_id)
  // Bug - Ticket 18653 (Fixed in 6.0.2.P2) to be changed soon
  //parameters.Add("WHERE", "ip_name_id='" + d.Id() + "'")

  // Sending the read request
  http_resp, body, err := s.Request("get", "rest/ip_alias_list", &parameters)

  if (err == nil) {
    var buf [](map[string]interface{})
    json.Unmarshal([]byte(body), &buf)

    // Shall be removed once Ticket 18653 is closed
    // Checking the answer
    if (http_resp.StatusCode == 200 && len(buf) > 0) {
      for i := 0; i < len(buf); i++ {
        r_ip_name_id, r_ip_name_id_exist := buf[i]["ip_name_id"].(string)
        r_ip_name_type, r_ip_name_type_exist := buf[i]["ip_name_type"].(string)
        r_alias_name, r_alias_name_exist := buf[i]["alias_name"].(string)

        if (r_ip_name_id_exist && strings.Compare(d.Id(), r_ip_name_id) == 0) {
          if (r_alias_name_exist) {
            d.Set("name", r_alias_name)
          }
          if (r_ip_name_type_exist) {
            d.Set("type", r_ip_name_type)
          }

          return nil
        }
      }
    }

    // Shall be restored once Ticket 18653 is closed
    // Checking the answer
    //if (http_resp.StatusCode == 200 && len(buf) > 0) {
    //  d.Set("name", buf[0]["alias_name"].(string))
    //  d.Set("type", buf[0]["ip_name_type"].(string))
    //
    //  return nil
    //}

    if (len(buf) > 0) {
      if errmsg, err_exist := buf[0]["errmsg"].(string); (err_exist) {
        // Log the error
        log.Printf("[DEBUG] SOLIDServer - Unable to find IP alias: %s (%s)", d.Get("name"), errmsg)
      }
    } else {
      // Log the error
      log.Printf("[DEBUG] SOLIDServer - Unable to find IP alias (oid): %s", d.Id())
    }

    // Do not unset the local ID to avoid inconsistency

    // Reporting a failure
    return fmt.Errorf("SOLIDServer - Unable to find IP alias: %s", d.Get("name").(string))
  }

  // Reporting a failure
  return err
}<|endoftext|>


<commit_before>package id3v2

import (
	"bufio"
	"bytes"
	"errors"
	"github.com/bogem/id3v2/frame"
	"github.com/bogem/id3v2/util"
	"io/ioutil"
	"os"
)

type Tag struct {
	frames    map[string]frame.Framer
	commonIDs map[string]string

	File         *os.File
	OriginalSize uint32
}

func (t *Tag) SetAttachedPicture(pf frame.PictureFramer) error {
	var f frame.APICSequencer
	id := t.commonIDs["Attached Picture"]

	existingFrame := t.frames[id]
	if existingFrame == nil {
		f = frame.NewAPICSequence()
	} else {
		f = existingFrame.(frame.APICSequencer)
	}

	if err := f.AddPicture(pf); err != nil {
		return err
	}

	t.frames[id] = f
	return nil
}

func (t *Tag) SetTextFrame(id string, text string) {
	var f frame.TextFramer

	existingFrame := t.frames[id]
	if existingFrame == nil {
		f = new(frame.TextFrame)
	} else {
		f = existingFrame.(frame.TextFramer)
	}

	f.SetText(text)
	t.frames[id] = f
}

func (t *Tag) SetTitle(title string) {
	t.SetTextFrame(t.commonIDs["Title"], title)
}

func (t *Tag) SetArtist(artist string) {
	t.SetTextFrame(t.commonIDs["Artist"], artist)
}

func (t *Tag) SetAlbum(album string) {
	t.SetTextFrame(t.commonIDs["Album"], album)
}

func (t *Tag) SetYear(year string) {
	t.SetTextFrame(t.commonIDs["Year"], year)
}

func (t *Tag) SetGenre(genre string) {
	t.SetTextFrame(t.commonIDs["Genre"], genre)
}

func NewTag(file *os.File) *Tag {
	return &Tag{
		frames:    make(map[string]frame.Framer),
		commonIDs: frame.V24CommonIDs,

		File:         file,
		OriginalSize: 0,
	}
}

func ParseTag(file *os.File) (*Tag, error) {
	header, err := ParseHeader(file)
	if err != nil {
		err = errors.New("Trying to parse tag header: " + err.Error())
		return nil, err
	}
	if header == nil {
		return NewTag(file), nil
	}
	if header.Version < 3 {
		err = errors.New("Unsupported version of ID3 tag")
		return nil, err
	}

	tag := &Tag{
		frames:    make(map[string]frame.Framer),
		commonIDs: frame.V24CommonIDs,

		File:         file,
		OriginalSize: TagHeaderSize + header.FramesSize,
	}

	return tag, nil
}

func (t *Tag) Flush() error {
	// Creating a temp file for mp3 file, which will contain new tag
	newFile, err := ioutil.TempFile("", "")
	if err != nil {
		return err
	}
	newFileBuf := bufio.NewWriter(newFile)

	// Writing to new file new tag header
	if _, err := newFileBuf.Write(FormTagHeader()); err != nil {
		return err
	}

	// Writing to new file new frames
	// And getting size of them
	frames, err := t.FormFrames()
	if err != nil {
		return err
	}
	framesSize, err := newFileBuf.Write(frames)
	if err != nil {
		return err
	}

	// Getting a music part of mp3
	// (Discarding an original tag of mp3)
	f := t.File
	defer f.Close()
	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		return err
	}
	originalFileBuf := bufio.NewReader(f)
	if _, err := originalFileBuf.Discard(int(t.OriginalSize)); err != nil {
		return err
	}

	// Writing to new file the music part
	if _, err = newFileBuf.ReadFrom(originalFileBuf); err != nil {
		return err
	}

	// Flushing the buffered data to new file
	if err = newFileBuf.Flush(); err != nil {
		return err
	}

	// Setting size of frames to new file
	if err = setSize(newFile, uint32(framesSize)); err != nil {
		return err
	}

	// Replacing original file with new file
	if err = os.Rename(newFile.Name(), f.Name()); err != nil {
		return err
	}

	// And closing it
	if err = newFile.Close(); err != nil {
		return err
	}

	return nil
}

func setSize(f *os.File, size uint32) (err error) {
	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		return err
	}

	sizeBytes, err := util.FormSize(size)
	if err != nil {
		return
	}

	if _, err = f.WriteAt(sizeBytes, 6); err != nil {
		return
	}

	return
}

func (t Tag) FormFrames() ([]byte, error) {
	b := bytesBufPool.Get().(*bytes.Buffer)
	b.Reset()

	for id, f := range t.frames {
		formedFrame := f.Form()
		frameHeader, err := formFrameHeader(f, id, uint32(len(formedFrame)))
		if err != nil {
			return nil, err
		}
		b.Write(frameHeader)
		b.Write(formedFrame)
	}

	bytesBufPool.Put(b)
	return b.Bytes(), nil
}

func formFrameHeader(f frame.Framer, id string, frameSize uint32) ([]byte, error) {
	b := bytesBufPool.Get().(*bytes.Buffer)
	b.Reset()

	b.WriteString(id)
	if size, err := util.FormSize(frameSize); err != nil {
		return nil, err
	} else {
		b.Write(size)
	}
	b.WriteByte(0)
	b.WriteByte(0)

	bytesBufPool.Put(b)
	return b.Bytes(), nil
}
<commit_msg>Delete useless argument in formFrameHeader<commit_after>package id3v2

import (
	"bufio"
	"bytes"
	"errors"
	"github.com/bogem/id3v2/frame"
	"github.com/bogem/id3v2/util"
	"io/ioutil"
	"os"
)

type Tag struct {
	frames    map[string]frame.Framer
	commonIDs map[string]string

	File         *os.File
	OriginalSize uint32
}

func (t *Tag) SetAttachedPicture(pf frame.PictureFramer) error {
	var f frame.APICSequencer
	id := t.commonIDs["Attached Picture"]

	existingFrame := t.frames[id]
	if existingFrame == nil {
		f = frame.NewAPICSequence()
	} else {
		f = existingFrame.(frame.APICSequencer)
	}

	if err := f.AddPicture(pf); err != nil {
		return err
	}

	t.frames[id] = f
	return nil
}

func (t *Tag) SetTextFrame(id string, text string) {
	var f frame.TextFramer

	existingFrame := t.frames[id]
	if existingFrame == nil {
		f = new(frame.TextFrame)
	} else {
		f = existingFrame.(frame.TextFramer)
	}

	f.SetText(text)
	t.frames[id] = f
}

func (t *Tag) SetTitle(title string) {
	t.SetTextFrame(t.commonIDs["Title"], title)
}

func (t *Tag) SetArtist(artist string) {
	t.SetTextFrame(t.commonIDs["Artist"], artist)
}

func (t *Tag) SetAlbum(album string) {
	t.SetTextFrame(t.commonIDs["Album"], album)
}

func (t *Tag) SetYear(year string) {
	t.SetTextFrame(t.commonIDs["Year"], year)
}

func (t *Tag) SetGenre(genre string) {
	t.SetTextFrame(t.commonIDs["Genre"], genre)
}

func NewTag(file *os.File) *Tag {
	return &Tag{
		frames:    make(map[string]frame.Framer),
		commonIDs: frame.V24CommonIDs,

		File:         file,
		OriginalSize: 0,
	}
}

func ParseTag(file *os.File) (*Tag, error) {
	header, err := ParseHeader(file)
	if err != nil {
		err = errors.New("Trying to parse tag header: " + err.Error())
		return nil, err
	}
	if header == nil {
		return NewTag(file), nil
	}
	if header.Version < 3 {
		err = errors.New("Unsupported version of ID3 tag")
		return nil, err
	}

	tag := &Tag{
		frames:    make(map[string]frame.Framer),
		commonIDs: frame.V24CommonIDs,

		File:         file,
		OriginalSize: TagHeaderSize + header.FramesSize,
	}

	return tag, nil
}

func (t *Tag) Flush() error {
	// Creating a temp file for mp3 file, which will contain new tag
	newFile, err := ioutil.TempFile("", "")
	if err != nil {
		return err
	}
	newFileBuf := bufio.NewWriter(newFile)

	// Writing to new file new tag header
	if _, err := newFileBuf.Write(FormTagHeader()); err != nil {
		return err
	}

	// Writing to new file new frames
	// And getting size of them
	frames, err := t.FormFrames()
	if err != nil {
		return err
	}
	framesSize, err := newFileBuf.Write(frames)
	if err != nil {
		return err
	}

	// Getting a music part of mp3
	// (Discarding an original tag of mp3)
	f := t.File
	defer f.Close()
	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		return err
	}
	originalFileBuf := bufio.NewReader(f)
	if _, err := originalFileBuf.Discard(int(t.OriginalSize)); err != nil {
		return err
	}

	// Writing to new file the music part
	if _, err = newFileBuf.ReadFrom(originalFileBuf); err != nil {
		return err
	}

	// Flushing the buffered data to new file
	if err = newFileBuf.Flush(); err != nil {
		return err
	}

	// Setting size of frames to new file
	if err = setSize(newFile, uint32(framesSize)); err != nil {
		return err
	}

	// Replacing original file with new file
	if err = os.Rename(newFile.Name(), f.Name()); err != nil {
		return err
	}

	// And closing it
	if err = newFile.Close(); err != nil {
		return err
	}

	return nil
}

func setSize(f *os.File, size uint32) (err error) {
	if _, err := f.Seek(0, os.SEEK_SET); err != nil {
		return err
	}

	sizeBytes, err := util.FormSize(size)
	if err != nil {
		return
	}

	if _, err = f.WriteAt(sizeBytes, 6); err != nil {
		return
	}

	return
}

func (t Tag) FormFrames() ([]byte, error) {
	b := bytesBufPool.Get().(*bytes.Buffer)
	b.Reset()

	for id, f := range t.frames {
		formedFrame := f.Form()
		frameHeader, err := formFrameHeader(id, uint32(len(formedFrame)))
		if err != nil {
			return nil, err
		}
		b.Write(frameHeader)
		b.Write(formedFrame)
	}

	bytesBufPool.Put(b)
	return b.Bytes(), nil
}

func formFrameHeader(id string, frameSize uint32) ([]byte, error) {
	b := bytesBufPool.Get().(*bytes.Buffer)
	b.Reset()

	b.WriteString(id)
	if size, err := util.FormSize(frameSize); err != nil {
		return nil, err
	} else {
		b.Write(size)
	}
	b.WriteByte(0)
	b.WriteByte(0)

	bytesBufPool.Put(b)
	return b.Bytes(), nil
}
<|endoftext|>


<commit_before>package mtree

import (
	"archive/tar"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

// Streamer creates a file hierarchy out of a tar stream
type Streamer interface {
	io.ReadCloser
	Hierarchy() (*DirectoryHierarchy, error)
}

var tarDefaultSetKeywords = []string{"type=file", "flags=none", "mode=0664"}

// NewTarStreamer streams a tar archive and creates a file hierarchy based off
// of the tar metadata headers
func NewTarStreamer(r io.Reader, keywords []string) Streamer {
	pR, pW := io.Pipe()
	ts := &tarStream{
		pipeReader: pR,
		pipeWriter: pW,
		creator:    dhCreator{DH: &DirectoryHierarchy{}},
		teeReader:  io.TeeReader(r, pW),
		tarReader:  tar.NewReader(pR),
		keywords:   keywords,
	}
	go ts.readHeaders() // I don't like this
	return ts
}

type tarStream struct {
	creator    dhCreator
	pipeReader *io.PipeReader
	pipeWriter *io.PipeWriter
	teeReader  io.Reader
	tarReader  *tar.Reader
	keywords   []string
	err        error
}

func (ts *tarStream) readHeaders() {
	// We have to start with the directory we're in, and anything beyond these
	// items is determined at the time a tar is extracted.
	rootComment := Entry{
		Raw:  "# .",
		Type: CommentType,
	}
	root := Entry{
		Name: ".",
		Type: RelativeType,
		Prev: &rootComment,
		Set: &Entry{
			Name: "meta-set",
			Type: SpecialType,
		},
	}
	metadataEntries := signatureEntries("<user specified tar archive>")
	for _, e := range metadataEntries {
		e.Pos = len(ts.creator.DH.Entries)
		ts.creator.DH.Entries = append(ts.creator.DH.Entries, e)
	}
	for {
		hdr, err := ts.tarReader.Next()
		if err != nil {
			flatten(&root, ts)
			ts.pipeReader.CloseWithError(err)
			return
		}

		// Because the content of the file may need to be read by several
		// KeywordFuncs, it needs to be an io.Seeker as well. So, just reading from
		// ts.tarReader is not enough.
		tmpFile, err := ioutil.TempFile("", "ts.payload.")
		if err != nil {
			ts.pipeReader.CloseWithError(err)
			return
		}
		// for good measure
		if err := tmpFile.Chmod(0600); err != nil {
			tmpFile.Close()
			os.Remove(tmpFile.Name())
			ts.pipeReader.CloseWithError(err)
			return
		}
		if _, err := io.Copy(tmpFile, ts.tarReader); err != nil {
			tmpFile.Close()
			os.Remove(tmpFile.Name())
			ts.pipeReader.CloseWithError(err)
			return
		}
		// Alright, it's either file or directory
		encodedName, err := Vis(filepath.Base(hdr.Name))
		if err != nil {
			tmpFile.Close()
			os.Remove(tmpFile.Name())
			ts.pipeReader.CloseWithError(err)
			return
		}
		e := Entry{
			Name: encodedName,
			Type: RelativeType,
		}

		// now collect keywords on the file
		for _, keyword := range ts.keywords {
			if keyword == "time" {
				keyword = "tar_time"
			}
			if keyFunc, ok := KeywordFuncs[keyword]; ok {
				// We can't extract directories on to disk, so "size" keyword
				// is irrelevant for now
				if hdr.FileInfo().IsDir() && keyword == "size" {
					continue
				}

				if string(hdr.Typeflag) == string('1') {
					// TODO: get number of hardlinks for a file
				}
				val, err := keyFunc(hdr.Name, hdr.FileInfo(), tmpFile)
				if err != nil {
					ts.setErr(err)
				}
				// for good measure, check that we actually get a value for a keyword
				if val != "" {
					e.Keywords = append(e.Keywords, val)
				}

				// don't forget to reset the reader
				if _, err := tmpFile.Seek(0, 0); err != nil {
					tmpFile.Close()
					os.Remove(tmpFile.Name())
					ts.pipeReader.CloseWithError(err)
					return
				}
			}
		}
		// collect meta-set keywords for a directory so that we can build the
		// actual sets in `flatten`
		if hdr.FileInfo().IsDir() {
			s := Entry{
				Name: "meta-set",
				Type: SpecialType,
			}
			for _, setKW := range SetKeywords {
				if setKW == "time" {
					setKW = "tar_time"
				}
				if keyFunc, ok := KeywordFuncs[setKW]; ok {
					val, err := keyFunc(hdr.Name, hdr.FileInfo(), tmpFile)
					if err != nil {
						ts.setErr(err)
					}
					if val != "" {
						s.Keywords = append(s.Keywords, val)
					}
					if _, err := tmpFile.Seek(0, 0); err != nil {
						tmpFile.Close()
						os.Remove(tmpFile.Name())
						ts.pipeReader.CloseWithError(err)
					}
				}
			}
			if filepath.Dir(filepath.Clean(hdr.Name)) == "." {
				root.Set = &s
			} else {
				e.Set = &s
			}
		}
		populateTree(&root, &e, hdr, ts)
		tmpFile.Close()
		os.Remove(tmpFile.Name())
	}
}

type relationship int

const (
	unknownDir relationship = iota
	sameDir
	childDir
	parentDir
)

// populateTree creates a file tree hierarchy using an Entry's Parent and
// Children fields. When examining the Entry e to insert in the tree, we
// determine if the path to that Entry exists yet. If it does, insert it in the
// appropriate position in the tree. If not, create a path with "placeholder"
// directories, and then insert the Entry. populateTree does not consider
// symbolic links yet.
func populateTree(root, e *Entry, hdr *tar.Header, ts *tarStream) {
	isDir := hdr.FileInfo().IsDir()
	wd := filepath.Clean(hdr.Name)

	if !isDir {
		// If entry is a file, we only want the directory it's in.
		wd = filepath.Dir(wd)
	}
	if filepath.Dir(wd) == "." {
		if isDir {
			root.Keywords = e.Keywords
		} else {
			root.Children = append([]*Entry{e}, root.Children...)
			e.Parent = root
		}
		return
	}

	dirNames := strings.Split(wd, "/")
	parent := root
	for _, name := range dirNames[1:] {
		if node := parent.Descend(name); node == nil {
			// Entry for directory doesn't exist in tree relative to root
			var newEntry *Entry
			if isDir {
				newEntry = e
			} else {
				encodedName, err := Vis(name)
				if err != nil {
					ts.setErr(err)
					return
				}
				newEntry = &Entry{
					Name: encodedName,
					Type: RelativeType,
				}
			}
			newEntry.Parent = parent
			parent.Children = append(parent.Children, newEntry)
			parent = newEntry
		} else {
			// Entry for directory exists in tree, just keep going
			parent = node
		}
	}
	if !isDir {
		parent.Children = append([]*Entry{e}, parent.Children...)
		e.Parent = parent
	} else {
		commentpath, err := e.Path()
		if err != nil {
			ts.setErr(err)
			return
		}
		commentEntry := Entry{
			Raw:  "# " + commentpath,
			Type: CommentType,
		}
		e.Prev = &commentEntry
	}
}

// After constructing the tree from the tar stream, we want to "flatten" this
// tree by appending Entry's into ts.creator.DH.Entries in an appropriate
// manner to simplify writing the output with ts.creator.DH.WriteTo
// root: the "head" of the sub-tree to flatten
// ts  : tarStream to keep track of Entry's
func flatten(root *Entry, ts *tarStream) {
	if root.Prev != nil {
		// root.Prev != nil implies root is a directory
		ts.creator.DH.Entries = append(ts.creator.DH.Entries,
			Entry{
				Type: BlankType,
				Pos:  len(ts.creator.DH.Entries),
			})
		root.Prev.Pos = len(ts.creator.DH.Entries)
		ts.creator.DH.Entries = append(ts.creator.DH.Entries, *root.Prev)

		// Check if we need a new set
		if ts.creator.curSet == nil {
			ts.creator.curSet = &Entry{
				Type:     SpecialType,
				Name:     "/set",
				Keywords: keywordSelector(append(tarDefaultSetKeywords, root.Set.Keywords...), ts.keywords),
				Pos:      len(ts.creator.DH.Entries),
			}
			ts.creator.DH.Entries = append(ts.creator.DH.Entries, *ts.creator.curSet)
		} else {
			needNewSet := false
			for _, k := range root.Set.Keywords {
				if !inSlice(k, ts.creator.curSet.Keywords) {
					needNewSet = true
					break
				}
			}
			if needNewSet {
				ts.creator.curSet = &Entry{
					Name:     "/set",
					Type:     SpecialType,
					Pos:      len(ts.creator.DH.Entries),
					Keywords: keywordSelector(append(tarDefaultSetKeywords, root.Set.Keywords...), ts.keywords),
				}
				ts.creator.DH.Entries = append(ts.creator.DH.Entries, *ts.creator.curSet)
			}
		}
	}
	root.Set = ts.creator.curSet
	root.Keywords = setDifference(root.Keywords, ts.creator.curSet.Keywords)
	root.Pos = len(ts.creator.DH.Entries)
	ts.creator.DH.Entries = append(ts.creator.DH.Entries, *root)

	for _, c := range root.Children {
		flatten(c, ts)
	}

	if root.Prev != nil {
		// Show a comment when stepping out
		root.Prev.Pos = len(ts.creator.DH.Entries)
		ts.creator.DH.Entries = append(ts.creator.DH.Entries, *root.Prev)
		dotEntry := Entry{
			Type: DotDotType,
			Name: "..",
			Pos:  len(ts.creator.DH.Entries),
		}
		ts.creator.DH.Entries = append(ts.creator.DH.Entries, dotEntry)
	}
}

// filter takes in a pointer to an Entry, and returns a slice of Entry's that
// satisfy the predicate p
func filter(root *Entry, p func(*Entry) bool) []Entry {
	var validEntrys []Entry
	if len(root.Children) > 0 || root.Prev != nil {
		for _, c := range root.Children {
			// if an Entry is a directory, filter the directory
			if c.Prev != nil {
				validEntrys = append(validEntrys, filter(c, p)...)
			}
			if p(c) {
				if c.Prev == nil {
					// prepend directories
					validEntrys = append([]Entry{*c}, validEntrys...)
				} else {
					validEntrys = append(validEntrys, *c)
				}
			}
		}
		return validEntrys
	}
	return nil
}

func setDifference(this, that []string) []string {
	if len(this) == 0 {
		return that
	}
	diff := []string{}
	for _, kv := range this {
		if !inSlice(kv, that) {
			diff = append(diff, kv)
		}
	}
	return diff
}

func compareDir(curDir, prevDir string) relationship {
	curDir = filepath.Clean(curDir)
	prevDir = filepath.Clean(prevDir)
	if curDir == prevDir {
		return sameDir
	}
	if filepath.Dir(curDir) == prevDir {
		return childDir
	}
	if curDir == filepath.Dir(prevDir) {
		return parentDir
	}
	return unknownDir
}

func (ts *tarStream) setErr(err error) {
	ts.err = err
}

func (ts *tarStream) Read(p []byte) (n int, err error) {
	return ts.teeReader.Read(p)
}

func (ts *tarStream) Close() error {
	return ts.pipeReader.Close()
}

func (ts *tarStream) Hierarchy() (*DirectoryHierarchy, error) {
	if ts.err != nil && ts.err != io.EOF {
		return nil, ts.err
	}
	return ts.creator.DH, nil
}
<commit_msg>tar: minor refactoring of populateTree and flatten<commit_after>package mtree

import (
	"archive/tar"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

// Streamer creates a file hierarchy out of a tar stream
type Streamer interface {
	io.ReadCloser
	Hierarchy() (*DirectoryHierarchy, error)
}

var tarDefaultSetKeywords = []string{"type=file", "flags=none", "mode=0664"}

// NewTarStreamer streams a tar archive and creates a file hierarchy based off
// of the tar metadata headers
func NewTarStreamer(r io.Reader, keywords []string) Streamer {
	pR, pW := io.Pipe()
	ts := &tarStream{
		pipeReader: pR,
		pipeWriter: pW,
		creator:    dhCreator{DH: &DirectoryHierarchy{}},
		teeReader:  io.TeeReader(r, pW),
		tarReader:  tar.NewReader(pR),
		keywords:   keywords,
	}
	go ts.readHeaders() // I don't like this
	return ts
}

type tarStream struct {
	creator    dhCreator
	pipeReader *io.PipeReader
	pipeWriter *io.PipeWriter
	teeReader  io.Reader
	tarReader  *tar.Reader
	keywords   []string
	err        error
}

func (ts *tarStream) readHeaders() {
	// We have to start with the directory we're in, and anything beyond these
	// items is determined at the time a tar is extracted.
	rootComment := Entry{
		Raw:  "# .",
		Type: CommentType,
	}
	root := Entry{
		Name: ".",
		Type: RelativeType,
		Prev: &rootComment,
		Set: &Entry{
			Name: "meta-set",
			Type: SpecialType,
		},
	}
	metadataEntries := signatureEntries("<user specified tar archive>")
	for _, e := range metadataEntries {
		e.Pos = len(ts.creator.DH.Entries)
		ts.creator.DH.Entries = append(ts.creator.DH.Entries, e)
	}
	for {
		hdr, err := ts.tarReader.Next()
		if err != nil {
			flatten(&root, &ts.creator, ts.keywords)
			ts.pipeReader.CloseWithError(err)
			return
		}
		// Because the content of the file may need to be read by several
		// KeywordFuncs, it needs to be an io.Seeker as well. So, just reading from
		// ts.tarReader is not enough.
		tmpFile, err := ioutil.TempFile("", "ts.payload.")
		if err != nil {
			ts.pipeReader.CloseWithError(err)
			return
		}
		// for good measure
		if err := tmpFile.Chmod(0600); err != nil {
			tmpFile.Close()
			os.Remove(tmpFile.Name())
			ts.pipeReader.CloseWithError(err)
			return
		}
		if _, err := io.Copy(tmpFile, ts.tarReader); err != nil {
			tmpFile.Close()
			os.Remove(tmpFile.Name())
			ts.pipeReader.CloseWithError(err)
			return
		}
		// Alright, it's either file or directory
		encodedName, err := Vis(filepath.Base(hdr.Name))
		if err != nil {
			tmpFile.Close()
			os.Remove(tmpFile.Name())
			ts.pipeReader.CloseWithError(err)
			return
		}
		e := Entry{
			Name: encodedName,
			Type: RelativeType,
		}

		// now collect keywords on the file
		for _, keyword := range ts.keywords {
			if keyword == "time" {
				keyword = "tar_time"
			}
			if keyFunc, ok := KeywordFuncs[keyword]; ok {
				// We can't extract directories on to disk, so "size" keyword
				// is irrelevant for now
				if hdr.FileInfo().IsDir() && keyword == "size" {
					continue
				}
				// TODO: handle hardlinks
				val, err := keyFunc(hdr.Name, hdr.FileInfo(), tmpFile)
				if err != nil {
					ts.setErr(err)
				}
				// for good measure, check that we actually get a value for a keyword
				if val != "" {
					e.Keywords = append(e.Keywords, val)
				}

				// don't forget to reset the reader
				if _, err := tmpFile.Seek(0, 0); err != nil {
					tmpFile.Close()
					os.Remove(tmpFile.Name())
					ts.pipeReader.CloseWithError(err)
					return
				}
			}
		}
		// collect meta-set keywords for a directory so that we can build the
		// actual sets in `flatten`
		if hdr.FileInfo().IsDir() {
			s := Entry{
				Name: "meta-set",
				Type: SpecialType,
			}
			for _, setKW := range SetKeywords {
				if setKW == "time" {
					setKW = "tar_time"
				}
				if keyFunc, ok := KeywordFuncs[setKW]; ok {
					val, err := keyFunc(hdr.Name, hdr.FileInfo(), tmpFile)
					if err != nil {
						ts.setErr(err)
					}
					if val != "" {
						s.Keywords = append(s.Keywords, val)
					}
					if _, err := tmpFile.Seek(0, 0); err != nil {
						tmpFile.Close()
						os.Remove(tmpFile.Name())
						ts.pipeReader.CloseWithError(err)
					}
				}
			}
			if filepath.Dir(filepath.Clean(hdr.Name)) == "." {
				root.Set = &s
			} else {
				e.Set = &s
			}
		}
		err = populateTree(&root, &e, hdr)
		if err != nil {
			ts.setErr(err)
		}
		tmpFile.Close()
		os.Remove(tmpFile.Name())
	}
}

type relationship int

const (
	unknownDir relationship = iota
	sameDir
	childDir
	parentDir
)

// populateTree creates a pseudo file tree hierarchy using an Entry's Parent and
// Children fields. When examining the Entry e to insert in the tree, we
// determine if the path to that Entry exists yet. If it does, insert it in the
// appropriate position in the tree. If not, create a path up until the Entry's
// directory that it is contained in. Then, insert the Entry.
// root: the "." Entry
//    e: the Entry we are looking to insert
//  hdr: the tar header struct associated with e
func populateTree(root, e *Entry, hdr *tar.Header) error {
	isDir := hdr.FileInfo().IsDir()
	wd := filepath.Clean(hdr.Name)
	if !isDir {
		// If entry is a file, we only want the directory it's in.
		wd = filepath.Dir(wd)
	}
	if filepath.Dir(wd) == "." {
		if isDir {
			root.Keywords = e.Keywords
		} else {
			root.Children = append([]*Entry{e}, root.Children...)
			e.Parent = root
		}
		return nil
	}
	dirNames := strings.Split(wd, "/")
	parent := root
	for _, name := range dirNames[1:] {
		encoded, err := Vis(name)
		if err != nil {
			return err
		}
		if node := parent.Descend(encoded); node == nil {
			// Entry for directory doesn't exist in tree relative to root
			newEntry := Entry{
				Name:   encoded,
				Type:   RelativeType,
				Parent: parent,
			}
			parent.Children = append(parent.Children, &newEntry)
			parent = &newEntry
		} else {
			// Entry for directory exists in tree, just keep going
			parent = node
		}
	}
	if !isDir {
		parent.Children = append([]*Entry{e}, parent.Children...)
		e.Parent = parent
	} else {
		// the "placeholder" directory already exists in the Entry "parent",
		// so now we have to replace it's underlying data with that from e,
		// as well as set the Parent field. Note that we don't set parent = e
		// because parent is already in the pseudo tree, we just need to
		// complete it's data.
		e.Parent = parent.Parent
		*parent = *e
		commentpath, err := parent.Path()
		if err != nil {
			return err
		}
		parent.Prev = &Entry{
			Raw:  "# " + commentpath,
			Type: CommentType,
		}
	}
	return nil
}

// After constructing a pseudo file hierarchy tree, we want to "flatten" this
// tree by putting the Entries into a slice with appropriate positioning.
// root: the "head" of the sub-tree to flatten
// creator: a dhCreator that helps with the '/set' keyword
// keywords: keywords specified by the user that should be evaluated
func flatten(root *Entry, creator *dhCreator, keywords []string) {
	if root.Prev != nil {
		// root.Prev != nil implies root is a directory
		creator.DH.Entries = append(creator.DH.Entries,
			Entry{
				Type: BlankType,
				Pos:  len(creator.DH.Entries),
			})
		root.Prev.Pos = len(creator.DH.Entries)
		creator.DH.Entries = append(creator.DH.Entries, *root.Prev)

		// Check if we need a new set
		if creator.curSet == nil {
			creator.curSet = &Entry{
				Type:     SpecialType,
				Name:     "/set",
				Keywords: keywordSelector(append(tarDefaultSetKeywords, root.Set.Keywords...), keywords),
				Pos:      len(creator.DH.Entries),
			}
			creator.DH.Entries = append(creator.DH.Entries, *creator.curSet)
		} else {
			needNewSet := false
			for _, k := range root.Set.Keywords {
				if !inSlice(k, creator.curSet.Keywords) {
					needNewSet = true
					break
				}
			}
			if needNewSet {
				creator.curSet = &Entry{
					Name:     "/set",
					Type:     SpecialType,
					Pos:      len(creator.DH.Entries),
					Keywords: keywordSelector(append(tarDefaultSetKeywords, root.Set.Keywords...), keywords),
				}
				creator.DH.Entries = append(creator.DH.Entries, *creator.curSet)
			}
		}
	}
	root.Set = creator.curSet
	root.Keywords = setDifference(root.Keywords, creator.curSet.Keywords)
	root.Pos = len(creator.DH.Entries)
	creator.DH.Entries = append(creator.DH.Entries, *root)

	for _, c := range root.Children {
		flatten(c, creator, keywords)
	}

	if root.Prev != nil {
		// Show a comment when stepping out
		root.Prev.Pos = len(creator.DH.Entries)
		creator.DH.Entries = append(creator.DH.Entries, *root.Prev)
		dotEntry := Entry{
			Type: DotDotType,
			Name: "..",
			Pos:  len(creator.DH.Entries),
		}
		creator.DH.Entries = append(creator.DH.Entries, dotEntry)
	}
}

// filter takes in a pointer to an Entry, and returns a slice of Entry's that
// satisfy the predicate p
func filter(root *Entry, p func(*Entry) bool) []Entry {
	var validEntrys []Entry
	if len(root.Children) > 0 || root.Prev != nil {
		for _, c := range root.Children {
			// if an Entry is a directory, filter the directory
			if c.Prev != nil {
				validEntrys = append(validEntrys, filter(c, p)...)
			}
			if p(c) {
				if c.Prev == nil {
					// prepend files
					validEntrys = append([]Entry{*c}, validEntrys...)
				} else {
					validEntrys = append(validEntrys, *c)
				}
			}
		}
		return validEntrys
	}
	return nil
}

func setDifference(this, that []string) []string {
	if len(this) == 0 {
		return that
	}
	diff := []string{}
	for _, kv := range this {
		if !inSlice(kv, that) {
			diff = append(diff, kv)
		}
	}
	return diff
}

func compareDir(curDir, prevDir string) relationship {
	curDir = filepath.Clean(curDir)
	prevDir = filepath.Clean(prevDir)
	if curDir == prevDir {
		return sameDir
	}
	if filepath.Dir(curDir) == prevDir {
		return childDir
	}
	if curDir == filepath.Dir(prevDir) {
		return parentDir
	}
	return unknownDir
}

func (ts *tarStream) setErr(err error) {
	ts.err = err
}

func (ts *tarStream) Read(p []byte) (n int, err error) {
	return ts.teeReader.Read(p)
}

func (ts *tarStream) Close() error {
	return ts.pipeReader.Close()
}

func (ts *tarStream) Hierarchy() (*DirectoryHierarchy, error) {
	if ts.err != nil && ts.err != io.EOF {
		return nil, ts.err
	}
	return ts.creator.DH, nil
}
<|endoftext|>


<commit_before>package tdb

import (
	"fmt"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/getlantern/golog"
	"github.com/oxtoacart/tdb/expr"
	"github.com/oxtoacart/vtime"
	"github.com/tecbot/gorocksdb"
)

var (
	log = golog.LoggerFor("tdb")
)

type TableStats struct {
	InsertedPoints  int64
	DroppedPoints   int64
	HotKeys         int64
	ArchivedBuckets int64
}

type DerivedField struct {
	Name string
	Expr expr.Expr
}

type table struct {
	name            string
	batchSize       int64
	clock           *vtime.Clock
	archiveByKey    *gorocksdb.DB
	resolution      time.Duration
	hotPeriod       time.Duration
	retentionPeriod time.Duration
	derivedFields   []DerivedField
	partitions      []*partition
	toArchive       chan *archiveRequest
	stats           TableStats
	statsMutex      sync.RWMutex
}

type DBOpts struct {
	Dir       string
	BatchSize int64
}

type DB struct {
	opts        *DBOpts
	tables      map[string]*table
	tablesMutex sync.RWMutex
}

func NewDB(opts *DBOpts) *DB {
	return &DB{opts: opts, tables: make(map[string]*table)}
}

func (db *DB) CreateTable(name string, resolution time.Duration, hotPeriod time.Duration, retentionPeriod time.Duration, derivedFields ...DerivedField) error {
	name = strings.ToLower(name)
	t := &table{
		name:            name,
		batchSize:       db.opts.BatchSize,
		clock:           vtime.NewClock(time.Time{}),
		resolution:      resolution,
		hotPeriod:       hotPeriod,
		retentionPeriod: retentionPeriod,
		derivedFields:   derivedFields,
		toArchive:       make(chan *archiveRequest, db.opts.BatchSize*100),
	}
	numCPU := runtime.NumCPU()
	t.partitions = make([]*partition, 0, numCPU)
	for i := 0; i < numCPU; i++ {
		p := &partition{
			t:       t,
			inserts: make(chan *insert, 100000/numCPU),
			tail:    make(map[string]*bucket),
		}
		t.partitions = append(t.partitions, p)
	}

	db.tablesMutex.Lock()
	defer db.tablesMutex.Unlock()

	if db.tables[name] != nil {
		return fmt.Errorf("Table %v already exists", name)
	}

	var err error
	t.archiveByKey, err = t.createDatabase(db.opts.Dir, "bykey")
	if err != nil {
		return fmt.Errorf("Unable to create rocksdb database: %v", err)
	}
	db.tables[name] = t

	for i := 0; i < numCPU; i++ {
		go t.partitions[i].processInserts()
	}

	go t.archive()
	go t.retain()

	return nil
}

func (t *table) createDatabase(dir string, suffix string) (*gorocksdb.DB, error) {
	opts := gorocksdb.NewDefaultOptions()
	bbtopts := gorocksdb.NewDefaultBlockBasedTableOptions()
	bbtopts.SetBlockCache(gorocksdb.NewLRUCache(256 * 1024 * 1024))
	filter := gorocksdb.NewBloomFilter(10)
	bbtopts.SetFilterPolicy(filter)
	opts.SetBlockBasedTableFactory(bbtopts)
	opts.SetCreateIfMissing(true)
	opts.SetMergeOperator(t)
	return gorocksdb.OpenDb(opts, filepath.Join(dir, t.name+"_"+suffix))
}

func (db *DB) TableStats(table string) TableStats {
	t := db.getTable(table)
	if t == nil {
		return TableStats{}
	}
	t.statsMutex.RLock()
	defer t.statsMutex.RUnlock()
	return t.stats
}

func (db *DB) Now(table string) time.Time {
	t := db.getTable(table)
	if t == nil {
		return time.Time{}
	}
	return t.clock.Now()
}

func (db *DB) getTable(table string) *table {
	db.tablesMutex.RLock()
	t := db.tables[strings.ToLower(table)]
	db.tablesMutex.RUnlock()
	return t
}

func roundTime(ts time.Time, resolution time.Duration) time.Time {
	rounded := ts.Round(resolution)
	if rounded.After(ts) {
		rounded = rounded.Add(-1 * resolution)
	}
	return rounded
}
<commit_msg>Creating database folders when necessary<commit_after>package tdb

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/getlantern/golog"
	"github.com/oxtoacart/tdb/expr"
	"github.com/oxtoacart/vtime"
	"github.com/tecbot/gorocksdb"
)

var (
	log = golog.LoggerFor("tdb")
)

type TableStats struct {
	InsertedPoints  int64
	DroppedPoints   int64
	HotKeys         int64
	ArchivedBuckets int64
}

type DerivedField struct {
	Name string
	Expr expr.Expr
}

type table struct {
	name            string
	batchSize       int64
	clock           *vtime.Clock
	archiveByKey    *gorocksdb.DB
	resolution      time.Duration
	hotPeriod       time.Duration
	retentionPeriod time.Duration
	derivedFields   []DerivedField
	partitions      []*partition
	toArchive       chan *archiveRequest
	stats           TableStats
	statsMutex      sync.RWMutex
}

type DBOpts struct {
	Dir       string
	BatchSize int64
}

type DB struct {
	opts        *DBOpts
	tables      map[string]*table
	tablesMutex sync.RWMutex
}

func NewDB(opts *DBOpts) *DB {
	return &DB{opts: opts, tables: make(map[string]*table)}
}

func (db *DB) CreateTable(name string, resolution time.Duration, hotPeriod time.Duration, retentionPeriod time.Duration, derivedFields ...DerivedField) error {
	name = strings.ToLower(name)
	t := &table{
		name:            name,
		batchSize:       db.opts.BatchSize,
		clock:           vtime.NewClock(time.Time{}),
		resolution:      resolution,
		hotPeriod:       hotPeriod,
		retentionPeriod: retentionPeriod,
		derivedFields:   derivedFields,
		toArchive:       make(chan *archiveRequest, db.opts.BatchSize*100),
	}
	numCPU := runtime.NumCPU()
	t.partitions = make([]*partition, 0, numCPU)
	for i := 0; i < numCPU; i++ {
		p := &partition{
			t:       t,
			inserts: make(chan *insert, 100000/numCPU),
			tail:    make(map[string]*bucket),
		}
		t.partitions = append(t.partitions, p)
	}

	db.tablesMutex.Lock()
	defer db.tablesMutex.Unlock()

	if db.tables[name] != nil {
		return fmt.Errorf("Table %v already exists", name)
	}

	err := os.MkdirAll(db.opts.Dir, 0755)
	if err != nil && !os.IsExist(err) {
		return fmt.Errorf("Unable to create folder for rocksdb database: %v", err)
	}
	t.archiveByKey, err = t.createDatabase(db.opts.Dir, "bykey")
	if err != nil {
		return fmt.Errorf("Unable to create rocksdb database: %v", err)
	}
	db.tables[name] = t

	for i := 0; i < numCPU; i++ {
		go t.partitions[i].processInserts()
	}

	go t.archive()
	go t.retain()

	return nil
}

func (t *table) createDatabase(dir string, suffix string) (*gorocksdb.DB, error) {
	opts := gorocksdb.NewDefaultOptions()
	bbtopts := gorocksdb.NewDefaultBlockBasedTableOptions()
	bbtopts.SetBlockCache(gorocksdb.NewLRUCache(256 * 1024 * 1024))
	filter := gorocksdb.NewBloomFilter(10)
	bbtopts.SetFilterPolicy(filter)
	opts.SetBlockBasedTableFactory(bbtopts)
	opts.SetCreateIfMissing(true)
	opts.SetMergeOperator(t)
	return gorocksdb.OpenDb(opts, filepath.Join(dir, t.name+"_"+suffix))
}

func (db *DB) TableStats(table string) TableStats {
	t := db.getTable(table)
	if t == nil {
		return TableStats{}
	}
	t.statsMutex.RLock()
	defer t.statsMutex.RUnlock()
	return t.stats
}

func (db *DB) Now(table string) time.Time {
	t := db.getTable(table)
	if t == nil {
		return time.Time{}
	}
	return t.clock.Now()
}

func (db *DB) getTable(table string) *table {
	db.tablesMutex.RLock()
	t := db.tables[strings.ToLower(table)]
	db.tablesMutex.RUnlock()
	return t
}

func roundTime(ts time.Time, resolution time.Duration) time.Time {
	rounded := ts.Round(resolution)
	if rounded.After(ts) {
		rounded = rounded.Add(-1 * resolution)
	}
	return rounded
}
<|endoftext|>


<commit_before>package drum

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"strings"
)

// config
// numSteps is the number of 'steps' played by an instrument each song.
const numSteps = 16

// Instrument is a high level representation of a single instrument in the
// pattern.
type Instrument struct {
	id    uint8
	name  string
	steps [numSteps]bool
}

// Pattern is a high level representation of a track pattern contained within a
// .splice file.
type Pattern struct {
	version     string
	tempo       float32
	instruments []Instrument
}

// String implements the stringer.
func (p *Pattern) String() string {

	// create string of track information according to spec
	//	Saved with HW Version: 0.708-alpha
	//	Tempo: 999
	//	(1) Kick	|x---|----|x---|----|
	//	(2) HiHat	|x-x-|x-x-|x-x-|x-x-|

	var buffer bytes.Buffer

	cleanedVersionString := strings.Trim(p.version, "\x00")
	buffer.WriteString(fmt.Sprintf("Saved with HW Version: %s\n", cleanedVersionString))
	buffer.WriteString(fmt.Sprintf("Tempo: %v\n", p.tempo))

	for _, in := range p.instruments {
		buffer.WriteString(fmt.Sprintf("(%v) %s\t", in.id, in.name))

		for i, step := range in.steps {
			if i%4 == 0 {
				buffer.WriteString("|")
			}

			switch {
			case step:
				buffer.WriteString("x")
			default:
				buffer.WriteString("-")
			}
		}

		buffer.WriteString("|\n")
	}

	return buffer.String()
}

// expectedHeader is a string that is expected to be present
// on `.splice` files to be decoded.
const expectedHeader = "SPLICE"

// DecodeFile decodes the drum machine file found at the provided path and returns
// a pointer to a parsed pattern which is the entry point to the rest of the data.
func DecodeFile(path string) (*Pattern, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	p, err := parseSpliceToPattern(file)
	if err != nil {
		fmt.Println("Error in parseSpliceToPattern: ", err)
		return nil, err
	}

	return p, nil
}

// parseSpliceToPattern decodes the given `.splice` files and stores
// the relevant information in the Pattern struct.
func parseSpliceToPattern(r io.Reader) (*Pattern, error) {
	var p Pattern

	var spliceHeader [len(expectedHeader)]byte
	if err := binary.Read(r, binary.BigEndian, &spliceHeader); err != nil {
		return nil, fmt.Errorf("unable to decode splice header: %v", err)
	}

	if expectedHeader != string(spliceHeader[:len(expectedHeader)]) {
		return nil, fmt.Errorf("decoded SPLICE header does not match expectedHeader")
	}

	var trackSize int64
	if err := binary.Read(r, binary.BigEndian, &trackSize); err != nil {
		return nil, fmt.Errorf("unable to decode trackSize: %v", err)
	}

	var version [32]byte
	if err := binary.Read(r, binary.BigEndian, &version); err != nil {
		return nil, fmt.Errorf("unable to decode version: %v", err)
	}
	p.version = string(version[:])

	if err := binary.Read(r, binary.LittleEndian, &p.tempo); err != nil {
		return nil, fmt.Errorf("unable to decode tempo: %v", err)
	}

	// NOTE: LimitReader needs to take `-36` = version(32) + tempo(4) into
	// account since we've already read in version and tempo
	const offset = 36
	lr := io.LimitReader(r, trackSize-offset)

	for {
		in, err := readInstrumentsFromTrack(lr)
		if err != nil {
			if err != io.EOF {
				return nil, err
			}
			break
		}

		p.instruments = append(p.instruments, in)
	}

	return &p, nil
}

// readInstrumentsFromTrack decodes the instrument information contained within
// the body of the Pattern and appends the newInst to the Pattern.instruments a
// true (bool) is returned when all the instruments have been read.
func readInstrumentsFromTrack(lr io.Reader) (Instrument, error) {
	var in Instrument

	if err := binary.Read(lr, binary.BigEndian, &in.id); err != nil {
		if err == io.EOF {
			return Instrument{}, err
		}
		return Instrument{}, fmt.Errorf("unable to decode instID: %v", err)
	}

	var nameLen int32
	if err := binary.Read(lr, binary.BigEndian, &nameLen); err != nil {
		return Instrument{}, fmt.Errorf("unable to decode instrument nameLen: %v", err)
	}

	name := make([]byte, nameLen)
	if err := binary.Read(lr, binary.LittleEndian, &name); err != nil {
		return Instrument{}, fmt.Errorf("unable to decode instrument nameBuf: %v", err)
	}
	in.name = string(name)

	var steps [numSteps]byte
	if err := binary.Read(lr, binary.LittleEndian, &steps); err != nil {
		return Instrument{}, fmt.Errorf("unable to decode instrument steps: %v", err)
	}

	for i := range steps {
		switch steps[i] {
		case 0x01:
			in.steps[i] = true
		case 0x00:
			in.steps[i] = false
		default:
			return Instrument{}, fmt.Errorf("unexpected values in instrument steps")
		}
	}

	return in, nil
}
<commit_msg>update variables and comments<commit_after>package drum

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"os"
	"strings"
)

// config
// numSteps is the number of 'steps' played by an instrument each song.
const numSteps = 16

// Instrument is a high level representation of a single instrument in the
// pattern.
type Instrument struct {
	id    uint8
	name  string
	steps [numSteps]bool
}

// Pattern is a high level representation of a track pattern contained within a
// .splice file.
type Pattern struct {
	version     string
	tempo       float32
	instruments []Instrument
}

// String implements the stringer.
func (p *Pattern) String() string {

	// create string of track information according to spec
	//	Saved with HW Version: 0.708-alpha
	//	Tempo: 999
	//	(1) Kick	|x---|----|x---|----|
	//	(2) HiHat	|x-x-|x-x-|x-x-|x-x-|

	var buf bytes.Buffer

	versTrim := strings.Trim(p.version, "\x00")
	buf.WriteString(fmt.Sprintf("Saved with HW Version: %s\n", versTrim))
	buf.WriteString(fmt.Sprintf("Tempo: %v\n", p.tempo))

	for _, in := range p.instruments {
		buf.WriteString(fmt.Sprintf("(%v) %s\t", in.id, in.name))

		for i, step := range in.steps {
			if i%4 == 0 {
				buf.WriteString("|")
			}

			switch {
			case step:
				buf.WriteString("x")
			default:
				buf.WriteString("-")
			}
		}

		buf.WriteString("|\n")
	}

	return buf.String()
}

// expectedHeader is a string that is expected to be present
// on `.splice` files to be decoded.
const expectedHeader = "SPLICE"

// DecodeFile decodes the drum machine file found at the provided path and returns
// a pointer to a parsed pattern which is the entry point to the rest of the data.
func DecodeFile(path string) (*Pattern, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	p, err := parseSpliceToPattern(file)
	if err != nil {
		fmt.Println("Error in parseSpliceToPattern: ", err)
		return nil, err
	}

	return p, nil
}

// parseSpliceToPattern decodes the given `.splice` files and stores the relevant
// information in the Pattern struct.
func parseSpliceToPattern(r io.Reader) (*Pattern, error) {
	var p Pattern

	var fHeader [len(expectedHeader)]byte
	if err := binary.Read(r, binary.BigEndian, &fHeader); err != nil {
		return nil, fmt.Errorf("unable to decode splice header: %v", err)
	}

	if expectedHeader != string(fHeader[:len(expectedHeader)]) {
		return nil, fmt.Errorf("decoded file header does not match expectedHeader")
	}

	var patSize int64
	if err := binary.Read(r, binary.BigEndian, &patSize); err != nil {
		return nil, fmt.Errorf("unable to decode patSize: %v", err)
	}

	var version [32]byte
	if err := binary.Read(r, binary.BigEndian, &version); err != nil {
		return nil, fmt.Errorf("unable to decode version: %v", err)
	}
	p.version = string(version[:])

	if err := binary.Read(r, binary.LittleEndian, &p.tempo); err != nil {
		return nil, fmt.Errorf("unable to decode tempo: %v", err)
	}

	// NOTE: LimitReader needs to be offset by `-36` = (version(32) + tempo(4))
	// since we've already read in version and tempo
	const offset = 36
	lr := io.LimitReader(r, patSize-offset)

	for {
		in, err := readInstrumentsFromTrack(lr)
		if err != nil {
			if err != io.EOF {
				return nil, err
			}
			break
		}

		p.instruments = append(p.instruments, in)
	}

	return &p, nil
}

// readInstrumentsFromTrack decodes and returns the instrument information
// contained within the body of the Pattern.
func readInstrumentsFromTrack(lr io.Reader) (Instrument, error) {
	var inst Instrument

	if err := binary.Read(lr, binary.BigEndian, &inst.id); err != nil {
		if err == io.EOF {
			return Instrument{}, err
		}
		return Instrument{}, fmt.Errorf("unable to decode id: %v", err)
	}

	var nameLen int32
	if err := binary.Read(lr, binary.BigEndian, &nameLen); err != nil {
		return Instrument{}, fmt.Errorf("unable to decode instrument nameLen: %v", err)
	}

	name := make([]byte, nameLen)
	if err := binary.Read(lr, binary.LittleEndian, &name); err != nil {
		return Instrument{}, fmt.Errorf("unable to decode instrument name: %v", err)
	}
	inst.name = string(name)

	var steps [numSteps]byte
	if err := binary.Read(lr, binary.LittleEndian, &steps); err != nil {
		return Instrument{}, fmt.Errorf("unable to decode instrument steps: %v", err)
	}

	for i := range steps {
		switch steps[i] {
		case 0x01:
			inst.steps[i] = true
		case 0x00:
			inst.steps[i] = false
		default:
			return Instrument{}, fmt.Errorf("unexpected values in encoded instrument steps")
		}
	}

	return inst, nil
}
<|endoftext|>


<commit_before>package Spiders

import (
	. "fmt"
	. "github.com/PuerkitoBio/goquery"
	"log"
	//	. "strconv"
	"os/exec"
	//	. "strings"
)

type TagStructures []string
type Job struct {
	Title string
	Link  string
	Date  []string
}

var cmd *exec.Cmd = exec.Command("open", "-a", "Safari")

func getSearchPages(keyWords, location []string, baseUrls string, a chan *Document) {
	for _, l := range location {
		for _, w := range keyWords {
			//Println(w, l)
			doc, err := NewDocument(Sprintf(baseUrls, w, l))
			if err != nil {
				log.Fatal(err)
			}
			//Println("\n ************* \n", Sprintf(baseUrls, w, l), "\n ***************")
			a <- doc
		}
	}
	close(a)
}

func getAllNodes(s *Document, tagStrc TagStructures) *Selection {
	temp := s.Find(tagStrc[0])
	for _, v := range tagStrc[1:] {
		temp = temp.Find(v)
	}
	return temp
}

func OpenJobPage(job Job) {
	err := exec.Command("open", job.Link).Start()
	if err != nil {
		log.Fatal(err)
	}
}

func FilterJobTitle(job Job) Bool {
	return false
}
<commit_msg>still thinking because go does no have Set data structure<commit_after>package Spiders

import (
	. "fmt"
	. "github.com/PuerkitoBio/goquery"
	"log"
	//	. "strconv"
	"os/exec"
	//. "strings"
)

type TagStructures []string
type Job struct {
	Title string
	Link  string
	Date  []string
}

var cmd *exec.Cmd = exec.Command("open", "-a", "Safari")

func getSearchPages(keyWords, location []string, baseUrls string, a chan *Document) {
	for _, l := range location {
		for _, w := range keyWords {
			//Println(w, l)
			doc, err := NewDocument(Sprintf(baseUrls, w, l))
			if err != nil {
				log.Fatal(err)
			}
			//Println("\n ************* \n", Sprintf(baseUrls, w, l), "\n ***************")
			a <- doc
		}
	}
	close(a)
}

func getAllNodes(s *Document, tagStrc TagStructures) *Selection {
	temp := s.Find(tagStrc[0])
	for _, v := range tagStrc[1:] {
		temp = temp.Find(v)
	}
	return temp
}

func OpenJobPage(job Job) {
	err := exec.Command("open", job.Link).Start()
	if err != nil {
		log.Fatal(err)
	}
}

/*
func FilterJobTitle(job Job, exceptWords *[]string) bool {
	titleWords := Split(job.Title, " ")
	return false
}
*/
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net/url"
	"os"
	"regexp"
	"runtime"
	"strings"
)

// Convert SCP-like URL to SSH URL(e.g. [user@]host.xz:path/to/repo.git/)
// ref. http://git-scm.com/docs/git-fetch#_git_urls
// (golang hasn't supported Perl-like negative look-behind match)
var hasSchemePattern = regexp.MustCompile("^[^:]+://")
var scpLikeUrlPattern = regexp.MustCompile("^([^@]+@)?([^:]+):/?(.+)$")

func NewURL(ref string) (*url.URL, error) {
	if !hasSchemePattern.MatchString(ref) && scpLikeUrlPattern.MatchString(ref) {
		matched := scpLikeUrlPattern.FindStringSubmatch(ref)
		user := matched[1]
		host := matched[2]
		path := matched[3]

		ref = fmt.Sprintf("ssh://%s%s/%s", user, host, path)
	}

	url, err := url.Parse(ref)
	if err != nil {
		return url, err
	}

	if !url.IsAbs() {
		if !strings.Contains(url.Path, "/") {
			url.Path, err = fillUsernameToPath(url.Path)
			if err != nil {
				return url, err
			}
		}
		url.Scheme = "https"
		url.Host = "github.com"
		if url.Path[0] != '/' {
			url.Path = "/" + url.Path
		}
	}

	return url, nil
}

func ConvertGitURLHTTPToSSH(url *url.URL) (*url.URL, error) {
	user := url.User.Username()
	if user == "" {
		user = "git"
	}
	sshURL := fmt.Sprintf("ssh://%s@%s%s", user, url.Host, url.Path)
	return url.Parse(sshURL)
}

func fillUsernameToPath(path string) (string, error) {
	user, err := GitConfigSingle("ghq.user")
	if err != nil {
		return path, err
	}
	if user == "" {
		user = os.Getenv("GITHUB_USER")
	}
	if user == "" {
		switch runtime.GOOS {
		case "windows":
			user = os.Getenv("USERNAME")
		default:
			user = os.Getenv("USER")
		}
	}
	if user == "" {
		// Make the error if it does not match any pattern
		return path, fmt.Errorf("set ghq.user to your gitconfig")
	}
	path = user + "/" + path
	return path, nil
}
<commit_msg>Fix nil pointer dereference on older Go versions<commit_after>package main

import (
	"fmt"
	"net/url"
	"os"
	"regexp"
	"runtime"
	"strings"
)

// Convert SCP-like URL to SSH URL(e.g. [user@]host.xz:path/to/repo.git/)
// ref. http://git-scm.com/docs/git-fetch#_git_urls
// (golang hasn't supported Perl-like negative look-behind match)
var hasSchemePattern = regexp.MustCompile("^[^:]+://")
var scpLikeUrlPattern = regexp.MustCompile("^([^@]+@)?([^:]+):/?(.+)$")

func NewURL(ref string) (*url.URL, error) {
	if !hasSchemePattern.MatchString(ref) && scpLikeUrlPattern.MatchString(ref) {
		matched := scpLikeUrlPattern.FindStringSubmatch(ref)
		user := matched[1]
		host := matched[2]
		path := matched[3]

		ref = fmt.Sprintf("ssh://%s%s/%s", user, host, path)
	}

	url, err := url.Parse(ref)
	if err != nil {
		return url, err
	}

	if !url.IsAbs() {
		if !strings.Contains(url.Path, "/") {
			url.Path, err = fillUsernameToPath(url.Path)
			if err != nil {
				return url, err
			}
		}
		url.Scheme = "https"
		url.Host = "github.com"
		if url.Path[0] != '/' {
			url.Path = "/" + url.Path
		}
	}

	return url, nil
}

func ConvertGitURLHTTPToSSH(url *url.URL) (*url.URL, error) {
	user := "git";
	if url.User != nil {
		user = url.User.Username()
	}
	sshURL := fmt.Sprintf("ssh://%s@%s%s", user, url.Host, url.Path)
	return url.Parse(sshURL)
}

func fillUsernameToPath(path string) (string, error) {
	user, err := GitConfigSingle("ghq.user")
	if err != nil {
		return path, err
	}
	if user == "" {
		user = os.Getenv("GITHUB_USER")
	}
	if user == "" {
		switch runtime.GOOS {
		case "windows":
			user = os.Getenv("USERNAME")
		default:
			user = os.Getenv("USER")
		}
	}
	if user == "" {
		// Make the error if it does not match any pattern
		return path, fmt.Errorf("set ghq.user to your gitconfig")
	}
	path = user + "/" + path
	return path, nil
}
<|endoftext|>


<commit_before>package main

import (
	"net/url"
	"os"
	"path/filepath"

	"github.com/motemen/ghq/utils"
)

// Represents a VCS backend.
type VCSBackend struct {
	// Clones a remote repository to local path.
	Clone func(*url.URL, string) error
	// Updates a cloned local repository.
	Update func(string) error
}

var GitBackend = &VCSBackend{
	Clone: func(remote *url.URL, local string) error {
		dir, _ := filepath.Split(local)
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			return err
		}

		return utils.Run("git", "clone", remote.String(), local)
	},
	Update: func(local string) error {
		return utils.RunInDir(local, "git", "remote", "update")
	},
}

var MercurialBackend = &VCSBackend{
	Clone: func(remote *url.URL, local string) error {
		dir, _ := filepath.Split(local)
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			return err
		}

		return utils.Run("hg", "clone", remote.String(), local)
	},
	Update: func(local string) error {
		return utils.RunInDir(local, "hg", "pull")
	},
}
<commit_msg>git: update is pull --ff-only<commit_after>package main

import (
	"net/url"
	"os"
	"path/filepath"

	"github.com/motemen/ghq/utils"
)

// Represents a VCS backend.
type VCSBackend struct {
	// Clones a remote repository to local path.
	Clone func(*url.URL, string) error
	// Updates a cloned local repository.
	Update func(string) error
}

var GitBackend = &VCSBackend{
	Clone: func(remote *url.URL, local string) error {
		dir, _ := filepath.Split(local)
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			return err
		}

		return utils.Run("git", "clone", remote.String(), local)
	},
	Update: func(local string) error {
		return utils.RunInDir(local, "git", "pull", "--ff-only")
	},
}

var MercurialBackend = &VCSBackend{
	Clone: func(remote *url.URL, local string) error {
		dir, _ := filepath.Split(local)
		err := os.MkdirAll(dir, 0755)
		if err != nil {
			return err
		}

		return utils.Run("hg", "clone", remote.String(), local)
	},
	Update: func(local string) error {
		return utils.RunInDir(local, "hg", "pull")
	},
}
<|endoftext|>


<commit_before>package main

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

var verbose bool
var force bool
var copy bool

var ext string = ".was"

func init() {
	flag.BoolVar(&copy, "c", false, "copy instead of move")
	flag.StringVar(&ext, "e", ext, "file extension")
	flag.BoolVar(&force, "f", false, "clobber any conflicting files")
	flag.BoolVar(&verbose, "v", false, "verbose output")
}

func main() {
	flag.Usage = usage

	flag.Parse()

	wasFiles := flag.Args()

	if len(wasFiles) < 1 {
		flag.Usage()
		os.Exit(2)
	}

	if !strings.HasPrefix(ext, ".") {
		ext = "." + ext
	}

	if verbose {
		fmt.Println("hello world:%v:%s:", verbose, wasFiles)
	}

FileLoop:
	for _, file := range wasFiles {
		if verbose {
			fmt.Fprintf(os.Stderr, "handling file:%s:len(file):%d:\n", file, len(file))
		}

		//chop off slash from directories
		file = filepath.Clean(file)

		if file == ext {
			fmt.Fprintf(os.Stderr, "ignoring %s:%v\n", ext)
			continue FileLoop
		}

		if _, err := os.Stat(file); err != nil {
			fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
			continue FileLoop
		}

		targetFile := file + ext
		if strings.HasSuffix(file, ext) {
			if verbose {
				fmt.Fprintf(os.Stderr, "doing unwas on:%s\n", targetFile)
			}
			targetFile = file[0 : len(file)-len(ext)]
		}

		if _, err := os.Stat(targetFile); err == nil {
			if verbose {
				fmt.Fprintf(os.Stderr, "target is blocked:%s\n", targetFile)
			}
			if !force {
				fmt.Printf("There's a file in the way:%s:\n", targetFile)
				fmt.Printf("Delete %s? Please type yes or no and then press enter:\n", targetFile)
				if askForConfirmation() {
					if err := os.RemoveAll(targetFile); err != nil {
						fmt.Fprintf(os.Stderr, "could not clear the way for new was file:skipping:%v\n", err)
						continue FileLoop
					}
				} else {
					fmt.Fprintf(os.Stderr, "user chose to not delete target:skipping:%s\n", targetFile)
					continue FileLoop
				}
			}
		}

		if verbose {
			fmt.Fprintf(os.Stderr, "target is clear:%s\n", file)
		}

		if copy {
			copyFileHandle, err := os.Open(file)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}
			defer copyFileHandle.Close()

			finfo, err := copyFileHandle.Stat()
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}

			if fmode := finfo.Mode(); fmode.IsDir() {
				fmt.Fprintf(os.Stderr, "skipping:copy is not supported for directories\n")
				continue FileLoop
			}

			targetFileHandle, err := os.Create(targetFile)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}
			defer targetFileHandle.Close()

			_, err = io.Copy(targetFileHandle, copyFileHandle)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}
		} else {
			if err := os.Rename(file, targetFile); err != nil {
				fmt.Fprintf(os.Stderr, "failed to was:%v\n", err)
				continue FileLoop
			}
		}

		if verbose {
			fmt.Fprintf(os.Stderr, "was'd:%s\n", file)
		}
	}
}

//swiped this from a gist:
//https://gist.github.com/albrow/5882501
func askForConfirmation() bool {
	consolereader := bufio.NewReader(os.Stdin)

	response, err := consolereader.ReadString('\n')
	if err != nil {
		fmt.Printf("%v\n", err)
		os.Exit(2)
	}
	okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
	nokayResponses := []string{"n", "N", "no", "No", "NO"}
	if containsString(okayResponses, response[:len(response)-1]) {
		return true
	} else if containsString(nokayResponses, response[:len(response)-1]) {
		return false
	} else {
		fmt.Println("Please type yes or no and then press enter:")
		return askForConfirmation()
	}
}

// posString returns the first index of element in slice.
// If slice does not contain element, returns -1.
func posString(slice []string, element string) int {
	for index, elem := range slice {
		if elem == element {
			return index
		}
	}
	return -1
}

// containsString returns true iff slice contains element
func containsString(slice []string, element string) bool {
	return !(posString(slice, element) == -1)
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, `

        Description:

Stupid simple but useful tool to move a file or directory and move it back later.
Was moves a list of files to files with a .was extension, and/or moves them back if they already have a .was extension.

	Examples:

was thisFile -> thisFile.was
was thisFile.was -> thisFile
was thisFile thatFile.was -> thisFile.was thatFile
was -c someFile -> someFile someFile.was
was -e=saw someFile -> someFile.saw

was filename1 [filename2 filename3 ...]

WIP

Make it return non-zero if there were any errors
Let user choose the extension.
Read file list from STDIN
`)

	flag.PrintDefaults()
	fmt.Fprintf(os.Stderr, "\n")
}
<commit_msg>accept file list from stdin<commit_after>package main

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

var verbose bool
var force bool
var copy bool

var ext string = ".was"

func init() {
	flag.BoolVar(&copy, "c", false, "copy instead of move")
	flag.StringVar(&ext, "e", ext, "file extension")
	flag.BoolVar(&force, "f", false, "clobber any conflicting files")
	flag.BoolVar(&verbose, "v", false, "verbose output")
}

func main() {
	flag.Usage = usage

	flag.Parse()

	wasFiles := flag.Args()

	if len(wasFiles) < 1 {
		wasFiles = filesFromStdin()
	}

	if len(wasFiles) < 1 {
		flag.Usage()
		os.Exit(2)
	}

	if !strings.HasPrefix(ext, ".") {
		ext = "." + ext
	}

	if verbose {
		fmt.Println("hello world:%v:%s:", verbose, wasFiles)
	}

FileLoop:
	for _, file := range wasFiles {
		if file == "" {
			if verbose {
				fmt.Fprintf(os.Stderr, "ignoring empty file\n")
			}
			continue FileLoop
		}

		if verbose {
			fmt.Fprintf(os.Stderr, "handling file:%s:len(file):%d:\n", file, len(file))
		}

		//chop off slash from directories
		file = filepath.Clean(file)

		if file == ext {
			fmt.Fprintf(os.Stderr, "ignoring %s:%v\n", ext)
			continue FileLoop
		}

		if _, err := os.Stat(file); err != nil {
			fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
			continue FileLoop
		}

		targetFile := file + ext
		if strings.HasSuffix(file, ext) {
			if verbose {
				fmt.Fprintf(os.Stderr, "doing unwas on:%s\n", targetFile)
			}
			targetFile = file[0 : len(file)-len(ext)]
		}

		if _, err := os.Stat(targetFile); err == nil {
			if verbose {
				fmt.Fprintf(os.Stderr, "target is blocked:%s\n", targetFile)
			}
			if !force {
				fmt.Printf("There's a file in the way:%s:\n", targetFile)
				fmt.Printf("Delete %s? Please type yes or no and then press enter:\n", targetFile)
				if askForConfirmation() {
					if err := os.RemoveAll(targetFile); err != nil {
						fmt.Fprintf(os.Stderr, "could not clear the way for new was file:skipping:%v\n", err)
						continue FileLoop
					}
				} else {
					fmt.Fprintf(os.Stderr, "user chose to not delete target:skipping:%s\n", targetFile)
					continue FileLoop
				}
			}
		}

		if verbose {
			fmt.Fprintf(os.Stderr, "target is clear:%s\n", file)
		}

		if copy {
			copyFileHandle, err := os.Open(file)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}
			defer copyFileHandle.Close()

			finfo, err := copyFileHandle.Stat()
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}

			if fmode := finfo.Mode(); fmode.IsDir() {
				fmt.Fprintf(os.Stderr, "skipping:copy is not supported for directories\n")
				continue FileLoop
			}

			targetFileHandle, err := os.Create(targetFile)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}
			defer targetFileHandle.Close()

			_, err = io.Copy(targetFileHandle, copyFileHandle)
			if err != nil {
				fmt.Fprintf(os.Stderr, "skipping:%v\n", err)
				continue FileLoop
			}
		} else {
			if err := os.Rename(file, targetFile); err != nil {
				fmt.Fprintf(os.Stderr, "failed to was:%v\n", err)
				continue FileLoop
			}
		}

		if verbose {
			fmt.Fprintf(os.Stderr, "was'd:%s\n", file)
		}
	}
}

//swiped this from a gist:
//https://gist.github.com/albrow/5882501
func askForConfirmation() bool {
	consolereader := bufio.NewReader(os.Stdin)

	response, err := consolereader.ReadString('\n')
	if err != nil {
		fmt.Printf("%v\n", err)
		os.Exit(2)
	}
	okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
	nokayResponses := []string{"n", "N", "no", "No", "NO"}
	if containsString(okayResponses, response[:len(response)-1]) {
		return true
	} else if containsString(nokayResponses, response[:len(response)-1]) {
		return false
	} else {
		fmt.Println("Please type yes or no and then press enter:")
		return askForConfirmation()
	}
}

// posString returns the first index of element in slice.
// If slice does not contain element, returns -1.
func posString(slice []string, element string) int {
	for index, elem := range slice {
		if elem == element {
			return index
		}
	}
	return -1
}

// containsString returns true iff slice contains element
func containsString(slice []string, element string) bool {
	return !(posString(slice, element) == -1)
}

func filesFromStdin() []string {
	bytes, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(2)
	}

	return strings.Split(string(bytes), "\n")
}

func usage() {
	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
	fmt.Fprintf(os.Stderr, `

        Description:

Stupid simple but useful tool to move a file or directory and move it back later.
Was moves a list of files to files with a .was extension, and/or moves them back if they already have a .was extension.

	Examples:

was thisFile -> thisFile.was
was thisFile.was -> thisFile
was thisFile thatFile.was -> thisFile.was thatFile
was -c someFile -> someFile someFile.was
was -e=saw someFile -> someFile.saw

was filename1 [filename2 filename3 ...]

WIP

Make it return non-zero if there were any errors
Let user choose the extension.
Read file list from STDIN
`)

	flag.PrintDefaults()
	fmt.Fprintf(os.Stderr, "\n")
}
<|endoftext|>


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

package main

import (
	"fmt"
	"html/template"
	"net/http"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/codegangsta/martini"

	"github.com/gogits/binding"

	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/modules/auth"
	"github.com/gogits/gogs/modules/base"
	"github.com/gogits/gogs/modules/log"
	"github.com/gogits/gogs/modules/mailer"
	"github.com/gogits/gogs/modules/middleware"
	"github.com/gogits/gogs/routers"
	"github.com/gogits/gogs/routers/admin"
	"github.com/gogits/gogs/routers/dev"
	"github.com/gogits/gogs/routers/repo"
	"github.com/gogits/gogs/routers/user"
)

var CmdWeb = cli.Command{
	Name:  "web",
	Usage: "just run",
	Description: `
gogs web`,
	Action: runWeb,
	Flags:  []cli.Flag{},
}

// globalInit is for global configuration reload-able.
func globalInit() {
	base.NewConfigContext()
	mailer.NewMailerContext()
	models.LoadModelsConfig()
	models.LoadRepoConfig()
	models.NewRepoContext()
	models.NewEngine()
}

// Check run mode(Default of martini is Dev).
func checkRunMode() {
	switch base.Cfg.MustValue("", "RUN_MODE") {
	case "prod":
		martini.Env = martini.Prod
	case "test":
		martini.Env = martini.Test
	}
	log.Info("Run Mode: %s", strings.Title(martini.Env))
}

func newMartini() *martini.ClassicMartini {
	r := martini.NewRouter()
	m := martini.New()
	m.Use(middleware.Logger())
	m.Use(martini.Recovery())
	m.Use(martini.Static("public"))
	m.MapTo(r, (*martini.Routes)(nil))
	m.Action(r.Handle)
	return &martini.ClassicMartini{m, r}
}

func runWeb(*cli.Context) {
	globalInit()
	base.NewServices()
	checkRunMode()
	log.Info("%s %s", base.AppName, base.AppVer)

	m := newMartini()

	// Middlewares.
	m.Use(middleware.Renderer(middleware.RenderOptions{Funcs: []template.FuncMap{base.TemplateFuncs}}))

	m.Use(middleware.InitContext())

	reqSignIn := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true})
	ignSignIn := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: base.Service.RequireSignInView})
	reqSignOut := middleware.Toggle(&middleware.ToggleOptions{SignOutRequire: true})

	// Routers.
	m.Get("/", ignSignIn, routers.Home)
	m.Get("/issues", reqSignIn, user.Issues)
	m.Get("/pulls", reqSignIn, user.Pulls)
	m.Get("/stars", reqSignIn, user.Stars)
	m.Get("/help", routers.Help)

	m.Group("/user", func(r martini.Router) {
		r.Any("/login", binding.BindIgnErr(auth.LogInForm{}), user.SignIn)
		r.Any("/sign_up", reqSignOut, binding.BindIgnErr(auth.RegisterForm{}), user.SignUp)
	}, reqSignOut)
	m.Group("/user", func(r martini.Router) {
		r.Any("/logout", user.SignOut)
		r.Any("/delete", user.Delete)
		r.Any("/setting", binding.BindIgnErr(auth.UpdateProfileForm{}), user.Setting)
	}, reqSignIn)
	m.Group("/user", func(r martini.Router) {
		r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
		r.Get("/activate", user.Activate)
	})

	m.Group("/user/setting", func(r martini.Router) {
		r.Any("/password", binding.BindIgnErr(auth.UpdatePasswdForm{}), user.SettingPassword)
		r.Any("/ssh", binding.BindIgnErr(auth.AddSSHKeyForm{}), user.SettingSSHKeys)
		r.Any("/notification", user.SettingNotification)
		r.Any("/security", user.SettingSecurity)
	}, reqSignIn)

	m.Get("/user/:username", ignSignIn, user.Profile)

	m.Any("/repo/create", reqSignIn, binding.BindIgnErr(auth.CreateRepoForm{}), repo.Create)

	adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true})

	m.Get("/admin", adminReq, admin.Dashboard)
	m.Group("/admin", func(r martini.Router) {
		r.Get("/users", admin.Users)
		r.Get("/repos", admin.Repositories)
		r.Get("/config", admin.Config)
	}, adminReq)
	m.Group("/admin/users", func(r martini.Router) {
		r.Any("/new", binding.BindIgnErr(auth.RegisterForm{}), admin.NewUser)
		r.Any("/:userid", binding.BindIgnErr(auth.AdminEditUserForm{}), admin.EditUser)
		r.Any("/:userid/delete", admin.DeleteUser)
	}, adminReq)

	m.Group("/:username/:reponame", func(r martini.Router) {
		r.Post("/settings", repo.SettingPost)
		r.Get("/settings", repo.Setting)
		r.Get("/action/:action", repo.Action)
	}, reqSignIn, middleware.RepoAssignment(true))
	m.Group("/:username/:reponame", func(r martini.Router) {
		r.Get("/commits/:branchname", repo.Commits)
		r.Get("/issues", repo.Issues)
		r.Any("/issues/new", binding.BindIgnErr(auth.CreateIssueForm{}), repo.CreateIssue)
		r.Get("/issues/:issueid", repo.ViewIssue)
		r.Get("/pulls", repo.Pulls)
		r.Get("/branches", repo.Branches)
		r.Get("/src/:branchname", repo.Single)
		r.Get("/src/:branchname/**", repo.Single)
		r.Get("/commits/:branchname", repo.Commits)
		r.Get("/commits/:branchname", repo.Commits)
	}, ignSignIn, middleware.RepoAssignment(true))

	// TODO: implement single commit page
	// m.Get("/:username/:reponame/commit/:commitid/**", ignSignIn, middleware.RepoAssignment(true), repo.Single)
	// m.Get("/:username/:reponame/commit/:commitid", ignSignIn, middleware.RepoAssignment(true), repo.Single)

	m.Group("/:username", func(r martini.Router) {
		r.Get("/:reponame", middleware.RepoAssignment(true), repo.Single)
		r.Any("/:reponame/**", repo.Http)
	}, ignSignIn)

	if martini.Env == martini.Dev {
		m.Get("/template/**", dev.TemplatePreview)
	}

	listenAddr := fmt.Sprintf("%s:%s",
		base.Cfg.MustValue("server", "HTTP_ADDR"),
		base.Cfg.MustValue("server", "HTTP_PORT", "3000"))
	log.Info("Listen: %s", listenAddr)
	if err := http.ListenAndServe(listenAddr, m); err != nil {
		log.Critical(err.Error())
	}
}
<commit_msg>minor fix<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"html/template"
	"net/http"
	"strings"

	"github.com/codegangsta/cli"
	"github.com/codegangsta/martini"

	"github.com/gogits/binding"

	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/modules/auth"
	"github.com/gogits/gogs/modules/base"
	"github.com/gogits/gogs/modules/log"
	"github.com/gogits/gogs/modules/mailer"
	"github.com/gogits/gogs/modules/middleware"
	"github.com/gogits/gogs/routers"
	"github.com/gogits/gogs/routers/admin"
	"github.com/gogits/gogs/routers/dev"
	"github.com/gogits/gogs/routers/repo"
	"github.com/gogits/gogs/routers/user"
)

var CmdWeb = cli.Command{
	Name:  "web",
	Usage: "just run",
	Description: `
gogs web`,
	Action: runWeb,
	Flags:  []cli.Flag{},
}

// globalInit is for global configuration reload-able.
func globalInit() {
	base.NewConfigContext()
	mailer.NewMailerContext()
	models.LoadModelsConfig()
	models.LoadRepoConfig()
	models.NewRepoContext()
	models.NewEngine()
}

// Check run mode(Default of martini is Dev).
func checkRunMode() {
	switch base.Cfg.MustValue("", "RUN_MODE") {
	case "prod":
		martini.Env = martini.Prod
	case "test":
		martini.Env = martini.Test
	}
	log.Info("Run Mode: %s", strings.Title(martini.Env))
}

func newMartini() *martini.ClassicMartini {
	r := martini.NewRouter()
	m := martini.New()
	m.Use(middleware.Logger())
	m.Use(martini.Recovery())
	m.Use(martini.Static("public"))
	m.MapTo(r, (*martini.Routes)(nil))
	m.Action(r.Handle)
	return &martini.ClassicMartini{m, r}
}

func runWeb(*cli.Context) {
	globalInit()
	base.NewServices()
	checkRunMode()
	log.Info("%s %s", base.AppName, base.AppVer)

	m := newMartini()

	// Middlewares.
	m.Use(middleware.Renderer(middleware.RenderOptions{Funcs: []template.FuncMap{base.TemplateFuncs}}))

	m.Use(middleware.InitContext())

	reqSignIn := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true})
	ignSignIn := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: base.Service.RequireSignInView})
	reqSignOut := middleware.Toggle(&middleware.ToggleOptions{SignOutRequire: true})

	// Routers.
	m.Get("/", ignSignIn, routers.Home)
	m.Get("/issues", reqSignIn, user.Issues)
	m.Get("/pulls", reqSignIn, user.Pulls)
	m.Get("/stars", reqSignIn, user.Stars)
	m.Get("/help", routers.Help)

	m.Group("/user", func(r martini.Router) {
		r.Any("/login", binding.BindIgnErr(auth.LogInForm{}), user.SignIn)
		r.Any("/sign_up", binding.BindIgnErr(auth.RegisterForm{}), user.SignUp)
	}, reqSignOut)
	m.Group("/user", func(r martini.Router) {
		r.Any("/logout", user.SignOut)
		r.Any("/delete", user.Delete)
		r.Any("/setting", binding.BindIgnErr(auth.UpdateProfileForm{}), user.Setting)
	}, reqSignIn)
	m.Group("/user", func(r martini.Router) {
		r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
		r.Get("/activate", user.Activate)
	})

	m.Group("/user/setting", func(r martini.Router) {
		r.Any("/password", binding.BindIgnErr(auth.UpdatePasswdForm{}), user.SettingPassword)
		r.Any("/ssh", binding.BindIgnErr(auth.AddSSHKeyForm{}), user.SettingSSHKeys)
		r.Any("/notification", user.SettingNotification)
		r.Any("/security", user.SettingSecurity)
	}, reqSignIn)

	m.Get("/user/:username", ignSignIn, user.Profile)

	m.Any("/repo/create", reqSignIn, binding.BindIgnErr(auth.CreateRepoForm{}), repo.Create)

	adminReq := middleware.Toggle(&middleware.ToggleOptions{SignInRequire: true, AdminRequire: true})

	m.Get("/admin", adminReq, admin.Dashboard)
	m.Group("/admin", func(r martini.Router) {
		r.Get("/users", admin.Users)
		r.Get("/repos", admin.Repositories)
		r.Get("/config", admin.Config)
	}, adminReq)
	m.Group("/admin/users", func(r martini.Router) {
		r.Any("/new", binding.BindIgnErr(auth.RegisterForm{}), admin.NewUser)
		r.Any("/:userid", binding.BindIgnErr(auth.AdminEditUserForm{}), admin.EditUser)
		r.Any("/:userid/delete", admin.DeleteUser)
	}, adminReq)

	m.Group("/:username/:reponame", func(r martini.Router) {
		r.Post("/settings", repo.SettingPost)
		r.Get("/settings", repo.Setting)
		r.Get("/action/:action", repo.Action)
	}, reqSignIn, middleware.RepoAssignment(true))
	m.Group("/:username/:reponame", func(r martini.Router) {
		r.Get("/commits/:branchname", repo.Commits)
		r.Get("/issues", repo.Issues)
		r.Any("/issues/new", binding.BindIgnErr(auth.CreateIssueForm{}), repo.CreateIssue)
		r.Get("/issues/:issueid", repo.ViewIssue)
		r.Get("/pulls", repo.Pulls)
		r.Get("/branches", repo.Branches)
		r.Get("/src/:branchname", repo.Single)
		r.Get("/src/:branchname/**", repo.Single)
		r.Get("/commits/:branchname", repo.Commits)
		r.Get("/commits/:branchname", repo.Commits)
	}, ignSignIn, middleware.RepoAssignment(true))

	// TODO: implement single commit page
	// m.Get("/:username/:reponame/commit/:commitid/**", ignSignIn, middleware.RepoAssignment(true), repo.Single)
	// m.Get("/:username/:reponame/commit/:commitid", ignSignIn, middleware.RepoAssignment(true), repo.Single)

	m.Group("/:username", func(r martini.Router) {
		r.Get("/:reponame", middleware.RepoAssignment(true), repo.Single)
		r.Any("/:reponame/**", repo.Http)
	}, ignSignIn)

	if martini.Env == martini.Dev {
		m.Get("/template/**", dev.TemplatePreview)
	}

	listenAddr := fmt.Sprintf("%s:%s",
		base.Cfg.MustValue("server", "HTTP_ADDR"),
		base.Cfg.MustValue("server", "HTTP_PORT", "3000"))
	log.Info("Listen: %s", listenAddr)
	if err := http.ListenAndServe(listenAddr, m); err != nil {
		log.Critical(err.Error())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"html/template"
	"log"
	"net/http"
	"os"
)

// Server is an abstraction that runs via a web interface
type Server struct {
	DB     *Database
	router http.Handler
	logger http.Handler
}

// NewServer instantiates a server with an active database
func NewServer(db *Database) *Server {
	s := Server{DB: db}
	s.router = s.BuildRouter()

	http.Handle("/", s.router)
	s.logger = handlers.LoggingHandler(os.Stdout, s.router)

	return &s
}

// StartHandler is the entry point to the web GUI
//
// If not authenticated, it allows for registration.
// If authenticated and a tournament is running, show that tournament.
// If authenticated and no tournament is running, show a list of tournaments.
func (s *Server) StartHandler(w http.ResponseWriter, r *http.Request) {
	t := getTemplates("static/tournaments.html")
	data := struct {
		Tournaments []*Tournament
	}{
		s.DB.Tournaments,
	}

	render(t, w, r, data)
}

// NewHandler shows the page to create a new tournament
func (s *Server) NewHandler(w http.ResponseWriter, r *http.Request) {
	// If there is a post to this URL, it means we are making a new tournament
	if r.Method == "POST" {
		name := r.PostFormValue("name")
		id := r.PostFormValue("id")
		t, _ := NewTournament(name, id, s.DB)
		log.Printf("Created tournament %s!", t.Name)
		http.Redirect(w, r, "/", 302)
		return
	}

	// Elsewise, show the GUI
	t := getTemplates("static/new.html")
	render(t, w, r, struct{}{})
}

// TournamentHandler shows the tournament view and handles tournaments
func (s *Server) TournamentHandler(w http.ResponseWriter, r *http.Request) {
	t := getTemplates("static/tournament.html", "static/match.html")
	vars := mux.Vars(r)
	data := struct {
		Tournament *Tournament
	}{
		s.DB.tournamentRef[vars["id"]],
	}

	render(t, w, r, data)
}

// MatchHandler shows the Match view and handles Matches
func (s *Server) MatchHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "The battle raged ever on.\n")
}

// ActionHandler handles judge requests for player action
func (s *Server) ActionHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Arrows were fired, archers were killed, and shots were had.\n")
}

// BuildRouter sets up the routes
func (s *Server) BuildRouter() http.Handler {
	r := mux.NewRouter()

	r.HandleFunc("/", s.StartHandler)
	r.HandleFunc("/new", s.NewHandler)
	r.HandleFunc("/{id}/", s.TournamentHandler)
	r.HandleFunc("/{id}/{kind:(tryout|runnerup|semi|final)}/{index:[0-9]+}/", s.MatchHandler)
	r.HandleFunc("/{id}/{kind:(tryout|runnerup|semi|final)}/{index:[0-9]+}/{player:[0-3]}", s.ActionHandler)

	return r
}

// Serve serves forever
func (s *Server) Serve() error {
	log.Print("Listening on :3420")
	return http.ListenAndServe(":3420", s.logger)
}

// getTemplates gets a template with the context set to `extra`, with index.html backing it.
func getTemplates(extra string) *template.Template {
	t, err := template.ParseFiles(extra, "static/index.html")
	if err != nil {
		log.Fatal(err)
	}

	return t
}

func render(t *template.Template, w http.ResponseWriter, r *http.Request, data interface{}) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	err := t.ExecuteTemplate(w, "base", data)
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	db, err := NewDatabase("production.db")
	if err != nil {
		log.Fatal(err)
	}

	err = NewServer(db).Serve()
	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>Modify getTemplates() to accept multiple arguments<commit_after>package main

import (
	"fmt"
	"github.com/gorilla/handlers"
	"github.com/gorilla/mux"
	"html/template"
	"log"
	"net/http"
	"os"
)

// Server is an abstraction that runs via a web interface
type Server struct {
	DB     *Database
	router http.Handler
	logger http.Handler
}

// NewServer instantiates a server with an active database
func NewServer(db *Database) *Server {
	s := Server{DB: db}
	s.router = s.BuildRouter()

	http.Handle("/", s.router)
	s.logger = handlers.LoggingHandler(os.Stdout, s.router)

	return &s
}

// StartHandler is the entry point to the web GUI
//
// If not authenticated, it allows for registration.
// If authenticated and a tournament is running, show that tournament.
// If authenticated and no tournament is running, show a list of tournaments.
func (s *Server) StartHandler(w http.ResponseWriter, r *http.Request) {
	t := getTemplates("static/tournaments.html")
	data := struct {
		Tournaments []*Tournament
	}{
		s.DB.Tournaments,
	}

	render(t, w, r, data)
}

// NewHandler shows the page to create a new tournament
func (s *Server) NewHandler(w http.ResponseWriter, r *http.Request) {
	// If there is a post to this URL, it means we are making a new tournament
	if r.Method == "POST" {
		name := r.PostFormValue("name")
		id := r.PostFormValue("id")
		t, _ := NewTournament(name, id, s.DB)
		log.Printf("Created tournament %s!", t.Name)
		http.Redirect(w, r, "/", 302)
		return
	}

	// Elsewise, show the GUI
	t := getTemplates("static/new.html")
	render(t, w, r, struct{}{})
}

// TournamentHandler shows the tournament view and handles tournaments
func (s *Server) TournamentHandler(w http.ResponseWriter, r *http.Request) {
	t := getTemplates("static/tournament.html", "static/match.html")
	vars := mux.Vars(r)
	data := struct {
		Tournament *Tournament
	}{
		s.DB.tournamentRef[vars["id"]],
	}

	render(t, w, r, data)
}

// MatchHandler shows the Match view and handles Matches
func (s *Server) MatchHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "The battle raged ever on.\n")
}

// ActionHandler handles judge requests for player action
func (s *Server) ActionHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "Arrows were fired, archers were killed, and shots were had.\n")
}

// BuildRouter sets up the routes
func (s *Server) BuildRouter() http.Handler {
	r := mux.NewRouter()

	r.HandleFunc("/", s.StartHandler)
	r.HandleFunc("/new", s.NewHandler)
	r.HandleFunc("/{id}/", s.TournamentHandler)
	r.HandleFunc("/{id}/{kind:(tryout|runnerup|semi|final)}/{index:[0-9]+}/", s.MatchHandler)
	r.HandleFunc("/{id}/{kind:(tryout|runnerup|semi|final)}/{index:[0-9]+}/{player:[0-3]}", s.ActionHandler)

	return r
}

// Serve serves forever
func (s *Server) Serve() error {
	log.Print("Listening on :3420")
	return http.ListenAndServe(":3420", s.logger)
}

// getTemplates gets a template with the context set to `extra`, with index.html backing it.
func getTemplates(items ...string) *template.Template {
	items = append(items, "static/index.html")
	t, err := template.ParseFiles(items...)
	if err != nil {
		log.Fatal(err)
	}

	return t
}

func render(t *template.Template, w http.ResponseWriter, r *http.Request, data interface{}) {
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	err := t.ExecuteTemplate(w, "base", data)
	if err != nil {
		log.Fatal(err)
	}
}

func main() {
	db, err := NewDatabase("production.db")
	if err != nil {
		log.Fatal(err)
	}

	err = NewServer(db).Serve()
	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>