<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package gcs

import (
	"bytes"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"time"
	"unicode/utf8"

	"golang.org/x/net/context"
	"google.golang.org/api/googleapi"
	storagev1 "google.golang.org/api/storage/v1"
	"google.golang.org/cloud"
	"google.golang.org/cloud/storage"
)

// A request to create an object, accepted by Bucket.CreateObject.
type CreateObjectRequest struct {
	// Attributes with which the object should be created. The Name field must be
	// set; other zero-valued fields are ignored.
	//
	// Object names must:
	//
	// *  be non-empty.
	// *  be no longer than 1024 bytes.
	// *  be valid UTF-8.
	// *  not contain the code point U+000A (line feed).
	// *  not contain the code point U+000D (carriage return).
	//
	// See here for authoritative documentation:
	//     https://cloud.google.com/storage/docs/bucket-naming#objectnames
	Attrs storage.ObjectAttrs

	// A reader from which to obtain the contents of the object. Must be non-nil.
	Contents io.Reader
}

// Bucket represents a GCS bucket, pre-bound with a bucket name and necessary
// authorization information.
//
// Each method that may block accepts a context object that is used for
// deadlines and cancellation. Users need not package authorization information
// into the context object (using cloud.WithContext or similar).
type Bucket interface {
	Name() string

	// List the objects in the bucket that meet the criteria defined by the
	// query, returning a result object that contains the results and potentially
	// a cursor for retrieving the next portion of the larger set of results.
	ListObjects(ctx context.Context, query *storage.Query) (*storage.Objects, error)

	// Create a reader for the contents of the object with the given name. The
	// caller must arrange for the reader to be closed when it is no longer
	// needed.
	NewReader(ctx context.Context, objectName string) (io.ReadCloser, error)

	// Create or overwrite an object according to the supplied request. The new
	// object is guaranteed to exist immediately for the purposes of reading (and
	// eventually for listing) after this method returns a nil error. It is
	// guaranteed not to exist before req.Contents returns io.EOF.
	CreateObject(ctx context.Context, req *CreateObjectRequest) (*storage.Object, error)

	// Delete the object with the given name.
	DeleteObject(ctx context.Context, name string) error
}

type bucket struct {
	projID     string
	client     *http.Client
	rawService *storagev1.Service
	name       string
}

func (b *bucket) Name() string {
	return b.name
}

func (b *bucket) ListObjects(ctx context.Context, query *storage.Query) (*storage.Objects, error) {
	authContext := cloud.WithContext(ctx, b.projID, b.client)
	return storage.ListObjects(authContext, b.name, query)
}

func (b *bucket) NewReader(ctx context.Context, objectName string) (io.ReadCloser, error) {
	authContext := cloud.WithContext(ctx, b.projID, b.client)
	return storage.NewReader(authContext, b.name, objectName)
}

func toRawAcls(in []storage.ACLRule) []*storagev1.ObjectAccessControl {
	out := make([]*storagev1.ObjectAccessControl, len(in))
	for i, rule := range in {
		out[i] = &storagev1.ObjectAccessControl{
			Entity: string(rule.Entity),
			Role:   string(rule.Role),
		}
	}

	return out
}

func fromRawAcls(in []*storagev1.ObjectAccessControl) []storage.ACLRule {
	out := make([]storage.ACLRule, len(in))
	for i, rule := range in {
		out[i] = storage.ACLRule{
			Entity: storage.ACLEntity(rule.Entity),
			Role:   storage.ACLRole(rule.Role),
		}
	}

	return out
}

func fromRfc3339(s string) (t time.Time, err error) {
	if s != "" {
		t, err = time.Parse(time.RFC3339, s)
	}

	return
}

func fromRawObject(
	bucketName string,
	in *storagev1.Object) (out *storage.Object, err error) {
	// Convert the easy fields.
	out = &storage.Object{
		Bucket:          bucketName,
		Name:            in.Name,
		ContentType:     in.ContentType,
		ContentLanguage: in.ContentLanguage,
		CacheControl:    in.CacheControl,
		ACL:             fromRawAcls(in.Acl),
		ContentEncoding: in.ContentEncoding,
		Size:            int64(in.Size),
		MediaLink:       in.MediaLink,
		Metadata:        in.Metadata,
		Generation:      in.Generation,
		MetaGeneration:  in.Metageneration,
		StorageClass:    in.StorageClass,
	}

	// Handle special cases.
	if in.Owner != nil {
		out.Owner = in.Owner.Entity
	}

	if out.Deleted, err = fromRfc3339(in.TimeDeleted); err != nil {
		err = fmt.Errorf("Decoding TimeDeleted field: %v", err)
		return
	}

	if out.Updated, err = fromRfc3339(in.Updated); err != nil {
		err = fmt.Errorf("Decoding Updated field: %v", err)
		return
	}

	if out.MD5, err = base64.StdEncoding.DecodeString(in.Md5Hash); err != nil {
		err = fmt.Errorf("Decoding Md5Hash field: %v", err)
		return
	}

	crc32cString, err := base64.StdEncoding.DecodeString(in.Crc32c)
	if err != nil {
		err = fmt.Errorf("Decoding Crc32c field: %v", err)
		return
	}

	if len(crc32cString) != 4 {
		err = fmt.Errorf("Wrong length for decoded Crc32c field: %d", len(crc32cString))
		return
	}

	out.CRC32C =
		uint32(crc32cString[0])<<24 |
			uint32(crc32cString[1])<<16 |
			uint32(crc32cString[2])<<8 |
			uint32(crc32cString[3])<<0

	return
}

type contentTypeReader struct {
	wrapped     io.Reader
	contentType string
}

var _ io.Reader = &contentTypeReader{}
var _ googleapi.ContentTyper = &contentTypeReader{}

func (r *contentTypeReader) Read(p []byte) (int, error) {
	return r.wrapped.Read(p)
}

func (r *contentTypeReader) ContentType() string {
	return r.contentType
}

func makeMedia(req *CreateObjectRequest) (r io.Reader, err error) {
	r = req.Contents

	// Work around a bug in the googleapi package: ConditionallyIncludeMedia
	// completely ignores I/O errors from the Reader you hand it (cf.
	// http://goo.gl/hA48zs and Google-internal bug ID 19417010).
	//
	// So buffer the entire contents in memory. :-(
	contents, err := ioutil.ReadAll(r)
	if err != nil {
		return
	}

	r = bytes.NewReader(contents)

	// Work around the following interaction:
	//
	// 1. The storage package attempts to sniff the content type from the media,
	// regardless of whether Object.ContentType has been explicitly set (cf.
	// http://goo.gl/Dlvq7j).
	//
	// 2. The sniffed content type goes into the HTTP headers and the explicit
	// ContentType field goes into the JSON body.
	//
	// 3. GCS apparently ignores the JSON body content type and stores the one
	// from the HTTP headers (cf. Google-internal bug ID 19416462).
	if req.Attrs.ContentType != "" {
		r = &contentTypeReader{r, req.Attrs.ContentType}
	}

	return
}

func (b *bucket) CreateObject(
	ctx context.Context,
	req *CreateObjectRequest) (o *storage.Object, err error) {
	// TODO(jacobsa): Refactor so that this is done once by NewConn.
	rawService, err := storagev1.New(b.client)
	if err != nil {
		err = fmt.Errorf("storagev1.New: %v", err)
		return
	}

	// As of 2015-02, the wrapped storage package doesn't check this for us,
	// causing silently transformed names:
	//     https://github.com/GoogleCloudPlatform/gcloud-golang/issues/111
	if !utf8.ValidString(req.Attrs.Name) {
		err = errors.New("Invalid object name: not valid UTF-8")
		return
	}

	// Set up an object struct based on the supplied attributes.
	inputObj := &storagev1.Object{
		Name:            req.Attrs.Name,
		Bucket:          b.Name(),
		ContentType:     req.Attrs.ContentType,
		ContentLanguage: req.Attrs.ContentLanguage,
		ContentEncoding: req.Attrs.ContentEncoding,
		CacheControl:    req.Attrs.CacheControl,
		Acl:             toRawAcls(req.Attrs.ACL),
		Metadata:        req.Attrs.Metadata,
	}

	// Set up an appropriate reader to hand to the call object below.
	media, err := makeMedia(req)
	if err != nil {
		return
	}

	// Configure a 'call' object.
	call := rawService.Objects.Insert(b.Name(), inputObj)
	call.Media(media)
	call.Projection("full")

	// Execute the call.
	rawObject, err := call.Do()
	if err != nil {
		return
	}

	// Convert the returned object.
	o, err = fromRawObject(b.Name(), rawObject)
	if err != nil {
		return
	}

	return
}

func (b *bucket) DeleteObject(ctx context.Context, name string) error {
	authContext := cloud.WithContext(ctx, b.projID, b.client)
	return storage.DeleteObject(authContext, b.name, name)
}
<commit_msg>Declared a generation precondition interface.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// Author: jacobsa@google.com (Aaron Jacobs)

package gcs

import (
	"bytes"
	"encoding/base64"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"time"
	"unicode/utf8"

	"golang.org/x/net/context"
	"google.golang.org/api/googleapi"
	storagev1 "google.golang.org/api/storage/v1"
	"google.golang.org/cloud"
	"google.golang.org/cloud/storage"
)

// A request to create an object, accepted by Bucket.CreateObject.
type CreateObjectRequest struct {
	// Attributes with which the object should be created. The Name field must be
	// set; other zero-valued fields are ignored.
	//
	// Object names must:
	//
	// *  be non-empty.
	// *  be no longer than 1024 bytes.
	// *  be valid UTF-8.
	// *  not contain the code point U+000A (line feed).
	// *  not contain the code point U+000D (carriage return).
	//
	// See here for authoritative documentation:
	//     https://cloud.google.com/storage/docs/bucket-naming#objectnames
	Attrs storage.ObjectAttrs

	// A reader from which to obtain the contents of the object. Must be non-nil.
	Contents io.Reader

	// If non-nil, the object will be created/overwritten only if the current
	// generation for the object name is equal to the given value. Zero means the
	// object does not exist.
	GenerationPrecondition *int64
}

// Bucket represents a GCS bucket, pre-bound with a bucket name and necessary
// authorization information.
//
// Each method that may block accepts a context object that is used for
// deadlines and cancellation. Users need not package authorization information
// into the context object (using cloud.WithContext or similar).
type Bucket interface {
	Name() string

	// List the objects in the bucket that meet the criteria defined by the
	// query, returning a result object that contains the results and potentially
	// a cursor for retrieving the next portion of the larger set of results.
	ListObjects(ctx context.Context, query *storage.Query) (*storage.Objects, error)

	// Create a reader for the contents of the object with the given name. The
	// caller must arrange for the reader to be closed when it is no longer
	// needed.
	NewReader(ctx context.Context, objectName string) (io.ReadCloser, error)

	// Create or overwrite an object according to the supplied request. The new
	// object is guaranteed to exist immediately for the purposes of reading (and
	// eventually for listing) after this method returns a nil error. It is
	// guaranteed not to exist before req.Contents returns io.EOF.
	CreateObject(ctx context.Context, req *CreateObjectRequest) (*storage.Object, error)

	// Delete the object with the given name.
	DeleteObject(ctx context.Context, name string) error
}

type bucket struct {
	projID     string
	client     *http.Client
	rawService *storagev1.Service
	name       string
}

func (b *bucket) Name() string {
	return b.name
}

func (b *bucket) ListObjects(ctx context.Context, query *storage.Query) (*storage.Objects, error) {
	authContext := cloud.WithContext(ctx, b.projID, b.client)
	return storage.ListObjects(authContext, b.name, query)
}

func (b *bucket) NewReader(ctx context.Context, objectName string) (io.ReadCloser, error) {
	authContext := cloud.WithContext(ctx, b.projID, b.client)
	return storage.NewReader(authContext, b.name, objectName)
}

func toRawAcls(in []storage.ACLRule) []*storagev1.ObjectAccessControl {
	out := make([]*storagev1.ObjectAccessControl, len(in))
	for i, rule := range in {
		out[i] = &storagev1.ObjectAccessControl{
			Entity: string(rule.Entity),
			Role:   string(rule.Role),
		}
	}

	return out
}

func fromRawAcls(in []*storagev1.ObjectAccessControl) []storage.ACLRule {
	out := make([]storage.ACLRule, len(in))
	for i, rule := range in {
		out[i] = storage.ACLRule{
			Entity: storage.ACLEntity(rule.Entity),
			Role:   storage.ACLRole(rule.Role),
		}
	}

	return out
}

func fromRfc3339(s string) (t time.Time, err error) {
	if s != "" {
		t, err = time.Parse(time.RFC3339, s)
	}

	return
}

func fromRawObject(
	bucketName string,
	in *storagev1.Object) (out *storage.Object, err error) {
	// Convert the easy fields.
	out = &storage.Object{
		Bucket:          bucketName,
		Name:            in.Name,
		ContentType:     in.ContentType,
		ContentLanguage: in.ContentLanguage,
		CacheControl:    in.CacheControl,
		ACL:             fromRawAcls(in.Acl),
		ContentEncoding: in.ContentEncoding,
		Size:            int64(in.Size),
		MediaLink:       in.MediaLink,
		Metadata:        in.Metadata,
		Generation:      in.Generation,
		MetaGeneration:  in.Metageneration,
		StorageClass:    in.StorageClass,
	}

	// Handle special cases.
	if in.Owner != nil {
		out.Owner = in.Owner.Entity
	}

	if out.Deleted, err = fromRfc3339(in.TimeDeleted); err != nil {
		err = fmt.Errorf("Decoding TimeDeleted field: %v", err)
		return
	}

	if out.Updated, err = fromRfc3339(in.Updated); err != nil {
		err = fmt.Errorf("Decoding Updated field: %v", err)
		return
	}

	if out.MD5, err = base64.StdEncoding.DecodeString(in.Md5Hash); err != nil {
		err = fmt.Errorf("Decoding Md5Hash field: %v", err)
		return
	}

	crc32cString, err := base64.StdEncoding.DecodeString(in.Crc32c)
	if err != nil {
		err = fmt.Errorf("Decoding Crc32c field: %v", err)
		return
	}

	if len(crc32cString) != 4 {
		err = fmt.Errorf("Wrong length for decoded Crc32c field: %d", len(crc32cString))
		return
	}

	out.CRC32C =
		uint32(crc32cString[0])<<24 |
			uint32(crc32cString[1])<<16 |
			uint32(crc32cString[2])<<8 |
			uint32(crc32cString[3])<<0

	return
}

type contentTypeReader struct {
	wrapped     io.Reader
	contentType string
}

var _ io.Reader = &contentTypeReader{}
var _ googleapi.ContentTyper = &contentTypeReader{}

func (r *contentTypeReader) Read(p []byte) (int, error) {
	return r.wrapped.Read(p)
}

func (r *contentTypeReader) ContentType() string {
	return r.contentType
}

func makeMedia(req *CreateObjectRequest) (r io.Reader, err error) {
	r = req.Contents

	// Work around a bug in the googleapi package: ConditionallyIncludeMedia
	// completely ignores I/O errors from the Reader you hand it (cf.
	// http://goo.gl/hA48zs and Google-internal bug ID 19417010).
	//
	// So buffer the entire contents in memory. :-(
	contents, err := ioutil.ReadAll(r)
	if err != nil {
		return
	}

	r = bytes.NewReader(contents)

	// Work around the following interaction:
	//
	// 1. The storage package attempts to sniff the content type from the media,
	// regardless of whether Object.ContentType has been explicitly set (cf.
	// http://goo.gl/Dlvq7j).
	//
	// 2. The sniffed content type goes into the HTTP headers and the explicit
	// ContentType field goes into the JSON body.
	//
	// 3. GCS apparently ignores the JSON body content type and stores the one
	// from the HTTP headers (cf. Google-internal bug ID 19416462).
	if req.Attrs.ContentType != "" {
		r = &contentTypeReader{r, req.Attrs.ContentType}
	}

	return
}

func (b *bucket) CreateObject(
	ctx context.Context,
	req *CreateObjectRequest) (o *storage.Object, err error) {
	// TODO(jacobsa): Refactor so that this is done once by NewConn.
	rawService, err := storagev1.New(b.client)
	if err != nil {
		err = fmt.Errorf("storagev1.New: %v", err)
		return
	}

	// As of 2015-02, the wrapped storage package doesn't check this for us,
	// causing silently transformed names:
	//     https://github.com/GoogleCloudPlatform/gcloud-golang/issues/111
	if !utf8.ValidString(req.Attrs.Name) {
		err = errors.New("Invalid object name: not valid UTF-8")
		return
	}

	// Set up an object struct based on the supplied attributes.
	inputObj := &storagev1.Object{
		Name:            req.Attrs.Name,
		Bucket:          b.Name(),
		ContentType:     req.Attrs.ContentType,
		ContentLanguage: req.Attrs.ContentLanguage,
		ContentEncoding: req.Attrs.ContentEncoding,
		CacheControl:    req.Attrs.CacheControl,
		Acl:             toRawAcls(req.Attrs.ACL),
		Metadata:        req.Attrs.Metadata,
	}

	// Set up an appropriate reader to hand to the call object below.
	media, err := makeMedia(req)
	if err != nil {
		return
	}

	// Configure a 'call' object.
	call := rawService.Objects.Insert(b.Name(), inputObj)
	call.Media(media)
	call.Projection("full")

	// Execute the call.
	rawObject, err := call.Do()
	if err != nil {
		return
	}

	// Convert the returned object.
	o, err = fromRawObject(b.Name(), rawObject)
	if err != nil {
		return
	}

	return
}

func (b *bucket) DeleteObject(ctx context.Context, name string) error {
	authContext := cloud.WithContext(ctx, b.projID, b.client)
	return storage.DeleteObject(authContext, b.name, name)
}
<|endoftext|>


<commit_before>package buildpackrunner

import (
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/cloudfoundry-incubator/cacheddownloader"
	"github.com/cloudfoundry/systemcerts"
	"github.com/pivotal-golang/archiver/extractor"
)

type ZipDownloader struct {
	downloader *cacheddownloader.Downloader
}

func IsZipFile(filename string) bool {
	return strings.HasSuffix(filename, ".zip")
}

func NewZipDownloader(skipSSLVerification bool) *ZipDownloader {
	return &ZipDownloader{
		downloader: cacheddownloader.NewDownloader(DOWNLOAD_TIMEOUT, 1, skipSSLVerification, systemcerts.SystemRootsPool()),
	}
}

func (z *ZipDownloader) DownloadAndExtract(u *url.URL, destination string) (uint64, error) {
	zipFile, err := ioutil.TempFile("", filepath.Base(u.Path))
	if err != nil {
		return 0, fmt.Errorf("Could not create zip file: %s", err.Error())
	}
	defer os.Remove(zipFile.Name())

	_, _, err = z.downloader.Download(u,
		func() (*os.File, error) {
			return os.OpenFile(zipFile.Name(), os.O_WRONLY, 0666)
		},
		cacheddownloader.CachingInfoType{},
		make(chan struct{}),
	)
	if err != nil {
		return 0, fmt.Errorf("Failed to download buildpack '%s': %s", u.String(), err.Error())
	}

	fi, err := zipFile.Stat()
	if err != nil {
		return 0, fmt.Errorf("Failed to obtain the size of the buildpack '%s': %s", u.String(), err.Error())
	}

	err = extractor.NewZip().Extract(zipFile.Name(), destination)
	if err != nil {
		return 0, fmt.Errorf("Failed to extract buildpack '%s': %s", u.String(), err.Error())
	}

	return uint64(fi.Size()), nil
}
<commit_msg>Checksum support for buildpackrunner<commit_after>package buildpackrunner

import (
	"fmt"
	"io/ioutil"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"github.com/cloudfoundry-incubator/cacheddownloader"
	"github.com/cloudfoundry/systemcerts"
	"github.com/pivotal-golang/archiver/extractor"
)

type ZipDownloader struct {
	downloader *cacheddownloader.Downloader
}

func IsZipFile(filename string) bool {
	return strings.HasSuffix(filename, ".zip")
}

func NewZipDownloader(skipSSLVerification bool) *ZipDownloader {
	return &ZipDownloader{
		downloader: cacheddownloader.NewDownloader(DOWNLOAD_TIMEOUT, 1, skipSSLVerification, systemcerts.SystemRootsPool()),
	}
}

func (z *ZipDownloader) DownloadAndExtract(u *url.URL, destination string) (uint64, error) {
	zipFile, err := ioutil.TempFile("", filepath.Base(u.Path))
	if err != nil {
		return 0, fmt.Errorf("Could not create zip file: %s", err.Error())
	}
	defer os.Remove(zipFile.Name())

	_, _, err = z.downloader.Download(u,
		func() (*os.File, error) {
			return os.OpenFile(zipFile.Name(), os.O_WRONLY, 0666)
		},
		cacheddownloader.CachingInfoType{},
		cacheddownloader.ChecksumInfoType{},
		make(chan struct{}),
	)
	if err != nil {
		return 0, fmt.Errorf("Failed to download buildpack '%s': %s", u.String(), err.Error())
	}

	fi, err := zipFile.Stat()
	if err != nil {
		return 0, fmt.Errorf("Failed to obtain the size of the buildpack '%s': %s", u.String(), err.Error())
	}

	err = extractor.NewZip().Extract(zipFile.Name(), destination)
	if err != nil {
		return 0, fmt.Errorf("Failed to extract buildpack '%s': %s", u.String(), err.Error())
	}

	return uint64(fi.Size()), nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, huangjunwei <huangjunwei@youmi.net>. All rights reserved.

package blog4go

import (
	"fmt"
	"os"
	"path"
	"strings"
	"sync"
	"time"
)

// ByteSize is type of sizes
type ByteSize int64

const (
	// unit of sizes

	_ = iota // ignore first value by assigning to blank identifier
	// KB unit of kilobyte
	KB ByteSize = 1 << (10 * iota)
	// MB unit of megabyte
	MB
	// GB unit of gigabyte
	GB

	// default logrotate condition

	// DefaultRotateSize is default size when size base logrotate needed
	DefaultRotateSize = 500 * MB
	// DefaultRotateLines is default lines when lines base logrotate needed
	DefaultRotateLines = 2000000 // 2 million

	// DefaultLogExpireDays
	DefaultLogExpireDays = 7
)

// baseFileWriter defines a writer for single file.
// It suppurts partially write while formatting message, logging level filtering,
// logrotate, user defined hook for every logging action, change configuration
// on the fly and logging with colors.
type baseFileWriter struct {
	// configuration about file
	// full path of the file, the same as configuration
	fileName string
	// current file name of the writer, may be changed with logrotate
	currentFileName string
	// the file object
	file *os.File

	// the BLog
	blog *BLog

	// close sign, default false
	// set this tag true if writer is closed
	closed bool

	// configuration about logrotate
	// exclusive lock use in logrotate
	rotateLock *sync.Mutex

	// configuration about time base logrotate
	// sign of time base logrotate, default false
	// set this tag true if logrotate in time base mode
	timeRotated bool
	// logs retention days when time base logrotate
	expireDays int64
	// signal send when time base rotate needed
	timeRotateSig chan bool

	// configuration about size && line base logrotate
	// sign of line base logrotate, default false
	// set this tag true if logrotate in line base mode
	lineRotated bool
	// line base logrotate threshold
	rotateLines int
	// total lines written from last size && line base logrotate
	currentLines int
	// sign of size base logrotate, default false
	// set this tag true if logrotate in size base mode
	sizeRotated bool
	// size rotate按行数、大小rotate, 后缀 xxx.1, xxx.2
	// signal send when size && line base logrotate
	sizeRotateSig chan bool
	// size base logrotate threshold
	rotateSize ByteSize
	// total size written after last size && line logrotate
	currentSize ByteSize
	// times of size && line base logrotate executions
	sizeRotateTimes int
	// channel used to sum up sizes written from last logrotate
	logSizeChan chan int

	// sign decided logging with colors or not, default false
	colored bool
}

// NewbaseFileWriter create a single file writer instance and return the poionter
// of it. When any errors happened during creation, a null writer and appropriate
// will be returned.
// fileName must be an absolute path to the destination log file
// rotate determine if it will logrotate
func newBaseFileWriter(fileName string, rotate bool) (fileWriter *baseFileWriter, err error) {
	fileWriter = new(baseFileWriter)
	fileWriter.fileName = fileName
	// open file target file
	if rotate {
		fileName = fmt.Sprintf("%s.%s", fileName, timeCache.date)
	}
	file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(0644))
	fileWriter.file = file
	fileWriter.currentFileName = fileName
	if nil != err {
		return fileWriter, err
	}
	fileWriter.blog = NewBLog(file)

	fileWriter.closed = false

	// about logrotate
	fileWriter.rotateLock = new(sync.Mutex)
	fileWriter.timeRotated = false
	fileWriter.expireDays = DefaultLogExpireDays
	fileWriter.timeRotateSig = make(chan bool)
	fileWriter.sizeRotateSig = make(chan bool)
	fileWriter.logSizeChan = make(chan int, 4096)

	fileWriter.lineRotated = false
	fileWriter.rotateSize = DefaultRotateSize
	fileWriter.currentSize = 0

	fileWriter.sizeRotated = false
	fileWriter.rotateLines = DefaultRotateLines
	fileWriter.currentLines = 0

	fileWriter.colored = false

	go fileWriter.daemon()

	return fileWriter, nil
}

// NewFileWriter initialize a file writer
// baseDir must be base directory of log files
// rotate determine if it will logrotate
func NewFileWriter(baseDir string, rotate bool) (err error) {
	singltonLock.Lock()
	defer singltonLock.Unlock()
	if nil != blog {
		return
	}

	fileWriter := new(MultiWriter)
	fileWriter.level = DEBUG
	fileWriter.closed = false

	fileWriter.writers = make(map[Level]Writer)
	for _, level := range Levels {
		fileName := fmt.Sprintf("%s.log", strings.ToLower(level.String()))
		writer, err := newBaseFileWriter(path.Join(baseDir, fileName), rotate)
		if nil != err {
			return err
		}
		fileWriter.writers[level] = writer
	}

	// log hook
	fileWriter.hook = nil
	fileWriter.hookLevel = DEBUG

	blog = fileWriter
	return
}

// daemon run in background as NewbaseFileWriter called.
// It flushes writer buffer every 1 second.
// It decides whether a time base when logrotate is needed.
// It sums up lines && sizes already written. Alse it does the lines &&
// size base logrotate
func (writer *baseFileWriter) daemon() {
	// tick every seconds
	// time base logrotate
	t := time.Tick(1 * time.Second)
	// tick every second
	// auto flush writer buffer
	f := time.Tick(1 * time.Second)

DaemonLoop:
	for {
		select {
		case <-f:
			if writer.closed {
				break DaemonLoop
			}

			writer.blog.flush()
		case <-t:
			if writer.closed {
				break DaemonLoop
			}

			if writer.timeRotated {
				date := time.Now().Format(DateFormat)
				if date != timeCache.date {
					// need time base logrotate
					writer.sizeRotateTimes = 0
				}

				// if fileName not equal to currentFileName, it needs a time base logrotate
				if fileName := fmt.Sprintf("%s.%s", writer.fileName, timeCache.date); writer.currentFileName != fileName {
					// lock at this place may cause logrotate not accurate, but reduce lock acquire
					// TODO have any better solution?
					writer.rotateLock.Lock()
					file, _ := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(0644))

					writer.file.Close()
					writer.blog.resetFile(file)
					writer.file = file
					writer.currentFileName = fileName
					writer.rotateLock.Unlock()

					// TODO expire logs
					// format the expired log file name
					date := timeCache.now.Add(time.Duration(-24 * (writer.expireDays + 1))).Format(DateFormat)
					expiredFileName := fmt.Sprintf("%s.%s", writer.fileName, date)
					// check if expired log exists
					if _, err := os.Stat(expiredFileName); os.IsNotExist(err) {
						os.Remove(expiredFileName)
					}
				}
			}

		// analyse lines && size written
		// do lines && size base logrotate
		case size := <-writer.logSizeChan:
			if writer.closed {
				break DaemonLoop
			}

			if !writer.sizeRotated && !writer.lineRotated {
				continue
			}

			writer.rotateLock.Lock()

			writer.currentSize += ByteSize(size)
			writer.currentLines++

			if (writer.sizeRotated && writer.currentSize > writer.rotateSize) || (writer.lineRotated && writer.currentLines > writer.rotateLines) {
				// need lines && size base logrotate
				writer.sizeRotateTimes++
				writer.currentSize = 0
				writer.currentLines = 0

				fileName := fmt.Sprintf("%s.%d", writer.fileName, writer.sizeRotateTimes+1)
				if writer.timeRotated {
					fileName = fmt.Sprintf("%s.%s.%d", writer.fileName, timeCache.date, writer.sizeRotateTimes+1)
				}
				file, _ := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(0644))

				writer.file.Close()
				writer.blog.resetFile(file)
				writer.file = file
			}
			writer.rotateLock.Unlock()
		}
	}
}

// write writes pure message with specific level
func (writer *baseFileWriter) write(level Level, format string) {
	var size = 0
	defer func() {
		// logrotate
		if writer.sizeRotated || writer.lineRotated {
			writer.logSizeChan <- size
		}
	}()

	if writer.closed {
		return
	}

	size = writer.blog.write(level, format)
}

// write formats message with specific level and write it
func (writer *baseFileWriter) writef(level Level, format string, args ...interface{}) {
	// 格式化构造message
	// 边解析边输出
	// 使用 % 作占位符

	// 统计日志size
	var size = 0

	defer func() {
		// logrotate
		if writer.sizeRotated || writer.lineRotated {
			writer.logSizeChan <- size
		}
	}()

	if writer.closed {
		return
	}

	size = writer.blog.writef(level, format, args...)
}

// Close close file writer
func (writer *baseFileWriter) Close() {
	if writer.closed {
		return
	}

	writer.blog.Close()
	writer.blog = nil
	writer.closed = true
}

// SetTimeRotated toggle time base logrotate on the fly
func (writer *baseFileWriter) SetTimeRotated(timeRotated bool) {
	writer.timeRotated = timeRotated
}

// RotateSize return size threshold when logrotate
func (writer *baseFileWriter) RotateSize() ByteSize {
	return writer.rotateSize
}

// SetRotateSize set size when logroatate
func (writer *baseFileWriter) SetRotateSize(rotateSize ByteSize) {
	if rotateSize > ByteSize(0) {
		writer.sizeRotated = true
		writer.rotateSize = rotateSize
	} else {
		writer.sizeRotated = false
	}
}

// RotateLine return line threshold when logrotate
func (writer *baseFileWriter) RotateLine() int {
	return writer.rotateLines
}

// SetRotateLines set line number when logrotate
func (writer *baseFileWriter) SetRotateLines(rotateLines int) {
	if rotateLines > 0 {
		writer.lineRotated = true
		writer.rotateLines = rotateLines
	} else {
		writer.lineRotated = false
	}
}

// Colored return whether writer log with color
func (writer *baseFileWriter) Colored() bool {
	return writer.colored
}

// SetColored set logging color
func (writer *baseFileWriter) SetColored(colored bool) {
	if colored == writer.colored {
		return
	}

	writer.colored = colored
	initPrefix(colored)
}

// Level return logging level threshold
func (writer *baseFileWriter) Level() Level {
	return writer.blog.Level()
}

// SetLevel set logging level threshold
func (writer *baseFileWriter) SetLevel(level Level) {
	writer.blog.SetLevel(level)
}

// SetHook do nothing
func (writer *baseFileWriter) SetHook(hook Hook) {
	return
}

// SetHookLevel do nothing
func (writer *baseFileWriter) SetHookLevel(level Level) {
	return
}

// flush flush logs to disk
func (writer *baseFileWriter) flush() {
	writer.blog.flush()
}

// Debug do nothing
func (writer *baseFileWriter) Debug(format string) {
	return
}

// Debugf do nothing
func (writer *baseFileWriter) Debugf(format string, args ...interface{}) {
	return
}

// Trace do nothing
func (writer *baseFileWriter) Trace(format string) {
	return
}

// Tracef do nothing
func (writer *baseFileWriter) Tracef(format string, args ...interface{}) {
	return
}

// Info do nothing
func (writer *baseFileWriter) Info(format string) {
	return
}

// Infof do nothing
func (writer *baseFileWriter) Infof(format string, args ...interface{}) {
	return
}

// Warn do nothing
func (writer *baseFileWriter) Warn(format string) {
	return
}

// Warnf do nothing
func (writer *baseFileWriter) Warnf(format string, args ...interface{}) {
	return
}

// Error do nothing
func (writer *baseFileWriter) Error(format string) {
	return
}

// Errorf do nothing
func (writer *baseFileWriter) Errorf(format string, args ...interface{}) {
	return
}

// Critical do nothing
func (writer *baseFileWriter) Critical(format string) {
	return
}

// Criticalf do nothing
func (writer *baseFileWriter) Criticalf(format string, args ...interface{}) {
	return
}
<commit_msg>fix golint<commit_after>// Copyright (c) 2015, huangjunwei <huangjunwei@youmi.net>. All rights reserved.

package blog4go

import (
	"fmt"
	"os"
	"path"
	"strings"
	"sync"
	"time"
)

// ByteSize is type of sizes
type ByteSize int64

const (
	// unit of sizes

	_ = iota // ignore first value by assigning to blank identifier
	// KB unit of kilobyte
	KB ByteSize = 1 << (10 * iota)
	// MB unit of megabyte
	MB
	// GB unit of gigabyte
	GB

	// default logrotate condition

	// DefaultRotateSize is default size when size base logrotate needed
	DefaultRotateSize = 500 * MB
	// DefaultRotateLines is default lines when lines base logrotate needed
	DefaultRotateLines = 2000000 // 2 million

	// DefaultLogExpireDays is the default days of logs to be keeped
	DefaultLogExpireDays = 7
)

// baseFileWriter defines a writer for single file.
// It suppurts partially write while formatting message, logging level filtering,
// logrotate, user defined hook for every logging action, change configuration
// on the fly and logging with colors.
type baseFileWriter struct {
	// configuration about file
	// full path of the file, the same as configuration
	fileName string
	// current file name of the writer, may be changed with logrotate
	currentFileName string
	// the file object
	file *os.File

	// the BLog
	blog *BLog

	// close sign, default false
	// set this tag true if writer is closed
	closed bool

	// configuration about logrotate
	// exclusive lock use in logrotate
	rotateLock *sync.Mutex

	// configuration about time base logrotate
	// sign of time base logrotate, default false
	// set this tag true if logrotate in time base mode
	timeRotated bool
	// logs retention days when time base logrotate
	expireDays int64
	// signal send when time base rotate needed
	timeRotateSig chan bool

	// configuration about size && line base logrotate
	// sign of line base logrotate, default false
	// set this tag true if logrotate in line base mode
	lineRotated bool
	// line base logrotate threshold
	rotateLines int
	// total lines written from last size && line base logrotate
	currentLines int
	// sign of size base logrotate, default false
	// set this tag true if logrotate in size base mode
	sizeRotated bool
	// size rotate按行数、大小rotate, 后缀 xxx.1, xxx.2
	// signal send when size && line base logrotate
	sizeRotateSig chan bool
	// size base logrotate threshold
	rotateSize ByteSize
	// total size written after last size && line logrotate
	currentSize ByteSize
	// times of size && line base logrotate executions
	sizeRotateTimes int
	// channel used to sum up sizes written from last logrotate
	logSizeChan chan int

	// sign decided logging with colors or not, default false
	colored bool
}

// NewbaseFileWriter create a single file writer instance and return the poionter
// of it. When any errors happened during creation, a null writer and appropriate
// will be returned.
// fileName must be an absolute path to the destination log file
// rotate determine if it will logrotate
func newBaseFileWriter(fileName string, rotate bool) (fileWriter *baseFileWriter, err error) {
	fileWriter = new(baseFileWriter)
	fileWriter.fileName = fileName
	// open file target file
	if rotate {
		fileName = fmt.Sprintf("%s.%s", fileName, timeCache.date)
	}
	file, err := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(0644))
	fileWriter.file = file
	fileWriter.currentFileName = fileName
	if nil != err {
		return fileWriter, err
	}
	fileWriter.blog = NewBLog(file)

	fileWriter.closed = false

	// about logrotate
	fileWriter.rotateLock = new(sync.Mutex)
	fileWriter.timeRotated = false
	fileWriter.expireDays = DefaultLogExpireDays
	fileWriter.timeRotateSig = make(chan bool)
	fileWriter.sizeRotateSig = make(chan bool)
	fileWriter.logSizeChan = make(chan int, 4096)

	fileWriter.lineRotated = false
	fileWriter.rotateSize = DefaultRotateSize
	fileWriter.currentSize = 0

	fileWriter.sizeRotated = false
	fileWriter.rotateLines = DefaultRotateLines
	fileWriter.currentLines = 0

	fileWriter.colored = false

	go fileWriter.daemon()

	return fileWriter, nil
}

// NewFileWriter initialize a file writer
// baseDir must be base directory of log files
// rotate determine if it will logrotate
func NewFileWriter(baseDir string, rotate bool) (err error) {
	singltonLock.Lock()
	defer singltonLock.Unlock()
	if nil != blog {
		return
	}

	fileWriter := new(MultiWriter)
	fileWriter.level = DEBUG
	fileWriter.closed = false

	fileWriter.writers = make(map[Level]Writer)
	for _, level := range Levels {
		fileName := fmt.Sprintf("%s.log", strings.ToLower(level.String()))
		writer, err := newBaseFileWriter(path.Join(baseDir, fileName), rotate)
		if nil != err {
			return err
		}
		fileWriter.writers[level] = writer
	}

	// log hook
	fileWriter.hook = nil
	fileWriter.hookLevel = DEBUG

	blog = fileWriter
	return
}

// daemon run in background as NewbaseFileWriter called.
// It flushes writer buffer every 1 second.
// It decides whether a time base when logrotate is needed.
// It sums up lines && sizes already written. Alse it does the lines &&
// size base logrotate
func (writer *baseFileWriter) daemon() {
	// tick every seconds
	// time base logrotate
	t := time.Tick(1 * time.Second)
	// tick every second
	// auto flush writer buffer
	f := time.Tick(1 * time.Second)

DaemonLoop:
	for {
		select {
		case <-f:
			if writer.closed {
				break DaemonLoop
			}

			writer.blog.flush()
		case <-t:
			if writer.closed {
				break DaemonLoop
			}

			if writer.timeRotated {
				date := time.Now().Format(DateFormat)
				if date != timeCache.date {
					// need time base logrotate
					writer.sizeRotateTimes = 0
				}

				// if fileName not equal to currentFileName, it needs a time base logrotate
				if fileName := fmt.Sprintf("%s.%s", writer.fileName, timeCache.date); writer.currentFileName != fileName {
					// lock at this place may cause logrotate not accurate, but reduce lock acquire
					// TODO have any better solution?
					writer.rotateLock.Lock()
					file, _ := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(0644))

					writer.file.Close()
					writer.blog.resetFile(file)
					writer.file = file
					writer.currentFileName = fileName
					writer.rotateLock.Unlock()

					// TODO expire logs
					// format the expired log file name
					date := timeCache.now.Add(time.Duration(-24 * (writer.expireDays + 1))).Format(DateFormat)
					expiredFileName := fmt.Sprintf("%s.%s", writer.fileName, date)
					// check if expired log exists
					if _, err := os.Stat(expiredFileName); os.IsNotExist(err) {
						os.Remove(expiredFileName)
					}
				}
			}

		// analyse lines && size written
		// do lines && size base logrotate
		case size := <-writer.logSizeChan:
			if writer.closed {
				break DaemonLoop
			}

			if !writer.sizeRotated && !writer.lineRotated {
				continue
			}

			writer.rotateLock.Lock()

			writer.currentSize += ByteSize(size)
			writer.currentLines++

			if (writer.sizeRotated && writer.currentSize > writer.rotateSize) || (writer.lineRotated && writer.currentLines > writer.rotateLines) {
				// need lines && size base logrotate
				writer.sizeRotateTimes++
				writer.currentSize = 0
				writer.currentLines = 0

				fileName := fmt.Sprintf("%s.%d", writer.fileName, writer.sizeRotateTimes+1)
				if writer.timeRotated {
					fileName = fmt.Sprintf("%s.%s.%d", writer.fileName, timeCache.date, writer.sizeRotateTimes+1)
				}
				file, _ := os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND|os.O_CREATE, os.FileMode(0644))

				writer.file.Close()
				writer.blog.resetFile(file)
				writer.file = file
			}
			writer.rotateLock.Unlock()
		}
	}
}

// write writes pure message with specific level
func (writer *baseFileWriter) write(level Level, format string) {
	var size = 0
	defer func() {
		// logrotate
		if writer.sizeRotated || writer.lineRotated {
			writer.logSizeChan <- size
		}
	}()

	if writer.closed {
		return
	}

	size = writer.blog.write(level, format)
}

// write formats message with specific level and write it
func (writer *baseFileWriter) writef(level Level, format string, args ...interface{}) {
	// 格式化构造message
	// 边解析边输出
	// 使用 % 作占位符

	// 统计日志size
	var size = 0

	defer func() {
		// logrotate
		if writer.sizeRotated || writer.lineRotated {
			writer.logSizeChan <- size
		}
	}()

	if writer.closed {
		return
	}

	size = writer.blog.writef(level, format, args...)
}

// Close close file writer
func (writer *baseFileWriter) Close() {
	if writer.closed {
		return
	}

	writer.blog.Close()
	writer.blog = nil
	writer.closed = true
}

// SetTimeRotated toggle time base logrotate on the fly
func (writer *baseFileWriter) SetTimeRotated(timeRotated bool) {
	writer.timeRotated = timeRotated
}

// RotateSize return size threshold when logrotate
func (writer *baseFileWriter) RotateSize() ByteSize {
	return writer.rotateSize
}

// SetRotateSize set size when logroatate
func (writer *baseFileWriter) SetRotateSize(rotateSize ByteSize) {
	if rotateSize > ByteSize(0) {
		writer.sizeRotated = true
		writer.rotateSize = rotateSize
	} else {
		writer.sizeRotated = false
	}
}

// RotateLine return line threshold when logrotate
func (writer *baseFileWriter) RotateLine() int {
	return writer.rotateLines
}

// SetRotateLines set line number when logrotate
func (writer *baseFileWriter) SetRotateLines(rotateLines int) {
	if rotateLines > 0 {
		writer.lineRotated = true
		writer.rotateLines = rotateLines
	} else {
		writer.lineRotated = false
	}
}

// Colored return whether writer log with color
func (writer *baseFileWriter) Colored() bool {
	return writer.colored
}

// SetColored set logging color
func (writer *baseFileWriter) SetColored(colored bool) {
	if colored == writer.colored {
		return
	}

	writer.colored = colored
	initPrefix(colored)
}

// Level return logging level threshold
func (writer *baseFileWriter) Level() Level {
	return writer.blog.Level()
}

// SetLevel set logging level threshold
func (writer *baseFileWriter) SetLevel(level Level) {
	writer.blog.SetLevel(level)
}

// SetHook do nothing
func (writer *baseFileWriter) SetHook(hook Hook) {
	return
}

// SetHookLevel do nothing
func (writer *baseFileWriter) SetHookLevel(level Level) {
	return
}

// flush flush logs to disk
func (writer *baseFileWriter) flush() {
	writer.blog.flush()
}

// Debug do nothing
func (writer *baseFileWriter) Debug(format string) {
	return
}

// Debugf do nothing
func (writer *baseFileWriter) Debugf(format string, args ...interface{}) {
	return
}

// Trace do nothing
func (writer *baseFileWriter) Trace(format string) {
	return
}

// Tracef do nothing
func (writer *baseFileWriter) Tracef(format string, args ...interface{}) {
	return
}

// Info do nothing
func (writer *baseFileWriter) Info(format string) {
	return
}

// Infof do nothing
func (writer *baseFileWriter) Infof(format string, args ...interface{}) {
	return
}

// Warn do nothing
func (writer *baseFileWriter) Warn(format string) {
	return
}

// Warnf do nothing
func (writer *baseFileWriter) Warnf(format string, args ...interface{}) {
	return
}

// Error do nothing
func (writer *baseFileWriter) Error(format string) {
	return
}

// Errorf do nothing
func (writer *baseFileWriter) Errorf(format string, args ...interface{}) {
	return
}

// Critical do nothing
func (writer *baseFileWriter) Critical(format string) {
	return
}

// Criticalf do nothing
func (writer *baseFileWriter) Criticalf(format string, args ...interface{}) {
	return
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/http/cgi"
	"os"
	"regexp"
	"syscall"

	"gitorious.org/gitorious/gitorious-proto/api"
	"gitorious.org/gitorious/gitorious-proto/common"
)

func say(w http.ResponseWriter, status int, s string, args ...interface{}) {
	http.Error(w, fmt.Sprintf(s, args...), status)
}

func requestBasicAuth(w http.ResponseWriter, s string) {
	w.Header().Set("WWW-Authenticate", `Basic realm="Gitorious"`)
	say(w, http.StatusUnauthorized, s)
}

var pathRegexp = regexp.MustCompile("^/(.+\\.git)(/.+)$")

func parsePath(path string) (string, string, error) {
	matches := pathRegexp.FindStringSubmatch(path)
	if matches == nil {
		return "", "", errors.New(fmt.Sprintf(`invalid path "%v"`, path))
	}

	return matches[1], matches[2], nil
}

func createHttpEnv(username, repoPath string, repoConfig *api.RepoConfig, translatedPath string) []string {
	env := common.CreateEnv("http", username, repoPath, repoConfig)

	env = append(env, "REMOTE_USER="+username) // enables "receive-pack" service (push) in git-http-backend
	env = append(env, "GIT_HTTP_EXPORT_ALL=1") // enables clones without "git-daemon-export-ok" magic file
	env = append(env, "PATH_TRANSLATED="+translatedPath)

	return env
}

func execGitHttpBackend(env []string, w http.ResponseWriter, req *http.Request) {
	cgiHandler := &cgi.Handler{
		Path: "/bin/sh",
		Args: []string{"-c", "git http-backend"},
		Dir:  ".",
		Env:  env,
	}

	cgiHandler.ServeHTTP(w, req)
}

type Handler struct {
	logger          *log.Logger
	internalApi     api.InternalApi
	repositoryStore common.RepositoryStore
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	logger := &common.SessionLogger{h.logger, req.RemoteAddr}

	logger.Printf("client connected")

	var username string

	if usernameOrEmail, password, ok := BasicAuth(req); ok {
		user, err := h.internalApi.AuthenticateUser(usernameOrEmail, password)
		if err != nil {
			say(w, http.StatusInternalServerError, "Error occured, please contact support")
			logger.Printf("%v, disconnecting...", err)
			return
		}

		if user != nil {
			username = user.Username
			logger.Printf("user authenticated as %v", username)
		} else {
			requestBasicAuth(w, "Invalid username or password")
			logger.Printf("invalid credentials, requesting basic auth, disconnecting...")
			return
		}
	}

	repoPath, slug, err := parsePath(req.URL.Path)
	if err != nil {
		say(w, http.StatusBadRequest, "Invalid command")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	if (req.URL.Query().Get("service") == "git-receive-pack" || slug == "/git-receive-pack") && username == "" {
		requestBasicAuth(w, "Anonymous pushing not allowed")
		logger.Printf("denying anonymous push, requesting basic auth, disconnecting...")
		return
	}

	repoConfig, err := h.internalApi.GetRepoConfig(repoPath, username)
	if err != nil {
		if httpErr, ok := err.(*api.HttpError); ok {
			if httpErr.StatusCode == 403 {
				requestBasicAuth(w, "Access denied")
				logger.Printf("%v, requesting basic auth, disconnecting...", err)
				return
			} else if httpErr.StatusCode == 404 {
				say(w, http.StatusNotFound, "Invalid repository path")
				logger.Printf("%v, disconnecting...", err)
				return
			}
		}

		say(w, http.StatusInternalServerError, "Error occured, please contact support")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	logger.Printf("real repo path: %v", repoConfig.RealPath)

	fullRepoPath, err := h.repositoryStore.GetFullRepoPath(repoConfig.RealPath)
	if err != nil {
		say(w, http.StatusInternalServerError, "Error occurred, please contact support")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	translatedPath := fullRepoPath + slug
	env := createHttpEnv(username, repoPath, repoConfig, translatedPath)

	logger.Printf(`invoking git-http-backend with translated path "%v"`, translatedPath)

	execGitHttpBackend(env, w, req)

	logger.Printf("done")
}

func main() {
	syscall.Umask(0022) // set umask for pushes

	var (
		reposRootPath  = flag.String("r", ".", "Directory containing git repositories")
		internalApiUrl = flag.String("api-url", "http://localhost:3000/api/internal", "Gitorious internal API URL")
		addr           = flag.String("l", ":6000", "Address/port to listen on")
	)
	flag.Parse()

	logger := log.New(os.Stdout, "", log.LstdFlags)
	internalApi := &api.GitoriousInternalApi{*internalApiUrl}
	repositoryStore := &common.GitoriousRepositoryStore{*reposRootPath}

	logger.Printf("listening on %v", *addr)

	http.Handle("/", &Handler{logger, internalApi, repositoryStore})
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<commit_msg>Log original http request<commit_after>package main

import (
	"errors"
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/http/cgi"
	"os"
	"regexp"
	"syscall"

	"gitorious.org/gitorious/gitorious-proto/api"
	"gitorious.org/gitorious/gitorious-proto/common"
)

func say(w http.ResponseWriter, status int, s string, args ...interface{}) {
	http.Error(w, fmt.Sprintf(s, args...), status)
}

func requestBasicAuth(w http.ResponseWriter, s string) {
	w.Header().Set("WWW-Authenticate", `Basic realm="Gitorious"`)
	say(w, http.StatusUnauthorized, s)
}

var pathRegexp = regexp.MustCompile("^/(.+\\.git)(/.+)$")

func parsePath(path string) (string, string, error) {
	matches := pathRegexp.FindStringSubmatch(path)
	if matches == nil {
		return "", "", errors.New(fmt.Sprintf(`invalid path "%v"`, path))
	}

	return matches[1], matches[2], nil
}

func createHttpEnv(username, repoPath string, repoConfig *api.RepoConfig, translatedPath string) []string {
	env := common.CreateEnv("http", username, repoPath, repoConfig)

	env = append(env, "REMOTE_USER="+username) // enables "receive-pack" service (push) in git-http-backend
	env = append(env, "GIT_HTTP_EXPORT_ALL=1") // enables clones without "git-daemon-export-ok" magic file
	env = append(env, "PATH_TRANSLATED="+translatedPath)

	return env
}

func execGitHttpBackend(env []string, w http.ResponseWriter, req *http.Request) {
	cgiHandler := &cgi.Handler{
		Path: "/bin/sh",
		Args: []string{"-c", "git http-backend"},
		Dir:  ".",
		Env:  env,
	}

	cgiHandler.ServeHTTP(w, req)
}

type Handler struct {
	logger          *log.Logger
	internalApi     api.InternalApi
	repositoryStore common.RepositoryStore
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	logger := &common.SessionLogger{h.logger, req.RemoteAddr}

	logger.Printf("client connected")

	var username string

	if usernameOrEmail, password, ok := BasicAuth(req); ok {
		user, err := h.internalApi.AuthenticateUser(usernameOrEmail, password)
		if err != nil {
			say(w, http.StatusInternalServerError, "Error occured, please contact support")
			logger.Printf("%v, disconnecting...", err)
			return
		}

		if user != nil {
			username = user.Username
			logger.Printf("user authenticated as %v", username)
		} else {
			requestBasicAuth(w, "Invalid username or password")
			logger.Printf("invalid credentials, requesting basic auth, disconnecting...")
			return
		}
	}

	logger.Printf("processing request: %v", req.URL.String())

	repoPath, slug, err := parsePath(req.URL.Path)
	if err != nil {
		say(w, http.StatusBadRequest, "Invalid command")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	if (req.URL.Query().Get("service") == "git-receive-pack" || slug == "/git-receive-pack") && username == "" {
		requestBasicAuth(w, "Anonymous pushing not allowed")
		logger.Printf("denying anonymous push, requesting basic auth, disconnecting...")
		return
	}

	repoConfig, err := h.internalApi.GetRepoConfig(repoPath, username)
	if err != nil {
		if httpErr, ok := err.(*api.HttpError); ok {
			if httpErr.StatusCode == 403 {
				requestBasicAuth(w, "Access denied")
				logger.Printf("%v, requesting basic auth, disconnecting...", err)
				return
			} else if httpErr.StatusCode == 404 {
				say(w, http.StatusNotFound, "Invalid repository path")
				logger.Printf("%v, disconnecting...", err)
				return
			}
		}

		say(w, http.StatusInternalServerError, "Error occured, please contact support")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	logger.Printf("real repo path: %v", repoConfig.RealPath)

	fullRepoPath, err := h.repositoryStore.GetFullRepoPath(repoConfig.RealPath)
	if err != nil {
		say(w, http.StatusInternalServerError, "Error occurred, please contact support")
		logger.Printf("%v, disconnecting...", err)
		return
	}

	translatedPath := fullRepoPath + slug
	env := createHttpEnv(username, repoPath, repoConfig, translatedPath)

	logger.Printf(`invoking git-http-backend with translated path "%v"`, translatedPath)

	execGitHttpBackend(env, w, req)

	logger.Printf("done")
}

func main() {
	syscall.Umask(0022) // set umask for pushes

	var (
		reposRootPath  = flag.String("r", ".", "Directory containing git repositories")
		internalApiUrl = flag.String("api-url", "http://localhost:3000/api/internal", "Gitorious internal API URL")
		addr           = flag.String("l", ":6000", "Address/port to listen on")
	)
	flag.Parse()

	logger := log.New(os.Stdout, "", log.LstdFlags)
	internalApi := &api.GitoriousInternalApi{*internalApiUrl}
	repositoryStore := &common.GitoriousRepositoryStore{*reposRootPath}

	logger.Printf("listening on %v", *addr)

	http.Handle("/", &Handler{logger, internalApi, repositoryStore})
	log.Fatal(http.ListenAndServe(*addr, nil))
}
<|endoftext|>


<commit_before>package db

import (
	"strconv"
	"time"
)

// StoreAPI is a database interface.
type StoreAPI interface {
	List() RecordList
	Load(string, bool) *Record
	Write(*Record, int64) bool
	Get(*Record, *View) *Sample
	Clear(*Record) bool
}

// Type describes an approach to Get.
type Type int

const (
	// None will be ignored.
	None Type = iota

	// Average finds the average over a duration.
	Average

	// Total adds the values in the specified duration.
	Total

	// ValueAt finds the value at given duration in the past, aka the value set
	// most recently before the resolved time.
	ValueAt
)

// View is a request for a view over a Record.
type View struct {
	Type Type
	Duration time.Duration
}

// Valid determines whether this View is valid. The nil View is valid.
func (v *View) Valid() bool {
	return v == nil || (v.Type != None && v.Duration >= time.Duration(0))
}

// Record is a header/file combination.
type Record struct {
	Name string
	When time.Time // creation time
}

// Valid determines whether this Record is valid.
func (r *Record) Valid() bool {
	return r != nil && len(r.Name) != 0
}

// Node returns the creation time of this Record as a uint64.
func (r *Record) Node() uint64 {
	if r == nil {
		return 0
	}
	return uint64(r.When.UnixNano())
}

// RecordList is a list of Record objects.
type RecordList []*Record

// Sample is a vector: a value valid at a specific time. Each Sample is
// independent and immutable. In cases where Sample represents a historic
// value, When will typically represent the time it was generated.
type Sample struct {
	Value int64
	When  time.Time
}

// Bytes converts this Sample to a byte array.
func (s *Sample) Bytes() []byte {
	if s == nil {
		return nil
	}
	out := make([]byte, 0, 16)
	out = strconv.AppendInt(out, s.Value, 10)
	return append(out, '\n')
}
<commit_msg>gofmt<commit_after>package db

import (
	"strconv"
	"time"
)

// StoreAPI is a database interface.
type StoreAPI interface {
	List() RecordList
	Load(string, bool) *Record
	Write(*Record, int64) bool
	Get(*Record, *View) *Sample
	Clear(*Record) bool
}

// Type describes an approach to Get.
type Type int

const (
	// None will be ignored.
	None Type = iota

	// Average finds the average over a duration.
	Average

	// Total adds the values in the specified duration.
	Total

	// ValueAt finds the value at given duration in the past, aka the value set
	// most recently before the resolved time.
	ValueAt
)

// View is a request for a view over a Record.
type View struct {
	Type     Type
	Duration time.Duration
}

// Valid determines whether this View is valid. The nil View is valid.
func (v *View) Valid() bool {
	return v == nil || (v.Type != None && v.Duration >= time.Duration(0))
}

// Record is a header/file combination.
type Record struct {
	Name string
	When time.Time // creation time
}

// Valid determines whether this Record is valid.
func (r *Record) Valid() bool {
	return r != nil && len(r.Name) != 0
}

// Node returns the creation time of this Record as a uint64.
func (r *Record) Node() uint64 {
	if r == nil {
		return 0
	}
	return uint64(r.When.UnixNano())
}

// RecordList is a list of Record objects.
type RecordList []*Record

// Sample is a vector: a value valid at a specific time. Each Sample is
// independent and immutable. In cases where Sample represents a historic
// value, When will typically represent the time it was generated.
type Sample struct {
	Value int64
	When  time.Time
}

// Bytes converts this Sample to a byte array.
func (s *Sample) Bytes() []byte {
	if s == nil {
		return nil
	}
	out := make([]byte, 0, 16)
	out = strconv.AppendInt(out, s.Value, 10)
	return append(out, '\n')
}
<|endoftext|>


<commit_before>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package cli

import (
	"fmt"

	"mynewt.apache.org/newt/newtmgr/config"
	"mynewt.apache.org/newt/newtmgr/protocol"
	"mynewt.apache.org/newt/newtmgr/transport"

	"github.com/spf13/cobra"
)

func echoRunCmd(cmd *cobra.Command, args []string) {
	cpm, err := config.NewConnProfileMgr()
	if err != nil {
		nmUsage(cmd, err)
	}

	profile, err := cpm.GetConnProfile(ConnProfileName)
	if err != nil {
		nmUsage(cmd, err)
	}

	conn, err := transport.NewConn(profile)
	if err != nil {
		nmUsage(cmd, err)
	}

	runner, err := protocol.NewCmdRunner(conn)
	if err != nil {
		nmUsage(cmd, err)
	}

	echo, err := protocol.NewEcho()
	if err != nil {
		nmUsage(cmd, err)
	}

	if len(args) != 1 {
		nmUsage(cmd, nil);
	}
	echo.Message = args[0]

	nmr, err := echo.EncodeWriteRequest()
	if err != nil {
		nmUsage(cmd, err)
	}

	if err := runner.WriteReq(nmr); err != nil {
		nmUsage(cmd, err)
	}

	rsp, err := runner.ReadResp()
	if err != nil {
		nmUsage(cmd, err)
	}

	ersp, err := protocol.DecodeEchoResponse(rsp.Data)
	if err != nil {
		nmUsage(cmd, err)
	}
	fmt.Println(ersp.Message)
}

func echoCmd() *cobra.Command {
	echoCmd := &cobra.Command{
		Use:   "echo",
		Short: "Send data to remote endpoint using newtmgr, and receive data back",
		Run:   echoRunCmd,
	}

	return echoCmd
}
<commit_msg>newtmgr; go formatting<commit_after>/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package cli

import (
	"fmt"

	"mynewt.apache.org/newt/newtmgr/config"
	"mynewt.apache.org/newt/newtmgr/protocol"
	"mynewt.apache.org/newt/newtmgr/transport"

	"github.com/spf13/cobra"
)

func echoRunCmd(cmd *cobra.Command, args []string) {
	cpm, err := config.NewConnProfileMgr()
	if err != nil {
		nmUsage(cmd, err)
	}

	profile, err := cpm.GetConnProfile(ConnProfileName)
	if err != nil {
		nmUsage(cmd, err)
	}

	conn, err := transport.NewConn(profile)
	if err != nil {
		nmUsage(cmd, err)
	}

	runner, err := protocol.NewCmdRunner(conn)
	if err != nil {
		nmUsage(cmd, err)
	}

	echo, err := protocol.NewEcho()
	if err != nil {
		nmUsage(cmd, err)
	}

	if len(args) != 1 {
		nmUsage(cmd, nil)
	}
	echo.Message = args[0]

	nmr, err := echo.EncodeWriteRequest()
	if err != nil {
		nmUsage(cmd, err)
	}

	if err := runner.WriteReq(nmr); err != nil {
		nmUsage(cmd, err)
	}

	rsp, err := runner.ReadResp()
	if err != nil {
		nmUsage(cmd, err)
	}

	ersp, err := protocol.DecodeEchoResponse(rsp.Data)
	if err != nil {
		nmUsage(cmd, err)
	}
	fmt.Println(ersp.Message)
}

func echoCmd() *cobra.Command {
	echoCmd := &cobra.Command{
		Use:   "echo",
		Short: "Send data to remote endpoint using newtmgr, and receive data back",
		Run:   echoRunCmd,
	}

	return echoCmd
}
<|endoftext|>


<commit_before>package orm

import (
	"testing"
)

func TestDeleteByID(t *testing.T) {
	//connect to Postgres
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	//check if the object is stored in the table and if the ID is populated after insert
	ormTest.DropTable()
	ormTest.CreateTable()
	dslTest := DSLTest{FieldString: "teststring", FieldInt: 123}
	err = ormTest.Save(&dslTest)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	id := dslTest.ID
	if id != 1 {
		t.Fatalf("\ndslTest.ID got:\t %v\nWant:\t\t\t 1\n", id)
	}

	n, err := ormTest.Delete().ByID(id)

	if n != 1 {
		t.Fatalf("\ndeleted got:\t %v\nWant:\t\t\t 1\n", n)
	}

	if err != nil {
		t.Fatalf("\nerr got:\t %v\nWant:\t\t\t nil\n", err)
	}

	dslTestFind, err := ormTest.Select().ByID(id)
	if dslTestFind != nil {
		t.Fatalf("\ndslTest got:\t %v\nWant:\t\t\t nil\n", dslTest)
	}

	if err.Error() != "sql: no rows in result set" {
		t.Fatalf("want: `sql: no rows in result set`, got: `%v`", err)
	}

	oldDeleteSQL := ormTest.deleteSQL
	ormTest.deleteSQL = "wrong-sql"
	n, err = ormTest.Delete().ByID(id)
	if err.Error() != "pq: syntax error at or near \"wrong\"" {
		t.Fatalf("want: `pq: syntax error at or near \"wrong\"`, got: `%v`", err)
	}
	ormTest.deleteSQL = oldDeleteSQL
}

func TestDeleteWhere(t *testing.T) {
	//connect to Postgres
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	//check if the object is stored in the table and if the ID is populated after insert
	ormTest.DropTable()
	ormTest.CreateTable()
	dslTest1 := DSLTest{FieldString: "teststring1", FieldInt: 111}
	err = ormTest.Save(&dslTest1)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTest2 := DSLTest{FieldString: "teststring2", FieldInt: 222}
	err = ormTest.Save(&dslTest2)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTestResults, err := ormTest.Select().Where("FieldString like 'teststring%'")
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if len(dslTestResults) != 2 {
		t.Fatalf("want: 2, got: %v", len(dslTestResults))
	}

	n, err := ormTest.Delete().Where("FieldString like 'teststring%'")
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if n != 2 {
		t.Fatalf("want: 2, got: %v", n)
	}

	oldDeleteSQL := ormTest.deleteSQL
	ormTest.deleteSQL = "wrong-sql"
	n, err = ormTest.Delete().Where("FieldString like 'teststring%'")
	if err.Error() != "pq: syntax error at or near \"wrong\"" {
		t.Fatalf("want: `pq: syntax error at or near \"wrong\"`, got: `%v`", err)
	}
	ormTest.deleteSQL = oldDeleteSQL
}
<commit_msg>Add unit test for DeleteAll<commit_after>package orm

import (
	"testing"
)

func TestDeleteByID(t *testing.T) {
	//connect to Postgres
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	//check if the object is stored in the table and if the ID is populated after insert
	ormTest.DropTable()
	ormTest.CreateTable()
	dslTest := DSLTest{FieldString: "teststring", FieldInt: 123}
	err = ormTest.Save(&dslTest)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	id := dslTest.ID
	if id != 1 {
		t.Fatalf("\ndslTest.ID got:\t %v\nWant:\t\t\t 1\n", id)
	}

	n, err := ormTest.Delete().ByID(id)

	if n != 1 {
		t.Fatalf("\ndeleted got:\t %v\nWant:\t\t\t 1\n", n)
	}

	if err != nil {
		t.Fatalf("\nerr got:\t %v\nWant:\t\t\t nil\n", err)
	}

	dslTestFind, err := ormTest.Select().ByID(id)
	if dslTestFind != nil {
		t.Fatalf("\ndslTest got:\t %v\nWant:\t\t\t nil\n", dslTest)
	}

	if err.Error() != "sql: no rows in result set" {
		t.Fatalf("want: `sql: no rows in result set`, got: `%v`", err)
	}

	oldDeleteSQL := ormTest.deleteSQL
	ormTest.deleteSQL = "wrong-sql"
	n, err = ormTest.Delete().ByID(id)
	if err.Error() != "pq: syntax error at or near \"wrong\"" {
		t.Fatalf("want: `pq: syntax error at or near \"wrong\"`, got: `%v`", err)
	}
	ormTest.deleteSQL = oldDeleteSQL
}

func TestDeleteWhere(t *testing.T) {
	//connect to Postgres
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	//check if the object is stored in the table and if the ID is populated after insert
	ormTest.DropTable()
	ormTest.CreateTable()
	dslTest1 := DSLTest{FieldString: "teststring1", FieldInt: 111}
	err = ormTest.Save(&dslTest1)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTest2 := DSLTest{FieldString: "teststring2", FieldInt: 222}
	err = ormTest.Save(&dslTest2)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTestResults, err := ormTest.Select().Where("FieldString like 'teststring%'")
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if len(dslTestResults) != 2 {
		t.Fatalf("want: 2, got: %v", len(dslTestResults))
	}

	n, err := ormTest.Delete().Where("FieldString like 'teststring%'")
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if n != 2 {
		t.Fatalf("want: 2, got: %v", n)
	}

	oldDeleteSQL := ormTest.deleteSQL
	ormTest.deleteSQL = "wrong-sql"
	n, err = ormTest.Delete().Where("FieldString like 'teststring%'")
	if err.Error() != "pq: syntax error at or near \"wrong\"" {
		t.Fatalf("want: `pq: syntax error at or near \"wrong\"`, got: `%v`", err)
	}
	ormTest.deleteSQL = oldDeleteSQL
}

func TestDeleteAll(t *testing.T) {
	//connect to Postgres
	orm, scream := ConnectToPostgres()
	if scream != nil {
		panic(scream)
	}

	ormTest, err := orm.NewHandler(DSLTest{})
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	//check if the object is stored in the table and if the ID is populated after insert
	ormTest.DropTable()
	ormTest.CreateTable()
	dslTest1 := DSLTest{FieldString: "teststring1", FieldInt: 111}
	err = ormTest.Save(&dslTest1)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTest2 := DSLTest{FieldString: "teststring2", FieldInt: 222}
	err = ormTest.Save(&dslTest2)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTest3 := DSLTest{FieldString: "teststring3", FieldInt: 333}
	err = ormTest.Save(&dslTest3)
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	dslTestResults, err := ormTest.Select().All()
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if len(dslTestResults) != 3 {
		t.Fatalf("want: 3, got: %v", len(dslTestResults))
	}

	n, err := ormTest.Delete().All()
	if err != nil {
		t.Fatalf("Err: %v", err)
	}

	if n != 3 {
		t.Fatalf("want: 3, got: %v", n)
	}

	oldDeleteSQL := ormTest.deleteSQL
	ormTest.deleteSQL = "wrong-sql"
	n, err = ormTest.Delete().All()
	if err.Error() != "pq: syntax error at or near \"wrong\"" {
		t.Fatalf("want: `pq: syntax error at or near \"wrong\"`, got: `%v`", err)
	}
	ormTest.deleteSQL = oldDeleteSQL
}
<|endoftext|>


<commit_before>package simpledb_test

import (
	"fmt"
	"os"

	"github.com/garyburd/redigo/redis"
	"github.com/northbright/simpledb"
)

func ExampleDB_Create() {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		fmt.Fprintf(os.Stderr, "redis.Dial() error: %v\n", err)
		return
	}
	defer c.Close()

	db := simpledb.Open("student")

	data := `{"name":"Bob Smith","tel":"13500135000"}`

	id, err := db.Create(c, data)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Create() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Create() ok: id: %v\n", id)

	// Output:
}

func ExampleDB_BatchCreate() {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		fmt.Fprintf(os.Stderr, "redis.Dial() error: %v\n", err)
		return
	}
	defer c.Close()

	db := simpledb.Open("student")

	data := []string{
		`{"name":"Frank Xu","tel":"13800138000"}`,
		`{"name":"Frank Wang","tel":"13600136000"}`,
		`{"name":"张三","tel":"13800138001"}`,
		`{"name":"李四","tel":"13800138002"}`,
		`{"name":"王大宝","tel":"13800138003"}`,
		`{"name":"王小宝","tel":"13800138003"}`,
	}

	ids, err := db.BatchCreate(c, data)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.BatchCreate() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.BatchCreate() ok: id: %v\n", ids)

	// Output:
}

func ExampleDB_Get() {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		fmt.Fprintf(os.Stderr, "redis.Dial() error: %v\n", err)
		return
	}
	defer c.Close()

	db := simpledb.Open("student")

	id := "1"
	data, err := db.Get(c, id)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Get() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Get() ok. id: %v, data: %v\n", id, data)

	// Output:
}

func ExampleDB_BatchGet() {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		fmt.Fprintf(os.Stderr, "redis.Dial() error: %v\n", err)
		return
	}
	defer c.Close()

	db := simpledb.Open("student")
	ids := []string{}

	// Search name matches Frank*
	ids, err = db.Search(c, `*"name":"Frank*"*`)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Search() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Search() ok: ids: %v\n", ids)

	dataMap, err := db.BatchGet(c, ids)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.BatchGet() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.BatchGet() ok.\n")
	for id, data := range dataMap {
		fmt.Fprintf(os.Stderr, "id: %v, data: %v\n", id, data)
	}

	// Output:
}

func ExampleDB_Search() {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		fmt.Fprintf(os.Stderr, "redis.Dial() error: %v\n", err)
		return
	}
	defer c.Close()

	db := simpledb.Open("student")
	ids := []string{}

	// Search name matches Frank*
	ids, err = db.Search(c, `*"name":"Frank*"*`)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Search() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Search() ok: ids: %v\n", ids)

	// Search name matches UTF8 string.
	ids, err = db.Search(c, `*"name":"王*宝"*`)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Search() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Search) ok: ids: %v\n", ids)

	// Test BatchGet()
	dataMap, err := db.BatchGet(c, ids)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.BatchGet() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.BatchGet() ok.\n")
	for k, v := range dataMap {
		fmt.Fprintf(os.Stderr, "id: %v, data: %v\n", k, v)
	}

	// Search tel matches 13800138003
	ids, err = db.Search(c, `*"tel":"13800138003"*`)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Search() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Search) ok: ids: %v\n", ids)

	// Search name matches Frank* and tel matches 13800138000.
	ids, err = db.Search(c, `*"name":"Frank*"*"tel":"13800138000"*`)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Search() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Search) ok: ids: %v\n", ids)

	// Output:
}
<commit_msg>Remove redundant search test case.<commit_after>package simpledb_test

import (
	"fmt"
	"os"

	"github.com/garyburd/redigo/redis"
	"github.com/northbright/simpledb"
)

func ExampleDB_Create() {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		fmt.Fprintf(os.Stderr, "redis.Dial() error: %v\n", err)
		return
	}
	defer c.Close()

	db := simpledb.Open("student")

	data := `{"name":"Bob Smith","tel":"13500135000"}`

	id, err := db.Create(c, data)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Create() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Create() ok: id: %v\n", id)

	// Output:
}

func ExampleDB_BatchCreate() {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		fmt.Fprintf(os.Stderr, "redis.Dial() error: %v\n", err)
		return
	}
	defer c.Close()

	db := simpledb.Open("student")

	data := []string{
		`{"name":"Frank Xu","tel":"13800138000"}`,
		`{"name":"Frank Wang","tel":"13600136000"}`,
		`{"name":"张三","tel":"13800138001"}`,
		`{"name":"李四","tel":"13800138002"}`,
		`{"name":"王大宝","tel":"13800138003"}`,
		`{"name":"王小宝","tel":"13800138003"}`,
	}

	ids, err := db.BatchCreate(c, data)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.BatchCreate() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.BatchCreate() ok: id: %v\n", ids)

	// Output:
}

func ExampleDB_Get() {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		fmt.Fprintf(os.Stderr, "redis.Dial() error: %v\n", err)
		return
	}
	defer c.Close()

	db := simpledb.Open("student")

	id := "1"
	data, err := db.Get(c, id)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Get() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Get() ok. id: %v, data: %v\n", id, data)

	// Output:
}

func ExampleDB_BatchGet() {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		fmt.Fprintf(os.Stderr, "redis.Dial() error: %v\n", err)
		return
	}
	defer c.Close()

	db := simpledb.Open("student")
	ids := []string{}

	// Search name matches Frank*
	ids, err = db.Search(c, `*"name":"Frank*"*`)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Search() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Search() ok: ids: %v\n", ids)

	dataMap, err := db.BatchGet(c, ids)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.BatchGet() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.BatchGet() ok.\n")
	for id, data := range dataMap {
		fmt.Fprintf(os.Stderr, "id: %v, data: %v\n", id, data)
	}

	// Output:
}

func ExampleDB_Search() {
	c, err := redis.Dial("tcp", ":6379")
	if err != nil {
		fmt.Fprintf(os.Stderr, "redis.Dial() error: %v\n", err)
		return
	}
	defer c.Close()

	db := simpledb.Open("student")
	ids := []string{}

	// Search name matches UTF8 string.
	ids, err = db.Search(c, `*"name":"王*宝"*`)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Search() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Search) ok: ids: %v\n", ids)

	// Test BatchGet()
	dataMap, err := db.BatchGet(c, ids)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.BatchGet() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.BatchGet() ok.\n")
	for k, v := range dataMap {
		fmt.Fprintf(os.Stderr, "id: %v, data: %v\n", k, v)
	}

	// Search name matches Frank* and tel matches 13800138000.
	ids, err = db.Search(c, `*"name":"Frank*"*"tel":"13800138000"*`)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.Search() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.Search) ok: ids: %v\n", ids)

	// Test BatchGet()
	dataMap, err = db.BatchGet(c, ids)
	if err != nil {
		fmt.Fprintf(os.Stderr, "db.BatchGet() error: %v\n", err)
		return
	}
	fmt.Fprintf(os.Stderr, "db.BatchGet() ok.\n")
	for k, v := range dataMap {
		fmt.Fprintf(os.Stderr, "id: %v, data: %v\n", k, v)
	}

	// Output:
}
<|endoftext|>


<commit_before>package protobuf

import (
	"fmt"

	alog "github.com/apex/log"
	proto "github.com/golang/protobuf/proto"
)

// Marshal is an implementation of a MarshalFunc specifically for use
// with this handler.  Although it accepts an empty interface type, it
// will only work with an apex.log.Entry type, and will panic if any
// other type is passed in.  Not that this mechanism also enforces the
// rule that any fields set must either be strings or satisfy the
// fmt.Stringer interface.
func Marshal(x interface{}) ([]byte, error) {
	var logEntry *alog.Entry
	var timestamp []byte
	var ok bool
	var fields map[string]string
	var stringer fmt.Stringer
	var str string

	if logEntry, ok = x.(*alog.Entry); !ok {
		return nil, fmt.Errorf("Attempted to marshal a type other than apex.log.Entry")
	}
	timestamp, err := logEntry.Timestamp.MarshalText()
	if err != nil {
		return nil, err
	}

	fields = make(map[string]string, len(logEntry.Fields))
	for key, value := range logEntry.Fields {
		// Enforcing the string or fmt.Stringer is a simple
		// way to ensure we can always push field data over
		// the line.  If we ever really want to reconstruct
		// types on the other side of NSQ then we'd probably
		// be just as well off wrapping gob.Encode and
		// gob.Decode as Marshal/Unmarshal.
		if str, ok = value.(string); ok {
			fields[key] = str
			continue
		}
		if stringer, ok = value.(fmt.Stringer); !ok {
			err := fmt.Errorf("Value for field %s is not a string, nor does it satisfy fmt.Stringer", key)
			return nil, err
		}
		fields[key] = stringer.String()
	}
	entry := &Entry{
		Level:     logEntry.Level.String(),
		Timestamp: timestamp,
		Message:   logEntry.Message,
		Fields:    fields,
	}
	return proto.Marshal(entry)
}

// Unmarshal is an implementation of a UnmarshalFunc specifically for
// unmarshalling an Entry back into apex.log.Entry.
func Unmarshal(data []byte, v interface{}) error {
	var entry *Entry
	var logEntry *alog.Entry
	var ok bool

	if logEntry, ok = v.(*alog.Entry); !ok {
		return fmt.Errorf("Attempted to unmarshal to a type other than apex.log.Entry")
	}

	entry = &Entry{}
	err := proto.Unmarshal(data, entry)
	if err != nil {
		return err
	}
	logEntry.Level = alog.MustParseLevel(entry.Level)
	logEntry.Timestamp.UnmarshalText(entry.Timestamp)
	logEntry.Message = entry.Message
	if logEntry.Fields == nil {
		logEntry.Fields = make(map[string]interface{}, len(entry.Fields))
	}
	for key, value := range entry.Fields {
		logEntry.Fields[key] = value
	}
	return nil
}
<commit_msg>Update comment to reflect returned Error rather than panic.<commit_after>package protobuf

import (
	"fmt"

	alog "github.com/apex/log"
	proto "github.com/golang/protobuf/proto"
)

// Marshal is an implementation of a MarshalFunc specifically for use
// with this handler.  Although it accepts an empty interface type, it
// will only work with an apex.log.Entry type, and will return an
// error if any other type is passed in.  Not that this mechanism also
// enforces the rule that any fields set must either be strings or
// satisfy the fmt.Stringer interface.
func Marshal(x interface{}) ([]byte, error) {
	var logEntry *alog.Entry
	var timestamp []byte
	var ok bool
	var fields map[string]string
	var stringer fmt.Stringer
	var str string

	if logEntry, ok = x.(*alog.Entry); !ok {
		return nil, fmt.Errorf("Attempted to marshal a type other than apex.log.Entry")
	}
	timestamp, err := logEntry.Timestamp.MarshalText()
	if err != nil {
		return nil, err
	}

	fields = make(map[string]string, len(logEntry.Fields))
	for key, value := range logEntry.Fields {
		// Enforcing the string or fmt.Stringer is a simple
		// way to ensure we can always push field data over
		// the line.  If we ever really want to reconstruct
		// types on the other side of NSQ then we'd probably
		// be just as well off wrapping gob.Encode and
		// gob.Decode as Marshal/Unmarshal.
		if str, ok = value.(string); ok {
			fields[key] = str
			continue
		}
		if stringer, ok = value.(fmt.Stringer); !ok {
			err := fmt.Errorf("Value for field %s is not a string, nor does it satisfy fmt.Stringer", key)
			return nil, err
		}
		fields[key] = stringer.String()
	}
	entry := &Entry{
		Level:     logEntry.Level.String(),
		Timestamp: timestamp,
		Message:   logEntry.Message,
		Fields:    fields,
	}
	return proto.Marshal(entry)
}

// Unmarshal is an implementation of a UnmarshalFunc specifically for
// unmarshalling an Entry back into apex.log.Entry.
func Unmarshal(data []byte, v interface{}) error {
	var entry *Entry
	var logEntry *alog.Entry
	var ok bool

	if logEntry, ok = v.(*alog.Entry); !ok {
		return fmt.Errorf("Attempted to unmarshal to a type other than apex.log.Entry")
	}

	entry = &Entry{}
	err := proto.Unmarshal(data, entry)
	if err != nil {
		return err
	}
	logEntry.Level = alog.MustParseLevel(entry.Level)
	logEntry.Timestamp.UnmarshalText(entry.Timestamp)
	logEntry.Message = entry.Message
	if logEntry.Fields == nil {
		logEntry.Fields = make(map[string]interface{}, len(entry.Fields))
	}
	for key, value := range entry.Fields {
		logEntry.Fields[key] = value
	}
	return nil
}
<|endoftext|>


<commit_before>package go500px

import "testing"

func TestGetPhotos(t *testing.T) {
	s := GetPhotos("8C6ImXPi4dKEnOWC3YwPnKQO1QIYbqaystDCsijC")
	if s == "" {
		t.Fatalf("Failed to get response")
	}
	t.Logf("Response: %s\n", s)
}
<commit_msg>Fix Test<commit_after>package go500px

import "testing"

func TestGetPhotos(t *testing.T) {
	photos, err := GetPhotos("8C6ImXPi4dKEnOWC3YwPnKQO1QIYbqaystDCsijC")
	if err != nil {
		t.Fatalf("Failed to execute request. Reason: %v", err)
	}

	if photos == nil {
		t.Fatalf("Failed to get response")
	}
}
<|endoftext|>