<commit_before>// Required to be main when building a shared library
package main

// typedef struct StartSessionReturn {
//     char *irmaQr;
//     char *token;
//     char *error;
// } StartSessionReturn;
//
// typedef struct HttpHeaders {
//     char **headerKeys;
//     char **headerValues;
//     int length;
// } HttpHeaders;
//
// typedef struct HandleProtocolMessageReturn {
//     int status;
//     char *body;
//     char *SessionResult;
// } HandleProtocolMessageReturn;
import "C"

import (
	"encoding/json"
	"unsafe"

	"github.com/go-errors/errors"
	"github.com/privacybydesign/irmago/server"
	"github.com/privacybydesign/irmago/internal/servercore"
)

var s *servercore.Server

//export Initialize
func Initialize(IrmaConfiguration *C.char) *C.char {
	if IrmaConfiguration == nil {
		return C.CString("Missing IrmaConfiguration.")
	}

	// Build the configuration structure
	conf := new(server.Configuration)
	err := json.Unmarshal([]byte(C.GoString(IrmaConfiguration)), conf)
	if err != nil {
		return C.CString(err.Error())
	}

	// Run the actual core function
	s, err = servercore.New(conf)

	// And properly return any errors
	if err == nil {
		return nil
	} else {
		return C.CString(err.Error())
	}
}

//export StartSession
func StartSession(requestString *C.char) C.struct_StartSessionReturn {
	// Create struct for return information
	var result C.struct_StartSessionReturn

	// Check that we have required input
	if requestString == nil {
		result.irmaQr = nil
		result.token = nil
		result.error = C.CString("Missing request string.")
		return result
	}

	// Run the actual core function
	qr, token, err := s.StartSession(C.GoString(requestString))

	// And properly return the result
	if err != nil {
		// return the core error
		result.irmaQr = nil
		result.token = nil
		result.error = C.CString(err.Error())
		return result
	}
	qrJson, err := json.Marshal(qr)
	if err != nil {
		// return encoding error
		result.irmaQr = nil
		result.token = nil
		result.error = C.CString(err.Error())
		return result
	}
	// return actual results
	result.irmaQr = C.CString(string(qrJson))
	result.token = C.CString(token)
	result.error = nil
	return result
}

//export GetSessionResult
func GetSessionResult(token *C.char) *C.char{
	// Check that we have required input
	if token == nil {
		return nil
	}

	// Run the actual core function
	result := s.GetSessionResult(C.GoString(token))

	// And properly return results
	if result == nil {
		// core error
		return nil
	}
	resultJson, err := json.Marshal(result)
	if err != nil {
		// encoding error
		return nil
	}
	return C.CString(string(resultJson))
}

//export GetRequest
func GetRequest(token *C.char) *C.char{
	// Check that we have required input
	if token == nil {
		return nil
	}

	// Run the core function
	result := s.GetRequest(C.GoString(token))

	// And properly return results
	if result == nil {
		// core error
		return nil
	}
	resultJson, err := json.Marshal(result)
	if err != nil {
		// encoding error
		return nil
	}
	return C.CString(string(resultJson))
}

//export CancelSession
func CancelSession(token *C.char) *C.char{
	// Check that we have required input
	if token == nil {
		return C.CString("Missing token.")
	}

	// Run the core function
	err := s.CancelSession(C.GoString(token))

	if err != nil {
		return C.CString(err.Error())
	}
	return nil
}

func convertHeaders(headers C.struct_HttpHeaders) (map[string][]string, error) {
	// Make the two arrays accessible via slices (https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices)
	headerKeys := (*[1<<30]*C.char)(unsafe.Pointer(headers.headerKeys))[:headers.length:headers.length]
	headerValues := (*[1<<30]*C.char)(unsafe.Pointer(headers.headerValues))[:headers.length:headers.length]

	// Check and convert the input
	result := map[string][]string{}
	for i := 0; i<int(headers.length); i++ {
		if headerKeys[i] == nil || headerValues[i] == nil {
			return map[string][]string{}, errors.New("Missing header key or value")
		}
		key := C.GoString(headerKeys[i])
		value := C.GoString(headerValues[i])
		result[key] = append(result[key], value)
	}

	return result, nil
}

//export HandleProtocolMessage
func HandleProtocolMessage(path *C.char, method *C.char, headers C.struct_HttpHeaders, message *C.char) C.struct_HandleProtocolMessageReturn {
	// Space for result
	var result C.struct_HandleProtocolMessageReturn

	// Check input
	if path == nil || method == nil || message == nil {
		result.status = 500
		result.body = C.CString("")
		result.SessionResult = nil
		return result
	}

	// Extract headers
	headerMap, err := convertHeaders(headers)
	if err != nil {
		result.status = 500
		result.body = C.CString("")
		result.SessionResult = nil
		return result
	}

	// Prepare return values
	status, body, session := s.HandleProtocolMessage(C.GoString(path), C.GoString(method), headerMap, []byte(C.GoString(message)))
	if session == nil {
		result.SessionResult = nil
	} else {
		// Convert SessionResult to JSON for return
		sessionJson, err := json.Marshal(session)
		if err != nil {
			result.status = 500
			result.body = C.CString("")
			result.SessionResult = nil
			return result
		}
		result.SessionResult = C.CString(string(sessionJson))
	}
	result.status = C.int(status)
	result.body = C.CString(string(body))
	return result
}

// Required to build a shared library
func main() {}
<commit_msg>Format code in irmac with goimports<commit_after>// Required to be main when building a shared library
package main

// typedef struct StartSessionReturn {
//     char *irmaQr;
//     char *token;
//     char *error;
// } StartSessionReturn;
//
// typedef struct HttpHeaders {
//     char **headerKeys;
//     char **headerValues;
//     int length;
// } HttpHeaders;
//
// typedef struct HandleProtocolMessageReturn {
//     int status;
//     char *body;
//     char *SessionResult;
// } HandleProtocolMessageReturn;
import "C"

import (
	"encoding/json"
	"unsafe"

	"github.com/go-errors/errors"
	"github.com/privacybydesign/irmago/internal/servercore"
	"github.com/privacybydesign/irmago/server"
)

var s *servercore.Server

//export Initialize
func Initialize(IrmaConfiguration *C.char) *C.char {
	if IrmaConfiguration == nil {
		return C.CString("Missing IrmaConfiguration.")
	}

	// Build the configuration structure
	conf := new(server.Configuration)
	err := json.Unmarshal([]byte(C.GoString(IrmaConfiguration)), conf)
	if err != nil {
		return C.CString(err.Error())
	}

	// Run the actual core function
	s, err = servercore.New(conf)

	// And properly return any errors
	if err == nil {
		return nil
	} else {
		return C.CString(err.Error())
	}
}

//export StartSession
func StartSession(requestString *C.char) C.struct_StartSessionReturn {
	// Create struct for return information
	var result C.struct_StartSessionReturn

	// Check that we have required input
	if requestString == nil {
		result.irmaQr = nil
		result.token = nil
		result.error = C.CString("Missing request string.")
		return result
	}

	// Run the actual core function
	qr, token, err := s.StartSession(C.GoString(requestString))

	// And properly return the result
	if err != nil {
		// return the core error
		result.irmaQr = nil
		result.token = nil
		result.error = C.CString(err.Error())
		return result
	}
	qrJson, err := json.Marshal(qr)
	if err != nil {
		// return encoding error
		result.irmaQr = nil
		result.token = nil
		result.error = C.CString(err.Error())
		return result
	}
	// return actual results
	result.irmaQr = C.CString(string(qrJson))
	result.token = C.CString(token)
	result.error = nil
	return result
}

//export GetSessionResult
func GetSessionResult(token *C.char) *C.char {
	// Check that we have required input
	if token == nil {
		return nil
	}

	// Run the actual core function
	result := s.GetSessionResult(C.GoString(token))

	// And properly return results
	if result == nil {
		// core error
		return nil
	}
	resultJson, err := json.Marshal(result)
	if err != nil {
		// encoding error
		return nil
	}
	return C.CString(string(resultJson))
}

//export GetRequest
func GetRequest(token *C.char) *C.char {
	// Check that we have required input
	if token == nil {
		return nil
	}

	// Run the core function
	result := s.GetRequest(C.GoString(token))

	// And properly return results
	if result == nil {
		// core error
		return nil
	}
	resultJson, err := json.Marshal(result)
	if err != nil {
		// encoding error
		return nil
	}
	return C.CString(string(resultJson))
}

//export CancelSession
func CancelSession(token *C.char) *C.char {
	// Check that we have required input
	if token == nil {
		return C.CString("Missing token.")
	}

	// Run the core function
	err := s.CancelSession(C.GoString(token))

	if err != nil {
		return C.CString(err.Error())
	}
	return nil
}

func convertHeaders(headers C.struct_HttpHeaders) (map[string][]string, error) {
	// Make the two arrays accessible via slices (https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices)
	headerKeys := (*[1 << 30]*C.char)(unsafe.Pointer(headers.headerKeys))[:headers.length:headers.length]
	headerValues := (*[1 << 30]*C.char)(unsafe.Pointer(headers.headerValues))[:headers.length:headers.length]

	// Check and convert the input
	result := map[string][]string{}
	for i := 0; i < int(headers.length); i++ {
		if headerKeys[i] == nil || headerValues[i] == nil {
			return map[string][]string{}, errors.New("Missing header key or value")
		}
		key := C.GoString(headerKeys[i])
		value := C.GoString(headerValues[i])
		result[key] = append(result[key], value)
	}

	return result, nil
}

//export HandleProtocolMessage
func HandleProtocolMessage(path *C.char, method *C.char, headers C.struct_HttpHeaders, message *C.char) C.struct_HandleProtocolMessageReturn {
	// Space for result
	var result C.struct_HandleProtocolMessageReturn

	// Check input
	if path == nil || method == nil || message == nil {
		result.status = 500
		result.body = C.CString("")
		result.SessionResult = nil
		return result
	}

	// Extract headers
	headerMap, err := convertHeaders(headers)
	if err != nil {
		result.status = 500
		result.body = C.CString("")
		result.SessionResult = nil
		return result
	}

	// Prepare return values
	status, body, session := s.HandleProtocolMessage(C.GoString(path), C.GoString(method), headerMap, []byte(C.GoString(message)))
	if session == nil {
		result.SessionResult = nil
	} else {
		// Convert SessionResult to JSON for return
		sessionJson, err := json.Marshal(session)
		if err != nil {
			result.status = 500
			result.body = C.CString("")
			result.SessionResult = nil
			return result
		}
		result.SessionResult = C.CString(string(sessionJson))
	}
	result.status = C.int(status)
	result.body = C.CString(string(body))
	return result
}

// Required to build a shared library
func main() {}
<|endoftext|>


<commit_before>package promclient

import (
	"github.com/jacksontj/promxy/promhttputil"
	"github.com/mailru/easyjson/jlexer"
)

type DataResult struct {
	Status    promhttputil.Status    `json:"status"`
	Data      promhttputil.QueryData `json:"data"`
	ErrorType promhttputil.ErrorType `json:"errorType,omitempty"`
	Error     string                 `json:"error,omitempty"`
}

func (s *DataResult) Merge(o *DataResult) error {
	result, err := promhttputil.MergeValues(s.Data.Result, o.Data.Result)
	if err != nil {
		return err
	}
	s.Data.Result = result
	return nil
}

// UnmarshalJSON supports json.Unmarshaler interface
func (v *DataResult) UnmarshalJSON(data []byte) error {
	r := jlexer.Lexer{Data: data}
	v.UnmarshalEasyJSON(&r)
	return r.Error()
}

// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (out *DataResult) UnmarshalEasyJSON(in *jlexer.Lexer) {
	isTopLevel := in.IsStart()
	if in.IsNull() {
		if isTopLevel {
			in.Consumed()
		}
		in.Skip()
		return
	}
	in.Delim('{')
	for !in.IsDelim('}') {
		key := in.UnsafeString()
		in.WantColon()
		if in.IsNull() {
			in.Skip()
			in.WantComma()
			continue
		}
		switch key {
		case "status":
			out.Status = promhttputil.Status(in.String())
		case "data":
			in.AddError(out.Data.UnmarshalJSON(in.Raw()))
		case "errorType":
			out.ErrorType = promhttputil.ErrorType(in.String())
		case "error":
			out.Error = string(in.String())
		default:
			in.SkipRecursive()
		}
		in.WantComma()
	}
	in.Delim('}')
	if isTopLevel {
		in.Consumed()
	}
}
<commit_msg>Remove unused method<commit_after>package promclient

import (
	"github.com/jacksontj/promxy/promhttputil"
	"github.com/mailru/easyjson/jlexer"
)

type DataResult struct {
	Status    promhttputil.Status    `json:"status"`
	Data      promhttputil.QueryData `json:"data"`
	ErrorType promhttputil.ErrorType `json:"errorType,omitempty"`
	Error     string                 `json:"error,omitempty"`
}

// UnmarshalJSON supports json.Unmarshaler interface
func (v *DataResult) UnmarshalJSON(data []byte) error {
	r := jlexer.Lexer{Data: data}
	v.UnmarshalEasyJSON(&r)
	return r.Error()
}

// UnmarshalEasyJSON supports easyjson.Unmarshaler interface
func (out *DataResult) UnmarshalEasyJSON(in *jlexer.Lexer) {
	isTopLevel := in.IsStart()
	if in.IsNull() {
		if isTopLevel {
			in.Consumed()
		}
		in.Skip()
		return
	}
	in.Delim('{')
	for !in.IsDelim('}') {
		key := in.UnsafeString()
		in.WantColon()
		if in.IsNull() {
			in.Skip()
			in.WantComma()
			continue
		}
		switch key {
		case "status":
			out.Status = promhttputil.Status(in.String())
		case "data":
			in.AddError(out.Data.UnmarshalJSON(in.Raw()))
		case "errorType":
			out.ErrorType = promhttputil.ErrorType(in.String())
		case "error":
			out.Error = string(in.String())
		default:
			in.SkipRecursive()
		}
		in.WantComma()
	}
	in.Delim('}')
	if isTopLevel {
		in.Consumed()
	}
}
<|endoftext|>


<commit_before>package boilingcore

import (
	"bufio"
	"bytes"
	"fmt"
	"go/format"
	"io/ioutil"
	"path/filepath"
	"regexp"
	"strconv"
	"text/template"

	"github.com/pkg/errors"
	"github.com/volatiletech/sqlboiler/importers"
)

var noEditDisclaimer = []byte(`// Code generated by SQLBoiler (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.

`)

var (
	// templateByteBuffer is re-used by all template construction to avoid
	// allocating more memory than is needed. This will later be a problem for
	// concurrency, address it then.
	templateByteBuffer = &bytes.Buffer{}

	rgxRemoveNumberedPrefix = regexp.MustCompile(`[0-9]+_`)
	rgxSyntaxError          = regexp.MustCompile(`(\d+):\d+: `)

	testHarnessWriteFile = ioutil.WriteFile
)

// generateOutput builds the file output and sends it to outHandler for saving
func generateOutput(state *State, data *templateData) error {
	return executeTemplates(executeTemplateData{
		state:                state,
		data:                 data,
		templates:            state.Templates,
		importSet:            state.Config.Imports.All,
		combineImportsOnType: true,
		fileSuffix:           ".go",
	})
}

// generateTestOutput builds the test file output and sends it to outHandler for saving
func generateTestOutput(state *State, data *templateData) error {
	return executeTemplates(executeTemplateData{
		state:                state,
		data:                 data,
		templates:            state.TestTemplates,
		importSet:            state.Config.Imports.Test,
		combineImportsOnType: false,
		fileSuffix:           "_test.go",
	})
}

// generateSingletonOutput processes the templates that should only be run
// one time.
func generateSingletonOutput(state *State, data *templateData) error {
	return executeSingletonTemplates(executeTemplateData{
		state:          state,
		data:           data,
		templates:      state.SingletonTemplates,
		importNamedSet: state.Config.Imports.Singleton,
		fileSuffix:     ".go",
	})
}

// generateSingletonTestOutput processes the templates that should only be run
// one time.
func generateSingletonTestOutput(state *State, data *templateData) error {
	return executeSingletonTemplates(executeTemplateData{
		state:          state,
		data:           data,
		templates:      state.SingletonTestTemplates,
		importNamedSet: state.Config.Imports.TestSingleton,
		fileSuffix:     ".go",
	})
}

type executeTemplateData struct {
	state *State
	data  *templateData

	templates *templateList

	importSet      importers.Set
	importNamedSet importers.Map

	combineImportsOnType bool

	fileSuffix string
}

func executeTemplates(e executeTemplateData) error {
	if e.data.Table.IsJoinTable {
		return nil
	}

	out := templateByteBuffer
	out.Reset()

	var imps importers.Set
	imps.Standard = e.importSet.Standard
	imps.ThirdParty = e.importSet.ThirdParty
	if e.combineImportsOnType {
		colTypes := make([]string, len(e.data.Table.Columns))
		for i, ct := range e.data.Table.Columns {
			colTypes[i] = ct.Type
		}

		imps = importers.AddTypeImports(imps, e.state.Config.Imports.BasedOnType, colTypes)
	}

	writeFileDisclaimer(out)
	writePackageName(out, e.state.Config.PkgName)
	writeImports(out, imps)

	for _, tplName := range e.templates.Templates() {
		if err := executeTemplate(out, e.templates.Template, tplName, e.data); err != nil {
			return err
		}
	}

	fName := e.data.Table.Name + e.fileSuffix
	if err := writeFile(e.state.Config.OutFolder, fName, out); err != nil {
		return err
	}

	return nil
}

func executeSingletonTemplates(e executeTemplateData) error {
	if e.data.Table.IsJoinTable {
		return nil
	}

	out := templateByteBuffer
	for _, tplName := range e.templates.Templates() {
		out.Reset()

		fName := tplName
		ext := filepath.Ext(fName)
		fName = rgxRemoveNumberedPrefix.ReplaceAllString(fName[:len(fName)-len(ext)], "")

		imps := importers.Set{
			Standard:   e.importNamedSet[fName].Standard,
			ThirdParty: e.importNamedSet[fName].ThirdParty,
		}

		writeFileDisclaimer(out)
		writePackageName(out, e.state.Config.PkgName)
		writeImports(out, imps)

		if err := executeTemplate(out, e.templates.Template, tplName, e.data); err != nil {
			return err
		}

		if err := writeFile(e.state.Config.OutFolder, fName+e.fileSuffix, out); err != nil {
			return err
		}
	}

	return nil
}

// writeFileDisclaimer writes the disclaimer at the top with a trailing
// newline so the package name doesn't get attached to it.
func writeFileDisclaimer(out *bytes.Buffer) {
	_, _ = out.Write(noEditDisclaimer)
}

// writePackageName writes the package name correctly, ignores errors
// since it's to the concrete buffer type which produces none
func writePackageName(out *bytes.Buffer, pkgName string) {
	_, _ = fmt.Fprintf(out, "package %s\n\n", pkgName)
}

// writeImports writes the package imports correctly, ignores errors
// since it's to the concrete buffer type which produces none
func writeImports(out *bytes.Buffer, imps importers.Set) {
	if impStr := imps.Format(); len(impStr) > 0 {
		_, _ = fmt.Fprintf(out, "%s\n", impStr)
	}
}

// writeFile writes to the given folder and filename, formatting the buffer
// given.
func writeFile(outFolder string, fileName string, input *bytes.Buffer) error {
	byt, err := formatBuffer(input)
	if err != nil {
		return err
	}

	path := filepath.Join(outFolder, fileName)
	if err = testHarnessWriteFile(path, byt, 0666); err != nil {
		return errors.Wrapf(err, "failed to write output file %s", path)
	}

	return nil
}

// executeTemplate takes a template and returns the output of the template
// execution.
func executeTemplate(buf *bytes.Buffer, t *template.Template, name string, data *templateData) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = errors.Errorf("failed to execute template: %s\npanic: %+v\n", name, r)
		}
	}()

	if err := t.ExecuteTemplate(buf, name, data); err != nil {
		return errors.Wrapf(err, "failed to execute template: %s", name)
	}
	return nil
}

func formatBuffer(buf *bytes.Buffer) ([]byte, error) {
	output, err := format.Source(buf.Bytes())
	if err == nil {
		return output, nil
	}

	matches := rgxSyntaxError.FindStringSubmatch(err.Error())
	if matches == nil {
		return nil, errors.Wrap(err, "failed to format template")
	}

	lineNum, _ := strconv.Atoi(matches[1])
	scanner := bufio.NewScanner(buf)
	errBuf := &bytes.Buffer{}
	line := 1
	for ; scanner.Scan(); line++ {
		if delta := line - lineNum; delta < -5 || delta > 5 {
			continue
		}

		if line == lineNum {
			errBuf.WriteString(">>>> ")
		} else {
			fmt.Fprintf(errBuf, "% 4d ", line)
		}
		errBuf.Write(scanner.Bytes())
		errBuf.WriteByte('\n')
	}

	return nil, errors.Wrapf(err, "failed to format template\n\n%s\n", errBuf.Bytes())
}
<commit_msg>Fix bug in template generation<commit_after>package boilingcore

import (
	"bufio"
	"bytes"
	"fmt"
	"go/format"
	"io/ioutil"
	"path/filepath"
	"regexp"
	"strconv"
	"text/template"

	"github.com/pkg/errors"
	"github.com/volatiletech/sqlboiler/importers"
)

var noEditDisclaimer = []byte(`// Code generated by SQLBoiler (https://github.com/volatiletech/sqlboiler). DO NOT EDIT.
// This file is meant to be re-generated in place and/or deleted at any time.

`)

var (
	// templateByteBuffer is re-used by all template construction to avoid
	// allocating more memory than is needed. This will later be a problem for
	// concurrency, address it then.
	templateByteBuffer = &bytes.Buffer{}

	rgxRemoveNumberedPrefix = regexp.MustCompile(`^[0-9]+_`)
	rgxSyntaxError          = regexp.MustCompile(`(\d+):\d+: `)

	testHarnessWriteFile = ioutil.WriteFile
)

// generateOutput builds the file output and sends it to outHandler for saving
func generateOutput(state *State, data *templateData) error {
	return executeTemplates(executeTemplateData{
		state:                state,
		data:                 data,
		templates:            state.Templates,
		importSet:            state.Config.Imports.All,
		combineImportsOnType: true,
		fileSuffix:           ".go",
	})
}

// generateTestOutput builds the test file output and sends it to outHandler for saving
func generateTestOutput(state *State, data *templateData) error {
	return executeTemplates(executeTemplateData{
		state:                state,
		data:                 data,
		templates:            state.TestTemplates,
		importSet:            state.Config.Imports.Test,
		combineImportsOnType: false,
		fileSuffix:           "_test.go",
	})
}

// generateSingletonOutput processes the templates that should only be run
// one time.
func generateSingletonOutput(state *State, data *templateData) error {
	return executeSingletonTemplates(executeTemplateData{
		state:          state,
		data:           data,
		templates:      state.SingletonTemplates,
		importNamedSet: state.Config.Imports.Singleton,
		fileSuffix:     ".go",
	})
}

// generateSingletonTestOutput processes the templates that should only be run
// one time.
func generateSingletonTestOutput(state *State, data *templateData) error {
	return executeSingletonTemplates(executeTemplateData{
		state:          state,
		data:           data,
		templates:      state.SingletonTestTemplates,
		importNamedSet: state.Config.Imports.TestSingleton,
		fileSuffix:     ".go",
	})
}

type executeTemplateData struct {
	state *State
	data  *templateData

	templates *templateList

	importSet      importers.Set
	importNamedSet importers.Map

	combineImportsOnType bool

	fileSuffix string
}

func executeTemplates(e executeTemplateData) error {
	if e.data.Table.IsJoinTable {
		return nil
	}

	out := templateByteBuffer
	out.Reset()

	var imps importers.Set
	imps.Standard = e.importSet.Standard
	imps.ThirdParty = e.importSet.ThirdParty
	if e.combineImportsOnType {
		colTypes := make([]string, len(e.data.Table.Columns))
		for i, ct := range e.data.Table.Columns {
			colTypes[i] = ct.Type
		}

		imps = importers.AddTypeImports(imps, e.state.Config.Imports.BasedOnType, colTypes)
	}

	writeFileDisclaimer(out)
	writePackageName(out, e.state.Config.PkgName)
	writeImports(out, imps)

	for _, tplName := range e.templates.Templates() {
		if err := executeTemplate(out, e.templates.Template, tplName, e.data); err != nil {
			return err
		}
	}

	fName := e.data.Table.Name + e.fileSuffix
	if err := writeFile(e.state.Config.OutFolder, fName, out); err != nil {
		return err
	}

	return nil
}

func executeSingletonTemplates(e executeTemplateData) error {
	if e.data.Table.IsJoinTable {
		return nil
	}

	out := templateByteBuffer
	for _, tplName := range e.templates.Templates() {
		out.Reset()

		fName := tplName
		ext := filepath.Ext(fName)
		fName = rgxRemoveNumberedPrefix.ReplaceAllString(fName[:len(fName)-len(ext)], "")

		imps := importers.Set{
			Standard:   e.importNamedSet[fName].Standard,
			ThirdParty: e.importNamedSet[fName].ThirdParty,
		}

		writeFileDisclaimer(out)
		writePackageName(out, e.state.Config.PkgName)
		writeImports(out, imps)

		if err := executeTemplate(out, e.templates.Template, tplName, e.data); err != nil {
			return err
		}

		if err := writeFile(e.state.Config.OutFolder, fName+e.fileSuffix, out); err != nil {
			return err
		}
	}

	return nil
}

// writeFileDisclaimer writes the disclaimer at the top with a trailing
// newline so the package name doesn't get attached to it.
func writeFileDisclaimer(out *bytes.Buffer) {
	_, _ = out.Write(noEditDisclaimer)
}

// writePackageName writes the package name correctly, ignores errors
// since it's to the concrete buffer type which produces none
func writePackageName(out *bytes.Buffer, pkgName string) {
	_, _ = fmt.Fprintf(out, "package %s\n\n", pkgName)
}

// writeImports writes the package imports correctly, ignores errors
// since it's to the concrete buffer type which produces none
func writeImports(out *bytes.Buffer, imps importers.Set) {
	if impStr := imps.Format(); len(impStr) > 0 {
		_, _ = fmt.Fprintf(out, "%s\n", impStr)
	}
}

// writeFile writes to the given folder and filename, formatting the buffer
// given.
func writeFile(outFolder string, fileName string, input *bytes.Buffer) error {
	byt, err := formatBuffer(input)
	if err != nil {
		return err
	}

	path := filepath.Join(outFolder, fileName)
	if err = testHarnessWriteFile(path, byt, 0666); err != nil {
		return errors.Wrapf(err, "failed to write output file %s", path)
	}

	return nil
}

// executeTemplate takes a template and returns the output of the template
// execution.
func executeTemplate(buf *bytes.Buffer, t *template.Template, name string, data *templateData) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = errors.Errorf("failed to execute template: %s\npanic: %+v\n", name, r)
		}
	}()

	if err := t.ExecuteTemplate(buf, name, data); err != nil {
		return errors.Wrapf(err, "failed to execute template: %s", name)
	}
	return nil
}

func formatBuffer(buf *bytes.Buffer) ([]byte, error) {
	output, err := format.Source(buf.Bytes())
	if err == nil {
		return output, nil
	}

	matches := rgxSyntaxError.FindStringSubmatch(err.Error())
	if matches == nil {
		return nil, errors.Wrap(err, "failed to format template")
	}

	lineNum, _ := strconv.Atoi(matches[1])
	scanner := bufio.NewScanner(buf)
	errBuf := &bytes.Buffer{}
	line := 1
	for ; scanner.Scan(); line++ {
		if delta := line - lineNum; delta < -5 || delta > 5 {
			continue
		}

		if line == lineNum {
			errBuf.WriteString(">>>> ")
		} else {
			fmt.Fprintf(errBuf, "% 4d ", line)
		}
		errBuf.Write(scanner.Bytes())
		errBuf.WriteByte('\n')
	}

	return nil, errors.Wrapf(err, "failed to format template\n\n%s\n", errBuf.Bytes())
}
<|endoftext|>


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

package walk

import (
	"syscall"
	"unsafe"
)

import . "github.com/lxn/go-winapi"

const (
	DlgCmdOK       = IDOK
	DlgCmdCancel   = IDCANCEL
	DlgCmdAbort    = IDABORT
	DlgCmdRetry    = IDRETRY
	DlgCmdIgnore   = IDIGNORE
	DlgCmdYes      = IDYES
	DlgCmdNo       = IDNO
	DlgCmdClose    = IDCLOSE
	DlgCmdHelp     = IDHELP
	DlgCmdTryAgain = IDTRYAGAIN
	DlgCmdContinue = IDCONTINUE
	DlgCmdTimeout  = IDTIMEOUT
)

const dialogWindowClass = `\o/ Walk_Dialog_Class \o/`

var dialogWindowClassRegistered bool

type dialogish interface {
	DefaultButton() *PushButton
	CancelButton() *PushButton
}

type Dialog struct {
	TopLevelWindow
	result               int
	defaultButton        *PushButton
	cancelButton         *PushButton
	centerInOwnerWhenRun bool
}

func NewDialog(owner RootWidget) (*Dialog, error) {
	ensureRegisteredWindowClass(dialogWindowClass, &dialogWindowClassRegistered)

	dlg := &Dialog{
		TopLevelWindow: TopLevelWindow{
			owner: owner,
		},
	}

	if err := initWidget(
		dlg,
		owner,
		dialogWindowClass,
		WS_CAPTION|WS_SYSMENU|WS_THICKFRAME,
		WS_EX_DLGMODALFRAME); err != nil {
		return nil, err
	}

	dlg.centerInOwnerWhenRun = owner != nil

	dlg.children = newWidgetList(dlg)

	// This forces display of focus rectangles, as soon as the user starts to type.
	SendMessage(dlg.hWnd, WM_CHANGEUISTATE, UIS_INITIALIZE, 0)

	dlg.result = DlgCmdClose

	return dlg, nil
}

func (dlg *Dialog) DefaultButton() *PushButton {
	return dlg.defaultButton
}

func (dlg *Dialog) SetDefaultButton(button *PushButton) error {
	if button != nil && !IsChild(dlg.hWnd, button.hWnd) {
		return newError("not a descendant of the dialog")
	}

	succeeded := false
	if dlg.defaultButton != nil {
		if err := dlg.defaultButton.setAndClearStyleBits(BS_PUSHBUTTON, BS_DEFPUSHBUTTON); err != nil {
			return err
		}
		defer func() {
			if !succeeded {
				dlg.defaultButton.setAndClearStyleBits(BS_DEFPUSHBUTTON, BS_PUSHBUTTON)
			}
		}()
	}

	if button != nil {
		if err := button.setAndClearStyleBits(BS_DEFPUSHBUTTON, BS_PUSHBUTTON); err != nil {
			return err
		}
	}

	dlg.defaultButton = button

	succeeded = true

	return nil
}

func (dlg *Dialog) CancelButton() *PushButton {
	return dlg.cancelButton
}

func (dlg *Dialog) SetCancelButton(button *PushButton) error {
	if button != nil && !IsChild(dlg.hWnd, button.hWnd) {
		return newError("not a descendant of the dialog")
	}

	dlg.cancelButton = button

	return nil
}

func (dlg *Dialog) Accept() {
	dlg.Close(DlgCmdOK)
}

func (dlg *Dialog) Cancel() {
	dlg.Close(DlgCmdCancel)
}

func (dlg *Dialog) Close(result int) {
	dlg.result = result

	dlg.TopLevelWindow.Close()
}

func firstFocusableDescendantCallback(hwnd HWND, lParam uintptr) uintptr {
	widget := widgetFromHWND(hwnd)

	if widget == nil || !widget.Visible() || !widget.Enabled() {
		return 1
	}

	style := uint(GetWindowLong(hwnd, GWL_STYLE))
	// FIXME: Ugly workaround for NumberEdit
	_, isTextSelectable := widget.(textSelectable)
	if style&WS_TABSTOP > 0 || isTextSelectable {
		hwndPtr := (*HWND)(unsafe.Pointer(lParam))
		*hwndPtr = hwnd
		return 0
	}

	return 1
}

var firstFocusableDescendantCallbackPtr = syscall.NewCallback(firstFocusableDescendantCallback)

func firstFocusableDescendant(container Container) Widget {
	var hwnd HWND

	EnumChildWindows(container.BaseWidget().hWnd, firstFocusableDescendantCallbackPtr, uintptr(unsafe.Pointer(&hwnd)))

	return widgetFromHWND(hwnd)
}

type textSelectable interface {
	SetTextSelection(start, end int)
}

func (dlg *Dialog) focusFirstCandidateDescendant() {
	widget := firstFocusableDescendant(dlg)
	if widget == nil {
		return
	}

	if err := widget.SetFocus(); err != nil {
		return
	}

	if textSel, ok := widget.(textSelectable); ok {
		textSel.SetTextSelection(0, -1)
	}
}

func (dlg *Dialog) Show() {
	dlg.TopLevelWindow.Show()

	dlg.focusFirstCandidateDescendant()
}

func (dlg *Dialog) Run() int {
	if dlg.owner != nil {
		ob := dlg.owner.Bounds()
		b := dlg.Bounds()
		if dlg.centerInOwnerWhenRun {
			dlg.SetBounds(Rectangle{
				ob.X + (ob.Width-b.Width)/2,
				ob.Y + (ob.Height-b.Height)/2,
				b.Width,
				b.Height,
			})
		}
	}

	dlg.Show()

	if dlg.owner != nil {
		dlg.owner.SetEnabled(false)
	}

	dlg.TopLevelWindow.Run()

	return dlg.result
}
<commit_msg>Make sure standalone dialogs start up with appropriate size.<commit_after>// Copyright 2010 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package walk

import (
	"syscall"
	"unsafe"
)

import . "github.com/lxn/go-winapi"

const (
	DlgCmdOK       = IDOK
	DlgCmdCancel   = IDCANCEL
	DlgCmdAbort    = IDABORT
	DlgCmdRetry    = IDRETRY
	DlgCmdIgnore   = IDIGNORE
	DlgCmdYes      = IDYES
	DlgCmdNo       = IDNO
	DlgCmdClose    = IDCLOSE
	DlgCmdHelp     = IDHELP
	DlgCmdTryAgain = IDTRYAGAIN
	DlgCmdContinue = IDCONTINUE
	DlgCmdTimeout  = IDTIMEOUT
)

const dialogWindowClass = `\o/ Walk_Dialog_Class \o/`

var dialogWindowClassRegistered bool

type dialogish interface {
	DefaultButton() *PushButton
	CancelButton() *PushButton
}

type Dialog struct {
	TopLevelWindow
	result               int
	defaultButton        *PushButton
	cancelButton         *PushButton
	centerInOwnerWhenRun bool
}

func NewDialog(owner RootWidget) (*Dialog, error) {
	ensureRegisteredWindowClass(dialogWindowClass, &dialogWindowClassRegistered)

	dlg := &Dialog{
		TopLevelWindow: TopLevelWindow{
			owner: owner,
		},
	}

	if err := initWidget(
		dlg,
		owner,
		dialogWindowClass,
		WS_CAPTION|WS_SYSMENU|WS_THICKFRAME,
		WS_EX_DLGMODALFRAME); err != nil {
		return nil, err
	}

	dlg.centerInOwnerWhenRun = owner != nil

	dlg.children = newWidgetList(dlg)

	// This forces display of focus rectangles, as soon as the user starts to type.
	SendMessage(dlg.hWnd, WM_CHANGEUISTATE, UIS_INITIALIZE, 0)

	dlg.result = DlgCmdClose

	return dlg, nil
}

func (dlg *Dialog) DefaultButton() *PushButton {
	return dlg.defaultButton
}

func (dlg *Dialog) SetDefaultButton(button *PushButton) error {
	if button != nil && !IsChild(dlg.hWnd, button.hWnd) {
		return newError("not a descendant of the dialog")
	}

	succeeded := false
	if dlg.defaultButton != nil {
		if err := dlg.defaultButton.setAndClearStyleBits(BS_PUSHBUTTON, BS_DEFPUSHBUTTON); err != nil {
			return err
		}
		defer func() {
			if !succeeded {
				dlg.defaultButton.setAndClearStyleBits(BS_DEFPUSHBUTTON, BS_PUSHBUTTON)
			}
		}()
	}

	if button != nil {
		if err := button.setAndClearStyleBits(BS_DEFPUSHBUTTON, BS_PUSHBUTTON); err != nil {
			return err
		}
	}

	dlg.defaultButton = button

	succeeded = true

	return nil
}

func (dlg *Dialog) CancelButton() *PushButton {
	return dlg.cancelButton
}

func (dlg *Dialog) SetCancelButton(button *PushButton) error {
	if button != nil && !IsChild(dlg.hWnd, button.hWnd) {
		return newError("not a descendant of the dialog")
	}

	dlg.cancelButton = button

	return nil
}

func (dlg *Dialog) Accept() {
	dlg.Close(DlgCmdOK)
}

func (dlg *Dialog) Cancel() {
	dlg.Close(DlgCmdCancel)
}

func (dlg *Dialog) Close(result int) {
	dlg.result = result

	dlg.TopLevelWindow.Close()
}

func firstFocusableDescendantCallback(hwnd HWND, lParam uintptr) uintptr {
	widget := widgetFromHWND(hwnd)

	if widget == nil || !widget.Visible() || !widget.Enabled() {
		return 1
	}

	style := uint(GetWindowLong(hwnd, GWL_STYLE))
	// FIXME: Ugly workaround for NumberEdit
	_, isTextSelectable := widget.(textSelectable)
	if style&WS_TABSTOP > 0 || isTextSelectable {
		hwndPtr := (*HWND)(unsafe.Pointer(lParam))
		*hwndPtr = hwnd
		return 0
	}

	return 1
}

var firstFocusableDescendantCallbackPtr = syscall.NewCallback(firstFocusableDescendantCallback)

func firstFocusableDescendant(container Container) Widget {
	var hwnd HWND

	EnumChildWindows(container.BaseWidget().hWnd, firstFocusableDescendantCallbackPtr, uintptr(unsafe.Pointer(&hwnd)))

	return widgetFromHWND(hwnd)
}

type textSelectable interface {
	SetTextSelection(start, end int)
}

func (dlg *Dialog) focusFirstCandidateDescendant() {
	widget := firstFocusableDescendant(dlg)
	if widget == nil {
		return
	}

	if err := widget.SetFocus(); err != nil {
		return
	}

	if textSel, ok := widget.(textSelectable); ok {
		textSel.SetTextSelection(0, -1)
	}
}

func (dlg *Dialog) Show() {
	dlg.TopLevelWindow.Show()

	dlg.focusFirstCandidateDescendant()
}

func (dlg *Dialog) Run() int {
	if dlg.owner != nil {
		ob := dlg.owner.Bounds()
		b := dlg.Bounds()
		if dlg.centerInOwnerWhenRun {
			dlg.SetBounds(Rectangle{
				ob.X + (ob.Width-b.Width)/2,
				ob.Y + (ob.Height-b.Height)/2,
				b.Width,
				b.Height,
			})
		}
	} else {
		dlg.SetBounds(dlg.Bounds())
	}

	dlg.Show()

	if dlg.owner != nil {
		dlg.owner.SetEnabled(false)
	}

	dlg.TopLevelWindow.Run()

	return dlg.result
}
<|endoftext|>


<commit_before>package auth

import (
	"crypto/subtle"
	"fmt"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"golang.org/x/net/context"
)

type digest_client struct {
	nc        uint64
	last_seen int64
}

type DigestAuth struct {
	Realm            string
	Opaque           string
	Secrets          SecretProvider
	PlainTextSecrets bool
	IgnoreNonceCount bool
	// Headers used by authenticator. Set to ProxyHeaders to use with
	// proxy server. When nil, NormalHeaders are used.
	Headers *Headers

	/*
	   Approximate size of Client's Cache. When actual number of
	   tracked client nonces exceeds
	   ClientCacheSize+ClientCacheTolerance, ClientCacheTolerance*2
	   older entries are purged.
	*/
	ClientCacheSize      int
	ClientCacheTolerance int

	clients map[string]*digest_client
	mutex   sync.RWMutex
}

// check that DigestAuth implements AuthenticatorInterface
var _ = (AuthenticatorInterface)((*DigestAuth)(nil))

type digest_cache_entry struct {
	nonce     string
	last_seen int64
}

type digest_cache []digest_cache_entry

func (c digest_cache) Less(i, j int) bool {
	return c[i].last_seen < c[j].last_seen
}

func (c digest_cache) Len() int {
	return len(c)
}

func (c digest_cache) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}

/*
 Purge removes count oldest entries from DigestAuth.clients
*/
func (a *DigestAuth) Purge(count int) {
	a.mutex.Lock()
	entries := make([]digest_cache_entry, 0, len(a.clients))
	for nonce, client := range a.clients {
		entries = append(entries, digest_cache_entry{nonce, client.last_seen})
	}
	cache := digest_cache(entries)
	sort.Sort(cache)
	for _, client := range cache[:count] {
		delete(a.clients, client.nonce)
	}
	a.mutex.Unlock()
}

/*
 http.Handler for DigestAuth which initiates the authentication process
 (or requires reauthentication).
*/
func (a *DigestAuth) RequireAuth(w http.ResponseWriter, r *http.Request) {
	a.mutex.RLock()
	if len(a.clients) > a.ClientCacheSize+a.ClientCacheTolerance {
		a.mutex.RUnlock()
		a.Purge(a.ClientCacheTolerance * 2)
	} else {
		a.mutex.RUnlock()
	}
	nonce := RandomKey()

	a.mutex.Lock()
	a.clients[nonce] = &digest_client{nc: 0, last_seen: time.Now().UnixNano()}
	a.mutex.Unlock()

	a.mutex.RLock()
	w.Header().Set(contentType, a.Headers.V().UnauthContentType)
	w.Header().Set(a.Headers.V().Authenticate,
		fmt.Sprintf(`Digest realm="%s", nonce="%s", opaque="%s", algorithm="MD5", qop="auth"`,
			a.Realm, nonce, a.Opaque))
	w.WriteHeader(a.Headers.V().UnauthCode)
	w.Write([]byte(a.Headers.V().UnauthResponse))
	a.mutex.RUnlock()
}

/*
 Parse Authorization header from the http.Request. Returns a map of
 auth parameters or nil if the header is not a valid parsable Digest
 auth header.
*/
func DigestAuthParams(authorization string) map[string]string {
	s := strings.SplitN(authorization, " ", 2)
	if len(s) != 2 || s[0] != "Digest" {
		return nil
	}

	return ParsePairs(s[1])
}

/*
 Check if request contains valid authentication data. Returns a pair
 of username, authinfo where username is the name of the authenticated
 user or an empty string and authinfo is the contents for the optional
 Authentication-Info response header.
*/
func (da *DigestAuth) CheckAuth(r *http.Request) (username string, authinfo *string) {
	da.mutex.RLock()
	defer da.mutex.RUnlock()
	username = ""
	authinfo = nil
	auth := DigestAuthParams(r.Header.Get(da.Headers.V().Authorization))
	if auth == nil {
		return "", nil
	}
	// RFC2617 Section 3.2.1 specifies that unset value of algorithm in
	// WWW-Authenticate Response header should be treated as
	// "MD5". According to section 3.2.2 the "algorithm" value in
	// subsequent Request Authorization header must be set to whatever
	// was supplied in the WWW-Authenticate Response header. This
	// implementation always returns an algorithm in WWW-Authenticate
	// header, however there seems to be broken clients in the wild
	// which do not set the algorithm. Assume the unset algorithm in
	// Authorization header to be equal to MD5.
	if _, ok := auth["algorithm"]; !ok {
		auth["algorithm"] = "MD5"
	}
	if da.Opaque != auth["opaque"] || auth["algorithm"] != "MD5" || auth["qop"] != "auth" {
		return "", nil
	}

	// Check if the requested URI matches auth header
	if r.RequestURI != auth["uri"] {
		// We allow auth["uri"] to be a full path prefix of request-uri
		// for some reason lost in history, which is probably wrong, but
		// used to be like that for quite some time
		// (https://tools.ietf.org/html/rfc2617#section-3.2.2 explicitly
		// says that auth["uri"] is the request-uri).
		//
		// TODO: make an option to allow only strict checking.
		switch u, err := url.Parse(auth["uri"]); {
		case err != nil:
			return "", nil
		case r.URL == nil:
			return "", nil
		case len(u.Path) > len(r.URL.Path):
			return "", nil
		case !strings.HasPrefix(r.URL.Path, u.Path):
			return "", nil
		}
	}

	HA1 := da.Secrets(auth["username"], da.Realm)
	if da.PlainTextSecrets {
		HA1 = H(auth["username"] + ":" + da.Realm + ":" + HA1)
	}
	HA2 := H(r.Method + ":" + auth["uri"])
	KD := H(strings.Join([]string{HA1, auth["nonce"], auth["nc"], auth["cnonce"], auth["qop"], HA2}, ":"))

	if subtle.ConstantTimeCompare([]byte(KD), []byte(auth["response"])) != 1 {
		return "", nil
	}

	// At this point crypto checks are completed and validated.
	// Now check if the session is valid.

	nc, err := strconv.ParseUint(auth["nc"], 16, 64)
	if err != nil {
		return "", nil
	}

	if client, ok := da.clients[auth["nonce"]]; !ok {
		return "", nil
	} else {
		if client.nc != 0 && client.nc >= nc && !da.IgnoreNonceCount {
			return "", nil
		}
		client.nc = nc
		client.last_seen = time.Now().UnixNano()
	}

	resp_HA2 := H(":" + auth["uri"])
	rspauth := H(strings.Join([]string{HA1, auth["nonce"], auth["nc"], auth["cnonce"], auth["qop"], resp_HA2}, ":"))

	info := fmt.Sprintf(`qop="auth", rspauth="%s", cnonce="%s", nc="%s"`, rspauth, auth["cnonce"], auth["nc"])
	return auth["username"], &info
}

/*
 Default values for ClientCacheSize and ClientCacheTolerance for DigestAuth
*/
const DefaultClientCacheSize = 1000
const DefaultClientCacheTolerance = 100

/*
 Wrap returns an Authenticator which uses HTTP Digest
 authentication. Arguments:

 realm: The authentication realm.

 secrets: SecretProvider which must return HA1 digests for the same
 realm as above.
*/
func (a *DigestAuth) Wrap(wrapped AuthenticatedHandlerFunc) http.HandlerFunc {
	a.mutex.RLock()
	defer a.mutex.RUnlock()

	return func(w http.ResponseWriter, r *http.Request) {
		if username, authinfo := a.CheckAuth(r); username == "" {
			a.RequireAuth(w, r)
		} else {
			ar := &AuthenticatedRequest{Request: *r, Username: username}
			if authinfo != nil {
				w.Header().Set(a.Headers.V().AuthInfo, *authinfo)
			}
			wrapped(w, ar)
		}
	}
}

/*
 JustCheck returns function which converts an http.HandlerFunc into a
 http.HandlerFunc which requires authentication. Username is passed as
 an extra X-Authenticated-Username header.
*/
func (a *DigestAuth) JustCheck(wrapped http.HandlerFunc) http.HandlerFunc {
	return a.Wrap(func(w http.ResponseWriter, ar *AuthenticatedRequest) {
		ar.Header.Set(AuthUsernameHeader, ar.Username)
		wrapped(w, &ar.Request)
	})
}

// NewContext returns a context carrying authentication information for the request.
func (a *DigestAuth) NewContext(ctx context.Context, r *http.Request) context.Context {
	a.mutex.Lock()
	username, authinfo := a.CheckAuth(r)
	info := &Info{Username: username, ResponseHeaders: make(http.Header)}
	if username != "" {
		info.Authenticated = true
		info.ResponseHeaders.Set(a.Headers.V().AuthInfo, *authinfo)
	} else {
		// return back digest WWW-Authenticate header
		if len(a.clients) > a.ClientCacheSize+a.ClientCacheTolerance {
			a.Purge(a.ClientCacheTolerance * 2)
		}
		nonce := RandomKey()
		a.clients[nonce] = &digest_client{nc: 0, last_seen: time.Now().UnixNano()}
		info.ResponseHeaders.Set(a.Headers.V().Authenticate,
			fmt.Sprintf(`Digest realm="%s", nonce="%s", opaque="%s", algorithm="MD5", qop="auth"`,
				a.Realm, nonce, a.Opaque))
	}
	a.mutex.Unlock()
	return context.WithValue(ctx, infoKey, info)
}

// NewDigestAuthenticator generates a new DigestAuth object
func NewDigestAuthenticator(realm string, secrets SecretProvider) *DigestAuth {
	da := &DigestAuth{
		Opaque:               RandomKey(),
		Realm:                realm,
		Secrets:              secrets,
		PlainTextSecrets:     false,
		ClientCacheSize:      DefaultClientCacheSize,
		ClientCacheTolerance: DefaultClientCacheTolerance,
		clients:              map[string]*digest_client{}}
	return da
}
<commit_msg>Cleanup locking logic.<commit_after>package auth

import (
	"crypto/subtle"
	"fmt"
	"net/http"
	"net/url"
	"sort"
	"strconv"
	"strings"
	"sync"
	"time"

	"golang.org/x/net/context"
)

type digest_client struct {
	nc        uint64
	last_seen int64
}

type DigestAuth struct {
	Realm            string
	Opaque           string
	Secrets          SecretProvider
	PlainTextSecrets bool
	IgnoreNonceCount bool
	// Headers used by authenticator. Set to ProxyHeaders to use with
	// proxy server. When nil, NormalHeaders are used.
	Headers *Headers

	/*
	   Approximate size of Client's Cache. When actual number of
	   tracked client nonces exceeds
	   ClientCacheSize+ClientCacheTolerance, ClientCacheTolerance*2
	   older entries are purged.
	*/
	ClientCacheSize      int
	ClientCacheTolerance int

	clients map[string]*digest_client
	mutex   sync.RWMutex
}

// check that DigestAuth implements AuthenticatorInterface
var _ = (AuthenticatorInterface)((*DigestAuth)(nil))

type digest_cache_entry struct {
	nonce     string
	last_seen int64
}

type digest_cache []digest_cache_entry

func (c digest_cache) Less(i, j int) bool {
	return c[i].last_seen < c[j].last_seen
}

func (c digest_cache) Len() int {
	return len(c)
}

func (c digest_cache) Swap(i, j int) {
	c[i], c[j] = c[j], c[i]
}

/*
 Purge removes count oldest entries from DigestAuth.clients
*/
func (a *DigestAuth) Purge(count int) {
	a.mutex.Lock()
	defer a.mutex.Unlock()
	entries := make([]digest_cache_entry, 0, len(a.clients))
	for nonce, client := range a.clients {
		entries = append(entries, digest_cache_entry{nonce, client.last_seen})
	}
	cache := digest_cache(entries)
	sort.Sort(cache)
	for _, client := range cache[:count] {
		delete(a.clients, client.nonce)
	}
}

/*
 http.Handler for DigestAuth which initiates the authentication process
 (or requires reauthentication).
*/
func (a *DigestAuth) RequireAuth(w http.ResponseWriter, r *http.Request) {
	a.mutex.RLock()
	clientsLen := len(a.clients)
	a.mutex.RUnlock()

	if clientsLen > a.ClientCacheSize+a.ClientCacheTolerance {
		a.Purge(a.ClientCacheTolerance * 2)
	}
	nonce := RandomKey()

	a.mutex.Lock()
	a.clients[nonce] = &digest_client{nc: 0, last_seen: time.Now().UnixNano()}
	a.mutex.Unlock()

	a.mutex.RLock()
	w.Header().Set(contentType, a.Headers.V().UnauthContentType)
	w.Header().Set(a.Headers.V().Authenticate,
		fmt.Sprintf(`Digest realm="%s", nonce="%s", opaque="%s", algorithm="MD5", qop="auth"`,
			a.Realm, nonce, a.Opaque))
	w.WriteHeader(a.Headers.V().UnauthCode)
	w.Write([]byte(a.Headers.V().UnauthResponse))
	a.mutex.RUnlock()
}

/*
 Parse Authorization header from the http.Request. Returns a map of
 auth parameters or nil if the header is not a valid parsable Digest
 auth header.
*/
func DigestAuthParams(authorization string) map[string]string {
	s := strings.SplitN(authorization, " ", 2)
	if len(s) != 2 || s[0] != "Digest" {
		return nil
	}

	return ParsePairs(s[1])
}

/*
 Check if request contains valid authentication data. Returns a pair
 of username, authinfo where username is the name of the authenticated
 user or an empty string and authinfo is the contents for the optional
 Authentication-Info response header.
*/
func (da *DigestAuth) CheckAuth(r *http.Request) (username string, authinfo *string) {
	da.mutex.RLock()
	defer da.mutex.RUnlock()
	username = ""
	authinfo = nil
	auth := DigestAuthParams(r.Header.Get(da.Headers.V().Authorization))
	if auth == nil {
		return "", nil
	}
	// RFC2617 Section 3.2.1 specifies that unset value of algorithm in
	// WWW-Authenticate Response header should be treated as
	// "MD5". According to section 3.2.2 the "algorithm" value in
	// subsequent Request Authorization header must be set to whatever
	// was supplied in the WWW-Authenticate Response header. This
	// implementation always returns an algorithm in WWW-Authenticate
	// header, however there seems to be broken clients in the wild
	// which do not set the algorithm. Assume the unset algorithm in
	// Authorization header to be equal to MD5.
	if _, ok := auth["algorithm"]; !ok {
		auth["algorithm"] = "MD5"
	}
	if da.Opaque != auth["opaque"] || auth["algorithm"] != "MD5" || auth["qop"] != "auth" {
		return "", nil
	}

	// Check if the requested URI matches auth header
	if r.RequestURI != auth["uri"] {
		// We allow auth["uri"] to be a full path prefix of request-uri
		// for some reason lost in history, which is probably wrong, but
		// used to be like that for quite some time
		// (https://tools.ietf.org/html/rfc2617#section-3.2.2 explicitly
		// says that auth["uri"] is the request-uri).
		//
		// TODO: make an option to allow only strict checking.
		switch u, err := url.Parse(auth["uri"]); {
		case err != nil:
			return "", nil
		case r.URL == nil:
			return "", nil
		case len(u.Path) > len(r.URL.Path):
			return "", nil
		case !strings.HasPrefix(r.URL.Path, u.Path):
			return "", nil
		}
	}

	HA1 := da.Secrets(auth["username"], da.Realm)
	if da.PlainTextSecrets {
		HA1 = H(auth["username"] + ":" + da.Realm + ":" + HA1)
	}
	HA2 := H(r.Method + ":" + auth["uri"])
	KD := H(strings.Join([]string{HA1, auth["nonce"], auth["nc"], auth["cnonce"], auth["qop"], HA2}, ":"))

	if subtle.ConstantTimeCompare([]byte(KD), []byte(auth["response"])) != 1 {
		return "", nil
	}

	// At this point crypto checks are completed and validated.
	// Now check if the session is valid.

	nc, err := strconv.ParseUint(auth["nc"], 16, 64)
	if err != nil {
		return "", nil
	}

	if client, ok := da.clients[auth["nonce"]]; !ok {
		return "", nil
	} else {
		if client.nc != 0 && client.nc >= nc && !da.IgnoreNonceCount {
			return "", nil
		}
		client.nc = nc
		client.last_seen = time.Now().UnixNano()
	}

	resp_HA2 := H(":" + auth["uri"])
	rspauth := H(strings.Join([]string{HA1, auth["nonce"], auth["nc"], auth["cnonce"], auth["qop"], resp_HA2}, ":"))

	info := fmt.Sprintf(`qop="auth", rspauth="%s", cnonce="%s", nc="%s"`, rspauth, auth["cnonce"], auth["nc"])
	return auth["username"], &info
}

/*
 Default values for ClientCacheSize and ClientCacheTolerance for DigestAuth
*/
const DefaultClientCacheSize = 1000
const DefaultClientCacheTolerance = 100

/*
 Wrap returns an Authenticator which uses HTTP Digest
 authentication. Arguments:

 realm: The authentication realm.

 secrets: SecretProvider which must return HA1 digests for the same
 realm as above.
*/
func (a *DigestAuth) Wrap(wrapped AuthenticatedHandlerFunc) http.HandlerFunc {
	a.mutex.RLock()
	defer a.mutex.RUnlock()

	return func(w http.ResponseWriter, r *http.Request) {
		if username, authinfo := a.CheckAuth(r); username == "" {
			a.RequireAuth(w, r)
		} else {
			ar := &AuthenticatedRequest{Request: *r, Username: username}
			if authinfo != nil {
				w.Header().Set(a.Headers.V().AuthInfo, *authinfo)
			}
			wrapped(w, ar)
		}
	}
}

/*
 JustCheck returns function which converts an http.HandlerFunc into a
 http.HandlerFunc which requires authentication. Username is passed as
 an extra X-Authenticated-Username header.
*/
func (a *DigestAuth) JustCheck(wrapped http.HandlerFunc) http.HandlerFunc {
	return a.Wrap(func(w http.ResponseWriter, ar *AuthenticatedRequest) {
		ar.Header.Set(AuthUsernameHeader, ar.Username)
		wrapped(w, &ar.Request)
	})
}

// NewContext returns a context carrying authentication information for the request.
func (a *DigestAuth) NewContext(ctx context.Context, r *http.Request) context.Context {
	a.mutex.Lock()
	defer a.mutex.Unlock()
	username, authinfo := a.CheckAuth(r)
	info := &Info{Username: username, ResponseHeaders: make(http.Header)}
	if username != "" {
		info.Authenticated = true
		info.ResponseHeaders.Set(a.Headers.V().AuthInfo, *authinfo)
	} else {
		// return back digest WWW-Authenticate header
		if len(a.clients) > a.ClientCacheSize+a.ClientCacheTolerance {
			a.Purge(a.ClientCacheTolerance * 2)
		}
		nonce := RandomKey()
		a.clients[nonce] = &digest_client{nc: 0, last_seen: time.Now().UnixNano()}
		info.ResponseHeaders.Set(a.Headers.V().Authenticate,
			fmt.Sprintf(`Digest realm="%s", nonce="%s", opaque="%s", algorithm="MD5", qop="auth"`,
				a.Realm, nonce, a.Opaque))
	}
	return context.WithValue(ctx, infoKey, info)
}

// NewDigestAuthenticator generates a new DigestAuth object
func NewDigestAuthenticator(realm string, secrets SecretProvider) *DigestAuth {
	da := &DigestAuth{
		Opaque:               RandomKey(),
		Realm:                realm,
		Secrets:              secrets,
		PlainTextSecrets:     false,
		ClientCacheSize:      DefaultClientCacheSize,
		ClientCacheTolerance: DefaultClientCacheTolerance,
		clients:              map[string]*digest_client{}}
	return da
}
<|endoftext|>


<commit_before>package bootstrap

import (
	"bytes"
	"io"
)

type Redactor struct {
	replacement []byte

	// Current offset from the start of the next input segment
	offset int

	// Minimum and maximum length of redactable string
	minlen int
	maxlen int

	// Table of Boyer-Moore skip distances, and values to redact matching this end byte
	table [255]struct {
		skip    int
		needles [][]byte
	}

	// Internal buffer for building redacted input into
	// Also holds the final portion of the previous Write call, in case of
	// sensitive values that cross Write boundaries
	outbuf []byte

	// Wrapped Writer that we'll send redacted output to
	output io.Writer
}

// Construct a new Redactor, and pre-compile the Boyer-Moore skip table
func NewRedactor(output io.Writer, replacement string, needles []string) *Redactor {
	minNeedleLen := 0
	maxNeedleLen := 0
	for _, needle := range needles {
		if len(needle) < minNeedleLen || minNeedleLen == 0 {
			minNeedleLen = len(needle)
		}
		if len(needle) > maxNeedleLen {
			maxNeedleLen = len(needle)
		}
	}

	redactor := &Redactor{
		replacement: []byte(replacement),
		output:      output,

		// Linux pipes can buffer up to 65536 bytes before flushing, so there's
		// a reasonable chance that's how much we'll get in a single Write().
		// maxNeedleLen is added since we may retain that many bytes to handle
		// matches crossing Write boundaries.
		// It's a reasonable starting capacity which hopefully means we don't
		// have to reallocate the array, but append() will grow it if necessary
		outbuf: make([]byte, 0, 65536+maxNeedleLen),

		// Since Boyer-Moore looks for the end of substrings, we can safely offset
		// processing by the length of the shortest string we're checking for
		// Since Boyer-Moore looks for the end of substrings, only bytes further
		// behind the iterator than the longest search string are guaranteed to not
		// be part of a match
		minlen: minNeedleLen,
		maxlen: maxNeedleLen,
		offset: minNeedleLen - 1,
	}

	// For bytes that don't appear in any of the substrings we're searching
	// for, it's safe to skip forward the length of the shortest search
	// string.
	// Start by setting this as a default for all bytes
	for i := range redactor.table {
		redactor.table[i].skip = minNeedleLen
	}

	for _, needle := range needles {
		for i, ch := range needle {
			// For bytes that do exist in search strings, find the shortest distance
			// between that byte appearing to the end of the same search string
			skip := len(needle) - i - 1
			if skip < redactor.table[ch].skip {
				redactor.table[ch].skip = skip
			}

			// Build a cache of which search substrings end in which bytes
			if skip == 0 {
				redactor.table[ch].needles = append(redactor.table[ch].needles, []byte(needle))
			}
		}
	}

	return redactor
}

func (redactor *Redactor) Write(input []byte) (int, error) {
	// Current iterator index, which may be a safe offset from 0
	cursor := redactor.offset

	// Current index which is guaranteed to be completely redacted
	// May lag behind cursor by up to the length of the longest search string
	doneTo := 0

	for cursor < len(input) {
		ch := input[cursor]
		skip := redactor.table[ch].skip

		// If the skip table tells us that there is no search string ending in
		// the current byte, skip forward by the indicated distance.
		if skip != 0 {
			cursor += skip

			// Also copy any content behind the cursor which is guaranteed not
			// to fall under a match
			confirmedTo := cursor - redactor.maxlen - 1
			if confirmedTo > len(input) {
				confirmedTo = len(input)
			}
			if confirmedTo > doneTo {
				redactor.outbuf = append(redactor.outbuf, input[doneTo:confirmedTo]...)
				doneTo = confirmedTo
			}

			continue
		}

		// We'll check for matching search strings here, but we'll still need
		// to move the cursor forward
		// Since Go slice syntax is not inclusive of the end index, moving it
		// forward now reduces the need to use `cursor-1` everywhere
		cursor++
		for _, needle := range redactor.table[ch].needles {
			// Since we're working backwards from what may be the end of a
			// string, it's possible that the start would be out of bounds
			startSubstr := cursor - len(needle)
			var candidate []byte

			if startSubstr >= 0 {
				// If the candidate string falls entirely within input, then just slice into input
				candidate = input[startSubstr:cursor]
			} else if -startSubstr < len(redactor.outbuf) {
				// If the candidate crosses the Write boundary, we need to
				// concatenate the two sections to compare against
				candidate = make([]byte, 0, len(needle))
				candidate = append(candidate, redactor.outbuf[-startSubstr:]...)
				candidate = append(candidate, input[:cursor]...)
			} else {
				// Final case is that the start index is out of bounds, and
				// it's impossible for it to match. Just move on to the next
				// search substring
				continue
			}

			if bytes.Equal(needle, candidate) {
				if startSubstr < 0 {
					// If we accepted a negative startSubstr, the output buffer
					// needs to be truncated to remove the partial match
					redactor.outbuf = redactor.outbuf[:len(redactor.outbuf)+startSubstr]
				} else if startSubstr > doneTo {
					// First, copy over anything behind the matched substring unmodified
					redactor.outbuf = append(redactor.outbuf, input[doneTo:startSubstr]...)
				}
				// Then, write a fixed string into the output, and move doneTo past the redaction
				redactor.outbuf = append(redactor.outbuf, redactor.replacement...)
				doneTo = cursor

				// The next end-of-string will be at least this far away so
				// it's safe to skip forward a bit
				cursor += redactor.minlen - 1
				break
			}
		}
	}

	// Push the output buffer down
	_, err := redactor.output.Write(redactor.outbuf)

	// There will probably be a segment at the end of the input which may be a
	// partial match crossing the Write boundary. This is retained in the
	// output buffer to compare against on the next call
	// Flush() needs to be called after the final Write(), or this bit won't
	// get written
	redactor.outbuf = append(redactor.outbuf[:0], input[doneTo:]...)

	// We can offset the next Write processing by how far cursor is ahead of
	// the end of this input segment
	redactor.offset = cursor - len(input)

	return len(input), err
}

// Flush should be called after the final Write. This will Write() anything
// retained in case of a partial match and reset the output buffer.
func (redactor Redactor) Sync() error {
	_, err := redactor.output.Write(redactor.outbuf)
	redactor.outbuf = redactor.outbuf[:0]
	return err
}
<commit_msg>Keep line endings out of the buffer<commit_after>package bootstrap

import (
	"bytes"
	"io"
)

type Redactor struct {
	replacement []byte

	// Current offset from the start of the next input segment
	offset int

	// Minimum and maximum length of redactable string
	minlen int
	maxlen int

	// Table of Boyer-Moore skip distances, and values to redact matching this end byte
	table [255]struct {
		skip    int
		needles [][]byte
	}

	// Internal buffer for building redacted input into
	// Also holds the final portion of the previous Write call, in case of
	// sensitive values that cross Write boundaries
	outbuf []byte

	// Wrapped Writer that we'll send redacted output to
	output io.Writer
}

// Construct a new Redactor, and pre-compile the Boyer-Moore skip table
func NewRedactor(output io.Writer, replacement string, needles []string) *Redactor {
	minNeedleLen := 0
	maxNeedleLen := 0
	for _, needle := range needles {
		if len(needle) < minNeedleLen || minNeedleLen == 0 {
			minNeedleLen = len(needle)
		}
		if len(needle) > maxNeedleLen {
			maxNeedleLen = len(needle)
		}
	}

	redactor := &Redactor{
		replacement: []byte(replacement),
		output:      output,

		// Linux pipes can buffer up to 65536 bytes before flushing, so there's
		// a reasonable chance that's how much we'll get in a single Write().
		// maxNeedleLen is added since we may retain that many bytes to handle
		// matches crossing Write boundaries.
		// It's a reasonable starting capacity which hopefully means we don't
		// have to reallocate the array, but append() will grow it if necessary
		outbuf: make([]byte, 0, 65536+maxNeedleLen),

		// Since Boyer-Moore looks for the end of substrings, we can safely offset
		// processing by the length of the shortest string we're checking for
		// Since Boyer-Moore looks for the end of substrings, only bytes further
		// behind the iterator than the longest search string are guaranteed to not
		// be part of a match
		minlen: minNeedleLen,
		maxlen: maxNeedleLen,
		offset: minNeedleLen - 1,
	}

	// For bytes that don't appear in any of the substrings we're searching
	// for, it's safe to skip forward the length of the shortest search
	// string.
	// Start by setting this as a default for all bytes
	for i := range redactor.table {
		redactor.table[i].skip = minNeedleLen
	}

	for _, needle := range needles {
		for i, ch := range needle {
			// For bytes that do exist in search strings, find the shortest distance
			// between that byte appearing to the end of the same search string
			skip := len(needle) - i - 1
			if skip < redactor.table[ch].skip {
				redactor.table[ch].skip = skip
			}

			// Build a cache of which search substrings end in which bytes
			if skip == 0 {
				redactor.table[ch].needles = append(redactor.table[ch].needles, []byte(needle))
			}
		}
	}

	return redactor
}

func (redactor *Redactor) Write(input []byte) (int, error) {
	// Current iterator index, which may be a safe offset from 0
	cursor := redactor.offset

	// Current index which is guaranteed to be completely redacted
	// May lag behind cursor by up to the length of the longest search string
	doneTo := 0

	for cursor < len(input) {
		ch := input[cursor]
		skip := redactor.table[ch].skip

		// If the skip table tells us that there is no search string ending in
		// the current byte, skip forward by the indicated distance.
		if skip != 0 {
			cursor += skip

			// Also copy any content behind the cursor which is guaranteed not
			// to fall under a match
			confirmedTo := cursor - redactor.maxlen - 1
			if confirmedTo > len(input) {
				confirmedTo = len(input)
			}
			if confirmedTo > doneTo {
				redactor.outbuf = append(redactor.outbuf, input[doneTo:confirmedTo]...)
				doneTo = confirmedTo
			}

			continue
		}

		// We'll check for matching search strings here, but we'll still need
		// to move the cursor forward
		// Since Go slice syntax is not inclusive of the end index, moving it
		// forward now reduces the need to use `cursor-1` everywhere
		cursor++
		for _, needle := range redactor.table[ch].needles {
			// Since we're working backwards from what may be the end of a
			// string, it's possible that the start would be out of bounds
			startSubstr := cursor - len(needle)
			var candidate []byte

			if startSubstr >= 0 {
				// If the candidate string falls entirely within input, then just slice into input
				candidate = input[startSubstr:cursor]
			} else if -startSubstr < len(redactor.outbuf) {
				// If the candidate crosses the Write boundary, we need to
				// concatenate the two sections to compare against
				candidate = make([]byte, 0, len(needle))
				candidate = append(candidate, redactor.outbuf[-startSubstr:]...)
				candidate = append(candidate, input[:cursor]...)
			} else {
				// Final case is that the start index is out of bounds, and
				// it's impossible for it to match. Just move on to the next
				// search substring
				continue
			}

			if bytes.Equal(needle, candidate) {
				if startSubstr < 0 {
					// If we accepted a negative startSubstr, the output buffer
					// needs to be truncated to remove the partial match
					redactor.outbuf = redactor.outbuf[:len(redactor.outbuf)+startSubstr]
				} else if startSubstr > doneTo {
					// First, copy over anything behind the matched substring unmodified
					redactor.outbuf = append(redactor.outbuf, input[doneTo:startSubstr]...)
				}
				// Then, write a fixed string into the output, and move doneTo past the redaction
				redactor.outbuf = append(redactor.outbuf, redactor.replacement...)
				doneTo = cursor

				// The next end-of-string will be at least this far away so
				// it's safe to skip forward a bit
				cursor += redactor.minlen - 1
				break
			}
		}
	}

	// We buffer the end of the input in order to catch passwords that fall over Write boundaries.
	// In the case of line-buffered input, that means we would hold back the
	// end of the line in a user-visible way. For this reason, we push through
	// any line endings immediately rather than hold them back.
	// Technically this means that passwords containing newlines aren't
	// guarateed to get redacted, but who does that anyway?
	for i := doneTo; i < len(input); i++ {
		if input[i] == byte('\n') {
			redactor.outbuf = append(redactor.outbuf, input[doneTo:i+1]...)
			doneTo = i+1
		}
	}

	// Push the output buffer down
	_, err := redactor.output.Write(redactor.outbuf)

	// There will probably be a segment at the end of the input which may be a
	// partial match crossing the Write boundary. This is retained in the
	// output buffer to compare against on the next call
	// Flush() needs to be called after the final Write(), or this bit won't
	// get written
	redactor.outbuf = append(redactor.outbuf[:0], input[doneTo:]...)

	// We can offset the next Write processing by how far cursor is ahead of
	// the end of this input segment
	redactor.offset = cursor - len(input)

	return len(input), err
}

// Flush should be called after the final Write. This will Write() anything
// retained in case of a partial match and reset the output buffer.
func (redactor Redactor) Sync() error {
	_, err := redactor.output.Write(redactor.outbuf)
	redactor.outbuf = redactor.outbuf[:0]
	return err
}
<|endoftext|>


<commit_before>package fetcher

import (
	"fmt"
)

const community = "https://git.alpinelinux.org/cgit/alpine-secdb/plain/v%s/community.yaml"
const main = "https://git.alpinelinux.org/cgit/alpine-secdb/plain/v%s/main.yaml"

func newAlpineFetchRequests(target []string) (reqs []fetchRequest) {
	for _, v := range target {
		reqs = append(reqs, fetchRequest{
			target: v,
			url:    fmt.Sprintf(community, v),
		}, fetchRequest{
			target: v,
			url:    fmt.Sprintf(main, v),
		})
	}
	return
}

// FetchAlpineFiles fetch from alpine secdb
// https://git.alpinelinux.org/cgit/alpine-secdb/tree/
func FetchAlpineFiles(versions []string) ([]FetchResult, error) {
	reqs := newAlpineFetchRequests(versions)
	if len(reqs) == 0 {
		return nil,
			fmt.Errorf("There are no versions to fetch")
	}
	results, err := fetchFeedFiles(reqs)
	if err != nil {
		return nil,
			fmt.Errorf("Failed to fetch. err: %s", err)
	}
	return results, nil
}
<commit_msg>fix(fetcher): fix URL of alpine sec-db<commit_after>package fetcher

import (
	"fmt"
)

const community = "https://raw.githubusercontent.com/alpinelinux/alpine-secdb/master/v%s/community.yaml"
const main = "https://raw.githubusercontent.com/alpinelinux/alpine-secdb/master/v%s/main.yaml"

func newAlpineFetchRequests(target []string) (reqs []fetchRequest) {
	for _, v := range target {
		reqs = append(reqs, fetchRequest{
			target: v,
			url:    fmt.Sprintf(community, v),
		}, fetchRequest{
			target: v,
			url:    fmt.Sprintf(main, v),
		})
	}
	return
}

// FetchAlpineFiles fetch from alpine secdb
// https://git.alpinelinux.org/cgit/alpine-secdb/tree/
func FetchAlpineFiles(versions []string) ([]FetchResult, error) {
	reqs := newAlpineFetchRequests(versions)
	if len(reqs) == 0 {
		return nil,
			fmt.Errorf("There are no versions to fetch")
	}
	results, err := fetchFeedFiles(reqs)
	if err != nil {
		return nil,
			fmt.Errorf("Failed to fetch. err: %s", err)
	}
	return results, nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"os"
	"strings"
)

type NinjaGenerator struct {
	f      *os.File
	nodes  []*DepNode
	vars   Vars
	ex     *Executor
	ruleId int
	done   map[string]bool
}

func NewNinjaGenerator(g *DepGraph) *NinjaGenerator {
	f, err := os.Create("build.ninja")
	if err != nil {
		panic(err)
	}
	return &NinjaGenerator{
		f:     f,
		nodes: g.nodes,
		vars:  g.vars,
		done:  make(map[string]bool),
	}
}

func stripShellComment(s string) string {
	if strings.IndexByte(s, '#') < 0 {
		// Fast path.
		return s
	}
	var escape bool
	var quote rune
	for i, c := range s {
		if quote > 0 {
			if quote == c && (quote == '\'' || !escape) {
				quote = 0
			}
		} else if !escape {
			if c == '#' {
				return s[:i]
			} else if c == '\'' || c == '"' || c == '`' {
				quote = c
			}
		}
		if escape {
			escape = false
		} else if c == '\\' {
			escape = true
		} else {
			escape = false
		}
	}
	return s
}

func genShellScript(runners []runner) string {
	var buf bytes.Buffer
	for i, r := range runners {
		if i > 0 {
			if runners[i-1].ignoreError {
				buf.WriteString(" ; ")
			} else {
				buf.WriteString(" && ")
			}
		}
		cmd := stripShellComment(r.cmd)
		cmd = trimLeftSpace(cmd)
		cmd = strings.Replace(cmd, "\\\n", " ", -1)
		cmd = strings.TrimRight(cmd, " \t\n;")
		cmd = strings.Replace(cmd, "$", "$$", -1)
		cmd = strings.Replace(cmd, "\t", " ", -1)
		buf.WriteString(cmd)
		if i == len(runners)-1 && r.ignoreError {
			buf.WriteString(" ; true")
		}
	}
	return buf.String()
}

func (n *NinjaGenerator) genRuleName() string {
	ruleName := fmt.Sprintf("rule%d", n.ruleId)
	n.ruleId++
	return ruleName
}

func (n *NinjaGenerator) emitBuild(output, rule, dep string) {
	fmt.Fprintf(n.f, "build %s: %s", output, rule)
	if dep != "" {
		fmt.Fprintf(n.f, " %s", dep)
	}
	fmt.Fprintf(n.f, "\n")
}

func getDepString(node *DepNode) string {
	var deps []string
	var orderOnlys []string
	for _, d := range node.Deps {
		if d.IsOrderOnly {
			orderOnlys = append(orderOnlys, d.Output)
		} else {
			deps = append(deps, d.Output)
		}
	}
	dep := ""
	if len(deps) > 0 {
		dep += fmt.Sprintf(" %s", strings.Join(deps, " "))
	}
	if len(orderOnlys) > 0 {
		dep += fmt.Sprintf(" || %s", strings.Join(orderOnlys, " "))
	}
	return dep
}

func genIntermediateTargetName(o string, i int) string {
	return fmt.Sprintf(".make_targets/%s@%d", o, i)
}

func (n *NinjaGenerator) emitNode(node *DepNode) {
	if n.done[node.Output] {
		return
	}
	n.done[node.Output] = true

	if len(node.Cmds) == 0 && len(node.Deps) == 0 && !node.IsPhony {
		return
	}

	runners, _ := n.ex.createRunners(node, true)
	ruleName := "phony"
	if len(runners) > 0 {
		ruleName = n.genRuleName()
		fmt.Fprintf(n.f, "rule %s\n", ruleName)
		fmt.Fprintf(n.f, " description = build $out\n")

		ss := genShellScript(runners)
		// It seems Linux is OK with ~130kB.
		// TODO: Find this number automatically.
		ArgLenLimit := 100 * 1000
		if len(ss) > ArgLenLimit {
			fmt.Fprintf(n.f, " rspfile = $out.rsp\n")
			fmt.Fprintf(n.f, " rspfile_content = %s\n", ss)
			ss = "sh $out.rsp"
		}
		fmt.Fprintf(n.f, " command = %s\n", ss)

	}
	n.emitBuild(node.Output, ruleName, getDepString(node))

	for _, d := range node.Deps {
		n.emitNode(d)
	}
}

func (n *NinjaGenerator) run() {
	n.ex = NewExecutor(n.vars)
	for _, node := range n.nodes {
		n.emitNode(node)
	}
	n.f.Close()
}

func GenerateNinja(g *DepGraph) {
	NewNinjaGenerator(g).run()
}
<commit_msg>Use "true" instead of an empty command<commit_after>package main

import (
	"bytes"
	"fmt"
	"os"
	"strings"
)

type NinjaGenerator struct {
	f      *os.File
	nodes  []*DepNode
	vars   Vars
	ex     *Executor
	ruleId int
	done   map[string]bool
}

func NewNinjaGenerator(g *DepGraph) *NinjaGenerator {
	f, err := os.Create("build.ninja")
	if err != nil {
		panic(err)
	}
	return &NinjaGenerator{
		f:     f,
		nodes: g.nodes,
		vars:  g.vars,
		done:  make(map[string]bool),
	}
}

func stripShellComment(s string) string {
	if strings.IndexByte(s, '#') < 0 {
		// Fast path.
		return s
	}
	var escape bool
	var quote rune
	for i, c := range s {
		if quote > 0 {
			if quote == c && (quote == '\'' || !escape) {
				quote = 0
			}
		} else if !escape {
			if c == '#' {
				return s[:i]
			} else if c == '\'' || c == '"' || c == '`' {
				quote = c
			}
		}
		if escape {
			escape = false
		} else if c == '\\' {
			escape = true
		} else {
			escape = false
		}
	}
	return s
}

func genShellScript(runners []runner) string {
	var buf bytes.Buffer
	for i, r := range runners {
		if i > 0 {
			if runners[i-1].ignoreError {
				buf.WriteString(" ; ")
			} else {
				buf.WriteString(" && ")
			}
		}
		cmd := stripShellComment(r.cmd)
		cmd = trimLeftSpace(cmd)
		cmd = strings.Replace(cmd, "\\\n", " ", -1)
		cmd = strings.TrimRight(cmd, " \t\n;")
		cmd = strings.Replace(cmd, "$", "$$", -1)
		cmd = strings.Replace(cmd, "\t", " ", -1)
		if cmd == "" {
			cmd = "true"
		}
		buf.WriteString(cmd)
		if i == len(runners)-1 && r.ignoreError {
			buf.WriteString(" ; true")
		}
	}
	return buf.String()
}

func (n *NinjaGenerator) genRuleName() string {
	ruleName := fmt.Sprintf("rule%d", n.ruleId)
	n.ruleId++
	return ruleName
}

func (n *NinjaGenerator) emitBuild(output, rule, dep string) {
	fmt.Fprintf(n.f, "build %s: %s", output, rule)
	if dep != "" {
		fmt.Fprintf(n.f, " %s", dep)
	}
	fmt.Fprintf(n.f, "\n")
}

func getDepString(node *DepNode) string {
	var deps []string
	var orderOnlys []string
	for _, d := range node.Deps {
		if d.IsOrderOnly {
			orderOnlys = append(orderOnlys, d.Output)
		} else {
			deps = append(deps, d.Output)
		}
	}
	dep := ""
	if len(deps) > 0 {
		dep += fmt.Sprintf(" %s", strings.Join(deps, " "))
	}
	if len(orderOnlys) > 0 {
		dep += fmt.Sprintf(" || %s", strings.Join(orderOnlys, " "))
	}
	return dep
}

func genIntermediateTargetName(o string, i int) string {
	return fmt.Sprintf(".make_targets/%s@%d", o, i)
}

func (n *NinjaGenerator) emitNode(node *DepNode) {
	if n.done[node.Output] {
		return
	}
	n.done[node.Output] = true

	if len(node.Cmds) == 0 && len(node.Deps) == 0 && !node.IsPhony {
		return
	}

	runners, _ := n.ex.createRunners(node, true)
	ruleName := "phony"
	if len(runners) > 0 {
		ruleName = n.genRuleName()
		fmt.Fprintf(n.f, "rule %s\n", ruleName)
		fmt.Fprintf(n.f, " description = build $out\n")

		ss := genShellScript(runners)
		// It seems Linux is OK with ~130kB.
		// TODO: Find this number automatically.
		ArgLenLimit := 100 * 1000
		if len(ss) > ArgLenLimit {
			fmt.Fprintf(n.f, " rspfile = $out.rsp\n")
			fmt.Fprintf(n.f, " rspfile_content = %s\n", ss)
			ss = "sh $out.rsp"
		}
		fmt.Fprintf(n.f, " command = %s\n", ss)

	}
	n.emitBuild(node.Output, ruleName, getDepString(node))

	for _, d := range node.Deps {
		n.emitNode(d)
	}
}

func (n *NinjaGenerator) run() {
	n.ex = NewExecutor(n.vars)
	for _, node := range n.nodes {
		n.emitNode(node)
	}
	n.f.Close()
}

func GenerateNinja(g *DepGraph) {
	NewNinjaGenerator(g).run()
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"github.com/russross/blackfriday"
	"io/ioutil"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"time"
)

type FileRepository struct {
	postDirectory string
}

func (f *FileRepository) FetchAllTags() ([]string, error) {
	posts, err := f.FetchAllPosts()

	// We're using a map to simulate a set
	tagMap := make(map[string]bool)

	for i := range posts {
		for j := range posts[i].Tags() {
			tagMap[posts[i].Tags()[j]] = true
		}
	}

	tags := []string{}

	for key := range tagMap {
		tags = append(tags, key)
	}

	sort.Strings(tags)

	return tags, err
}

func (f *FileRepository) FetchPostWithUrl(url string) (*BlogPost, error) {
	posts, err := f.FetchAllPosts()

	if err != nil {
		return nil, err
	}

	for i := range posts {
		if posts[i].Url() == url {
			return posts[i], err
		}
	}

	err = errors.New("Could not find post")

	return nil, err
}

func (f *FileRepository) FetchPostsWithTag(tag string) ([]*BlogPost, error) {
	posts, err := f.FetchAllPosts()

	if err != nil {
		return nil, err
	}

	filteredPosts := []*BlogPost{}

	for i := range posts {
		if posts[i].ContainsTag(tag) {
			filteredPosts = append(filteredPosts, posts[i])
		}
	}

	return filteredPosts, err
}

func (f *FileRepository) PostDirectory() string {
	return f.postDirectory
}

func (f *FileRepository) SetPostDirectory(s string) {
	f.postDirectory = s
}

func (f *FileRepository) FetchPostsInRange(start, count int) (BlogPosts, error) {
	posts, err := f.FetchAllPosts()

	if start + count > len(posts) {
		count = len(posts) - start
	}

	log.Println(start)
	log.Println(count)
	log.Println(len(posts))

	return posts[start:start + count + 1], err
}

func (f *FileRepository) FetchAllPosts() (BlogPosts, error) {

	dirname := f.postDirectory + string(filepath.Separator)

	files, err := ioutil.ReadDir(dirname)

	posts := BlogPosts{}

	for i := range files {

		if files[i].IsDir() {
			continue
		}

		if filepath.Ext(files[i].Name()) != ".md" {
			continue
		}

		post, err := f.FetchPost(files[i].Name())

		if err != nil {
			return nil, err
		}

		posts = append(posts, post)
	}

	sort.Sort(posts)

	return posts, err
}

func (f *FileRepository) FetchPost(filename string) (*BlogPost, error) {

	post := new(BlogPost)

	dirname := f.postDirectory + string(filepath.Separator)

	file, err := ioutil.ReadFile(dirname + filename)

	if err != nil {
		return post, err
	}

	file = []byte(f.extractHeader(string(file), post))

	htmlFlags := blackfriday.HTML_USE_SMARTYPANTS
	extensions := blackfriday.EXTENSION_HARD_LINE_BREAK | blackfriday.EXTENSION_FENCED_CODE | blackfriday.EXTENSION_NO_INTRA_EMPHASIS

	renderer := blackfriday.HtmlRenderer(htmlFlags, post.Title(), "")

	output := blackfriday.Markdown(file, renderer, extensions)

	post.SetBody(string(output))

	return post, nil
}

func (f *FileRepository) extractHeader(text string, post *BlogPost) string {

	lines := strings.Split(text, "\n")

	headerSize := 0

	for i := range lines {
		if strings.Contains(lines[i], ":") {
			components := strings.Split(lines[i], ":")

			header := strings.ToLower(strings.Trim(components[0], " "))
			separatorIndex := strings.Index(lines[i], ":") + 1
			data := strings.Trim(lines[i][separatorIndex:], " ")

			switch header {
			case "title":
				post.SetTitle(data)
			case "tags":

				tags := strings.Split(data, ",")

				formattedTags := []string{}

				for j := range tags {
					tags[j] = strings.Trim(tags[j], " ")
					tags[j] = strings.Replace(tags[j], " ", "-", -1)

					if tags[j] != "" {
						formattedTags = append(formattedTags, tags[j])
					}
				}

				post.SetTags(formattedTags)
			case "date":
				post.SetPublishDate(stringToTime(data))
			default:
				continue
			}

			headerSize += len(lines[i]) + 1
		} else {
			break
		}
	}

	return text[headerSize:]
}

func stringToTime(s string) time.Time {

	year, err := strconv.Atoi(s[:4])

	if err != nil {
		return time.Unix(0, 0)
	}

	month, err := strconv.Atoi(s[5:7])

	if err != nil {
		return time.Unix(0, 0)
	}

	day, err := strconv.Atoi(s[8:10])

	if err != nil {
		return time.Unix(0, 0)
	}

	hour, err := strconv.Atoi(s[11:13])

	if err != nil {
		return time.Unix(0, 0)
	}

	minute, err := strconv.Atoi(s[14:16])

	if err != nil {
		return time.Unix(0, 0)
	}

	seconds, err := strconv.Atoi(s[17:19])

	if err != nil {
		return time.Unix(0, 0)
	}

	location, err := time.LoadLocation("UTC")

	return time.Date(year, time.Month(month), day, hour, minute, seconds, 0, location)
}
<commit_msg>Another fix for the ranged post retriever.<commit_after>package main

import (
	"errors"
	"github.com/russross/blackfriday"
	"io/ioutil"
	"path/filepath"
	"sort"
	"strconv"
	"strings"
	"time"
	"log"
)

type FileRepository struct {
	postDirectory string
}

func (f *FileRepository) FetchAllTags() ([]string, error) {
	posts, err := f.FetchAllPosts()

	// We're using a map to simulate a set
	tagMap := make(map[string]bool)

	for i := range posts {
		for j := range posts[i].Tags() {
			tagMap[posts[i].Tags()[j]] = true
		}
	}

	tags := []string{}

	for key := range tagMap {
		tags = append(tags, key)
	}

	sort.Strings(tags)

	return tags, err
}

func (f *FileRepository) FetchPostWithUrl(url string) (*BlogPost, error) {
	posts, err := f.FetchAllPosts()

	if err != nil {
		return nil, err
	}

	for i := range posts {
		if posts[i].Url() == url {
			return posts[i], err
		}
	}

	err = errors.New("Could not find post")

	return nil, err
}

func (f *FileRepository) FetchPostsWithTag(tag string) ([]*BlogPost, error) {
	posts, err := f.FetchAllPosts()

	if err != nil {
		return nil, err
	}

	filteredPosts := []*BlogPost{}

	for i := range posts {
		if posts[i].ContainsTag(tag) {
			filteredPosts = append(filteredPosts, posts[i])
		}
	}

	return filteredPosts, err
}

func (f *FileRepository) PostDirectory() string {
	return f.postDirectory
}

func (f *FileRepository) SetPostDirectory(s string) {
	f.postDirectory = s
}

func (f *FileRepository) FetchPostsInRange(start, count int) (BlogPosts, error) {
	posts, err := f.FetchAllPosts()

	if start + count > len(posts) {
		count = len(posts) - start
	}

	log.Println(start)
	log.Println(count)
	log.Println(len(posts))

	return posts[start:start + count + 1], err
}

func (f *FileRepository) FetchAllPosts() (BlogPosts, error) {

	dirname := f.postDirectory + string(filepath.Separator)

	files, err := ioutil.ReadDir(dirname)

	posts := BlogPosts{}

	for i := range files {

		if files[i].IsDir() {
			continue
		}

		if filepath.Ext(files[i].Name()) != ".md" {
			continue
		}

		post, err := f.FetchPost(files[i].Name())

		if err != nil {
			return nil, err
		}

		posts = append(posts, post)
	}

	sort.Sort(posts)

	return posts, err
}

func (f *FileRepository) FetchPost(filename string) (*BlogPost, error) {

	post := new(BlogPost)

	dirname := f.postDirectory + string(filepath.Separator)

	file, err := ioutil.ReadFile(dirname + filename)

	if err != nil {
		return post, err
	}

	file = []byte(f.extractHeader(string(file), post))

	htmlFlags := blackfriday.HTML_USE_SMARTYPANTS
	extensions := blackfriday.EXTENSION_HARD_LINE_BREAK | blackfriday.EXTENSION_FENCED_CODE | blackfriday.EXTENSION_NO_INTRA_EMPHASIS

	renderer := blackfriday.HtmlRenderer(htmlFlags, post.Title(), "")

	output := blackfriday.Markdown(file, renderer, extensions)

	post.SetBody(string(output))

	return post, nil
}

func (f *FileRepository) extractHeader(text string, post *BlogPost) string {

	lines := strings.Split(text, "\n")

	headerSize := 0

	for i := range lines {
		if strings.Contains(lines[i], ":") {
			components := strings.Split(lines[i], ":")

			header := strings.ToLower(strings.Trim(components[0], " "))
			separatorIndex := strings.Index(lines[i], ":") + 1
			data := strings.Trim(lines[i][separatorIndex:], " ")

			switch header {
			case "title":
				post.SetTitle(data)
			case "tags":

				tags := strings.Split(data, ",")

				formattedTags := []string{}

				for j := range tags {
					tags[j] = strings.Trim(tags[j], " ")
					tags[j] = strings.Replace(tags[j], " ", "-", -1)

					if tags[j] != "" {
						formattedTags = append(formattedTags, tags[j])
					}
				}

				post.SetTags(formattedTags)
			case "date":
				post.SetPublishDate(stringToTime(data))
			default:
				continue
			}

			headerSize += len(lines[i]) + 1
		} else {
			break
		}
	}

	return text[headerSize:]
}

func stringToTime(s string) time.Time {

	year, err := strconv.Atoi(s[:4])

	if err != nil {
		return time.Unix(0, 0)
	}

	month, err := strconv.Atoi(s[5:7])

	if err != nil {
		return time.Unix(0, 0)
	}

	day, err := strconv.Atoi(s[8:10])

	if err != nil {
		return time.Unix(0, 0)
	}

	hour, err := strconv.Atoi(s[11:13])

	if err != nil {
		return time.Unix(0, 0)
	}

	minute, err := strconv.Atoi(s[14:16])

	if err != nil {
		return time.Unix(0, 0)
	}

	seconds, err := strconv.Atoi(s[17:19])

	if err != nil {
		return time.Unix(0, 0)
	}

	location, err := time.LoadLocation("UTC")

	return time.Date(year, time.Month(month), day, hour, minute, seconds, 0, location)
}
<|endoftext|>


<commit_before>package main
const (
  VERSION = "1.0-alpha"
  BUILD_DATE = "2016-04-15 09:25"
)
<commit_msg>Updated version<commit_after>package main
const (
  VERSION = "1.0-alpha"
  BUILD_DATE = "2016-04-22 12:05"
)
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package drive

import (
	"fmt"

	drive "github.com/odeke-em/google-api-go-client/drive/v2"
	"github.com/odeke-em/log"
)

const Version = "0.1.8"

const (
	Barely = iota
	AlmostExceeded
	HalfwayExceeded
	Exceeded
	Unknown
)

const (
	AboutNone = 1 << iota
	AboutQuota
	AboutFileSizes
	AboutFeatures
)

func (g *Commands) About(mask int) (err error) {
	defer PrintVersion()
	if mask == AboutNone {
		return nil
	}

	about, err := g.rem.About()
	if err != nil {
		return err
	}
	printSummary(g.log, about, mask)

	return nil
}

func quotaRequested(mask int) bool {
	return (mask & AboutQuota) != 0
}

func fileSizesRequested(mask int) bool {
	return (mask & AboutFileSizes) != 0
}

func featuresRequested(mask int) bool {
	return (mask & AboutFeatures) != 0
}

func printSummary(logy *log.Logger, about *drive.About, mask int) {
	if quotaRequested(mask) {
		quotaInformation(logy, about)
	}
	if fileSizesRequested(mask) {
		fileSizesInfo(logy, about)
	}

	if featuresRequested(mask) {
		featuresInformation(logy, about)
	}
}

func fileSizesInfo(logy *log.Logger, about *drive.About) {
	if len(about.MaxUploadSizes) >= 1 {
		logy.Logln("\n* Maximum upload sizes per file type *")
		logy.Logf("%-50s %-20s\n", "FileType", "Size")
		for _, uploadInfo := range about.MaxUploadSizes {
			logy.Logf("%-50s %-20s\n", uploadInfo.Type, prettyBytes(uploadInfo.Size))
		}
		logy.Logln()
	}
	return
}

func featuresInformation(logy *log.Logger, about *drive.About) {
	if len(about.Features) >= 1 {
		logy.Logf("%-30s %-30s\n", "Feature", "Request limit (queries/second)")
		for _, feature := range about.Features {
			if feature.FeatureName == "" {
				continue
			}
			logy.Logf("%-30s %-30f\n", feature.FeatureName, feature.FeatureRate)
		}
		logy.Logln()
	}
}

func quotaInformation(logy *log.Logger, about *drive.About) {
	freeBytes := about.QuotaBytesTotal - about.QuotaBytesUsed

	logy.Logf(
		"Name: %s\nAccount type:\t%s\nBytes Used:\t%-20d (%s)\n"+
			"Bytes Free:\t%-20d (%s)\nBytes InTrash:\t%-20d (%s)\n"+
			"Total Bytes:\t%-20d (%s)\n",
		about.Name, about.QuotaType,
		about.QuotaBytesUsed, prettyBytes(about.QuotaBytesUsed),
		freeBytes, prettyBytes(freeBytes),
		about.QuotaBytesUsedInTrash, prettyBytes(about.QuotaBytesUsedInTrash),
		about.QuotaBytesTotal, prettyBytes(about.QuotaBytesTotal))

	if len(about.QuotaBytesByService) >= 1 {
		logy.Logln("\n* Space used by Google Services *")
		logy.Logf("%-36s %-36s\n", "Service", "Bytes")
		for _, quotaService := range about.QuotaBytesByService {
			logy.Logf("%-36s %-36s\n", quotaService.ServiceName, prettyBytes(quotaService.BytesUsed))
		}
		logy.Logf("%-36s %-36s\n", "Space used by all Google Apps",
			prettyBytes(about.QuotaBytesUsedAggregate))
	}
	logy.Logln()
}

func (g *Commands) QuotaStatus(query int64) (status int, err error) {
	if query < 0 {
		return Unknown, err
	}

	about, err := g.rem.About()
	if err != nil {
		return Unknown, err
	}

	// Sanity check
	if about.QuotaBytesTotal < 1 {
		return Unknown, fmt.Errorf("QuotaBytesTotal < 1")
	}

	toBeUsed := query + about.QuotaBytesUsed
	if toBeUsed >= about.QuotaBytesTotal {
		return Exceeded, nil
	}

	percentage := float64(toBeUsed) / float64(about.QuotaBytesTotal)
	if percentage < 0.5 {
		return Barely, nil
	}
	if percentage < 0.8 {
		return HalfwayExceeded, nil
	}
	return AlmostExceeded, nil
}
<commit_msg>version bump<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package drive

import (
	"fmt"

	drive "github.com/odeke-em/google-api-go-client/drive/v2"
	"github.com/odeke-em/log"
)

const Version = "0.1.9"

const (
	Barely = iota
	AlmostExceeded
	HalfwayExceeded
	Exceeded
	Unknown
)

const (
	AboutNone = 1 << iota
	AboutQuota
	AboutFileSizes
	AboutFeatures
)

func (g *Commands) About(mask int) (err error) {
	defer PrintVersion()
	if mask == AboutNone {
		return nil
	}

	about, err := g.rem.About()
	if err != nil {
		return err
	}
	printSummary(g.log, about, mask)

	return nil
}

func quotaRequested(mask int) bool {
	return (mask & AboutQuota) != 0
}

func fileSizesRequested(mask int) bool {
	return (mask & AboutFileSizes) != 0
}

func featuresRequested(mask int) bool {
	return (mask & AboutFeatures) != 0
}

func printSummary(logy *log.Logger, about *drive.About, mask int) {
	if quotaRequested(mask) {
		quotaInformation(logy, about)
	}
	if fileSizesRequested(mask) {
		fileSizesInfo(logy, about)
	}

	if featuresRequested(mask) {
		featuresInformation(logy, about)
	}
}

func fileSizesInfo(logy *log.Logger, about *drive.About) {
	if len(about.MaxUploadSizes) >= 1 {
		logy.Logln("\n* Maximum upload sizes per file type *")
		logy.Logf("%-50s %-20s\n", "FileType", "Size")
		for _, uploadInfo := range about.MaxUploadSizes {
			logy.Logf("%-50s %-20s\n", uploadInfo.Type, prettyBytes(uploadInfo.Size))
		}
		logy.Logln()
	}
	return
}

func featuresInformation(logy *log.Logger, about *drive.About) {
	if len(about.Features) >= 1 {
		logy.Logf("%-30s %-30s\n", "Feature", "Request limit (queries/second)")
		for _, feature := range about.Features {
			if feature.FeatureName == "" {
				continue
			}
			logy.Logf("%-30s %-30f\n", feature.FeatureName, feature.FeatureRate)
		}
		logy.Logln()
	}
}

func quotaInformation(logy *log.Logger, about *drive.About) {
	freeBytes := about.QuotaBytesTotal - about.QuotaBytesUsed

	logy.Logf(
		"Name: %s\nAccount type:\t%s\nBytes Used:\t%-20d (%s)\n"+
			"Bytes Free:\t%-20d (%s)\nBytes InTrash:\t%-20d (%s)\n"+
			"Total Bytes:\t%-20d (%s)\n",
		about.Name, about.QuotaType,
		about.QuotaBytesUsed, prettyBytes(about.QuotaBytesUsed),
		freeBytes, prettyBytes(freeBytes),
		about.QuotaBytesUsedInTrash, prettyBytes(about.QuotaBytesUsedInTrash),
		about.QuotaBytesTotal, prettyBytes(about.QuotaBytesTotal))

	if len(about.QuotaBytesByService) >= 1 {
		logy.Logln("\n* Space used by Google Services *")
		logy.Logf("%-36s %-36s\n", "Service", "Bytes")
		for _, quotaService := range about.QuotaBytesByService {
			logy.Logf("%-36s %-36s\n", quotaService.ServiceName, prettyBytes(quotaService.BytesUsed))
		}
		logy.Logf("%-36s %-36s\n", "Space used by all Google Apps",
			prettyBytes(about.QuotaBytesUsedAggregate))
	}
	logy.Logln()
}

func (g *Commands) QuotaStatus(query int64) (status int, err error) {
	if query < 0 {
		return Unknown, err
	}

	about, err := g.rem.About()
	if err != nil {
		return Unknown, err
	}

	// Sanity check
	if about.QuotaBytesTotal < 1 {
		return Unknown, fmt.Errorf("QuotaBytesTotal < 1")
	}

	toBeUsed := query + about.QuotaBytesUsed
	if toBeUsed >= about.QuotaBytesTotal {
		return Exceeded, nil
	}

	percentage := float64(toBeUsed) / float64(about.QuotaBytesTotal)
	if percentage < 0.5 {
		return Barely, nil
	}
	if percentage < 0.8 {
		return HalfwayExceeded, nil
	}
	return AlmostExceeded, nil
}
<|endoftext|>