<commit_before>package encoding

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"encoding/xml"
	"errors"
	"reflect"
	"strings"
)

func init() {
	gob.Register(WrapperError{})
}

type WrapperError struct {
	Type      string      `json:"type" xml:"type"`
	ErrString string      `json:"errorString" xml:"error-string"`
	Err       interface{} `json:"error" xml:"error"`
}

func (we WrapperError) Error() string {
	if e, ok := we.Err.(error); ok {
		return e.Error()
	}

	return we.ErrString
}

var ErrUnexpectedJSONDelim = errors.New("Unexpected JSON Delim")

// implements encoding/json.Unmarshaler
func (we *WrapperError) UnmarshalJSON(p []byte) error {
	buf := bytes.NewBuffer(p)
	dec := json.NewDecoder(buf)

	typ := reflect.TypeOf(*we)
	getTag := func(name string) string {
		n, _ := typ.FieldByName(name)
		return n.Tag.Get("json")
	}

	for {
		t, err := dec.Token()
		if err != nil {
			return err
		}
		if delim, ok := t.(json.Delim); ok {
			// have a deliminator
			switch delim.String() {
			case "{":
				continue
			case "}":
				return nil
			default:
				// unexpected Delim
				return ErrUnexpectedJSONDelim
			}
		}

		if str, ok := t.(string); ok {
			switch str {
			case getTag("Type"):
				err = dec.Decode(&we.Type)
				if err != nil {
					break
				}

				e, err := GetErrorInstance(we.Type)
				if err == nil {
					we.Err = e
				}
			case getTag("ErrString"):
				err = dec.Decode(&we.ErrString)
			case getTag("Err"):
				err = dec.Decode(&we.Err)
				if we.Err != nil {
					we.Err = reflect.Indirect(reflect.ValueOf(we.Err)).Interface()
				}
			default:
				continue
			}
		}

		if err != nil {
			return err
		}
	}
	return nil
}

var ErrUnexpectedElementType = errors.New("Unexpected XML Element Type")

// implements encoding/xml.Unmarshaler
func (we *WrapperError) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	typ := reflect.TypeOf(*we)

	getTag := func(name string) string {
		n, _ := typ.FieldByName(name)
		return n.Tag.Get("xml")
	}
	for {
		t, err := d.Token()
		if err != nil {
			return err
		}
		if t == start.End() {
			// we've consumed everything there is
			return nil
		}

		startToken, ok := t.(xml.StartElement)
		if t == nil || !ok {
			return ErrUnexpectedElementType
		}

		switch startToken.Name.Local {
		case getTag("Type"):
			err = d.DecodeElement(&we.Type, &startToken)
			if err != nil {
				break
			}
			if e, err := GetErrorInstance(we.Type); err == nil {
				we.Err = e
			}
		case getTag("ErrString"):
			err = d.DecodeElement(&we.ErrString, &startToken)
		case getTag("Err"):
			err = d.DecodeElement(&we.Err, &startToken)
			if we.Err != nil {
				we.Err = reflect.Indirect(reflect.ValueOf(we.Err)).Interface()
			}
		default:
		}

		if err != nil {
			return err
		}
	}

	return nil
}

func WrapError(e error) *WrapperError {
	t := reflect.TypeOf(e)
	if _, err := GetErrorInstance(t.String()); err != nil {
		// don't transmit errors.errorString types
		return &WrapperError{
			Type:      t.String(),
			ErrString: e.Error(),
		}
	}

	// perhaps some further checking to see if it adheres to the encoding
	// requirements.

	return &WrapperError{
		Type:      t.String(),
		ErrString: e.Error(),
		Err:       e,
	}
}

var ErrBlacklisted = errors.New("This Error type isn't able to registered, as it is not encodable / decodable")
var ErrDuplicate = errors.New("You tried to register a duplicate type")
var ErrUnknownError = errors.New("The type specified hasn't be registered")

var registeredErrors = make(map[string]reflect.Type)

// RegisterError will attempt to register the given Error with the encoders /
// decoders and will make it available for Decoding errors for the encoders /
// decoders.
//
// This will not automatically register this error type with encoding/gob
func RegisterError(e error) error {
	t := reflect.TypeOf(e)
	if reflect.TypeOf(ErrBlacklisted) == t {
		return ErrBlacklisted
	}

	// ensure that we have a pointer
	if t.Kind() == reflect.Ptr {
		t = reflect.ValueOf(e).Type()
	}

	if registeredErrors[t.String()] != nil {
		return ErrDuplicate
	}

	// store the type information
	registeredErrors[t.String()] = t
	return nil
}

// GetErrorInstance will use reflection to attempt and instanciate a new error
// of the given type string.  The error returned will be a pointer.
func GetErrorInstance(s string) (interface{}, error) {
	s = strings.TrimPrefix(s, "*")
	if registeredErrors[s] == nil {
		return nil, ErrUnknownError
	}

	return reflect.New(registeredErrors[s]).Interface(), nil
}
<commit_msg>add handling of embedding github.com/go-kit/kit/transport/http.Error automatically<commit_after>package encoding

import (
	"bytes"
	"encoding/gob"
	"encoding/json"
	"encoding/xml"
	"errors"
	"reflect"
	"strings"

	kittransporthttp "github.com/go-kit/kit/transport/http"
)

func init() {
	gob.Register(WrapperError{})
	gob.Register(kittransporthttp.Error{})
	RegisterError(kittransporthttp.Error{})
}

type WrapperError struct {
	Type      string      `json:"type" xml:"type"`
	ErrString string      `json:"errorString" xml:"error-string"`
	Err       interface{} `json:"error" xml:"error"`
}

func (we WrapperError) Error() string {
	if e, ok := we.Err.(error); ok {
		return e.Error()
	}

	return we.ErrString
}

var ErrUnexpectedJSONDelim = errors.New("Unexpected JSON Delim")

// implements encoding/json.Unmarshaler
func (we *WrapperError) UnmarshalJSON(p []byte) error {
	buf := bytes.NewBuffer(p)
	dec := json.NewDecoder(buf)

	typ := reflect.TypeOf(*we)
	getTag := func(name string) string {
		n, _ := typ.FieldByName(name)
		return n.Tag.Get("json")
	}

	for {
		t, err := dec.Token()
		if err != nil {
			return err
		}
		if delim, ok := t.(json.Delim); ok {
			// have a deliminator
			switch delim.String() {
			case "{":
				continue
			case "}":
				return nil
			default:
				// unexpected Delim
				return ErrUnexpectedJSONDelim
			}
		}

		if str, ok := t.(string); ok {
			switch str {
			case getTag("Type"):
				err = dec.Decode(&we.Type)
				if err != nil {
					break
				}

				e, err := GetErrorInstance(we.Type)
				if err == nil {
					we.Err = e
				}
			case getTag("ErrString"):
				err = dec.Decode(&we.ErrString)
			case getTag("Err"):
				if kitErr, ok := we.Err.(*kittransporthttp.Error); ok {
					func(kitErr *kittransporthttp.Error, dec *json.Decoder) error {
						for {
							t, err := dec.Token()
							if err != nil {
								return err
							}

							if delim, ok := t.(json.Delim); ok {
								switch delim.String() {
								case "{":
									continue
								case "}":
									return nil
								default:
									// unexpected Delim
									return ErrUnexpectedJSONDelim
								}
							}

							if str, ok := t.(string); ok {
								switch str {
								case "Domain":
									err = dec.Decode(&kitErr.Domain)
								case "Err":
									var e WrapperError
									err = dec.Decode(&e)
									if err != nil {
										return err
									}

									kitErr.Err = e.Err.(error)
								}
							}

							if err != nil {
								return err
							}
						}
					}(kitErr, dec)

					// we have kit transport error, special case... need to
					// multi-layer unwrap...

					// { "Domain": "str", "Err": "WrappedErr" }
					if we.Err != nil {
						we.Err = reflect.Indirect(reflect.ValueOf(we.Err)).Interface()
					}
					break
				}

				err = dec.Decode(&we.Err)
				if we.Err != nil {
					we.Err = reflect.Indirect(reflect.ValueOf(we.Err)).Interface()
				}
			default:
				continue
			}
		}

		if err != nil {
			return err
		}
	}
	return nil
}

var ErrUnexpectedElementType = errors.New("Unexpected XML Element Type")

// implements encoding/xml.Unmarshaler
func (we *WrapperError) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	typ := reflect.TypeOf(*we)

	getTag := func(name string) string {
		n, _ := typ.FieldByName(name)
		return n.Tag.Get("xml")
	}
	for {
		t, err := d.Token()
		if err != nil {
			return err
		}
		if t == start.End() {
			// we've consumed everything there is
			return nil
		}

		startToken, ok := t.(xml.StartElement)
		if t == nil || !ok {
			return ErrUnexpectedElementType
		}

		switch startToken.Name.Local {
		case getTag("Type"):
			err = d.DecodeElement(&we.Type, &startToken)
			if err != nil {
				break
			}
			if e, err := GetErrorInstance(we.Type); err == nil {
				we.Err = e
			}
		case getTag("ErrString"):
			err = d.DecodeElement(&we.ErrString, &startToken)
		case getTag("Err"):
			if kitErr, ok := we.Err.(*kittransporthttp.Error); ok {
				func(kitErr *kittransporthttp.Error, d *xml.Decoder, start xml.StartElement) error {
					for {
						t, err := d.Token()
						if err != nil {
							return err
						}
						if t == start.End() {
							// we've consumed everything there is
							return nil
						}

						startToken, ok := t.(xml.StartElement)
						if t == nil || !ok {
							return ErrUnexpectedElementType
						}

						switch startToken.Name.Local {
						case "Domain":
							err = d.DecodeElement(&kitErr.Domain, &startToken)
						case "Err":
							var e WrapperError
							err = d.DecodeElement(&e, &startToken)
							if err != nil {
								return err
							}

							kitErr.Err = e.Err.(error)
						}

						if err != nil {
							return err
						}
					}
				}(kitErr, d, startToken)

				// we have kit transport error, special case... need to
				// multi-layer unwrap...

				// { "Domain": "str", "Err": "WrappedErr" }
				if we.Err != nil {
					we.Err = reflect.Indirect(reflect.ValueOf(we.Err)).Interface()
				}
				break
			}

			err = d.DecodeElement(&we.Err, &startToken)
			if we.Err != nil {
				we.Err = reflect.Indirect(reflect.ValueOf(we.Err)).Interface()
			}
		default:
		}

		if err != nil {
			return err
		}
	}

	return nil
}

func WrapError(e error) *WrapperError {
	t := reflect.TypeOf(e)
	if _, err := GetErrorInstance(t.String()); err != nil {
		// don't transmit errors.errorString types
		return &WrapperError{
			Type:      t.String(),
			ErrString: e.Error(),
		}
	}

	// perhaps some further checking to see if it adheres to the encoding
	// requirements.

	switch v := e.(type) {
	case kittransporthttp.Error:
		return &WrapperError{
			Type:      t.String(),
			ErrString: e.Error(),
			Err: kittransporthttp.Error{
				Domain: v.Domain,
				Err:    WrapError(v.Err),
			},
		}
	case *kittransporthttp.Error:
		return &WrapperError{
			Type:      t.String(),
			ErrString: e.Error(),
			Err: kittransporthttp.Error{
				Domain: v.Domain,
				Err:    WrapError(v.Err),
			},
		}
	}

	return &WrapperError{
		Type:      t.String(),
		ErrString: e.Error(),
		Err:       e,
	}
}

var ErrBlacklisted = errors.New("This Error type isn't able to registered, as it is not encodable / decodable")
var ErrDuplicate = errors.New("You tried to register a duplicate type")
var ErrUnknownError = errors.New("The type specified hasn't be registered")

var registeredErrors = make(map[string]reflect.Type)

// RegisterError will attempt to register the given Error with the encoders /
// decoders and will make it available for Decoding errors for the encoders /
// decoders.
//
// This will not automatically register this error type with encoding/gob
func RegisterError(e error) error {
	t := reflect.TypeOf(e)
	if reflect.TypeOf(ErrBlacklisted) == t {
		return ErrBlacklisted
	}

	// ensure that we do not have a pointer
	if t.Kind() == reflect.Ptr {
		t = reflect.ValueOf(e).Type()
	}

	if registeredErrors[t.String()] != nil {
		return ErrDuplicate
	}

	// store the type information
	registeredErrors[t.String()] = t
	return nil
}

// GetErrorInstance will use reflection to attempt and instanciate a new error
// of the given type string.  The error returned will be a pointer.
func GetErrorInstance(s string) (interface{}, error) {
	s = strings.TrimPrefix(s, "*")
	if registeredErrors[s] == nil {
		return nil, ErrUnknownError
	}

	return reflect.New(registeredErrors[s]).Interface(), nil
}
<|endoftext|>


<commit_before>package models

import (
	_ "github.com/go-sql-driver/mysql"
	"github.com/lunny/xorm"
	"fmt"
)

func main() {
	xorm.
}<commit_msg>willing to use beego/orm instead of xorm because xorm can`t change table name easily<commit_after>package models

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"github.com/lunny/xorm"
)

func main() {
	xorm.NewEngine("mysql", dataSourceName)
}
<|endoftext|>


<commit_before>package testutil

import (
	"bufio"
	"bytes"
	"os"
	"os/exec"
	"strings"
	"text/template"
	"unicode"
)

// dedent is a helper function that trims repeated, leading spaces from several
// lines of text. This is useful for long, inline commands that are indented to
// match the surrounding code but should be interpreted without the space:
// e.g.:
// func() {
//   BashCmd(`
//     cat <<EOF
//     This is a test
//     EOF
//   `)
// }
// Should evaluate:
// $ cat <<EOF
// > This is a test
// > EOF
// not:
// $      cat <<EOF
// >      This is a test
// >      EOF  # doesn't terminate heredoc b/c of space
// such that the heredoc doesn't end properly
func dedent(cmd string) string {
	notSpace := func(r rune) bool {
		return !unicode.IsSpace(r)
	}

	prefix := "-" // non-space character indicates no prefix has been established
	s := bufio.NewScanner(strings.NewReader(cmd))
	var dedentedCmd bytes.Buffer
	for s.Scan() {
		i := strings.IndexFunc(s.Text(), notSpace)
		if i == -1 {
			continue // blank line (or spaces-only line)--ignore completely
		} else if prefix == "-" {
			prefix = s.Text()[:i] // first non-blank line, set prefix
			dedentedCmd.WriteString(s.Text()[i:])
			dedentedCmd.WriteRune('\n')
		} else if strings.HasPrefix(s.Text(), prefix) {
			dedentedCmd.WriteString(s.Text()[len(prefix):]) // remove prefix
			dedentedCmd.WriteRune('\n')
		} else {
			return cmd // no common prefix--break early
		}
	}
	return dedentedCmd.String()
}

// Cmd is a convenience function that replaces exec.Command. It's both shorter
// and it uses the current process's stderr as output for the command, which
// makes debugging failures much easier (i.e. you get an error message
// rather than "exit status 1")
func Cmd(name string, args ...string) *exec.Cmd {
	cmd := exec.Command(name, args...)
	cmd.Stderr = os.Stderr
	// for convenience, simulate hitting "enter" after any prompt. This can easily
	// be replaced
	cmd.Stdin = strings.NewReader("\n")
	cmd.Env = os.Environ()
	return cmd
}

// BashCmd is a convenience function that:
// 1. Performs a Go template substitution on 'cmd' using the strings in 'subs'
// 2. Returns a command that runs the result string from 1 as a Bash script
func BashCmd(cmd string, subs ...string) *exec.Cmd {
	if len(subs)%2 == 1 {
		panic("some variable does not have a corresponding value")
	}

	// copy 'subs' into a map
	subsMap := make(map[string]string)
	for i := 0; i < len(subs); i += 2 {
		subsMap[subs[i]] = subs[i+1]
	}

	// Warn users that they must install 'match' if they want to run tests with
	// this library, and enable 'pipefail' so that if any 'match' in a chain
	// fails, the whole command fails.
	buf := &bytes.Buffer{}
	buf.WriteString(`
set -e -o pipefail

# Try to ignore pipefail errors (encountered when writing to a closed pipe).
# Processes like 'yes' are essentially guaranteed to hit this, and because of
# -e -o pipefail they will crash the whole script. We need these options,
# though, for 'match' to work, so for now we work around pipefail errors on a
# cmd-by-cmd basis. See "The Infamous SIGPIPE Signal"
# http://www.tldp.org/LDP/lpg/node20.html
pipeerr=141 # typical error code returned by unix utils when SIGPIPE is raised
function yes {
	/usr/bin/yes || test "$?" -eq "${pipeerr}"
}
export -f yes # use in subshells too

which match >/dev/null || {
	echo "You must have 'match' installed to run these tests. Please run:" >&2
	echo "  go install ./src/testing/match" >&2
	exit 1
}`)
	buf.WriteRune('\n')

	// do the substitution
	template.Must(template.New("").Parse(dedent(cmd))).Execute(buf, subsMap)
	res := exec.Command("/bin/bash")
	res.Stderr = os.Stderr
	// useful for debugging, but makes logs too noisy:
	// res.Stdout = os.Stdout
	res.Stdin = buf
	res.Env = os.Environ()
	return res
}
<commit_msg>BashCmd warns if cmd text mixes spaces and tabs<commit_after>package testutil

import (
	"bufio"
	"bytes"
	"fmt"
	"os"
	"os/exec"
	"strings"
	"text/template"
	"unicode"
)

// dedent is a helper function that trims repeated, leading spaces from several
// lines of text. This is useful for long, inline commands that are indented to
// match the surrounding code but should be interpreted without the space:
// e.g.:
// func() {
//   BashCmd(`
//     cat <<EOF
//     This is a test
//     EOF
//   `)
// }
// Should evaluate:
// $ cat <<EOF
// > This is a test
// > EOF
// not:
// $      cat <<EOF
// >      This is a test
// >      EOF  # doesn't terminate heredoc b/c of space
// such that the heredoc doesn't end properly
func dedent(cmd string) string {
	notSpace := func(r rune) bool {
		return !unicode.IsSpace(r)
	}

	prefix := "-" // non-space character indicates no prefix has been established
	s := bufio.NewScanner(strings.NewReader(cmd))
	var dedentedCmd bytes.Buffer
	for s.Scan() {
		i := strings.IndexFunc(s.Text(), notSpace)
		if i == -1 {
			continue // blank line (or spaces-only line)--ignore completely
		} else if prefix == "-" {
			prefix = s.Text()[:i] // first non-blank line, set prefix
			dedentedCmd.WriteString(s.Text()[i:])
			dedentedCmd.WriteRune('\n')
		} else if strings.HasPrefix(s.Text(), prefix) {
			dedentedCmd.WriteString(s.Text()[len(prefix):]) // remove prefix
			dedentedCmd.WriteRune('\n')
		} else {
			fmt.Fprintf(os.Stderr,
				"\nWARNING: the line\n  %q\ncannot be dedented as missing the prefix %q\n",
				s.Text(), prefix)
			return cmd // no common prefix--break early
		}
	}
	return dedentedCmd.String()
}

// Cmd is a convenience function that replaces exec.Command. It's both shorter
// and it uses the current process's stderr as output for the command, which
// makes debugging failures much easier (i.e. you get an error message
// rather than "exit status 1")
func Cmd(name string, args ...string) *exec.Cmd {
	cmd := exec.Command(name, args...)
	cmd.Stderr = os.Stderr
	// for convenience, simulate hitting "enter" after any prompt. This can easily
	// be replaced
	cmd.Stdin = strings.NewReader("\n")
	cmd.Env = os.Environ()
	return cmd
}

// BashCmd is a convenience function that:
// 1. Performs a Go template substitution on 'cmd' using the strings in 'subs'
// 2. Returns a command that runs the result string from 1 as a Bash script
func BashCmd(cmd string, subs ...string) *exec.Cmd {
	if len(subs)%2 == 1 {
		panic("some variable does not have a corresponding value")
	}

	// copy 'subs' into a map
	subsMap := make(map[string]string)
	for i := 0; i < len(subs); i += 2 {
		subsMap[subs[i]] = subs[i+1]
	}

	// Warn users that they must install 'match' if they want to run tests with
	// this library, and enable 'pipefail' so that if any 'match' in a chain
	// fails, the whole command fails.
	buf := &bytes.Buffer{}
	buf.WriteString(`
set -e -o pipefail

# Try to ignore pipefail errors (encountered when writing to a closed pipe).
# Processes like 'yes' are essentially guaranteed to hit this, and because of
# -e -o pipefail they will crash the whole script. We need these options,
# though, for 'match' to work, so for now we work around pipefail errors on a
# cmd-by-cmd basis. See "The Infamous SIGPIPE Signal"
# http://www.tldp.org/LDP/lpg/node20.html
pipeerr=141 # typical error code returned by unix utils when SIGPIPE is raised
function yes {
	/usr/bin/yes || test "$?" -eq "${pipeerr}"
}
export -f yes # use in subshells too

which match >/dev/null || {
	echo "You must have 'match' installed to run these tests. Please run:" >&2
	echo "  go install ./src/testing/match" >&2
	exit 1
}`)
	buf.WriteRune('\n')

	// do the substitution
	template.Must(template.New("").Parse(dedent(cmd))).Execute(buf, subsMap)
	res := exec.Command("/bin/bash")
	res.Stderr = os.Stderr
	// useful for debugging, but makes logs too noisy:
	// res.Stdout = os.Stdout
	res.Stdin = buf
	res.Env = os.Environ()
	return res
}
<|endoftext|>


<commit_before>package models

import (
	"database/sql"
	"time"
)

type Announce struct {
	PK    int
	URL   string
	Date  time.Time
	Price string
	Title string

	Fetched time.Time

	PlacePK int
}

func CreateTableAnnounces() error {
	_, err := db.Exec(`CREATE TABLE IF NOT EXISTS pollbc_announces (
		pk serial PRIMARY KEY,
		url text UNIQUE NOT NULL,
		date timestamp with time zone NOT NULL,
		price text,
		title text NOT NULL,
		fetched timestamp with time zone NOT NULL,
		place_pk serial REFERENCES pollbc_places(pk)
	);`)
	return err
}

func HasAnnounce(url string) (bool, error) {
	var pk int
	err := db.QueryRow("SELECT pk FROM pollbc_announces WHERE url=$1", url).Scan(&pk)
	if err == sql.ErrNoRows {
		return false, nil
	} else if err != nil {
		return false, err
	} else {
		return true, nil
	}
}

func InsertAnnounce(ann Announce) error {
	_, err := db.Exec("INSERT INTO pollbc_announces (url, date, price, title, fetched, place_pk) VALUES ($1, $2, $3, $4, $5, $6)",
		ann.URL, ann.Date, ann.Price, ann.Title, ann.Fetched, ann.PlacePK)
	return err
}

func SelectAnnounces() ([]Announce, error) {
	rows, err := db.Query("SELECT * FROM pollbc_announces ORDER BY date DESC LIMIT 35")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	return scanAnnounces(rows)
}

func SelectAnnouncesWherePlacePK(placePK int) ([]Announce, error) {
	rows, err := db.Query("SELECT * FROM pollbc_announces WHERE place_pk=$1 ORDER BY date DESC LIMIT 35", placePK)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	return scanAnnounces(rows)
}

func SelectAnnouncesWhereDepartmentPK(departmendPK int) ([]Announce, error) {
	rows, err := db.Query("SELECT * FROM pollbc_announces WHERE place_pk IN (SELECT pk from pollbc_places WHERE department_pk=$1) ORDER BY date DESC LIMIT 35", departmendPK)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	return scanAnnounces(rows)
}

func scanAnnounces(rows *sql.Rows) ([]Announce, error) {
	ann := make([]Announce, 0)
	for rows.Next() {
		a := Announce{}
		err := rows.Scan(&a.PK, &a.URL, &a.Date, &a.Price, &a.Title, &a.Fetched, &a.PlacePK)
		if err != nil {
			return ann, err
		}

		ann = append(ann, a)
	}
	if err := rows.Err(); err != nil {
		return ann, err
	}
	return ann, nil
}

func DeleteAnnounces() (int64, error) {
	res, err := db.Exec("DELETE FROM pollbc_announces WHERE date < NOW() - interval '1 week'")
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}
<commit_msg>Keep announces during one month<commit_after>package models

import (
	"database/sql"
	"time"
)

type Announce struct {
	PK    int
	URL   string
	Date  time.Time
	Price string
	Title string

	Fetched time.Time

	PlacePK int
}

func CreateTableAnnounces() error {
	_, err := db.Exec(`CREATE TABLE IF NOT EXISTS pollbc_announces (
		pk serial PRIMARY KEY,
		url text UNIQUE NOT NULL,
		date timestamp with time zone NOT NULL,
		price text,
		title text NOT NULL,
		fetched timestamp with time zone NOT NULL,
		place_pk serial REFERENCES pollbc_places(pk)
	);`)
	return err
}

func HasAnnounce(url string) (bool, error) {
	var pk int
	err := db.QueryRow("SELECT pk FROM pollbc_announces WHERE url=$1", url).Scan(&pk)
	if err == sql.ErrNoRows {
		return false, nil
	} else if err != nil {
		return false, err
	} else {
		return true, nil
	}
}

func InsertAnnounce(ann Announce) error {
	_, err := db.Exec("INSERT INTO pollbc_announces (url, date, price, title, fetched, place_pk) VALUES ($1, $2, $3, $4, $5, $6)",
		ann.URL, ann.Date, ann.Price, ann.Title, ann.Fetched, ann.PlacePK)
	return err
}

func SelectAnnounces() ([]Announce, error) {
	rows, err := db.Query("SELECT * FROM pollbc_announces ORDER BY date DESC LIMIT 35")
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	return scanAnnounces(rows)
}

func SelectAnnouncesWherePlacePK(placePK int) ([]Announce, error) {
	rows, err := db.Query("SELECT * FROM pollbc_announces WHERE place_pk=$1 ORDER BY date DESC LIMIT 35", placePK)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	return scanAnnounces(rows)
}

func SelectAnnouncesWhereDepartmentPK(departmendPK int) ([]Announce, error) {
	rows, err := db.Query("SELECT * FROM pollbc_announces WHERE place_pk IN (SELECT pk from pollbc_places WHERE department_pk=$1) ORDER BY date DESC LIMIT 35", departmendPK)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	return scanAnnounces(rows)
}

func scanAnnounces(rows *sql.Rows) ([]Announce, error) {
	ann := make([]Announce, 0)
	for rows.Next() {
		a := Announce{}
		err := rows.Scan(&a.PK, &a.URL, &a.Date, &a.Price, &a.Title, &a.Fetched, &a.PlacePK)
		if err != nil {
			return ann, err
		}

		ann = append(ann, a)
	}
	if err := rows.Err(); err != nil {
		return ann, err
	}
	return ann, nil
}

func DeleteAnnounces() (int64, error) {
	res, err := db.Exec("DELETE FROM pollbc_announces WHERE date < NOW() - interval '1 month'")
	if err != nil {
		return 0, err
	}
	return res.RowsAffected()
}
<|endoftext|>


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

package models

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/Unknwon/com"

	"github.com/gogits/gogs/modules/log"
	"github.com/gogits/gogs/modules/process"
)

const (
	// "### autogenerated by gitgos, DO NOT EDIT\n"
	_TPL_PUBLICK_KEY = `command="%s serv key-%d",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n"
)

var (
	ErrKeyAlreadyExist = errors.New("Public key already exist")
	ErrKeyNotExist     = errors.New("Public key does not exist")
)

var sshOpLocker = sync.Mutex{}

var (
	SshPath string // SSH directory.
	appPath string // Execution(binary) path.
)

// exePath returns the executable path.
func exePath() (string, error) {
	file, err := exec.LookPath(os.Args[0])
	if err != nil {
		return "", err
	}
	return filepath.Abs(file)
}

// homeDir returns the home directory of current user.
func homeDir() string {
	home, err := com.HomeDir()
	if err != nil {
		log.Fatal(4, "Fail to get home directory: %v", err)
	}
	return home
}

func init() {
	var err error

	if appPath, err = exePath(); err != nil {
		log.Fatal(4, "fail to get app path: %v\n", err)
	}
	appPath = strings.Replace(appPath, "\\", "/", -1)

	// Determine and create .ssh path.
	SshPath = filepath.Join(homeDir(), ".ssh")
	if err = os.MkdirAll(SshPath, 0700); err != nil {
		log.Fatal(4, "fail to create SshPath(%s): %v\n", SshPath, err)
	}
}

// PublicKey represents a SSH key.
type PublicKey struct {
	Id                int64
	OwnerId           int64  `xorm:"UNIQUE(s) INDEX NOT NULL"`
	Name              string `xorm:"UNIQUE(s) NOT NULL"`
	Fingerprint       string
	Content           string    `xorm:"TEXT NOT NULL"`
	Created           time.Time `xorm:"CREATED"`
	Updated           time.Time
	HasRecentActivity bool `xorm:"-"`
	HasUsed           bool `xorm:"-"`
}

// GetAuthorizedString generates and returns formatted public key string for authorized_keys file.
func (key *PublicKey) GetAuthorizedString() string {
	return fmt.Sprintf(_TPL_PUBLICK_KEY, appPath, key.Id, key.Content)
}

var (
	MinimumKeySize = map[string]int{
		"(ED25519)": 256,
		"(ECDSA)":   256,
		"(NTRU)":    1087,
		"(MCE)":     1702,
		"(McE)":     1702,
		"(RSA)":     2048,
	}
)

// CheckPublicKeyString checks if the given public key string is recognized by SSH.
func CheckPublicKeyString(content string) (bool, error) {
	if strings.ContainsAny(content, "\n\r") {
		return false, errors.New("Only a single line with a single key please")
	}

	// write the key to a file…
	tmpFile, err := ioutil.TempFile(os.TempDir(), "keytest")
	if err != nil {
		return false, err
	}
	tmpPath := tmpFile.Name()
	defer os.Remove(tmpPath)
	tmpFile.WriteString(content)
	tmpFile.Close()

	// … see if ssh-keygen recognizes its contents
	stdout, stderr, err := process.Exec("CheckPublicKeyString", "ssh-keygen", "-l", "-f", tmpPath)
	if err != nil {
		return false, errors.New("ssh-keygen -l -f: " + stderr)
	} else if len(stdout) < 2 {
		return false, errors.New("ssh-keygen returned not enough output to evaluate the key")
	}
	sshKeygenOutput := strings.Split(stdout, " ")
	if len(sshKeygenOutput) < 4 {
		return false, errors.New("Not enough fields returned by ssh-keygen -l -f")
	}
	keySize, err := com.StrTo(sshKeygenOutput[0]).Int()
	if err != nil {
		return false, errors.New("Cannot get key size of the given key")
	}
	keyType := strings.TrimSpace(sshKeygenOutput[len(sshKeygenOutput)-1])

	if minimumKeySize := MinimumKeySize[keyType]; minimumKeySize == 0 {
		return false, errors.New("Sorry, unrecognized public key type")
	} else if keySize < minimumKeySize {
		return false, fmt.Errorf("The minimum accepted size of a public key %s is %d", keyType, minimumKeySize)
	}

	return true, nil
}

// saveAuthorizedKeyFile writes SSH key content to authorized_keys file.
func saveAuthorizedKeyFile(key *PublicKey) error {
	sshOpLocker.Lock()
	defer sshOpLocker.Unlock()

	fpath := filepath.Join(SshPath, "authorized_keys")
	f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
	if err != nil {
		return err
	}
	finfo, err := f.Stat()
	if err != nil {
		return err
	}
	if finfo.Mode().Perm() > 0600 {
		log.Error(3, "authorized_keys file has unusual permission flags: %s - setting to -rw-------", finfo.Mode().Perm().String())
		f.Chmod(0600)
	}

	defer f.Close()

	_, err = f.WriteString(key.GetAuthorizedString())
	return err
}

// AddPublicKey adds new public key to database and authorized_keys file.
func AddPublicKey(key *PublicKey) (err error) {
	has, err := x.Get(key)
	if err != nil {
		return err
	} else if has {
		return ErrKeyAlreadyExist
	}

	// Calculate fingerprint.
	tmpPath := strings.Replace(path.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()),
		"id_rsa.pub"), "\\", "/", -1)
	os.MkdirAll(path.Dir(tmpPath), os.ModePerm)
	if err = ioutil.WriteFile(tmpPath, []byte(key.Content), os.ModePerm); err != nil {
		return err
	}
	stdout, stderr, err := process.Exec("AddPublicKey", "ssh-keygen", "-l", "-f", tmpPath)
	if err != nil {
		return errors.New("ssh-keygen -l -f: " + stderr)
	} else if len(stdout) < 2 {
		return errors.New("Not enough output for calculating fingerprint")
	}
	key.Fingerprint = strings.Split(stdout, " ")[1]

	// Save SSH key.
	if _, err = x.Insert(key); err != nil {
		return err
	} else if err = saveAuthorizedKeyFile(key); err != nil {
		// Roll back.
		if _, err2 := x.Delete(key); err2 != nil {
			return err2
		}
		return err
	}

	return nil
}

// ListPublicKey returns a list of all public keys that user has.
func ListPublicKey(uid int64) ([]*PublicKey, error) {
	keys := make([]*PublicKey, 0, 5)
	err := x.Find(&keys, &PublicKey{OwnerId: uid})
	if err != nil {
		return nil, err
	}

	for _, key := range keys {
		key.HasUsed = key.Updated.After(key.Created)
		key.HasRecentActivity = key.Updated.Add(7 * 24 * time.Hour).After(time.Now())
	}
	return keys, nil
}

// rewriteAuthorizedKeys finds and deletes corresponding line in authorized_keys file.
func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error {
	sshOpLocker.Lock()
	defer sshOpLocker.Unlock()

	fr, err := os.Open(p)
	if err != nil {
		return err
	}
	defer fr.Close()

	fw, err := os.OpenFile(tmpP, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
	if err != nil {
		return err
	}
	defer fw.Close()

	isFound := false
	keyword := fmt.Sprintf("key-%d", key.Id)
	buf := bufio.NewReader(fr)
	for {
		line, errRead := buf.ReadString('\n')
		line = strings.TrimSpace(line)

		if errRead != nil {
			if errRead != io.EOF {
				return errRead
			}

			// Reached end of file, if nothing to read then break,
			// otherwise handle the last line.
			if len(line) == 0 {
				break
			}
		}

		// Found the line and copy rest of file.
		if !isFound && strings.Contains(line, keyword) && strings.Contains(line, key.Content) {
			isFound = true
			continue
		}
		// Still finding the line, copy the line that currently read.
		if _, err = fw.WriteString(line + "\n"); err != nil {
			return err
		}

		if errRead == io.EOF {
			break
		}
	}
	return nil
}

// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
func DeletePublicKey(key *PublicKey) error {
	has, err := x.Get(key)
	if err != nil {
		return err
	} else if !has {
		return ErrKeyNotExist
	}

	if _, err = x.Delete(key); err != nil {
		return err
	}

	fpath := filepath.Join(SshPath, "authorized_keys")
	tmpPath := filepath.Join(SshPath, "authorized_keys.tmp")
	if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil {
		return err
	} else if err = os.Remove(fpath); err != nil {
		return err
	}
	return os.Rename(tmpPath, fpath)
}
<commit_msg>Moved defer f.Close() up so there is no chance of returning without closing and handled an error on f.Chmod<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package models

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/Unknwon/com"

	"github.com/gogits/gogs/modules/log"
	"github.com/gogits/gogs/modules/process"
)

const (
	// "### autogenerated by gitgos, DO NOT EDIT\n"
	_TPL_PUBLICK_KEY = `command="%s serv key-%d",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty %s` + "\n"
)

var (
	ErrKeyAlreadyExist = errors.New("Public key already exist")
	ErrKeyNotExist     = errors.New("Public key does not exist")
)

var sshOpLocker = sync.Mutex{}

var (
	SshPath string // SSH directory.
	appPath string // Execution(binary) path.
)

// exePath returns the executable path.
func exePath() (string, error) {
	file, err := exec.LookPath(os.Args[0])
	if err != nil {
		return "", err
	}
	return filepath.Abs(file)
}

// homeDir returns the home directory of current user.
func homeDir() string {
	home, err := com.HomeDir()
	if err != nil {
		log.Fatal(4, "Fail to get home directory: %v", err)
	}
	return home
}

func init() {
	var err error

	if appPath, err = exePath(); err != nil {
		log.Fatal(4, "fail to get app path: %v\n", err)
	}
	appPath = strings.Replace(appPath, "\\", "/", -1)

	// Determine and create .ssh path.
	SshPath = filepath.Join(homeDir(), ".ssh")
	if err = os.MkdirAll(SshPath, 0700); err != nil {
		log.Fatal(4, "fail to create SshPath(%s): %v\n", SshPath, err)
	}
}

// PublicKey represents a SSH key.
type PublicKey struct {
	Id                int64
	OwnerId           int64  `xorm:"UNIQUE(s) INDEX NOT NULL"`
	Name              string `xorm:"UNIQUE(s) NOT NULL"`
	Fingerprint       string
	Content           string    `xorm:"TEXT NOT NULL"`
	Created           time.Time `xorm:"CREATED"`
	Updated           time.Time
	HasRecentActivity bool `xorm:"-"`
	HasUsed           bool `xorm:"-"`
}

// GetAuthorizedString generates and returns formatted public key string for authorized_keys file.
func (key *PublicKey) GetAuthorizedString() string {
	return fmt.Sprintf(_TPL_PUBLICK_KEY, appPath, key.Id, key.Content)
}

var (
	MinimumKeySize = map[string]int{
		"(ED25519)": 256,
		"(ECDSA)":   256,
		"(NTRU)":    1087,
		"(MCE)":     1702,
		"(McE)":     1702,
		"(RSA)":     2048,
	}
)

// CheckPublicKeyString checks if the given public key string is recognized by SSH.
func CheckPublicKeyString(content string) (bool, error) {
	if strings.ContainsAny(content, "\n\r") {
		return false, errors.New("Only a single line with a single key please")
	}

	// write the key to a file…
	tmpFile, err := ioutil.TempFile(os.TempDir(), "keytest")
	if err != nil {
		return false, err
	}
	tmpPath := tmpFile.Name()
	defer os.Remove(tmpPath)
	tmpFile.WriteString(content)
	tmpFile.Close()

	// … see if ssh-keygen recognizes its contents
	stdout, stderr, err := process.Exec("CheckPublicKeyString", "ssh-keygen", "-l", "-f", tmpPath)
	if err != nil {
		return false, errors.New("ssh-keygen -l -f: " + stderr)
	} else if len(stdout) < 2 {
		return false, errors.New("ssh-keygen returned not enough output to evaluate the key")
	}
	sshKeygenOutput := strings.Split(stdout, " ")
	if len(sshKeygenOutput) < 4 {
		return false, errors.New("Not enough fields returned by ssh-keygen -l -f")
	}
	keySize, err := com.StrTo(sshKeygenOutput[0]).Int()
	if err != nil {
		return false, errors.New("Cannot get key size of the given key")
	}
	keyType := strings.TrimSpace(sshKeygenOutput[len(sshKeygenOutput)-1])

	if minimumKeySize := MinimumKeySize[keyType]; minimumKeySize == 0 {
		return false, errors.New("Sorry, unrecognized public key type")
	} else if keySize < minimumKeySize {
		return false, fmt.Errorf("The minimum accepted size of a public key %s is %d", keyType, minimumKeySize)
	}

	return true, nil
}

// saveAuthorizedKeyFile writes SSH key content to authorized_keys file.
func saveAuthorizedKeyFile(key *PublicKey) error {
	sshOpLocker.Lock()
	defer sshOpLocker.Unlock()

	fpath := filepath.Join(SshPath, "authorized_keys")
	f, err := os.OpenFile(fpath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
	if err != nil {
		return err
	}
	defer f.Close()
	finfo, err := f.Stat()
	if err != nil {
		return err
	}
	if finfo.Mode().Perm() > 0600 {
		log.Error(3, "authorized_keys file has unusual permission flags: %s - setting to -rw-------", finfo.Mode().Perm().String())
		err = f.Chmod(0600)
		if err != nil {
			return err
		}
	}

	_, err = f.WriteString(key.GetAuthorizedString())
	return err
}

// AddPublicKey adds new public key to database and authorized_keys file.
func AddPublicKey(key *PublicKey) (err error) {
	has, err := x.Get(key)
	if err != nil {
		return err
	} else if has {
		return ErrKeyAlreadyExist
	}

	// Calculate fingerprint.
	tmpPath := strings.Replace(path.Join(os.TempDir(), fmt.Sprintf("%d", time.Now().Nanosecond()),
		"id_rsa.pub"), "\\", "/", -1)
	os.MkdirAll(path.Dir(tmpPath), os.ModePerm)
	if err = ioutil.WriteFile(tmpPath, []byte(key.Content), os.ModePerm); err != nil {
		return err
	}
	stdout, stderr, err := process.Exec("AddPublicKey", "ssh-keygen", "-l", "-f", tmpPath)
	if err != nil {
		return errors.New("ssh-keygen -l -f: " + stderr)
	} else if len(stdout) < 2 {
		return errors.New("Not enough output for calculating fingerprint")
	}
	key.Fingerprint = strings.Split(stdout, " ")[1]

	// Save SSH key.
	if _, err = x.Insert(key); err != nil {
		return err
	} else if err = saveAuthorizedKeyFile(key); err != nil {
		// Roll back.
		if _, err2 := x.Delete(key); err2 != nil {
			return err2
		}
		return err
	}

	return nil
}

// ListPublicKey returns a list of all public keys that user has.
func ListPublicKey(uid int64) ([]*PublicKey, error) {
	keys := make([]*PublicKey, 0, 5)
	err := x.Find(&keys, &PublicKey{OwnerId: uid})
	if err != nil {
		return nil, err
	}

	for _, key := range keys {
		key.HasUsed = key.Updated.After(key.Created)
		key.HasRecentActivity = key.Updated.Add(7 * 24 * time.Hour).After(time.Now())
	}
	return keys, nil
}

// rewriteAuthorizedKeys finds and deletes corresponding line in authorized_keys file.
func rewriteAuthorizedKeys(key *PublicKey, p, tmpP string) error {
	sshOpLocker.Lock()
	defer sshOpLocker.Unlock()

	fr, err := os.Open(p)
	if err != nil {
		return err
	}
	defer fr.Close()

	fw, err := os.OpenFile(tmpP, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
	if err != nil {
		return err
	}
	defer fw.Close()

	isFound := false
	keyword := fmt.Sprintf("key-%d", key.Id)
	buf := bufio.NewReader(fr)
	for {
		line, errRead := buf.ReadString('\n')
		line = strings.TrimSpace(line)

		if errRead != nil {
			if errRead != io.EOF {
				return errRead
			}

			// Reached end of file, if nothing to read then break,
			// otherwise handle the last line.
			if len(line) == 0 {
				break
			}
		}

		// Found the line and copy rest of file.
		if !isFound && strings.Contains(line, keyword) && strings.Contains(line, key.Content) {
			isFound = true
			continue
		}
		// Still finding the line, copy the line that currently read.
		if _, err = fw.WriteString(line + "\n"); err != nil {
			return err
		}

		if errRead == io.EOF {
			break
		}
	}
	return nil
}

// DeletePublicKey deletes SSH key information both in database and authorized_keys file.
func DeletePublicKey(key *PublicKey) error {
	has, err := x.Get(key)
	if err != nil {
		return err
	} else if !has {
		return ErrKeyNotExist
	}

	if _, err = x.Delete(key); err != nil {
		return err
	}

	fpath := filepath.Join(SshPath, "authorized_keys")
	tmpPath := filepath.Join(SshPath, "authorized_keys.tmp")
	if err = rewriteAuthorizedKeys(key, fpath, tmpPath); err != nil {
		return err
	} else if err = os.Remove(fpath); err != nil {
		return err
	}
	return os.Rename(tmpPath, fpath)
}
<|endoftext|>


<commit_before>package native

import (
    "fmt"
    "time"
    "unsafe"
    . "jvmgo/any"
    "jvmgo/rtda"
    rtc "jvmgo/rtda/class"
)

// register native methods
func init() {
    rtc.SetRegisterNatives(registerNatives)
    jlSystem("nanoTime",            "()J",                      nanoTime)
    jlSystem("currentTimeMillis",   "()J",                      currentTimeMillis)
    jlSystem("identityHashCode",    "(Ljava/lang/Object;)I",    identityHashCode)
    jlObject("getClass",            "()Ljava/lang/Class;",      getClass)
    jlClass ("getName0",            "()Ljava/lang/String;",     getName0)
    // hack
    rtc.RegisterNativeMethod("jvmgo/SystemOut", "println", "(Ljava/lang/String;)V", jvmgo_SystemOut_println)
}

func jlSystem(name, desc string, method Any) {
    rtc.RegisterNativeMethod("java/lang/System", name, desc, method)
}
func jlObject(name, desc string, method Any) {
    rtc.RegisterNativeMethod("java/lang/Object", name, desc, method)
}
func jlClass(name, desc string, method Any) {
    rtc.RegisterNativeMethod("java/lang/Class", name, desc, method)
}

func registerNatives(operandStack *rtda.OperandStack) {
    // todo
}

// java.lang.System
func nanoTime(stack *rtda.OperandStack) {
    nanoTime := time.Now().UnixNano()
    stack.PushLong(nanoTime)
}
func currentTimeMillis(stack *rtda.OperandStack) {
    millis := time.Now().UnixNano() / 1000
    stack.PushLong(millis)
}
func identityHashCode(stack *rtda.OperandStack) {
    // todo
    ref := stack.PopRef()
    hashCode := int32(uintptr(unsafe.Pointer(ref)))
    stack.PushInt(hashCode)
}

// java.lang.Object
func getClass(stack *rtda.OperandStack) {
    this := stack.PopRef()
    class := this.Class().Obj()
    stack.PushRef(class)
}

// java.lang.Class
func getName0(stack *rtda.OperandStack) {
    panic("getname0")
}

// hack
func jvmgo_SystemOut_println(stack *rtda.OperandStack) {
    str := stack.PopRef()
    this := stack.PopRef()
    this.Class()
    chars := str.Class().GetField("value", "[C").GetValue(str).(*rtc.Obj).Fields().([]uint16)
    for _, char := range chars {
        fmt.Printf("%c", char)
    }
    fmt.Println()
}
<commit_msg>natice: java.lang.Class. getClassLoader0()<commit_after>package native

import (
    "fmt"
    "time"
    "unsafe"
    . "jvmgo/any"
    "jvmgo/rtda"
    rtc "jvmgo/rtda/class"
)

// register native methods
func init() {
    rtc.SetRegisterNatives(registerNatives)
    jlSystem("nanoTime",            "()J",                          nanoTime)
    jlSystem("currentTimeMillis",   "()J",                          currentTimeMillis)
    jlSystem("identityHashCode",    "(Ljava/lang/Object;)I",        identityHashCode)
    jlObject("getClass",            "()Ljava/lang/Class;",          getClass)
    jlClass ("getName0",            "()Ljava/lang/String;",         getName0)
    jlClass ("getClassLoader0",     "()Ljava/lang/ClassLoader;",    getClassLoader0)
    // hack
    rtc.RegisterNativeMethod("jvmgo/SystemOut", "println", "(Ljava/lang/String;)V", jvmgo_SystemOut_println)
}

func jlSystem(name, desc string, method Any) {
    rtc.RegisterNativeMethod("java/lang/System", name, desc, method)
}
func jlObject(name, desc string, method Any) {
    rtc.RegisterNativeMethod("java/lang/Object", name, desc, method)
}
func jlClass(name, desc string, method Any) {
    rtc.RegisterNativeMethod("java/lang/Class", name, desc, method)
}

func registerNatives(operandStack *rtda.OperandStack) {
    // todo
}

// java.lang.System
func nanoTime(stack *rtda.OperandStack) {
    nanoTime := time.Now().UnixNano()
    stack.PushLong(nanoTime)
}
func currentTimeMillis(stack *rtda.OperandStack) {
    millis := time.Now().UnixNano() / 1000
    stack.PushLong(millis)
}
func identityHashCode(stack *rtda.OperandStack) {
    // todo
    ref := stack.PopRef()
    hashCode := int32(uintptr(unsafe.Pointer(ref)))
    stack.PushInt(hashCode)
}

// java.lang.Object
func getClass(stack *rtda.OperandStack) {
    this := stack.PopRef()
    class := this.Class().Obj()
    stack.PushRef(class)
}

// java.lang.Class
func getName0(stack *rtda.OperandStack) {
    panic("getName0")
}
func getClassLoader0(stack *rtda.OperandStack) {
    // todo
    stack.PushRef(nil)
}

// hack
func jvmgo_SystemOut_println(stack *rtda.OperandStack) {
    str := stack.PopRef()
    this := stack.PopRef()
    this.Class()
    chars := str.Class().GetField("value", "[C").GetValue(str).(*rtc.Obj).Fields().([]uint16)
    for _, char := range chars {
        fmt.Printf("%c", char)
    }
    fmt.Println()
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"time"

	humanize "github.com/dustin/go-humanize"
	"github.com/dustin/go-humanize/english"
	"github.com/fatih/color"
	"github.com/minio/cli"
	json "github.com/minio/colorjson"
	"github.com/minio/madmin-go"
	"github.com/minio/mc/pkg/probe"
	"github.com/minio/pkg/console"
)

var adminInfoCmd = cli.Command{
	Name:         "info",
	Usage:        "display MinIO server information",
	Action:       mainAdminInfo,
	OnUsageError: onUsageError,
	Before:       setGlobalsFromContext,
	Flags:        globalFlags,
	CustomHelpTemplate: `NAME:
  {{.HelpName}} - {{.Usage}}

USAGE:
  {{.HelpName}} TARGET

FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}
EXAMPLES:
  1. Get server information of the 'play' MinIO server.
     {{.Prompt}} {{.HelpName}} play/
`,
}

// Wrap "Info" message together with fields "Status" and "Error"
type clusterStruct struct {
	Status string             `json:"status"`
	Error  string             `json:"error,omitempty"`
	Info   madmin.InfoMessage `json:"info,omitempty"`
}

// String provides colorized info messages depending on the type of a server
//        FS server                          non-FS server
// ==============================  ===================================
// ● <ip>:<port>                   ● <ip>:<port>
//   Uptime: xxx                     Uptime: xxx
//   Version: xxx                    Version: xxx
//   Network: X/Y OK                 Network: X/Y OK
//
// U Used, B Buckets, O Objects    Drives: N/N OK
//
//                                   U Used, B Buckets, O Objects
//                                   N drives online, K drives offline
//
func (u clusterStruct) String() (msg string) {
	// Check cluster level "Status" field for error
	if u.Status == "error" {
		fatal(probe.NewError(errors.New(u.Error)), "Unable to get service status")
	}

	// If nothing has been collected, error out
	if u.Info.Servers == nil {
		fatal(probe.NewError(errors.New("Unable to get service status")), "")
	}

	// Initialization
	var totalOnlineDisksCluster int
	var totalOfflineDisksCluster int

	// Color palette initialization
	console.SetColor("Info", color.New(color.FgGreen, color.Bold))
	console.SetColor("InfoFail", color.New(color.FgRed, color.Bold))
	console.SetColor("InfoWarning", color.New(color.FgYellow, color.Bold))

	// MinIO server type default
	backendType := "Unknown"
	// Set the type of MinIO server ("FS", "Erasure", "Unknown")
	v := reflect.ValueOf(u.Info.Backend)
	if v.Kind() == reflect.Map {
		for _, key := range v.MapKeys() {
			val := v.MapIndex(key)
			switch t := val.Interface().(type) {
			case string:
				backendType = t
			}
		}
	}

	coloredDot := console.Colorize("Info", dot)
	if madmin.ItemState(u.Info.Mode) == madmin.ItemInitializing {
		coloredDot = console.Colorize("InfoWarning", dot)
	}

	// Loop through each server and put together info for each one
	for _, srv := range u.Info.Servers {
		// Check if MinIO server is offline ("Mode" field),
		// If offline, error out
		if srv.State == "offline" {
			// "PrintB" is color blue in console library package
			msg += fmt.Sprintf("%s  %s\n", console.Colorize("InfoFail", dot), console.Colorize("PrintB", srv.Endpoint))
			msg += fmt.Sprintf("   Uptime: %s\n", console.Colorize("InfoFail", "offline"))

			if backendType != "FS" {
				// Info about drives on a server, only available for non-FS types
				var OffDisks int
				var OnDisks int
				var dispNoOfDisks string
				for _, disk := range srv.Disks {
					switch disk.State {
					case madmin.DriveStateOk:
						fallthrough
					case madmin.DriveStateUnformatted:
						OnDisks++
					default:
						OffDisks++
					}
				}

				totalDisksPerServer := OnDisks + OffDisks
				totalOnlineDisksCluster += OnDisks
				totalOfflineDisksCluster += OffDisks

				dispNoOfDisks = strconv.Itoa(OnDisks) + "/" + strconv.Itoa(totalDisksPerServer)
				msg += fmt.Sprintf("   Drives: %s %s\n", dispNoOfDisks, console.Colorize("InfoFail", "OK "))
			}

			msg += "\n"

			// Continue to the next server
			continue
		}

		// Print server title
		msg += fmt.Sprintf("%s  %s\n", coloredDot, console.Colorize("PrintB", srv.Endpoint))

		// Uptime
		msg += fmt.Sprintf("   Uptime: %s\n", console.Colorize("Info",
			humanize.RelTime(time.Now(), time.Now().Add(time.Duration(srv.Uptime)*time.Second), "", "")))

		// Version
		version := srv.Version
		if srv.Version == "DEVELOPMENT.GOGET" {
			version = "<development>"
		}
		msg += fmt.Sprintf("   Version: %s\n", version)

		// Network info, only available for non-FS types
		var connectionAlive int
		totalNodes := strconv.Itoa(len(srv.Network))
		if srv.Network != nil {
			for _, v := range srv.Network {
				if v == "online" {
					connectionAlive++
				}
			}
			displayNwInfo := strconv.Itoa(connectionAlive) + "/" + totalNodes
			msg += fmt.Sprintf("   Network: %s %s\n", displayNwInfo, console.Colorize("Info", "OK "))
		}

		if backendType != "FS" {
			// Info about drives on a server, only available for non-FS types
			var OffDisks int
			var OnDisks int
			var dispNoOfDisks string
			for _, disk := range srv.Disks {
				switch disk.State {
				case madmin.DriveStateOk:
					fallthrough
				case madmin.DriveStateUnformatted:
					OnDisks++
				default:
					OffDisks++
				}
			}

			totalDisksPerServer := OnDisks + OffDisks
			totalOnlineDisksCluster += OnDisks
			totalOfflineDisksCluster += OffDisks

			dispNoOfDisks = strconv.Itoa(OnDisks) + "/" + strconv.Itoa(totalDisksPerServer)
			msg += fmt.Sprintf("   Drives: %s %s\n", dispNoOfDisks, console.Colorize("Info", "OK "))

		}

		msg += "\n"
	}

	// Summary on used space, total no of buckets and
	// total no of objects at the Cluster level
	usedTotal := humanize.IBytes(uint64(u.Info.Usage.Size))
	if u.Info.Buckets.Count > 0 {
		msg += fmt.Sprintf("%s Used, %s, %s\n", usedTotal,
			english.Plural(int(u.Info.Buckets.Count), "Bucket", ""),
			english.Plural(int(u.Info.Objects.Count), "Object", ""))
	}
	if backendType != "FS" {
		// Summary on total no of online and total
		// number of offline disks at the Cluster level
		msg += fmt.Sprintf("%s online, %s offline\n",
			english.Plural(totalOnlineDisksCluster, "drive", ""),
			english.Plural(totalOfflineDisksCluster, "drive", ""))
	}

	// Remove the last new line if any
	// since this is a String() function
	msg = strings.TrimSuffix(msg, "\n")
	return
}

// JSON jsonifies service status message.
func (u clusterStruct) JSON() string {
	statusJSONBytes, e := json.MarshalIndent(u, "", "    ")
	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")

	return string(statusJSONBytes)
}

// checkAdminInfoSyntax - validate arguments passed by a user
func checkAdminInfoSyntax(ctx *cli.Context) {
	if len(ctx.Args()) == 0 || len(ctx.Args()) > 1 {
		cli.ShowCommandHelpAndExit(ctx, "info", 1) // last argument is exit code
	}
}

func mainAdminInfo(ctx *cli.Context) error {
	checkAdminInfoSyntax(ctx)

	// Get the alias parameter from cli
	args := ctx.Args()
	aliasedURL := args.Get(0)

	// Create a new MinIO Admin Client
	client, err := newAdminClient(aliasedURL)
	fatalIf(err, "Unable to initialize admin connection.")

	var clusterInfo clusterStruct
	// Fetch info of all servers (cluster or single server)
	admInfo, e := client.ServerInfo(globalContext)
	if e != nil {
		clusterInfo.Status = "error"
		clusterInfo.Error = e.Error()
	} else {
		clusterInfo.Status = "success"
		clusterInfo.Error = ""
	}
	clusterInfo.Info = admInfo
	printMsg(clusterStruct(clusterInfo))

	return nil
}
<commit_msg>Order mc admin info output by endpoint (#3804)<commit_after>// Copyright (c) 2015-2021 MinIO, Inc.
//
// This file is part of MinIO Object Storage stack
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

package cmd

import (
	"errors"
	"fmt"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"time"

	humanize "github.com/dustin/go-humanize"
	"github.com/dustin/go-humanize/english"
	"github.com/fatih/color"
	"github.com/minio/cli"
	json "github.com/minio/colorjson"
	"github.com/minio/madmin-go"
	"github.com/minio/mc/pkg/probe"
	"github.com/minio/pkg/console"
)

var adminInfoCmd = cli.Command{
	Name:         "info",
	Usage:        "display MinIO server information",
	Action:       mainAdminInfo,
	OnUsageError: onUsageError,
	Before:       setGlobalsFromContext,
	Flags:        globalFlags,
	CustomHelpTemplate: `NAME:
  {{.HelpName}} - {{.Usage}}

USAGE:
  {{.HelpName}} TARGET

FLAGS:
  {{range .VisibleFlags}}{{.}}
  {{end}}
EXAMPLES:
  1. Get server information of the 'play' MinIO server.
     {{.Prompt}} {{.HelpName}} play/
`,
}

// Wrap "Info" message together with fields "Status" and "Error"
type clusterStruct struct {
	Status string             `json:"status"`
	Error  string             `json:"error,omitempty"`
	Info   madmin.InfoMessage `json:"info,omitempty"`
}

// String provides colorized info messages depending on the type of a server
//        FS server                          non-FS server
// ==============================  ===================================
// ● <ip>:<port>                   ● <ip>:<port>
//   Uptime: xxx                     Uptime: xxx
//   Version: xxx                    Version: xxx
//   Network: X/Y OK                 Network: X/Y OK
//
// U Used, B Buckets, O Objects    Drives: N/N OK
//
//                                   U Used, B Buckets, O Objects
//                                   N drives online, K drives offline
//
func (u clusterStruct) String() (msg string) {
	// Check cluster level "Status" field for error
	if u.Status == "error" {
		fatal(probe.NewError(errors.New(u.Error)), "Unable to get service status")
	}

	// If nothing has been collected, error out
	if u.Info.Servers == nil {
		fatal(probe.NewError(errors.New("Unable to get service status")), "")
	}

	// Initialization
	var totalOnlineDisksCluster int
	var totalOfflineDisksCluster int

	// Color palette initialization
	console.SetColor("Info", color.New(color.FgGreen, color.Bold))
	console.SetColor("InfoFail", color.New(color.FgRed, color.Bold))
	console.SetColor("InfoWarning", color.New(color.FgYellow, color.Bold))

	// MinIO server type default
	backendType := "Unknown"
	// Set the type of MinIO server ("FS", "Erasure", "Unknown")
	v := reflect.ValueOf(u.Info.Backend)
	if v.Kind() == reflect.Map {
		for _, key := range v.MapKeys() {
			val := v.MapIndex(key)
			switch t := val.Interface().(type) {
			case string:
				backendType = t
			}
		}
	}

	coloredDot := console.Colorize("Info", dot)
	if madmin.ItemState(u.Info.Mode) == madmin.ItemInitializing {
		coloredDot = console.Colorize("InfoWarning", dot)
	}

	sort.Slice(u.Info.Servers, func(i, j int) bool {
		return u.Info.Servers[i].Endpoint < u.Info.Servers[j].Endpoint
	})

	// Loop through each server and put together info for each one
	for _, srv := range u.Info.Servers {
		// Check if MinIO server is offline ("Mode" field),
		// If offline, error out
		if srv.State == "offline" {
			// "PrintB" is color blue in console library package
			msg += fmt.Sprintf("%s  %s\n", console.Colorize("InfoFail", dot), console.Colorize("PrintB", srv.Endpoint))
			msg += fmt.Sprintf("   Uptime: %s\n", console.Colorize("InfoFail", "offline"))

			if backendType != "FS" {
				// Info about drives on a server, only available for non-FS types
				var OffDisks int
				var OnDisks int
				var dispNoOfDisks string
				for _, disk := range srv.Disks {
					switch disk.State {
					case madmin.DriveStateOk:
						fallthrough
					case madmin.DriveStateUnformatted:
						OnDisks++
					default:
						OffDisks++
					}
				}

				totalDisksPerServer := OnDisks + OffDisks
				totalOnlineDisksCluster += OnDisks
				totalOfflineDisksCluster += OffDisks

				dispNoOfDisks = strconv.Itoa(OnDisks) + "/" + strconv.Itoa(totalDisksPerServer)
				msg += fmt.Sprintf("   Drives: %s %s\n", dispNoOfDisks, console.Colorize("InfoFail", "OK "))
			}

			msg += "\n"

			// Continue to the next server
			continue
		}

		// Print server title
		msg += fmt.Sprintf("%s  %s\n", coloredDot, console.Colorize("PrintB", srv.Endpoint))

		// Uptime
		msg += fmt.Sprintf("   Uptime: %s\n", console.Colorize("Info",
			humanize.RelTime(time.Now(), time.Now().Add(time.Duration(srv.Uptime)*time.Second), "", "")))

		// Version
		version := srv.Version
		if srv.Version == "DEVELOPMENT.GOGET" {
			version = "<development>"
		}
		msg += fmt.Sprintf("   Version: %s\n", version)

		// Network info, only available for non-FS types
		var connectionAlive int
		totalNodes := strconv.Itoa(len(srv.Network))
		if srv.Network != nil {
			for _, v := range srv.Network {
				if v == "online" {
					connectionAlive++
				}
			}
			displayNwInfo := strconv.Itoa(connectionAlive) + "/" + totalNodes
			msg += fmt.Sprintf("   Network: %s %s\n", displayNwInfo, console.Colorize("Info", "OK "))
		}

		if backendType != "FS" {
			// Info about drives on a server, only available for non-FS types
			var OffDisks int
			var OnDisks int
			var dispNoOfDisks string
			for _, disk := range srv.Disks {
				switch disk.State {
				case madmin.DriveStateOk:
					fallthrough
				case madmin.DriveStateUnformatted:
					OnDisks++
				default:
					OffDisks++
				}
			}

			totalDisksPerServer := OnDisks + OffDisks
			totalOnlineDisksCluster += OnDisks
			totalOfflineDisksCluster += OffDisks

			dispNoOfDisks = strconv.Itoa(OnDisks) + "/" + strconv.Itoa(totalDisksPerServer)
			msg += fmt.Sprintf("   Drives: %s %s\n", dispNoOfDisks, console.Colorize("Info", "OK "))

		}

		msg += "\n"
	}

	// Summary on used space, total no of buckets and
	// total no of objects at the Cluster level
	usedTotal := humanize.IBytes(uint64(u.Info.Usage.Size))
	if u.Info.Buckets.Count > 0 {
		msg += fmt.Sprintf("%s Used, %s, %s\n", usedTotal,
			english.Plural(int(u.Info.Buckets.Count), "Bucket", ""),
			english.Plural(int(u.Info.Objects.Count), "Object", ""))
	}
	if backendType != "FS" {
		// Summary on total no of online and total
		// number of offline disks at the Cluster level
		msg += fmt.Sprintf("%s online, %s offline\n",
			english.Plural(totalOnlineDisksCluster, "drive", ""),
			english.Plural(totalOfflineDisksCluster, "drive", ""))
	}

	// Remove the last new line if any
	// since this is a String() function
	msg = strings.TrimSuffix(msg, "\n")
	return
}

// JSON jsonifies service status message.
func (u clusterStruct) JSON() string {
	statusJSONBytes, e := json.MarshalIndent(u, "", "    ")
	fatalIf(probe.NewError(e), "Unable to marshal into JSON.")

	return string(statusJSONBytes)
}

// checkAdminInfoSyntax - validate arguments passed by a user
func checkAdminInfoSyntax(ctx *cli.Context) {
	if len(ctx.Args()) == 0 || len(ctx.Args()) > 1 {
		cli.ShowCommandHelpAndExit(ctx, "info", 1) // last argument is exit code
	}
}

func mainAdminInfo(ctx *cli.Context) error {
	checkAdminInfoSyntax(ctx)

	// Get the alias parameter from cli
	args := ctx.Args()
	aliasedURL := args.Get(0)

	// Create a new MinIO Admin Client
	client, err := newAdminClient(aliasedURL)
	fatalIf(err, "Unable to initialize admin connection.")

	var clusterInfo clusterStruct
	// Fetch info of all servers (cluster or single server)
	admInfo, e := client.ServerInfo(globalContext)
	if e != nil {
		clusterInfo.Status = "error"
		clusterInfo.Error = e.Error()
	} else {
		clusterInfo.Status = "success"
		clusterInfo.Error = ""
	}
	clusterInfo.Info = admInfo
	printMsg(clusterStruct(clusterInfo))

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/ancientlore/vbscribble/vblexer"
	"github.com/ancientlore/vbscribble/vbscanner"
)

var (
	respWrite = flag.Bool("rw", false, "Use Response.Write formatting")
)

func main() {
	flag.Parse()

	for _, pattern := range flag.Args() {
		files, err := filepath.Glob(pattern)
		if err != nil {
			log.Fatal(err)
		}
		for _, f := range files {
			fi, err := os.Stat(f)
			if err != nil {
				log.Fatal(err)
			}
			if !fi.IsDir() {
				fmt.Fprintln(os.Stderr, "\n*** ", f, " ***")
				fil, err := os.Open(f)
				if err != nil {
					log.Fatal(err)
				}
				func(fil io.Reader, f string) {
					var lex vblexer.Lex
					defer func() {
						if r := recover(); r != nil {
							log.Print("PARSE ERROR ", f, ":", lex.Line, ": ", r)
						}
					}()
					lex.Init(fil, f, vbscanner.HTML_MODE)
					aft := ""
					tabs := 0
					startLine := true
					paren := false
					prevK := vblexer.EOF
					var prevT interface{}
					needStarter := false
					remTabAfterEOL := false
					if *respWrite {
						fmt.Print("<%")
					}
					for k, t, v := lex.Lex(); k != vblexer.EOF; k, t, v = lex.Lex() {
						if needStarter {
							fmt.Print("<%")
							needStarter = false
						}
						if startLine {
							if k == vblexer.STATEMENT {
								if t == "End" {
									pv := v
									k, t, v = lex.Lex()
									if k != vblexer.EOF {
										t = "End " + t.(string)
										v = pv + " " + v
										tabs--
										/*
											if t == "End Select" {
												tabs--
											}
										*/
									}
								}
								switch t {
								case "Else", "ElseIf", "Case", "Wend", "Next", "Loop":
									tabs--
								}
							}
							if tabs < 0 {
								tabs = 0
							}
							if prevK != vblexer.HTML {
								fmt.Print(strings.Repeat("\t", tabs))
							}
							if remTabAfterEOL {
								remTabAfterEOL = false
								tabs--
							}
							startLine = false
							aft = ""
							paren = false
						} else {
							aft = " "
						}
						if paren {
							paren = false
							aft = ""
						}
						if prevK == vblexer.STATEMENT && prevT == "Then" {
							if k != vblexer.EOL && k != vblexer.HTML {
								tabs--
							}
						}
						switch k {
						case vblexer.EOF:
						case vblexer.STATEMENT:
							fmt.Print(aft)
							fmt.Print(t)
							switch t {
							case "If", "Function", "Sub", "Class", "Property": // "Select"
								if !(prevK == vblexer.STATEMENT && prevT == "Exit") {
									tabs++
								}
							case "Else":
								if !(prevK == vblexer.STATEMENT && prevT == "Case") {
									tabs++
								}
							case "ElseIf", "Case", "While", "For": // "Do"
								tabs++
							}
						case vblexer.FUNCTION:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.KEYWORD, vblexer.KEYWORD_BOOL:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.COLOR_CONSTANT, vblexer.COMPARE_CONSTANT, vblexer.DATE_CONSTANT, vblexer.DATEFORMAT_CONSTANT, vblexer.MISC_CONSTANT, vblexer.MSGBOX_CONSTANT, vblexer.STRING_CONSTANT, vblexer.TRISTATE_CONSTANT, vblexer.VARTYPE_CONSTANT:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.IDENTIFIER:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.STRING:
							fmt.Print(aft)
							fmt.Printf("\"%s\"", strings.Replace(v, "\"", "\"\"", -1))
						case vblexer.INT:
							fmt.Print(aft)
							fmt.Print(v)
						case vblexer.FLOAT:
							fmt.Print(aft)
							fmt.Print(v)
						case vblexer.DATE:
							fmt.Print(aft)
							fmt.Print("#", v, "#")
						case vblexer.COMMENT:
							fmt.Print(aft)
							fmt.Printf("' %s", t)
						case vblexer.HTML:
							if *respWrite {
								lines := strings.Split(strings.Replace(v, "\r", "", -1), "\n")
								for index, line := range lines {
									if index == 0 {
										fmt.Println()
										fmt.Print(aft)
										fmt.Print("Response.Write ")
									} else {
										fmt.Print(strings.Repeat("\t", tabs+1))
										fmt.Print("& vbCrLf & ")
									}
									fmt.Printf("\"%s\"\n", strings.Replace(line, "\"", "\"\"", -1))
								}
							} else {
								if prevK != vblexer.EOF {
									fmt.Print(aft)
									fmt.Print("%>")
								}
								fmt.Print(v)
								needStarter = true
							}
							startLine = true
						case vblexer.CHAR:
							if prevK == vblexer.STATEMENT {
								fmt.Print(aft)
							}
							fmt.Print(t)
							if t == "(" {
								paren = true
							}
						case vblexer.EOL:
							if t == ":" {
								fmt.Print(aft)
								fmt.Print(t)
								fmt.Print(" ")
							} else {
								fmt.Println()
							}
							startLine = true
						case vblexer.OP:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.CONTINUATION:
							fmt.Print(aft)
							fmt.Print(t)
							tabs++
							remTabAfterEOL = true
						default:
							panic("Unexpected token type")
						}
						prevK = k
						prevT = t
					}
					if *respWrite {
						fmt.Println("%>")
					}
				}(fil, f)
				fil.Close()
			}
		}
	}
}
<commit_msg>Support With<commit_after>package main

import (
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"

	"github.com/ancientlore/vbscribble/vblexer"
	"github.com/ancientlore/vbscribble/vbscanner"
)

var (
	respWrite = flag.Bool("rw", false, "Use Response.Write formatting")
)

func main() {
	flag.Parse()

	for _, pattern := range flag.Args() {
		files, err := filepath.Glob(pattern)
		if err != nil {
			log.Fatal(err)
		}
		for _, f := range files {
			fi, err := os.Stat(f)
			if err != nil {
				log.Fatal(err)
			}
			if !fi.IsDir() {
				fmt.Fprintln(os.Stderr, "\n*** ", f, " ***")
				fil, err := os.Open(f)
				if err != nil {
					log.Fatal(err)
				}
				func(fil io.Reader, f string) {
					var lex vblexer.Lex
					defer func() {
						if r := recover(); r != nil {
							log.Print("PARSE ERROR ", f, ":", lex.Line, ": ", r)
						}
					}()
					lex.Init(fil, f, vbscanner.HTML_MODE)
					aft := ""
					tabs := 0
					startLine := true
					paren := false
					prevK := vblexer.EOF
					var prevT interface{}
					needStarter := false
					remTabAfterEOL := false
					if *respWrite {
						fmt.Print("<%")
					}
					for k, t, v := lex.Lex(); k != vblexer.EOF; k, t, v = lex.Lex() {
						if needStarter {
							fmt.Print("<%")
							needStarter = false
						}
						if startLine {
							if k == vblexer.STATEMENT {
								if t == "End" {
									pv := v
									k, t, v = lex.Lex()
									if k != vblexer.EOF {
										t = "End " + t.(string)
										v = pv + " " + v
										tabs--
										/*
											if t == "End Select" {
												tabs--
											}
										*/
									}
								}
								switch t {
								case "Else", "ElseIf", "Case", "Wend", "Next", "Loop":
									tabs--
								}
							}
							if tabs < 0 {
								tabs = 0
							}
							if prevK != vblexer.HTML {
								fmt.Print(strings.Repeat("\t", tabs))
							}
							if remTabAfterEOL {
								remTabAfterEOL = false
								tabs--
							}
							startLine = false
							aft = ""
							paren = false
						} else {
							aft = " "
						}
						if paren {
							paren = false
							aft = ""
						}
						if prevK == vblexer.STATEMENT && prevT == "Then" {
							if k != vblexer.EOL && k != vblexer.HTML {
								tabs--
							}
						}
						switch k {
						case vblexer.EOF:
						case vblexer.STATEMENT:
							fmt.Print(aft)
							fmt.Print(t)
							switch t {
							case "If", "Function", "Sub", "Class", "Property": // "Select"
								if !(prevK == vblexer.STATEMENT && prevT == "Exit") {
									tabs++
								}
							case "Else":
								if !(prevK == vblexer.STATEMENT && prevT == "Case") {
									tabs++
								}
							case "ElseIf", "Case", "While", "For", "With": // "Do"
								tabs++
							}
						case vblexer.FUNCTION:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.KEYWORD, vblexer.KEYWORD_BOOL:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.COLOR_CONSTANT, vblexer.COMPARE_CONSTANT, vblexer.DATE_CONSTANT, vblexer.DATEFORMAT_CONSTANT, vblexer.MISC_CONSTANT, vblexer.MSGBOX_CONSTANT, vblexer.STRING_CONSTANT, vblexer.TRISTATE_CONSTANT, vblexer.VARTYPE_CONSTANT:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.IDENTIFIER:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.STRING:
							fmt.Print(aft)
							fmt.Printf("\"%s\"", strings.Replace(v, "\"", "\"\"", -1))
						case vblexer.INT:
							fmt.Print(aft)
							fmt.Print(v)
						case vblexer.FLOAT:
							fmt.Print(aft)
							fmt.Print(v)
						case vblexer.DATE:
							fmt.Print(aft)
							fmt.Print("#", v, "#")
						case vblexer.COMMENT:
							fmt.Print(aft)
							fmt.Printf("' %s", t)
						case vblexer.HTML:
							if *respWrite {
								lines := strings.Split(strings.Replace(v, "\r", "", -1), "\n")
								for index, line := range lines {
									if index == 0 {
										fmt.Println()
										fmt.Print(aft)
										fmt.Print("Response.Write ")
									} else {
										fmt.Print(strings.Repeat("\t", tabs+1))
										fmt.Print("& vbCrLf & ")
									}
									fmt.Printf("\"%s\"\n", strings.Replace(line, "\"", "\"\"", -1))
								}
							} else {
								if prevK != vblexer.EOF {
									fmt.Print(aft)
									fmt.Print("%>")
								}
								fmt.Print(v)
								needStarter = true
							}
							startLine = true
						case vblexer.CHAR:
							if prevK == vblexer.STATEMENT {
								fmt.Print(aft)
							}
							fmt.Print(t)
							if t == "(" {
								paren = true
							}
						case vblexer.EOL:
							if t == ":" {
								fmt.Print(aft)
								fmt.Print(t)
								fmt.Print(" ")
							} else {
								fmt.Println()
							}
							startLine = true
						case vblexer.OP:
							fmt.Print(aft)
							fmt.Print(t)
						case vblexer.CONTINUATION:
							fmt.Print(aft)
							fmt.Print(t)
							tabs++
							remTabAfterEOL = true
						default:
							panic("Unexpected token type")
						}
						prevK = k
						prevT = t
					}
					if *respWrite {
						fmt.Println("%>")
					}
				}(fil, f)
				fil.Close()
			}
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors.

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

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

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

package main

import (
	"context"
	"fmt"
	"math/rand"
	"net/http"
	"net/http/pprof"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"syscall"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	discovery "k8s.io/apimachinery/pkg/version"
	"k8s.io/apiserver/pkg/server/healthz"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	certutil "k8s.io/client-go/util/cert"
	"k8s.io/klog/v2"

	"k8s.io/ingress-nginx/internal/file"
	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
	"k8s.io/ingress-nginx/internal/ingress/controller"
	"k8s.io/ingress-nginx/internal/ingress/metric"
	"k8s.io/ingress-nginx/internal/k8s"
	"k8s.io/ingress-nginx/internal/net/ssl"
	"k8s.io/ingress-nginx/internal/nginx"
	"k8s.io/ingress-nginx/version"
)

func main() {
	klog.InitFlags(nil)

	rand.Seed(time.Now().UnixNano())

	fmt.Println(version.String())

	showVersion, conf, err := parseFlags()
	if showVersion {
		os.Exit(0)
	}

	if err != nil {
		klog.Fatal(err)
	}

	err = file.CreateRequiredDirectories()
	if err != nil {
		klog.Fatal(err)
	}

	kubeClient, err := createApiserverClient(conf.APIServerHost, conf.RootCAFile, conf.KubeConfigFile)
	if err != nil {
		handleFatalInitError(err)
	}

	if len(conf.DefaultService) > 0 {
		err := checkService(conf.DefaultService, kubeClient)
		if err != nil {
			klog.Fatal(err)
		}

		klog.InfoS("Valid default backend", "service", conf.DefaultService)
	}

	if len(conf.PublishService) > 0 {
		err := checkService(conf.PublishService, kubeClient)
		if err != nil {
			klog.Fatal(err)
		}
	}

	if conf.Namespace != "" {
		_, err = kubeClient.CoreV1().Namespaces().Get(context.TODO(), conf.Namespace, metav1.GetOptions{})
		if err != nil {
			klog.Fatalf("No namespace with name %v found: %v", conf.Namespace, err)
		}
	}

	conf.FakeCertificate = ssl.GetFakeSSLCert()
	klog.InfoS("SSL fake certificate created", "file", conf.FakeCertificate.PemFileName)

	var isNetworkingIngressAvailable bool

	isNetworkingIngressAvailable, k8s.IsIngressV1Beta1Ready, _ = k8s.NetworkingIngressAvailable(kubeClient)
	if !isNetworkingIngressAvailable {
		klog.Fatalf("ingress-nginx requires Kubernetes v1.14.0 or higher")
	}

	if k8s.IsIngressV1Beta1Ready {
		klog.InfoS("Enabling new Ingress features available since Kubernetes v1.18")
		k8s.IngressClass, err = kubeClient.NetworkingV1beta1().IngressClasses().
			Get(context.TODO(), class.IngressClass, metav1.GetOptions{})
		if err != nil {
			if !errors.IsNotFound(err) {
				if !errors.IsUnauthorized(err) && !errors.IsForbidden(err) {
					klog.Fatalf("Error searching IngressClass: %v", err)
				}

				klog.ErrorS(err, "Searching IngressClass", "class", class.IngressClass)
			}

			klog.Warningf("No IngressClass resource with name %v found. Only annotation will be used.", class.IngressClass)

			// TODO: remove once this is fixed in client-go
			k8s.IngressClass = nil
		}

		if k8s.IngressClass != nil && k8s.IngressClass.Spec.Controller != k8s.IngressNGINXController {
			klog.Fatalf("IngressClass with name %v is not valid for ingress-nginx (invalid Spec.Controller)", class.IngressClass)
		}
	}

	conf.Client = kubeClient

	err = k8s.GetIngressPod(kubeClient)
	if err != nil {
		klog.Fatalf("Unexpected error obtaining ingress-nginx pod: %v", err)
	}

	reg := prometheus.NewRegistry()

	reg.MustRegister(prometheus.NewGoCollector())
	reg.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{
		PidFn:        func() (int, error) { return os.Getpid(), nil },
		ReportErrors: true,
	}))

	mc := metric.NewDummyCollector()
	if conf.EnableMetrics {
		mc, err = metric.NewCollector(conf.MetricsPerHost, reg)
		if err != nil {
			klog.Fatalf("Error creating prometheus collector:  %v", err)
		}
	}
	mc.Start()

	if conf.EnableProfiling {
		go registerProfiler()
	}

	ngx := controller.NewNGINXController(conf, mc)

	mux := http.NewServeMux()
	registerHealthz(nginx.HealthPath, ngx, mux)
	registerMetrics(reg, mux)

	go startHTTPServer(conf.ListenPorts.Health, mux)
	go ngx.Start()

	handleSigterm(ngx, func(code int) {
		os.Exit(code)
	})
}

type exiter func(code int)

func handleSigterm(ngx *controller.NGINXController, exit exiter) {
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGTERM)
	<-signalChan
	klog.InfoS("Received SIGTERM, shutting down")

	exitCode := 0
	if err := ngx.Stop(); err != nil {
		klog.Warningf("Error during shutdown: %v", err)
		exitCode = 1
	}

	klog.InfoS("Handled quit, awaiting Pod deletion")
	time.Sleep(10 * time.Second)

	klog.InfoS("Exiting", "code", exitCode)
	exit(exitCode)
}

// createApiserverClient creates a new Kubernetes REST client. apiserverHost is
// the URL of the API server in the format protocol://address:port/pathPrefix,
// kubeConfig is the location of a kubeconfig file. If defined, the kubeconfig
// file is loaded first, the URL of the API server read from the file is then
// optionally overridden by the value of apiserverHost.
// If neither apiserverHost nor kubeConfig is passed in, we assume the
// controller runs inside Kubernetes and fallback to the in-cluster config. If
// the in-cluster config is missing or fails, we fallback to the default config.
func createApiserverClient(apiserverHost, rootCAFile, kubeConfig string) (*kubernetes.Clientset, error) {
	cfg, err := clientcmd.BuildConfigFromFlags(apiserverHost, kubeConfig)
	if err != nil {
		return nil, err
	}

	// TODO: remove after k8s v1.22
	cfg.WarningHandler = rest.NoWarnings{}

	// Configure the User-Agent used for the HTTP requests made to the API server.
	cfg.UserAgent = fmt.Sprintf(
		"%s/%s (%s/%s) ingress-nginx/%s",
		filepath.Base(os.Args[0]),
		version.RELEASE,
		runtime.GOOS,
		runtime.GOARCH,
		version.COMMIT,
	)

	if apiserverHost != "" && rootCAFile != "" {
		tlsClientConfig := rest.TLSClientConfig{}

		if _, err := certutil.NewPool(rootCAFile); err != nil {
			klog.ErrorS(err, "Loading CA config", "file", rootCAFile)
		} else {
			tlsClientConfig.CAFile = rootCAFile
		}

		cfg.TLSClientConfig = tlsClientConfig
	}

	klog.InfoS("Creating API client", "host", cfg.Host)

	client, err := kubernetes.NewForConfig(cfg)
	if err != nil {
		return nil, err
	}

	var v *discovery.Info

	// The client may fail to connect to the API server in the first request.
	// https://github.com/kubernetes/ingress-nginx/issues/1968
	defaultRetry := wait.Backoff{
		Steps:    10,
		Duration: 1 * time.Second,
		Factor:   1.5,
		Jitter:   0.1,
	}

	var lastErr error
	retries := 0
	klog.V(2).InfoS("Trying to discover Kubernetes version")
	err = wait.ExponentialBackoff(defaultRetry, func() (bool, error) {
		v, err = client.Discovery().ServerVersion()

		if err == nil {
			return true, nil
		}

		lastErr = err
		klog.V(2).ErrorS(err, "Unexpected error discovering Kubernetes version", "attempt", retries)
		retries++
		return false, nil
	})

	// err is returned in case of timeout in the exponential backoff (ErrWaitTimeout)
	if err != nil {
		return nil, lastErr
	}

	// this should not happen, warn the user
	if retries > 0 {
		klog.Warningf("Initial connection to the Kubernetes API server was retried %d times.", retries)
	}

	klog.InfoS("Running in Kubernetes cluster",
		"major", v.Major,
		"minor", v.Minor,
		"git", v.GitVersion,
		"state", v.GitTreeState,
		"commit", v.GitCommit,
		"platform", v.Platform,
	)

	return client, nil
}

// Handler for fatal init errors. Prints a verbose error message and exits.
func handleFatalInitError(err error) {
	klog.Fatalf("Error while initiating a connection to the Kubernetes API server. "+
		"This could mean the cluster is misconfigured (e.g. it has invalid API server certificates "+
		"or Service Accounts configuration). Reason: %s\n"+
		"Refer to the troubleshooting guide for more information: "+
		"https://kubernetes.github.io/ingress-nginx/troubleshooting/",
		err)
}

func registerHealthz(healthPath string, ic *controller.NGINXController, mux *http.ServeMux) {
	// expose health check endpoint (/healthz)
	healthz.InstallPathHandler(mux,
		healthPath,
		healthz.PingHealthz,
		ic,
	)
}

func registerMetrics(reg *prometheus.Registry, mux *http.ServeMux) {
	mux.Handle(
		"/metrics",
		promhttp.InstrumentMetricHandler(
			reg,
			promhttp.HandlerFor(reg, promhttp.HandlerOpts{}),
		),
	)
}

func registerProfiler() {
	mux := http.NewServeMux()

	mux.HandleFunc("/debug/pprof/", pprof.Index)
	mux.HandleFunc("/debug/pprof/heap", pprof.Index)
	mux.HandleFunc("/debug/pprof/mutex", pprof.Index)
	mux.HandleFunc("/debug/pprof/goroutine", pprof.Index)
	mux.HandleFunc("/debug/pprof/threadcreate", pprof.Index)
	mux.HandleFunc("/debug/pprof/block", pprof.Index)
	mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
	mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
	mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
	mux.HandleFunc("/debug/pprof/trace", pprof.Trace)

	server := &http.Server{
		Addr:    fmt.Sprintf("127.0.0.1:%v", nginx.ProfilerPort),
		Handler: mux,
	}
	klog.Fatal(server.ListenAndServe())
}

func startHTTPServer(port int, mux *http.ServeMux) {
	server := &http.Server{
		Addr:              fmt.Sprintf(":%v", port),
		Handler:           mux,
		ReadTimeout:       10 * time.Second,
		ReadHeaderTimeout: 10 * time.Second,
		WriteTimeout:      300 * time.Second,
		IdleTimeout:       120 * time.Second,
	}
	klog.Fatal(server.ListenAndServe())
}

func checkService(key string, kubeClient *kubernetes.Clientset) error {
	ns, name, err := k8s.ParseNameNS(key)
	if err != nil {
		return err
	}

	_, err = kubeClient.CoreV1().Services(ns).Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		if errors.IsUnauthorized(err) || errors.IsForbidden(err) {
			return fmt.Errorf("✖ the cluster seems to be running with a restrictive Authorization mode and the Ingress controller does not have the required permissions to operate normally")
		}

		if errors.IsNotFound(err) {
			return fmt.Errorf("No service with name %v found in namespace %v: %v", name, ns, err)
		}

		return fmt.Errorf("Unexpected error searching service with name %v in namespace %v: %v", name, ns, err)
	}

	return nil
}
<commit_msg>Improve ingress class error message<commit_after>/*
Copyright 2015 The Kubernetes Authors.

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

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

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

package main

import (
	"context"
	"fmt"
	"math/rand"
	"net/http"
	"net/http/pprof"
	"os"
	"os/signal"
	"path/filepath"
	"runtime"
	"syscall"
	"time"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/wait"
	discovery "k8s.io/apimachinery/pkg/version"
	"k8s.io/apiserver/pkg/server/healthz"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
	certutil "k8s.io/client-go/util/cert"
	"k8s.io/klog/v2"

	"k8s.io/ingress-nginx/internal/file"
	"k8s.io/ingress-nginx/internal/ingress/annotations/class"
	"k8s.io/ingress-nginx/internal/ingress/controller"
	"k8s.io/ingress-nginx/internal/ingress/metric"
	"k8s.io/ingress-nginx/internal/k8s"
	"k8s.io/ingress-nginx/internal/net/ssl"
	"k8s.io/ingress-nginx/internal/nginx"
	"k8s.io/ingress-nginx/version"
)

func main() {
	klog.InitFlags(nil)

	rand.Seed(time.Now().UnixNano())

	fmt.Println(version.String())

	showVersion, conf, err := parseFlags()
	if showVersion {
		os.Exit(0)
	}

	if err != nil {
		klog.Fatal(err)
	}

	err = file.CreateRequiredDirectories()
	if err != nil {
		klog.Fatal(err)
	}

	kubeClient, err := createApiserverClient(conf.APIServerHost, conf.RootCAFile, conf.KubeConfigFile)
	if err != nil {
		handleFatalInitError(err)
	}

	if len(conf.DefaultService) > 0 {
		err := checkService(conf.DefaultService, kubeClient)
		if err != nil {
			klog.Fatal(err)
		}

		klog.InfoS("Valid default backend", "service", conf.DefaultService)
	}

	if len(conf.PublishService) > 0 {
		err := checkService(conf.PublishService, kubeClient)
		if err != nil {
			klog.Fatal(err)
		}
	}

	if conf.Namespace != "" {
		_, err = kubeClient.CoreV1().Namespaces().Get(context.TODO(), conf.Namespace, metav1.GetOptions{})
		if err != nil {
			klog.Fatalf("No namespace with name %v found: %v", conf.Namespace, err)
		}
	}

	conf.FakeCertificate = ssl.GetFakeSSLCert()
	klog.InfoS("SSL fake certificate created", "file", conf.FakeCertificate.PemFileName)

	var isNetworkingIngressAvailable bool

	isNetworkingIngressAvailable, k8s.IsIngressV1Beta1Ready, _ = k8s.NetworkingIngressAvailable(kubeClient)
	if !isNetworkingIngressAvailable {
		klog.Fatalf("ingress-nginx requires Kubernetes v1.14.0 or higher")
	}

	if k8s.IsIngressV1Beta1Ready {
		klog.InfoS("Enabling new Ingress features available since Kubernetes v1.18")
		k8s.IngressClass, err = kubeClient.NetworkingV1beta1().IngressClasses().
			Get(context.TODO(), class.IngressClass, metav1.GetOptions{})
		if err != nil {
			if !errors.IsNotFound(err) {
				if !errors.IsUnauthorized(err) && !errors.IsForbidden(err) {
					klog.Fatalf("Error searching IngressClass: %v", err)
				}

				klog.ErrorS(err, "Searching IngressClass", "class", class.IngressClass)
			}

			klog.Warningf("No IngressClass resource with name %v found. Only annotation will be used.", class.IngressClass)

			// TODO: remove once this is fixed in client-go
			k8s.IngressClass = nil
		}

		if k8s.IngressClass != nil && k8s.IngressClass.Spec.Controller != k8s.IngressNGINXController {
			klog.Errorf(`Invalid IngressClass (Spec.Controller) value "%v". Should be "%v"`, k8s.IngressClass.Spec.Controller, k8s.IngressNGINXController)
			klog.Fatalf("IngressClass with name %v is not valid for ingress-nginx (invalid Spec.Controller)", class.IngressClass)
		}
	}

	conf.Client = kubeClient

	err = k8s.GetIngressPod(kubeClient)
	if err != nil {
		klog.Fatalf("Unexpected error obtaining ingress-nginx pod: %v", err)
	}

	reg := prometheus.NewRegistry()

	reg.MustRegister(prometheus.NewGoCollector())
	reg.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{
		PidFn:        func() (int, error) { return os.Getpid(), nil },
		ReportErrors: true,
	}))

	mc := metric.NewDummyCollector()
	if conf.EnableMetrics {
		mc, err = metric.NewCollector(conf.MetricsPerHost, reg)
		if err != nil {
			klog.Fatalf("Error creating prometheus collector:  %v", err)
		}
	}
	mc.Start()

	if conf.EnableProfiling {
		go registerProfiler()
	}

	ngx := controller.NewNGINXController(conf, mc)

	mux := http.NewServeMux()
	registerHealthz(nginx.HealthPath, ngx, mux)
	registerMetrics(reg, mux)

	go startHTTPServer(conf.ListenPorts.Health, mux)
	go ngx.Start()

	handleSigterm(ngx, func(code int) {
		os.Exit(code)
	})
}

type exiter func(code int)

func handleSigterm(ngx *controller.NGINXController, exit exiter) {
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGTERM)
	<-signalChan
	klog.InfoS("Received SIGTERM, shutting down")

	exitCode := 0
	if err := ngx.Stop(); err != nil {
		klog.Warningf("Error during shutdown: %v", err)
		exitCode = 1
	}

	klog.InfoS("Handled quit, awaiting Pod deletion")
	time.Sleep(10 * time.Second)

	klog.InfoS("Exiting", "code", exitCode)
	exit(exitCode)
}

// createApiserverClient creates a new Kubernetes REST client. apiserverHost is
// the URL of the API server in the format protocol://address:port/pathPrefix,
// kubeConfig is the location of a kubeconfig file. If defined, the kubeconfig
// file is loaded first, the URL of the API server read from the file is then
// optionally overridden by the value of apiserverHost.
// If neither apiserverHost nor kubeConfig is passed in, we assume the
// controller runs inside Kubernetes and fallback to the in-cluster config. If
// the in-cluster config is missing or fails, we fallback to the default config.
func createApiserverClient(apiserverHost, rootCAFile, kubeConfig string) (*kubernetes.Clientset, error) {
	cfg, err := clientcmd.BuildConfigFromFlags(apiserverHost, kubeConfig)
	if err != nil {
		return nil, err
	}

	// TODO: remove after k8s v1.22
	cfg.WarningHandler = rest.NoWarnings{}

	// Configure the User-Agent used for the HTTP requests made to the API server.
	cfg.UserAgent = fmt.Sprintf(
		"%s/%s (%s/%s) ingress-nginx/%s",
		filepath.Base(os.Args[0]),
		version.RELEASE,
		runtime.GOOS,
		runtime.GOARCH,
		version.COMMIT,
	)

	if apiserverHost != "" && rootCAFile != "" {
		tlsClientConfig := rest.TLSClientConfig{}

		if _, err := certutil.NewPool(rootCAFile); err != nil {
			klog.ErrorS(err, "Loading CA config", "file", rootCAFile)
		} else {
			tlsClientConfig.CAFile = rootCAFile
		}

		cfg.TLSClientConfig = tlsClientConfig
	}

	klog.InfoS("Creating API client", "host", cfg.Host)

	client, err := kubernetes.NewForConfig(cfg)
	if err != nil {
		return nil, err
	}

	var v *discovery.Info

	// The client may fail to connect to the API server in the first request.
	// https://github.com/kubernetes/ingress-nginx/issues/1968
	defaultRetry := wait.Backoff{
		Steps:    10,
		Duration: 1 * time.Second,
		Factor:   1.5,
		Jitter:   0.1,
	}

	var lastErr error
	retries := 0
	klog.V(2).InfoS("Trying to discover Kubernetes version")
	err = wait.ExponentialBackoff(defaultRetry, func() (bool, error) {
		v, err = client.Discovery().ServerVersion()

		if err == nil {
			return true, nil
		}

		lastErr = err
		klog.V(2).ErrorS(err, "Unexpected error discovering Kubernetes version", "attempt", retries)
		retries++
		return false, nil
	})

	// err is returned in case of timeout in the exponential backoff (ErrWaitTimeout)
	if err != nil {
		return nil, lastErr
	}

	// this should not happen, warn the user
	if retries > 0 {
		klog.Warningf("Initial connection to the Kubernetes API server was retried %d times.", retries)
	}

	klog.InfoS("Running in Kubernetes cluster",
		"major", v.Major,
		"minor", v.Minor,
		"git", v.GitVersion,
		"state", v.GitTreeState,
		"commit", v.GitCommit,
		"platform", v.Platform,
	)

	return client, nil
}

// Handler for fatal init errors. Prints a verbose error message and exits.
func handleFatalInitError(err error) {
	klog.Fatalf("Error while initiating a connection to the Kubernetes API server. "+
		"This could mean the cluster is misconfigured (e.g. it has invalid API server certificates "+
		"or Service Accounts configuration). Reason: %s\n"+
		"Refer to the troubleshooting guide for more information: "+
		"https://kubernetes.github.io/ingress-nginx/troubleshooting/",
		err)
}

func registerHealthz(healthPath string, ic *controller.NGINXController, mux *http.ServeMux) {
	// expose health check endpoint (/healthz)
	healthz.InstallPathHandler(mux,
		healthPath,
		healthz.PingHealthz,
		ic,
	)
}

func registerMetrics(reg *prometheus.Registry, mux *http.ServeMux) {
	mux.Handle(
		"/metrics",
		promhttp.InstrumentMetricHandler(
			reg,
			promhttp.HandlerFor(reg, promhttp.HandlerOpts{}),
		),
	)
}

func registerProfiler() {
	mux := http.NewServeMux()

	mux.HandleFunc("/debug/pprof/", pprof.Index)
	mux.HandleFunc("/debug/pprof/heap", pprof.Index)
	mux.HandleFunc("/debug/pprof/mutex", pprof.Index)
	mux.HandleFunc("/debug/pprof/goroutine", pprof.Index)
	mux.HandleFunc("/debug/pprof/threadcreate", pprof.Index)
	mux.HandleFunc("/debug/pprof/block", pprof.Index)
	mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
	mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
	mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
	mux.HandleFunc("/debug/pprof/trace", pprof.Trace)

	server := &http.Server{
		Addr:    fmt.Sprintf("127.0.0.1:%v", nginx.ProfilerPort),
		Handler: mux,
	}
	klog.Fatal(server.ListenAndServe())
}

func startHTTPServer(port int, mux *http.ServeMux) {
	server := &http.Server{
		Addr:              fmt.Sprintf(":%v", port),
		Handler:           mux,
		ReadTimeout:       10 * time.Second,
		ReadHeaderTimeout: 10 * time.Second,
		WriteTimeout:      300 * time.Second,
		IdleTimeout:       120 * time.Second,
	}
	klog.Fatal(server.ListenAndServe())
}

func checkService(key string, kubeClient *kubernetes.Clientset) error {
	ns, name, err := k8s.ParseNameNS(key)
	if err != nil {
		return err
	}

	_, err = kubeClient.CoreV1().Services(ns).Get(context.TODO(), name, metav1.GetOptions{})
	if err != nil {
		if errors.IsUnauthorized(err) || errors.IsForbidden(err) {
			return fmt.Errorf("✖ the cluster seems to be running with a restrictive Authorization mode and the Ingress controller does not have the required permissions to operate normally")
		}

		if errors.IsNotFound(err) {
			return fmt.Errorf("No service with name %v found in namespace %v: %v", name, ns, err)
		}

		return fmt.Errorf("Unexpected error searching service with name %v in namespace %v: %v", name, ns, err)
	}

	return nil
}
<|endoftext|>