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

package main

// imports for this file should not contain "os".
import (
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	. "github.com/kardianos/govendor/context"
	"github.com/kardianos/govendor/migrate"
)

var help = `govendor: copy go packages locally. Uses vendor folder.
govendor init
govendor list [-v] [-no-status] [+<status>] [import-path-filter]
govendor {add, update, remove} [-n] [-short | -long] [+status] [import-path-filter]
govendor migrate [auto, godep, internal]

	init
		create a vendor file if it does not exist.

	add
		copy one or more packages into the vendor folder.

	update
		update one or more packages from GOPATH into the vendor folder.

	remove
		remove one or more packages from the vendor folder.

	migrate
		change from a one schema to use the vendor folder.

Expanding "..."
	A package import path may be expanded to other paths that
	show up in "govendor list" be ending the "import-path" with "...".
	NOTE: this uses the import tree from "vendor list" and NOT the file system.

Flags
	-n		print actions but do not run them
	-short	chooses the shorter path in case of conflict
	-long	chooses the longer path in case of conflict

Status list:
	external - package does not share root path
	vendor - vendor folder; copied locally
	unused - the package has been copied locally, but isn't used
	local - shares the root path and is not a vendor package
	missing - referenced but not found in GOROOT or GOPATH
	std - standard library package
	program - package is a main package
	---
	all - all of the above status

Status can be referenced by their initial letters.
	"st" == "std"
	"e" == "external"

Ignoring files with build tags:
	The "vendor.json" file contains a string field named "ignore".
	It may contain a space separated list of build tags to ignore when
	listing and copying files. By default the init command adds the
	the "test" tag to the ignore list.

Example:
	govendor add github.com/kardianos/osext
	govendor update github.com/kardianos/...
	govendor add +external
	govendor update +ven github.com/company/project/... bitbucket.org/user/pkg
	govendor remove +vendor
	govendor list +ext +std

If using go1.5, ensure you set GO15VENDOREXPERIMENT=1
`

var (
	normal = []Status{StatusExternal, StatusVendor, StatusUnused, StatusMissing, StatusLocal, StatusProgram}
	all    = []Status{StatusExternal, StatusVendor, StatusUnused, StatusMissing, StatusLocal, StatusProgram, StatusStandard}
)

func parseStatus(s string) (status []Status, err error) {
	switch {
	case strings.HasPrefix("external", s):
		status = []Status{StatusExternal}
	case strings.HasPrefix("vendor", s):
		status = []Status{StatusVendor}
	case strings.HasPrefix("unused", s):
		status = []Status{StatusUnused}
	case strings.HasPrefix("missing", s):
		status = []Status{StatusMissing}
	case strings.HasPrefix("local", s):
		status = []Status{StatusLocal}
	case strings.HasPrefix("program", s):
		status = []Status{StatusProgram}
	case strings.HasPrefix("std", s):
		status = []Status{StatusStandard}
	case strings.HasPrefix("standard", s):
		status = []Status{StatusStandard}
	case strings.HasPrefix("all", s):
		status = all
	default:
		err = fmt.Errorf("unknown status %q", s)
	}
	return
}

type filterImport struct {
	Import string
	Added  bool // Used to prevent imports from begin added twice.
}

type filter struct {
	Status []Status
	Import []*filterImport
}

func (f filter) HasStatus(item StatusItem) bool {
	for _, s := range f.Status {
		if s == item.Status {
			return true
		}
	}
	return false
}
func (f filter) HasImport(item StatusItem) bool {
	for _, imp := range f.Import {
		if imp.Import == item.Local || imp.Import == item.Canonical {
			imp.Added = true
			return true
		}
		if strings.HasSuffix(imp.Import, "/...") {
			base := strings.TrimSuffix(imp.Import, "/...")
			if strings.HasPrefix(item.Local, base) || strings.HasPrefix(item.Canonical, base) {
				imp.Added = true
				return true
			}
		}
		if strings.HasSuffix(imp.Import, "...") {
			base := strings.TrimSuffix(imp.Import, "...")
			if strings.HasPrefix(item.Local, base) || strings.HasPrefix(item.Canonical, base) {
				imp.Added = true
				return true
			}
		}
	}
	return false
}

func parseFilter(args []string) (filter, error) {
	f := filter{
		Status: make([]Status, 0, len(args)),
		Import: make([]*filterImport, 0, len(args)),
	}
	for _, a := range args {
		if len(a) == 0 {
			continue
		}
		// Check if item is a status.
		if a[0] == '+' {
			ss, err := parseStatus(a[1:])
			if err != nil {
				return f, err
			}
			f.Status = append(f.Status, ss...)
		} else {
			f.Import = append(f.Import, &filterImport{Import: a})
		}
	}
	return f, nil
}

// run is isoloated from main and os.Args to help with testing.
// Shouldn't directly print to console, just write through w.
func run(w io.Writer, appArgs []string) (bool, error) {
	if len(appArgs) == 1 {
		return true, nil
	}

	cmd := appArgs[1]
	switch cmd {
	case "init":
		ctx, err := NewContextWD(true)
		if err != nil {
			return false, err
		}
		ctx.VendorFile.Ignore = "test" // Add default ignore rule.
		err = ctx.WriteVendorFile()
		if err != nil {
			return false, err
		}
		err = os.MkdirAll(filepath.Join(ctx.RootDir, ctx.VendorFolder), 0777)
		if err != nil {
			return false, err
		}
	case "list":
		listFlags := flag.NewFlagSet("list", flag.ContinueOnError)
		verbose := listFlags.Bool("v", false, "verbose")
		noStatus := listFlags.Bool("no-status", false, "do not show the status")
		err := listFlags.Parse(appArgs[2:])
		if err != nil {
			return true, err
		}
		args := listFlags.Args()
		f, err := parseFilter(args)
		if err != nil {
			return true, err
		}
		if len(f.Status) == 0 {
			f.Status = append(f.Status, normal...)
		}
		// Print all listed status.
		ctx, err := NewContextWD(false)
		if err != nil {
			return checkNewContextError(err)
		}
		list, err := ctx.Status()
		if err != nil {
			return false, err
		}

		formatSame := "%[1]v %[2]s\n"
		formatDifferent := "%[1]v %[2]s\n"
		if *verbose {
			formatDifferent = "%[1]v %[2]s ::%[3]s\n"
		}
		if *noStatus {
			formatSame = "%[2]s\n"
			formatDifferent = "%[2]s\n"
			if *verbose {
				formatDifferent = "%[2]s ::%[3]s\n"
			}
		}
		for _, item := range list {
			if f.HasStatus(item) == false {
				continue
			}
			if len(f.Import) != 0 && f.HasImport(item) == false {
				continue
			}

			if item.Local == item.Canonical {
				fmt.Fprintf(w, formatSame, item.Status, item.Canonical)
			} else {
				fmt.Fprintf(w, formatDifferent, item.Status, item.Canonical, strings.TrimPrefix(item.Local, ctx.RootImportPath))
			}
			if *verbose {
				for i, imp := range item.ImportedBy {
					if i != len(item.ImportedBy)-1 {
						fmt.Fprintf(w, "  ├── %s\n", imp)
					} else {
						fmt.Fprintf(w, "  └── %s\n", imp)
					}
				}
			}
		}
	case "add", "update", "remove":
		listFlags := flag.NewFlagSet("list", flag.ContinueOnError)
		dryrun := listFlags.Bool("n", false, "dry-run")
		short := listFlags.Bool("short", false, "choose the short path")
		long := listFlags.Bool("long", false, "choose the long path")
		err := listFlags.Parse(appArgs[2:])
		if err != nil {
			return true, err
		}
		if *short && *long {
			return false, errors.New("cannot select both long and short path")
		}
		args := listFlags.Args()
		if len(args) == 0 {
			return true, errors.New("missing package or status")
		}
		f, err := parseFilter(args)
		if err != nil {
			return true, err
		}
		ctx, err := NewContextWD(false)
		if err != nil {
			return checkNewContextError(err)
		}
		list, err := ctx.Status()
		if err != nil {
			return true, err
		}

		var mod Modify
		switch cmd {
		case "add":
			mod = Add
		case "update":
			mod = Update
		case "remove":
			mod = Remove
		}

		for _, item := range list {
			if f.HasStatus(item) {
				err = ctx.ModifyImport(item.Local, mod)
				if err != nil {
					return false, err
				}
			}
			if f.HasImport(item) {
				err = ctx.ModifyImport(item.Local, mod)
				if err != nil {
					return false, err
				}
			}
		}
		// If import path was not added from list, then add in here.
		for _, imp := range f.Import {
			if imp.Added {
				continue
			}
			importPath := strings.TrimSuffix(imp.Import, "...")
			importPath = strings.TrimSuffix(importPath, "/")
			err = ctx.ModifyImport(importPath, mod)
			if err != nil {
				return false, err
			}
		}

		// Auto-resolve package conflicts.
		conflicts := ctx.Check()
		conflicts = ctx.ResolveAutoVendorFileOrigin(conflicts)
		if *long {
			conflicts = ResolveAutoLongestPath(conflicts)
		}
		if *short {
			conflicts = ResolveAutoShortestPath(conflicts)
		}
		ctx.ResloveApply(conflicts)

		if *dryrun {
			for _, op := range ctx.Operation {
				if len(op.Dest) == 0 {
					fmt.Fprintf(w, "Remove %q\n", op.Src)
				} else {
					fmt.Fprintf(w, "Copy %q -> %q\n", op.Src, op.Dest)
					for _, ignore := range op.IgnoreFile {
						fmt.Fprintf(w, "\tIgnore %q\n", ignore)
					}
				}
			}
			return false, nil
		}

		// Write out vendor file and do change.
		err = ctx.WriteVendorFile()
		if err != nil {
			return false, err
		}
		err = ctx.Alter()
		if err != nil {
			return false, err
		}
	case "migrate":
		args := appArgs[2:]
		from := migrate.Auto
		if len(args) > 0 {
			switch args[0] {
			case "auto":
				from = migrate.Auto
			case "gb":
				from = migrate.Gb
			case "godep":
				from = migrate.Godep
			case "internal":
				from = migrate.Internal
			default:
				return true, fmt.Errorf("Unknown migrate command %q", args[0])
			}
		}
		return false, migrate.MigrateWD(from)
	default:
		return true, fmt.Errorf("Unknown command %q", cmd)
	}
	return false, nil
}

func checkNewContextError(err error) (bool, error) {
	// Diagnose error, show current value of 1.5vendor, suggest alter.
	if err == nil {
		return false, nil
	}
	if _, is := err.(ErrMissingVendorFile); is {
		expValue := os.Getenv("GO15VENDOREXPERIMENT")
		err = fmt.Errorf(`%v

GO15VENDOREXPERIMENT=%q
It is possible this project requires changing the above env var
or the project is not initialized.
`, err, expValue)
		return false, err
	}
	return false, err
}
<commit_msg>govendor: update not found message<commit_after>// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

// imports for this file should not contain "os".
import (
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	. "github.com/kardianos/govendor/context"
	"github.com/kardianos/govendor/migrate"
)

var help = `govendor: copy go packages locally. Uses vendor folder.
govendor init
govendor list [-v] [-no-status] [+<status>] [import-path-filter]
govendor {add, update, remove} [-n] [-short | -long] [+status] [import-path-filter]
govendor migrate [auto, godep, internal]

	init
		create a vendor file if it does not exist.

	add
		copy one or more packages into the vendor folder.

	update
		update one or more packages from GOPATH into the vendor folder.

	remove
		remove one or more packages from the vendor folder.

	migrate
		change from a one schema to use the vendor folder.

Expanding "..."
	A package import path may be expanded to other paths that
	show up in "govendor list" be ending the "import-path" with "...".
	NOTE: this uses the import tree from "vendor list" and NOT the file system.

Flags
	-n		print actions but do not run them
	-short	chooses the shorter path in case of conflict
	-long	chooses the longer path in case of conflict

Status list:
	external - package does not share root path
	vendor - vendor folder; copied locally
	unused - the package has been copied locally, but isn't used
	local - shares the root path and is not a vendor package
	missing - referenced but not found in GOROOT or GOPATH
	std - standard library package
	program - package is a main package
	---
	all - all of the above status

Status can be referenced by their initial letters.
	"st" == "std"
	"e" == "external"

Ignoring files with build tags:
	The "vendor.json" file contains a string field named "ignore".
	It may contain a space separated list of build tags to ignore when
	listing and copying files. By default the init command adds the
	the "test" tag to the ignore list.

Example:
	govendor add github.com/kardianos/osext
	govendor update github.com/kardianos/...
	govendor add +external
	govendor update +ven github.com/company/project/... bitbucket.org/user/pkg
	govendor remove +vendor
	govendor list +ext +std

If using go1.5, ensure you set GO15VENDOREXPERIMENT=1
`

var (
	normal = []Status{StatusExternal, StatusVendor, StatusUnused, StatusMissing, StatusLocal, StatusProgram}
	all    = []Status{StatusExternal, StatusVendor, StatusUnused, StatusMissing, StatusLocal, StatusProgram, StatusStandard}
)

func parseStatus(s string) (status []Status, err error) {
	switch {
	case strings.HasPrefix("external", s):
		status = []Status{StatusExternal}
	case strings.HasPrefix("vendor", s):
		status = []Status{StatusVendor}
	case strings.HasPrefix("unused", s):
		status = []Status{StatusUnused}
	case strings.HasPrefix("missing", s):
		status = []Status{StatusMissing}
	case strings.HasPrefix("local", s):
		status = []Status{StatusLocal}
	case strings.HasPrefix("program", s):
		status = []Status{StatusProgram}
	case strings.HasPrefix("std", s):
		status = []Status{StatusStandard}
	case strings.HasPrefix("standard", s):
		status = []Status{StatusStandard}
	case strings.HasPrefix("all", s):
		status = all
	default:
		err = fmt.Errorf("unknown status %q", s)
	}
	return
}

type filterImport struct {
	Import string
	Added  bool // Used to prevent imports from begin added twice.
}

type filter struct {
	Status []Status
	Import []*filterImport
}

func (f filter) HasStatus(item StatusItem) bool {
	for _, s := range f.Status {
		if s == item.Status {
			return true
		}
	}
	return false
}
func (f filter) HasImport(item StatusItem) bool {
	for _, imp := range f.Import {
		if imp.Import == item.Local || imp.Import == item.Canonical {
			imp.Added = true
			return true
		}
		if strings.HasSuffix(imp.Import, "/...") {
			base := strings.TrimSuffix(imp.Import, "/...")
			if strings.HasPrefix(item.Local, base) || strings.HasPrefix(item.Canonical, base) {
				imp.Added = true
				return true
			}
		}
		if strings.HasSuffix(imp.Import, "...") {
			base := strings.TrimSuffix(imp.Import, "...")
			if strings.HasPrefix(item.Local, base) || strings.HasPrefix(item.Canonical, base) {
				imp.Added = true
				return true
			}
		}
	}
	return false
}

func parseFilter(args []string) (filter, error) {
	f := filter{
		Status: make([]Status, 0, len(args)),
		Import: make([]*filterImport, 0, len(args)),
	}
	for _, a := range args {
		if len(a) == 0 {
			continue
		}
		// Check if item is a status.
		if a[0] == '+' {
			ss, err := parseStatus(a[1:])
			if err != nil {
				return f, err
			}
			f.Status = append(f.Status, ss...)
		} else {
			f.Import = append(f.Import, &filterImport{Import: a})
		}
	}
	return f, nil
}

// run is isoloated from main and os.Args to help with testing.
// Shouldn't directly print to console, just write through w.
func run(w io.Writer, appArgs []string) (bool, error) {
	if len(appArgs) == 1 {
		return true, nil
	}

	cmd := appArgs[1]
	switch cmd {
	case "init":
		ctx, err := NewContextWD(true)
		if err != nil {
			return false, err
		}
		ctx.VendorFile.Ignore = "test" // Add default ignore rule.
		err = ctx.WriteVendorFile()
		if err != nil {
			return false, err
		}
		err = os.MkdirAll(filepath.Join(ctx.RootDir, ctx.VendorFolder), 0777)
		if err != nil {
			return false, err
		}
	case "list":
		listFlags := flag.NewFlagSet("list", flag.ContinueOnError)
		verbose := listFlags.Bool("v", false, "verbose")
		noStatus := listFlags.Bool("no-status", false, "do not show the status")
		err := listFlags.Parse(appArgs[2:])
		if err != nil {
			return true, err
		}
		args := listFlags.Args()
		f, err := parseFilter(args)
		if err != nil {
			return true, err
		}
		if len(f.Status) == 0 {
			f.Status = append(f.Status, normal...)
		}
		// Print all listed status.
		ctx, err := NewContextWD(false)
		if err != nil {
			return checkNewContextError(err)
		}
		list, err := ctx.Status()
		if err != nil {
			return false, err
		}

		formatSame := "%[1]v %[2]s\n"
		formatDifferent := "%[1]v %[2]s\n"
		if *verbose {
			formatDifferent = "%[1]v %[2]s ::%[3]s\n"
		}
		if *noStatus {
			formatSame = "%[2]s\n"
			formatDifferent = "%[2]s\n"
			if *verbose {
				formatDifferent = "%[2]s ::%[3]s\n"
			}
		}
		for _, item := range list {
			if f.HasStatus(item) == false {
				continue
			}
			if len(f.Import) != 0 && f.HasImport(item) == false {
				continue
			}

			if item.Local == item.Canonical {
				fmt.Fprintf(w, formatSame, item.Status, item.Canonical)
			} else {
				fmt.Fprintf(w, formatDifferent, item.Status, item.Canonical, strings.TrimPrefix(item.Local, ctx.RootImportPath))
			}
			if *verbose {
				for i, imp := range item.ImportedBy {
					if i != len(item.ImportedBy)-1 {
						fmt.Fprintf(w, "  ├── %s\n", imp)
					} else {
						fmt.Fprintf(w, "  └── %s\n", imp)
					}
				}
			}
		}
	case "add", "update", "remove":
		listFlags := flag.NewFlagSet("list", flag.ContinueOnError)
		dryrun := listFlags.Bool("n", false, "dry-run")
		short := listFlags.Bool("short", false, "choose the short path")
		long := listFlags.Bool("long", false, "choose the long path")
		err := listFlags.Parse(appArgs[2:])
		if err != nil {
			return true, err
		}
		if *short && *long {
			return false, errors.New("cannot select both long and short path")
		}
		args := listFlags.Args()
		if len(args) == 0 {
			return true, errors.New("missing package or status")
		}
		f, err := parseFilter(args)
		if err != nil {
			return true, err
		}
		ctx, err := NewContextWD(false)
		if err != nil {
			return checkNewContextError(err)
		}
		list, err := ctx.Status()
		if err != nil {
			return true, err
		}

		var mod Modify
		switch cmd {
		case "add":
			mod = Add
		case "update":
			mod = Update
		case "remove":
			mod = Remove
		}

		for _, item := range list {
			if f.HasStatus(item) {
				err = ctx.ModifyImport(item.Local, mod)
				if err != nil {
					return false, err
				}
			}
			if f.HasImport(item) {
				err = ctx.ModifyImport(item.Local, mod)
				if err != nil {
					return false, err
				}
			}
		}
		// If import path was not added from list, then add in here.
		for _, imp := range f.Import {
			if imp.Added {
				continue
			}
			importPath := strings.TrimSuffix(imp.Import, "...")
			importPath = strings.TrimSuffix(importPath, "/")
			err = ctx.ModifyImport(importPath, mod)
			if err != nil {
				return false, err
			}
		}

		// Auto-resolve package conflicts.
		conflicts := ctx.Check()
		conflicts = ctx.ResolveAutoVendorFileOrigin(conflicts)
		if *long {
			conflicts = ResolveAutoLongestPath(conflicts)
		}
		if *short {
			conflicts = ResolveAutoShortestPath(conflicts)
		}
		ctx.ResloveApply(conflicts)

		if *dryrun {
			for _, op := range ctx.Operation {
				if len(op.Dest) == 0 {
					fmt.Fprintf(w, "Remove %q\n", op.Src)
				} else {
					fmt.Fprintf(w, "Copy %q -> %q\n", op.Src, op.Dest)
					for _, ignore := range op.IgnoreFile {
						fmt.Fprintf(w, "\tIgnore %q\n", ignore)
					}
				}
			}
			return false, nil
		}

		// Write out vendor file and do change.
		err = ctx.WriteVendorFile()
		if err != nil {
			return false, err
		}
		err = ctx.Alter()
		if err != nil {
			return false, err
		}
	case "migrate":
		args := appArgs[2:]
		from := migrate.Auto
		if len(args) > 0 {
			switch args[0] {
			case "auto":
				from = migrate.Auto
			case "gb":
				from = migrate.Gb
			case "godep":
				from = migrate.Godep
			case "internal":
				from = migrate.Internal
			default:
				return true, fmt.Errorf("Unknown migrate command %q", args[0])
			}
		}
		return false, migrate.MigrateWD(from)
	default:
		return true, fmt.Errorf("Unknown command %q", cmd)
	}
	return false, nil
}

func checkNewContextError(err error) (bool, error) {
	// Diagnose error, show current value of 1.5vendor, suggest alter.
	if err == nil {
		return false, nil
	}
	if _, is := err.(ErrMissingVendorFile); is {
		err = fmt.Errorf(`%v

Ensure the current folder or a parent folder contains a folder named "vendor".
In in doubt, run "govendor init" in the project root.
`, err)
		return false, err
	}
	return false, err
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/0xe2-0x9a-0x9b/Go-SDL/sdl"
	"github.com/remogatto/application"
	"log"
	"unsafe"
)

type sdlSurface struct {
	surface *sdl.Surface
}

func (s *sdlSurface) width() uint {
	return uint(s.surface.W)
}

func (s *sdlSurface) height() uint {
	return uint(s.surface.H)
}

func (s *sdlSurface) bpp() uint {
	return uint(s.surface.Format.BytesPerPixel)
}

func (s *sdlSurface) pitch() uint {
	return uint(s.surface.Pitch)
}

// Return the address of pixel at (x,y)
func (s *sdlSurface) addrXY(x, y uint) uintptr {
	pixels := uintptr(s.surface.Pixels)
	offset := uintptr(y*s.pitch() + x*s.bpp())
	return pixels + offset
}

func newSDLSurface(w, h int) *sdlSurface {
	surface := sdl.CreateRGBSurface(sdl.SWSURFACE, w, h, 32, 0, 0, 0, 0)
	if surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	return &sdlSurface{surface}
}

// Create an SDL surface suitable for an unscaled screen
func newUnscaledSurface() *sdlSurface {
	return newSDLSurface(DISPLAY_WIDTH, DISPLAY_HEIGHT)
}

type sdlScreen interface {
	renderDisplay(data *DisplayData, paletteR, paletteG, paletteB []byte) *sdlSurface
	display() *sdlSurface
	border() *sdlSurface
	screen() *sdlSurface
	displayRect() *sdl.Rect
}

type sdlUnscaledScreen struct {
	screenSurface, borderSurface, displaySurface *sdlSurface
}

func newSDLUnscaledScreen() *sdlUnscaledScreen {
	screenSurface := &sdlSurface{sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, sdl.SWSURFACE)}
	if screenSurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	borderSurface := &sdlSurface{sdl.CreateRGBSurface(sdl.SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 32, 0, 0, 0, 0)}
	if borderSurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	displaySurface := &sdlSurface{sdl.CreateRGBSurface(sdl.SWSURFACE, DISPLAY_WIDTH, DISPLAY_HEIGHT, 32, 0, 0, 0, 0)}
	if displaySurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	return &sdlUnscaledScreen{screenSurface, borderSurface, displaySurface}
}

func (screen *sdlUnscaledScreen) renderDisplay(data *DisplayData, paletteR, paletteG, paletteB []byte) *sdlSurface {
	surface := screen.displaySurface
	surface.surface.Lock()
	for y := uint(0); y < DISPLAY_HEIGHT; y++ {
		wy := y * DISPLAY_WIDTH
		for x := uint(0); x < DISPLAY_WIDTH; x++ {
			addr := surface.addrXY(x, y)
			index := data[wy+x]
			color := rgba{paletteR[index], paletteG[index], paletteB[index], 0}
			*(*uint32)(unsafe.Pointer(addr)) = color.value32()
		}
	}
	surface.surface.Unlock()
	return surface
}

func (screen *sdlUnscaledScreen) displayRect() *sdl.Rect {
	return &sdl.Rect{BORDER_LEFT_RIGHT, BORDER_TOP_BOTTOM, DISPLAY_WIDTH, DISPLAY_HEIGHT}
}

func (screen *sdlUnscaledScreen) border() *sdlSurface {
	return screen.borderSurface
}

func (screen *sdlUnscaledScreen) screen() *sdlSurface {
	return screen.screenSurface
}

func (screen *sdlUnscaledScreen) display() *sdlSurface {
	return screen.displaySurface
}

type sdl2xScreen struct {
	screenSurface, borderSurface, displaySurface *sdlSurface
}

func newSDL2xScreen(fullScreen bool) *sdl2xScreen {
	sdlMode := sdl.SWSURFACE
	if fullScreen {
		application.Logf("%s", "Activate fullscreen mode")
		sdlMode = sdl.FULLSCREEN
		sdl.ShowCursor(sdl.DISABLE)
	}
	screenSurface := &sdlSurface{sdl.SetVideoMode(SCREEN_WIDTH*2, SCREEN_HEIGHT*2, 32, uint32(sdlMode))}
	if screenSurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	borderSurface := &sdlSurface{sdl.CreateRGBSurface(sdl.SWSURFACE, SCREEN_WIDTH*2, SCREEN_HEIGHT*2, 32, 0, 0, 0, 0)}
	if borderSurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	displaySurface := &sdlSurface{sdl.CreateRGBSurface(sdl.SWSURFACE, DISPLAY_WIDTH*2, DISPLAY_HEIGHT*2, 32, 0, 0, 0, 0)}
	if displaySurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	return &sdl2xScreen{screenSurface, borderSurface, displaySurface}
}

func (screen *sdl2xScreen) renderDisplay(data *DisplayData, paletteR, paletteG, paletteB []byte) *sdlSurface {
	surface := screen.displaySurface
	bpp := uintptr(surface.bpp())
	pitch := uintptr(surface.pitch())
	surface.surface.Lock()
	for y := uint(0); y < DISPLAY_HEIGHT; y++ {
		wy := y * DISPLAY_WIDTH
		for x := uint(0); x < DISPLAY_WIDTH; x++ {
			addr := surface.addrXY(2*x, 2*y)
			index := data[wy+x]
			color := rgba{paletteR[index], paletteG[index], paletteB[index], 0}.value32()
			// Fill a 2x2 rectangle
			*(*uint32)(unsafe.Pointer(addr)) = color
			*(*uint32)(unsafe.Pointer(addr + bpp)) = color
			*(*uint32)(unsafe.Pointer(addr + pitch)) = color
			*(*uint32)(unsafe.Pointer(addr + pitch + bpp)) = color
		}
	}
	surface.surface.Unlock()
	return surface
}

func (screen *sdl2xScreen) border() *sdlSurface {
	return screen.borderSurface
}

func (screen *sdl2xScreen) screen() *sdlSurface {
	return screen.screenSurface
}

func (screen *sdl2xScreen) display() *sdlSurface {
	return screen.displaySurface
}

func (screen *sdl2xScreen) displayRect() *sdl.Rect {
	return &sdl.Rect{BORDER_LEFT_RIGHT * 2, BORDER_TOP_BOTTOM * 2, DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2}
}

type sdlLoop struct {
	displayData                  chan *DisplayData
	paletteValue                 chan PaletteValue
	updateBorder                 chan byte
	pause, terminate             chan int
	paletteR, paletteG, paletteB [32]byte
	screen                       sdlScreen
}

func newSDLLoop(screen sdlScreen) *sdlLoop {
	return &sdlLoop{
		screen:       screen,
		displayData:  make(chan *DisplayData),
		paletteValue: make(chan PaletteValue),
		updateBorder: make(chan byte),
		pause:        make(chan int),
		terminate:    make(chan int),
	}
}

func (l *sdlLoop) Pause() chan int {
	return l.pause
}

func (l *sdlLoop) Terminate() chan int {
	return l.terminate
}

func (l *sdlLoop) Display() chan<- *DisplayData {
	return l.displayData
}

func (l *sdlLoop) WritePalette() chan<- PaletteValue {
	return l.paletteValue
}

func (l *sdlLoop) UpdateBorder() chan<- byte {
	return l.updateBorder
}

func (l *sdlLoop) Run() {
	for {
		select {
		case <-l.pause:
			l.pause <- 0

		case <-l.terminate:
			l.terminate <- 0

		case data := <-l.displayData:
			l.render(data)

		case value := <-l.paletteValue:
			l.paletteR[value.index] = value.r
			l.paletteG[value.index] = value.g
			l.paletteB[value.index] = value.b

		case value := <-l.updateBorder:
			l.renderBorder(value)

		}
	}
}

func (l *sdlLoop) render(data *DisplayData) {
	displayRect := l.screen.displayRect()
	// render surface
	displaySurface := l.screen.renderDisplay(data, l.paletteR[:], l.paletteG[:], l.paletteB[:])
	// copy display surface on border surface
	l.screen.border().surface.Blit(&sdl.Rect{0, 0, 0, 0}, displaySurface.surface, nil)
	// flip surface
	l.screen.screen().surface.Blit(&sdl.Rect{displayRect.X, displayRect.Y, 0, 0}, l.screen.border().surface, nil)
	l.screen.screen().surface.Flip()
}

func (l *sdlLoop) renderBorder(index byte) {
	color := rgba{l.paletteR[index], l.paletteG[index], l.paletteB[index], 0}.value32()
	display := l.screen.display()
	border := l.screen.border()
	border.surface.FillRect(nil, color)
	displayRect := l.screen.displayRect()
	// copy display surface on border surface
	l.screen.screen().surface.Blit(nil, l.screen.border().surface, nil)
	// flip surface
	l.screen.screen().surface.Blit(&sdl.Rect{displayRect.X, displayRect.Y, 0, 0}, display.surface, nil)
	l.screen.screen().surface.Flip()
}
<commit_msg>Fix compilation on 32-bit machines<commit_after>package main

import (
	"github.com/0xe2-0x9a-0x9b/Go-SDL/sdl"
	"github.com/remogatto/application"
	"log"
	"unsafe"
)

type sdlSurface struct {
	surface *sdl.Surface
}

func (s *sdlSurface) width() uint {
	return uint(s.surface.W)
}

func (s *sdlSurface) height() uint {
	return uint(s.surface.H)
}

func (s *sdlSurface) bpp() uint {
	return uint(s.surface.Format.BytesPerPixel)
}

func (s *sdlSurface) pitch() uint {
	return uint(s.surface.Pitch)
}

// Return the address of pixel at (x,y)
func (s *sdlSurface) addrXY(x, y uint) uintptr {
	pixels := uintptr(s.surface.Pixels)
	offset := uintptr(y*s.pitch() + x*s.bpp())
	return pixels + offset
}

func newSDLSurface(w, h int) *sdlSurface {
	surface := sdl.CreateRGBSurface(sdl.SWSURFACE, w, h, 32, 0, 0, 0, 0)
	if surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	return &sdlSurface{surface}
}

// Create an SDL surface suitable for an unscaled screen
func newUnscaledSurface() *sdlSurface {
	return newSDLSurface(DISPLAY_WIDTH, DISPLAY_HEIGHT)
}

type sdlScreen interface {
	renderDisplay(data *DisplayData, paletteR, paletteG, paletteB []byte) *sdlSurface
	display() *sdlSurface
	border() *sdlSurface
	screen() *sdlSurface
	displayRect() *sdl.Rect
}

type sdlUnscaledScreen struct {
	screenSurface, borderSurface, displaySurface *sdlSurface
}

func newSDLUnscaledScreen() *sdlUnscaledScreen {
	screenSurface := &sdlSurface{sdl.SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, sdl.SWSURFACE)}
	if screenSurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	borderSurface := &sdlSurface{sdl.CreateRGBSurface(sdl.SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 32, 0, 0, 0, 0)}
	if borderSurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	displaySurface := &sdlSurface{sdl.CreateRGBSurface(sdl.SWSURFACE, DISPLAY_WIDTH, DISPLAY_HEIGHT, 32, 0, 0, 0, 0)}
	if displaySurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	return &sdlUnscaledScreen{screenSurface, borderSurface, displaySurface}
}

func (screen *sdlUnscaledScreen) renderDisplay(data *DisplayData, paletteR, paletteG, paletteB []byte) *sdlSurface {
	surface := screen.displaySurface
	surface.surface.Lock()
	for y := uint(0); y < DISPLAY_HEIGHT; y++ {
		wy := y * DISPLAY_WIDTH
		for x := uint(0); x < DISPLAY_WIDTH; x++ {
			addr := surface.addrXY(x, y)
			index := data[wy+x]
			color := rgba{paletteR[index], paletteG[index], paletteB[index], 0}
			*(*uint32)(unsafe.Pointer(addr)) = color.value32()
		}
	}
	surface.surface.Unlock()
	return surface
}

func (screen *sdlUnscaledScreen) displayRect() *sdl.Rect {
	return &sdl.Rect{BORDER_LEFT_RIGHT, BORDER_TOP_BOTTOM, DISPLAY_WIDTH, DISPLAY_HEIGHT}
}

func (screen *sdlUnscaledScreen) border() *sdlSurface {
	return screen.borderSurface
}

func (screen *sdlUnscaledScreen) screen() *sdlSurface {
	return screen.screenSurface
}

func (screen *sdlUnscaledScreen) display() *sdlSurface {
	return screen.displaySurface
}

type sdl2xScreen struct {
	screenSurface, borderSurface, displaySurface *sdlSurface
}

func newSDL2xScreen(fullScreen bool) *sdl2xScreen {
	sdlMode := uint32(sdl.SWSURFACE)
	if fullScreen {
		application.Logf("%s", "Activate fullscreen mode")
		sdlMode = sdl.FULLSCREEN
		sdl.ShowCursor(sdl.DISABLE)
	}
	screenSurface := &sdlSurface{sdl.SetVideoMode(SCREEN_WIDTH*2, SCREEN_HEIGHT*2, 32, sdlMode)}
	if screenSurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	borderSurface := &sdlSurface{sdl.CreateRGBSurface(sdl.SWSURFACE, SCREEN_WIDTH*2, SCREEN_HEIGHT*2, 32, 0, 0, 0, 0)}
	if borderSurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	displaySurface := &sdlSurface{sdl.CreateRGBSurface(sdl.SWSURFACE, DISPLAY_WIDTH*2, DISPLAY_HEIGHT*2, 32, 0, 0, 0, 0)}
	if displaySurface.surface == nil {
		log.Printf("%s", sdl.GetError())
		application.Exit()
		return nil
	}
	return &sdl2xScreen{screenSurface, borderSurface, displaySurface}
}

func (screen *sdl2xScreen) renderDisplay(data *DisplayData, paletteR, paletteG, paletteB []byte) *sdlSurface {
	surface := screen.displaySurface
	bpp := uintptr(surface.bpp())
	pitch := uintptr(surface.pitch())
	surface.surface.Lock()
	for y := uint(0); y < DISPLAY_HEIGHT; y++ {
		wy := y * DISPLAY_WIDTH
		for x := uint(0); x < DISPLAY_WIDTH; x++ {
			addr := surface.addrXY(2*x, 2*y)
			index := data[wy+x]
			color := rgba{paletteR[index], paletteG[index], paletteB[index], 0}.value32()
			// Fill a 2x2 rectangle
			*(*uint32)(unsafe.Pointer(addr)) = color
			*(*uint32)(unsafe.Pointer(addr + bpp)) = color
			*(*uint32)(unsafe.Pointer(addr + pitch)) = color
			*(*uint32)(unsafe.Pointer(addr + pitch + bpp)) = color
		}
	}
	surface.surface.Unlock()
	return surface
}

func (screen *sdl2xScreen) border() *sdlSurface {
	return screen.borderSurface
}

func (screen *sdl2xScreen) screen() *sdlSurface {
	return screen.screenSurface
}

func (screen *sdl2xScreen) display() *sdlSurface {
	return screen.displaySurface
}

func (screen *sdl2xScreen) displayRect() *sdl.Rect {
	return &sdl.Rect{BORDER_LEFT_RIGHT * 2, BORDER_TOP_BOTTOM * 2, DISPLAY_WIDTH * 2, DISPLAY_HEIGHT * 2}
}

type sdlLoop struct {
	displayData                  chan *DisplayData
	paletteValue                 chan PaletteValue
	updateBorder                 chan byte
	pause, terminate             chan int
	paletteR, paletteG, paletteB [32]byte
	screen                       sdlScreen
}

func newSDLLoop(screen sdlScreen) *sdlLoop {
	return &sdlLoop{
		screen:       screen,
		displayData:  make(chan *DisplayData),
		paletteValue: make(chan PaletteValue),
		updateBorder: make(chan byte),
		pause:        make(chan int),
		terminate:    make(chan int),
	}
}

func (l *sdlLoop) Pause() chan int {
	return l.pause
}

func (l *sdlLoop) Terminate() chan int {
	return l.terminate
}

func (l *sdlLoop) Display() chan<- *DisplayData {
	return l.displayData
}

func (l *sdlLoop) WritePalette() chan<- PaletteValue {
	return l.paletteValue
}

func (l *sdlLoop) UpdateBorder() chan<- byte {
	return l.updateBorder
}

func (l *sdlLoop) Run() {
	for {
		select {
		case <-l.pause:
			l.pause <- 0

		case <-l.terminate:
			l.terminate <- 0

		case data := <-l.displayData:
			l.render(data)

		case value := <-l.paletteValue:
			l.paletteR[value.index] = value.r
			l.paletteG[value.index] = value.g
			l.paletteB[value.index] = value.b

		case value := <-l.updateBorder:
			l.renderBorder(value)

		}
	}
}

func (l *sdlLoop) render(data *DisplayData) {
	displayRect := l.screen.displayRect()
	// render surface
	displaySurface := l.screen.renderDisplay(data, l.paletteR[:], l.paletteG[:], l.paletteB[:])
	// copy display surface on border surface
	l.screen.border().surface.Blit(&sdl.Rect{0, 0, 0, 0}, displaySurface.surface, nil)
	// flip surface
	l.screen.screen().surface.Blit(&sdl.Rect{displayRect.X, displayRect.Y, 0, 0}, l.screen.border().surface, nil)
	l.screen.screen().surface.Flip()
}

func (l *sdlLoop) renderBorder(index byte) {
	color := rgba{l.paletteR[index], l.paletteG[index], l.paletteB[index], 0}.value32()
	display := l.screen.display()
	border := l.screen.border()
	border.surface.FillRect(nil, color)
	displayRect := l.screen.displayRect()
	// copy display surface on border surface
	l.screen.screen().surface.Blit(nil, l.screen.border().surface, nil)
	// flip surface
	l.screen.screen().surface.Blit(&sdl.Rect{displayRect.X, displayRect.Y, 0, 0}, display.surface, nil)
	l.screen.screen().surface.Flip()
}
<|endoftext|>


<commit_before>package goline
/*
 *  Filename:    set.go
 *  Package:     goline
 *  Author:      Bryan Matsuo <bmatsuo@soe.ucsc.edu>
 *  Created:     Fri Aug 19 03:15:13 PDT 2011
 *  Description:
 */
import (
    "strings"
    "fmt"
)

// An interface for sets of values.
type AnswerSet interface {
    Has(x interface{}) bool
    String() string
}

//  Composite answer sets (AnswerSetUnion and AnswerSetIntersection objects)
//  are tools available to create more complex AnswerSet objects not provided
//  by goline. For example open, or half-open, intervals can be constructed by
//  taking the intersection of two bounded answer sets.
type CompositeAnswerSet interface {
    AnswerSet
    Size() int
    Set(i int) AnswerSet
}

func compositeString(composite CompositeAnswerSet, name string) string {
    strs := make([]string, composite.Size())
    for i := range strs {
        strs[i] = composite.Set(i).String()
    }
    return fmt.Sprintf("%s of %s", strings.Join(strs, ", and "))
}

//  When making set intersections it is much easier to unknowingly create
//  empty AnswerSets that cannot be detected effectively. Exercise extreme
//  caution if creating set intersetions dynamically.
type AnswerSetIntersection []AnswerSet
type AnswerSetUnion []AnswerSet

var (
    Universe = AnswerSetIntersection{}
    EmptySet = AnswerSetUnion{}
)

func (set AnswerSetIntersection) Size() int { return len(set) }
func (set AnswerSetUnion) Size() int        { return len(set) }

func (set AnswerSetIntersection) Set(i int) AnswerSet { return set[i] }
func (set AnswerSetUnion) Set(i int) AnswerSet        { return set[i] }

func (set AnswerSetIntersection) String() string { return compositeString(set, "intersection") }
func (set AnswerSetUnion) String() string        { return compositeString(set, "union") }

func (set AnswerSetIntersection) Has(x interface{}) bool {
    for i := range set {
        if !set[i].Has(x) {
            return false
        }
    }
    return true
}
func (set AnswerSetUnion) Has(x interface{}) bool {
    for i := range set {
        if set[i].Has(x) {
            return true
        }
    }
    return false
}

type Direction uint

const (
    Above Direction = iota
    Below
)

var infty = []string{Above: "Infinity", Below: "-Infinity"}

func (d Direction) Infinity() string { return infty[d] }

// A range of uint64 values [Min, Max]
type UintRange struct {
    Min, Max uint64
}
// A range of int64 values [Min, Max]
type IntRange struct {
    Min, Max int64
}
// A range of float64 values [Min, Max]
type FloatRange struct {
    Min, Max float64
}
// A range of string values [Min, Max]
type StringRange struct {
    Min, Max string
}

func (r UintRange) String() string   { return fmt.Sprintf("range [%v, %v]", r.Min, r.Max) }
func (r IntRange) String() string    { return fmt.Sprintf("range [%v, %v]", r.Min, r.Max) }
func (r FloatRange) String() string  { return fmt.Sprintf("range [%v, %v]", r.Min, r.Max) }
func (r StringRange) String() string { return fmt.Sprintf("range [%#v, %#v]", r.Min, r.Max) }

func (ur UintRange) Has(x interface{}) bool {
    switch x.(type) {
    case uint64:
        y := x.(uint64)
        return y >= ur.Min && y <= ur.Max
    }
    panic(makeErrorMemberType(ur, x))
}
func (ur IntRange) Has(x interface{}) bool {
    switch x.(type) {
    case int64:
        y := x.(int64)
        return y >= ur.Min && y <= ur.Max
    }
    panic(makeErrorMemberType(ur, x))
}
func (ur FloatRange) Has(x interface{}) bool {
    switch x.(type) {
    case float64:
        y := x.(float64)
        return y >= ur.Min && y <= ur.Max
    }
    panic(makeErrorMemberType(ur, x))
}
func (ur StringRange) Has(x interface{}) bool {
    switch x.(type) {
    case string:
        y := x.(string)
        return y >= ur.Min && y <= ur.Max
    }
    panic(makeErrorMemberType(ur, x))
}

type StringSet []string

func (set StringSet) Has(x interface{}) bool {
    switch x.(type) {
    case string:
        y := x.(string)
        for _, s := range set {
            if s == y {
                return true
            }
        }
        return false
    }
    panic(makeErrorMemberType(set, x))
}

func (set StringSet) String() string {
    n := len(set)
    if n == 0 {
        return "{}"
    }
    length := 4*n + 4
    for _, s := range set {
        length += len(s)
    }
    var j int
    p := make([]byte, length)
    j += copy(p, "set {")
    for i, s := range set {
        j += copy(p[j:], []byte{'"'})
        j += copy(p[j:], s)
        j += copy(p[j:], []byte{'"'})
        if i < n-1 {
            j += copy(p[j:], ", ")
        }
    }
    j += copy(p[j:], "}")
    return string(p)
}

type shellCommandSet StringSet

func (set shellCommandSet) Has(x interface{}) bool {
    switch x.(type) {
    case string:
        y := x.(string)
        name, _ := splitShellCmd(y)
        for i := range set {
            if set[i] == name {
                return true
            }
        }
        return false
    }
    panic(makeErrorMemberType(set, x))
}

func (set shellCommandSet) String() string { return StringSet(set).String() }

//  An interval with only one bound, X.
type UintBounded struct {
    Direction
    X   uint64
}
//  An interval with only one bound, X.
type IntBounded struct {
    Direction
    X   int64
}
//  An interval with only one bound, X.
type FloatBounded struct {
    Direction
    X   float64
}
//  An interval with only one bound, X.
type StringBounded struct {
    Direction
    X   string
}

func (r UintBounded) String() string {
    if r.Direction == Above {
        return fmt.Sprintf("range [%v, %s)", r.X, r.Infinity())
    }
    return fmt.Sprintf("range (%s, %v]", r.Infinity(), r.X)
}
func (r IntBounded) String() string {
    if r.Direction == Above {
        return fmt.Sprintf("range [%v, %s)", r.X, r.Infinity())
    }
    return fmt.Sprintf("range (%s, %v]", r.Infinity(), r.X)
}
func (r FloatBounded) String() string {
    if r.Direction == Above {
        return fmt.Sprintf("range [%v, %s)", r.X, r.Infinity())
    }
    return fmt.Sprintf("range (%s, %v]", r.Infinity(), r.X)
}
func (r StringBounded) String() string {
    if r.Direction == Above {
        return fmt.Sprintf("range [%v, %s)", r.X, r.Infinity())
    }
    return fmt.Sprintf("range (%#s, %v]", r.Infinity(), r.X)
}

func (r UintBounded) Has(x interface{}) bool {
    switch x.(type) {
    case uint64:
        y := x.(uint64)
        switch r.Direction {
        case Above:
            return y >= r.X
        case Below:
            return y <= r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r IntBounded) Has(x interface{}) bool {
    switch x.(type) {
    case int64:
        y := x.(int64)
        switch r.Direction {
        case Above:
            return y >= r.X
        case Below:
            return y <= r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r FloatBounded) Has(x interface{}) bool {
    switch x.(type) {
    case float64:
        y := x.(float64)
        switch r.Direction {
        case Above:
            return y >= r.X
        case Below:
            return y <= r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r StringBounded) Has(x interface{}) bool {
    switch x.(type) {
    case string:
        y := x.(string)
        switch r.Direction {
        case Above:
            return y >= r.X
        case Below:
            return y <= r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}

//  An interval strictly bounded by a single number.
type UintBoundedStrictly UintBounded
//  An interval strictly bounded by a single number.
type IntBoundedStrictly IntBounded
//  An interval strictly bounded by a single number.
type FloatBoundedStrictly FloatBounded
//  An interval strictly bounded by a single number.
type StringBoundedStrictly StringBounded

// TODO: Fix the String method so that it returns open intervals
func (r UintBoundedStrictly) String() string   { return UintBounded(r).String() }
// TODO: Fix the String method so that it returns open intervals
func (r IntBoundedStrictly) String() string    { return IntBounded(r).String() }
// TODO: Fix the String method so that it returns open intervals
func (r FloatBoundedStrictly) String() string  { return FloatBounded(r).String() }
// TODO: Fix the String method so that it returns open intervals
func (r StringBoundedStrictly) String() string { return StringBounded(r).String() }

func (r UintBoundedStrictly) Has(x interface{}) bool {
    switch x.(type) {
    case uint64:
        y := x.(uint64)
        switch r.Direction {
        case Above:
            return y > r.X
        case Below:
            return y < r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r IntBoundedStrictly) Has(x interface{}) bool {
    switch x.(type) {
    case int64:
        y := x.(int64)
        switch r.Direction {
        case Above:
            return y > r.X
        case Below:
            return y < r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r FloatBoundedStrictly) Has(x interface{}) bool {
    switch x.(type) {
    case float64:
        y := x.(float64)
        switch r.Direction {
        case Above:
            return y > r.X
        case Below:
            return y < r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r StringBoundedStrictly) Has(x interface{}) bool {
    switch x.(type) {
    case string:
        y := x.(string)
        switch r.Direction {
        case Above:
            return y > r.X
        case Below:
            return y < r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
<commit_msg>Add a lot of set documentation.<commit_after>package goline
/*
 *  Filename:    set.go
 *  Package:     goline
 *  Author:      Bryan Matsuo <bmatsuo@soe.ucsc.edu>
 *  Created:     Fri Aug 19 03:15:13 PDT 2011
 *  Description:
 */
import (
    "strings"
    "fmt"
)

// An interface for sets of values.
type AnswerSet interface {
    Has(x interface{}) bool
    String() string
}

//  Composite answer sets (AnswerSetUnion and AnswerSetIntersection objects)
//  are tools available to create more complex AnswerSet objects not provided
//  by goline. For example open, or half-open, intervals can be constructed by
//  taking the intersection of two bounded answer sets.
type CompositeAnswerSet interface {
    AnswerSet
    Size() int
    Set(i int) AnswerSet
}

func compositeString(composite CompositeAnswerSet, name string) string {
    strs := make([]string, composite.Size())
    for i := range strs {
        strs[i] = composite.Set(i).String()
    }
    return fmt.Sprintf("%s of %s", strings.Join(strs, ", and "))
}

//  When making set intersections it is much easier to unknowingly create
//  empty AnswerSets that cannot be detected effectively. Exercise extreme
//  caution if creating set intersetions dynamically.
type AnswerSetIntersection []AnswerSet
type AnswerSetUnion []AnswerSet

var (
    Universe = AnswerSetIntersection{}
    EmptySet = AnswerSetUnion{}
)

//  The number of sets in the intersection.
func (set AnswerSetIntersection) Size() int { return len(set) }
//  The number of sets in the union.
func (set AnswerSetUnion) Size() int        { return len(set) }

//  The AnswerSet at index i.
func (set AnswerSetIntersection) Set(i int) AnswerSet { return set[i] }
//  The AnswerSet at index i.
func (set AnswerSetUnion) Set(i int) AnswerSet        { return set[i] }

func (set AnswerSetIntersection) String() string { return compositeString(set, "intersection") }
func (set AnswerSetUnion) String() string        { return compositeString(set, "union") }

//  Returns true if all AnswerSets in the intersection have x. Always returns
//  true if the intersection is empty.
func (set AnswerSetIntersection) Has(x interface{}) bool {
    for i := range set {
        if !set[i].Has(x) {
            return false
        }
    }
    return true
}
//  Returns true if any AnswerSets in the intersection have x. Always returns
//  false if the intersection is empty.
func (set AnswerSetUnion) Has(x interface{}) bool {
    for i := range set {
        if set[i].Has(x) {
            return true
        }
    }
    return false
}

//  The Direction type is used to define one-sided intervals on the number line.
//  For a given number X use this picture of the number line to guide your
//  intuition.
//
//      Infinity ... <----------------|----------------> ... Infinity
//                  Below             X             Above
type Direction uint

const (
    Above Direction = iota
    Below
)

var infty = []string{Above: "Infinity", Below: "-Infinity"}

//  Returns "Inifinty" or "-Infinity" depending on d's value.
func (d Direction) Infinity() string { return infty[d] }

//  A range of uint64 values [Min, Max].
type UintRange struct {
    Min, Max uint64
}
//  A range of int64 values [Min, Max].
type IntRange struct {
    Min, Max int64
}
//  A range of float64 values [Min, Max].
type FloatRange struct {
    Min, Max float64
}
//  A range of string values [Min, Max].
type StringRange struct {
    Min, Max string
}

func (r UintRange) String() string   { return fmt.Sprintf("range [%v, %v]", r.Min, r.Max) }
func (r IntRange) String() string    { return fmt.Sprintf("range [%v, %v]", r.Min, r.Max) }
func (r FloatRange) String() string  { return fmt.Sprintf("range [%v, %v]", r.Min, r.Max) }
func (r StringRange) String() string { return fmt.Sprintf("range [%#v, %#v]", r.Min, r.Max) }

func (ur UintRange) Has(x interface{}) bool {
    switch x.(type) {
    case uint64:
        y := x.(uint64)
        return y >= ur.Min && y <= ur.Max
    }
    panic(makeErrorMemberType(ur, x))
}
func (ur IntRange) Has(x interface{}) bool {
    switch x.(type) {
    case int64:
        y := x.(int64)
        return y >= ur.Min && y <= ur.Max
    }
    panic(makeErrorMemberType(ur, x))
}
func (ur FloatRange) Has(x interface{}) bool {
    switch x.(type) {
    case float64:
        y := x.(float64)
        return y >= ur.Min && y <= ur.Max
    }
    panic(makeErrorMemberType(ur, x))
}
func (ur StringRange) Has(x interface{}) bool {
    switch x.(type) {
    case string:
        y := x.(string)
        return y >= ur.Min && y <= ur.Max
    }
    panic(makeErrorMemberType(ur, x))
}

//  A simple set consisting of any string elements.
type StringSet []string

//  Compares x (string) to each element in set.
func (set StringSet) Has(x interface{}) bool {
    switch x.(type) {
    case string:
        y := x.(string)
        for _, s := range set {
            if s == y {
                return true
            }
        }
        return false
    }
    panic(makeErrorMemberType(set, x))
}

//  A string using notation `{"item1", "item2", ...}`
func (set StringSet) String() string {
    n := len(set)
    if n == 0 {
        return "{}"
    }
    length := 4*n + 4
    for _, s := range set {
        length += len(s)
    }
    var j int
    p := make([]byte, length)
    j += copy(p, "set {")
    for i, s := range set {
        j += copy(p[j:], []byte{'"'})
        j += copy(p[j:], s)
        j += copy(p[j:], []byte{'"'})
        if i < n-1 {
            j += copy(p[j:], ", ")
        }
    }
    j += copy(p[j:], "}")
    return string(p)
}

type shellCommandSet StringSet

func (set shellCommandSet) Has(x interface{}) bool {
    switch x.(type) {
    case string:
        y := x.(string)
        name, _ := splitShellCmd(y)
        for i := range set {
            if set[i] == name {
                return true
            }
        }
        return false
    }
    panic(makeErrorMemberType(set, x))
}

func (set shellCommandSet) String() string { return StringSet(set).String() }

//  An interval with only one bound, X.
type UintBounded struct {
    Direction
    X   uint64
}
//  An interval with only one bound, X.
type IntBounded struct {
    Direction
    X   int64
}
//  An interval with only one bound, X.
type FloatBounded struct {
    Direction
    X   float64
}
//  An interval with only one bound, X.
type StringBounded struct {
    Direction
    X   string
}

func (r UintBounded) String() string {
    if r.Direction == Above {
        return fmt.Sprintf("range [%v, %s)", r.X, r.Infinity())
    }
    return fmt.Sprintf("range (%s, %v]", r.Infinity(), r.X)
}
func (r IntBounded) String() string {
    if r.Direction == Above {
        return fmt.Sprintf("range [%v, %s)", r.X, r.Infinity())
    }
    return fmt.Sprintf("range (%s, %v]", r.Infinity(), r.X)
}
func (r FloatBounded) String() string {
    if r.Direction == Above {
        return fmt.Sprintf("range [%v, %s)", r.X, r.Infinity())
    }
    return fmt.Sprintf("range (%s, %v]", r.Infinity(), r.X)
}
func (r StringBounded) String() string {
    if r.Direction == Above {
        return fmt.Sprintf("range [%v, %s)", r.X, r.Infinity())
    }
    return fmt.Sprintf("range (%#s, %v]", r.Infinity(), r.X)
}

func (r UintBounded) Has(x interface{}) bool {
    switch x.(type) {
    case uint64:
        y := x.(uint64)
        switch r.Direction {
        case Above:
            return y >= r.X
        case Below:
            return y <= r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r IntBounded) Has(x interface{}) bool {
    switch x.(type) {
    case int64:
        y := x.(int64)
        switch r.Direction {
        case Above:
            return y >= r.X
        case Below:
            return y <= r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r FloatBounded) Has(x interface{}) bool {
    switch x.(type) {
    case float64:
        y := x.(float64)
        switch r.Direction {
        case Above:
            return y >= r.X
        case Below:
            return y <= r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r StringBounded) Has(x interface{}) bool {
    switch x.(type) {
    case string:
        y := x.(string)
        switch r.Direction {
        case Above:
            return y >= r.X
        case Below:
            return y <= r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}

//  An interval strictly bounded by a single number.
type UintBoundedStrictly UintBounded
//  An interval strictly bounded by a single number.
type IntBoundedStrictly IntBounded
//  An interval strictly bounded by a single number.
type FloatBoundedStrictly FloatBounded
//  An interval strictly bounded by a single number.
type StringBoundedStrictly StringBounded

// TODO: Fix the String method so that it returns open intervals
func (r UintBoundedStrictly) String() string   { return UintBounded(r).String() }
// TODO: Fix the String method so that it returns open intervals
func (r IntBoundedStrictly) String() string    { return IntBounded(r).String() }
// TODO: Fix the String method so that it returns open intervals
func (r FloatBoundedStrictly) String() string  { return FloatBounded(r).String() }
// TODO: Fix the String method so that it returns open intervals
func (r StringBoundedStrictly) String() string { return StringBounded(r).String() }

func (r UintBoundedStrictly) Has(x interface{}) bool {
    switch x.(type) {
    case uint64:
        y := x.(uint64)
        switch r.Direction {
        case Above:
            return y > r.X
        case Below:
            return y < r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r IntBoundedStrictly) Has(x interface{}) bool {
    switch x.(type) {
    case int64:
        y := x.(int64)
        switch r.Direction {
        case Above:
            return y > r.X
        case Below:
            return y < r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r FloatBoundedStrictly) Has(x interface{}) bool {
    switch x.(type) {
    case float64:
        y := x.(float64)
        switch r.Direction {
        case Above:
            return y > r.X
        case Below:
            return y < r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
func (r StringBoundedStrictly) Has(x interface{}) bool {
    switch x.(type) {
    case string:
        y := x.(string)
        switch r.Direction {
        case Above:
            return y > r.X
        case Below:
            return y < r.X
        }
    }
    panic(makeErrorMemberType(r, x))
}
<|endoftext|>


<commit_before>package storage

import (
	"io/ioutil"
	"os"
	"strings"
	"sync"

	"github.com/chrislusf/seaweedfs/weed/glog"
	"fmt"
)

type DiskLocation struct {
	Directory      string
	MaxVolumeCount int
	volumes        map[VolumeId]*Volume
	sync.RWMutex
}

func NewDiskLocation(dir string, maxVolumeCount int) *DiskLocation {
	location := &DiskLocation{Directory: dir, MaxVolumeCount: maxVolumeCount}
	location.volumes = make(map[VolumeId]*Volume)
	return location
}

func (l *DiskLocation) volumeIdFromPath(dir os.FileInfo) (VolumeId, string, error) {
	name := dir.Name()
	if !dir.IsDir() && strings.HasSuffix(name, ".dat") {
		collection := ""
		base := name[:len(name) - len(".dat")]
		i := strings.LastIndex(base, "_")
		if i > 0 {
			collection, base = base[0:i], base[i + 1:]
		}
		vol, err := NewVolumeId(base);
		return vol, collection, err
	}

	return 0, "", fmt.Errorf("Path is not a volume: %s", name)
}

func (l *DiskLocation) loadExistingVolume(dir os.FileInfo, needleMapKind NeedleMapType, mutex *sync.RWMutex) {
	name := dir.Name()
	if !dir.IsDir() && strings.HasSuffix(name, ".dat") {
		vid, collection, err := l.volumeIdFromPath(dir)
		if err == nil {
			mutex.RLock()
			_, found := l.volumes[vid]
			mutex.RUnlock()
			if !found {
				if v, e := NewVolume(l.Directory, collection, vid, needleMapKind, nil, nil, 0); e == nil {
					mutex.Lock()
					l.volumes[vid] = v
					mutex.Unlock()
					glog.V(0).Infof("data file %s, replicaPlacement=%s v=%d size=%d ttl=%s",
						l.Directory+"/"+name, v.ReplicaPlacement, v.Version(), v.Size(), v.Ttl.String())
				} else {
					glog.V(0).Infof("new volume %s error %s", name, e)
				}
			}
		}
	}
}

func (l *DiskLocation) concurrentLoadingVolumes(needleMapKind NeedleMapType, concurrentFlag bool) {
	var concurrency int
	if concurrentFlag {
		//You could choose a better optimized concurency value after testing at your environment
		concurrency = 10
	} else {
		concurrency = 1
	}

	task_queue := make(chan os.FileInfo, 10*concurrency)
	go func() {
		if dirs, err := ioutil.ReadDir(l.Directory); err == nil {
			for _, dir := range dirs {
				task_queue <- dir
			}
		}
		close(task_queue)
	}()

	var wg sync.WaitGroup
	var mutex sync.RWMutex
	for workerNum := 0; workerNum < concurrency; workerNum++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for dir := range task_queue {
				l.loadExistingVolume(dir, needleMapKind, &mutex)
			}
		}()
	}
	wg.Wait()

}

func (l *DiskLocation) loadExistingVolumes(needleMapKind NeedleMapType) {
	l.Lock()
	defer l.Unlock()

	l.concurrentLoadingVolumes(needleMapKind, true)

	glog.V(0).Infoln("Store started on dir:", l.Directory, "with", len(l.volumes), "volumes", "max", l.MaxVolumeCount)
}

func (l *DiskLocation) DeleteCollectionFromDiskLocation(collection string) (e error) {
	l.Lock()
	defer l.Unlock()

	for k, v := range l.volumes {
		if v.Collection == collection {
			e = l.deleteVolumeById(k)
			if e != nil {
				return
			}
		}
	}
	return
}

func (l *DiskLocation) deleteVolumeById(vid VolumeId) (e error) {
	v, ok := l.volumes[vid]
	if !ok {
		return
	}
	e = v.Destroy()
	if e != nil {
		return
	}
	delete(l.volumes, vid)
	return
}

func (l *DiskLocation) LoadVolume(vid VolumeId, needleMapKind NeedleMapType) bool {
	if dirs, err := ioutil.ReadDir(l.Directory); err == nil {
		for _, dir := range dirs {
			volId, _, err := l.volumeIdFromPath(dir)
			if vid == volId && err == nil {
				var mutex sync.RWMutex
				l.loadExistingVolume(dir, needleMapKind, &mutex)
				return true
			}
		}
	}

	return false
}

func (l *DiskLocation) DeleteVolume(vid VolumeId) (error) {
	_, ok := l.volumes[vid]
	if !ok {
		return fmt.Errorf("Volume not found, VolumeId: %d", vid)
	}
	return l.deleteVolumeById(vid)
}

func (l *DiskLocation) UnloadVolume(vid VolumeId) (error) {
	_, ok := l.volumes[vid]
	if !ok {
		return fmt.Errorf("Volume not loaded, VolumeId: %d", vid)
	}
	delete(l.volumes, vid)
	return nil
}

func (l *DiskLocation) SetVolume(vid VolumeId, volume *Volume) {
	l.Lock()
	defer l.Unlock()

	l.volumes[vid] = volume
}

func (l *DiskLocation) FindVolume(vid VolumeId) (*Volume, bool) {
	l.RLock()
	defer l.RUnlock()

	v, ok := l.volumes[vid]
	return v, ok
}

func (l *DiskLocation) VolumesLen() int {
	l.RLock()
	defer l.RUnlock()

	return len(l.volumes)
}

func (l *DiskLocation) Close() {
	l.Lock()
	defer l.Unlock()

	for _, v := range l.volumes {
		v.Close()
	}
	return
}
<commit_msg>add locking to access l.volumes<commit_after>package storage

import (
	"io/ioutil"
	"os"
	"strings"
	"sync"

	"fmt"

	"github.com/chrislusf/seaweedfs/weed/glog"
)

type DiskLocation struct {
	Directory      string
	MaxVolumeCount int
	volumes        map[VolumeId]*Volume
	sync.RWMutex
}

func NewDiskLocation(dir string, maxVolumeCount int) *DiskLocation {
	location := &DiskLocation{Directory: dir, MaxVolumeCount: maxVolumeCount}
	location.volumes = make(map[VolumeId]*Volume)
	return location
}

func (l *DiskLocation) volumeIdFromPath(dir os.FileInfo) (VolumeId, string, error) {
	name := dir.Name()
	if !dir.IsDir() && strings.HasSuffix(name, ".dat") {
		collection := ""
		base := name[:len(name)-len(".dat")]
		i := strings.LastIndex(base, "_")
		if i > 0 {
			collection, base = base[0:i], base[i+1:]
		}
		vol, err := NewVolumeId(base)
		return vol, collection, err
	}

	return 0, "", fmt.Errorf("Path is not a volume: %s", name)
}

func (l *DiskLocation) loadExistingVolume(dir os.FileInfo, needleMapKind NeedleMapType, mutex *sync.RWMutex) {
	name := dir.Name()
	if !dir.IsDir() && strings.HasSuffix(name, ".dat") {
		vid, collection, err := l.volumeIdFromPath(dir)
		if err == nil {
			mutex.RLock()
			_, found := l.volumes[vid]
			mutex.RUnlock()
			if !found {
				if v, e := NewVolume(l.Directory, collection, vid, needleMapKind, nil, nil, 0); e == nil {
					mutex.Lock()
					l.volumes[vid] = v
					mutex.Unlock()
					glog.V(0).Infof("data file %s, replicaPlacement=%s v=%d size=%d ttl=%s",
						l.Directory+"/"+name, v.ReplicaPlacement, v.Version(), v.Size(), v.Ttl.String())
				} else {
					glog.V(0).Infof("new volume %s error %s", name, e)
				}
			}
		}
	}
}

func (l *DiskLocation) concurrentLoadingVolumes(needleMapKind NeedleMapType, concurrentFlag bool) {
	var concurrency int
	if concurrentFlag {
		//You could choose a better optimized concurency value after testing at your environment
		concurrency = 10
	} else {
		concurrency = 1
	}

	task_queue := make(chan os.FileInfo, 10*concurrency)
	go func() {
		if dirs, err := ioutil.ReadDir(l.Directory); err == nil {
			for _, dir := range dirs {
				task_queue <- dir
			}
		}
		close(task_queue)
	}()

	var wg sync.WaitGroup
	var mutex sync.RWMutex
	for workerNum := 0; workerNum < concurrency; workerNum++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for dir := range task_queue {
				l.loadExistingVolume(dir, needleMapKind, &mutex)
			}
		}()
	}
	wg.Wait()

}

func (l *DiskLocation) loadExistingVolumes(needleMapKind NeedleMapType) {
	l.Lock()
	defer l.Unlock()

	l.concurrentLoadingVolumes(needleMapKind, true)

	glog.V(0).Infoln("Store started on dir:", l.Directory, "with", len(l.volumes), "volumes", "max", l.MaxVolumeCount)
}

func (l *DiskLocation) DeleteCollectionFromDiskLocation(collection string) (e error) {
	l.Lock()
	defer l.Unlock()

	for k, v := range l.volumes {
		if v.Collection == collection {
			e = l.deleteVolumeById(k)
			if e != nil {
				return
			}
		}
	}
	return
}

func (l *DiskLocation) deleteVolumeById(vid VolumeId) (e error) {
	v, ok := l.volumes[vid]
	if !ok {
		return
	}
	e = v.Destroy()
	if e != nil {
		return
	}
	delete(l.volumes, vid)
	return
}

func (l *DiskLocation) LoadVolume(vid VolumeId, needleMapKind NeedleMapType) bool {
	if dirs, err := ioutil.ReadDir(l.Directory); err == nil {
		for _, dir := range dirs {
			volId, _, err := l.volumeIdFromPath(dir)
			if vid == volId && err == nil {
				var mutex sync.RWMutex
				l.loadExistingVolume(dir, needleMapKind, &mutex)
				return true
			}
		}
	}

	return false
}

func (l *DiskLocation) DeleteVolume(vid VolumeId) error {
	l.Lock()
	defer l.Unlock()

	_, ok := l.volumes[vid]
	if !ok {
		return fmt.Errorf("Volume not found, VolumeId: %d", vid)
	}
	return l.deleteVolumeById(vid)
}

func (l *DiskLocation) UnloadVolume(vid VolumeId) error {
	l.Lock()
	defer l.Unlock()

	_, ok := l.volumes[vid]
	if !ok {
		return fmt.Errorf("Volume not loaded, VolumeId: %d", vid)
	}
	delete(l.volumes, vid)
	return nil
}

func (l *DiskLocation) SetVolume(vid VolumeId, volume *Volume) {
	l.Lock()
	defer l.Unlock()

	l.volumes[vid] = volume
}

func (l *DiskLocation) FindVolume(vid VolumeId) (*Volume, bool) {
	l.RLock()
	defer l.RUnlock()

	v, ok := l.volumes[vid]
	return v, ok
}

func (l *DiskLocation) VolumesLen() int {
	l.RLock()
	defer l.RUnlock()

	return len(l.volumes)
}

func (l *DiskLocation) Close() {
	l.Lock()
	defer l.Unlock()

	for _, v := range l.volumes {
		v.Close()
	}
	return
}
<|endoftext|>


<commit_before>package topology

import (
	"github.com/chrislusf/seaweedfs/weed/storage/erasure_coding"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
)

func (dn *DataNode) GetEcShards() (ret []*erasure_coding.EcVolumeInfo) {
	dn.RLock()
	for _, ecVolumeInfo := range dn.ecShards {
		ret = append(ret, ecVolumeInfo)
	}
	dn.RUnlock()
	return ret
}

func (dn *DataNode) UpdateEcShards(actualShards []*erasure_coding.EcVolumeInfo) (newShards, deletedShards []*erasure_coding.EcVolumeInfo) {
	// prepare the new ec shard map
	actualEcShardMap := make(map[needle.VolumeId]*erasure_coding.EcVolumeInfo)
	for _, ecShards := range actualShards {
		actualEcShardMap[ecShards.VolumeId] = ecShards
	}

	// found out the newShards and deletedShards
	dn.ecShardsLock.RLock()
	for vid, ecShards := range dn.ecShards {
		if actualEcShards, ok := actualEcShardMap[vid]; !ok {
			// dn registered ec shards not found in the new set of ec shards
			deletedShards = append(deletedShards, ecShards)
		} else {
			// found, but maybe the actual shard could be missing
			a := actualEcShards.Minus(ecShards)
			if a.ShardIdCount() > 0 {
				newShards = append(newShards, a)
			}
			d := ecShards.Minus(actualEcShards)
			if d.ShardIdCount() > 0 {
				deletedShards = append(deletedShards, d)
			}
		}
	}
	for _, ecShards := range actualShards {
		if _, found := dn.ecShards[ecShards.VolumeId]; !found {
			newShards = append(newShards, ecShards)
		}
	}
	dn.ecShardsLock.RUnlock()

	if len(newShards) > 0 || len(deletedShards) > 0 {
		// if changed, set to the new ec shard map
		dn.ecShardsLock.Lock()
		dn.ecShards = actualEcShardMap
		dn.UpAdjustEcShardCountDelta(int64(len(newShards) - len(deletedShards)))
		dn.ecShardsLock.Unlock()
	}

	return
}

func (dn *DataNode) DeltaUpdateEcShards(newShards, deletedShards []*erasure_coding.EcVolumeInfo) {

	for _, newShard := range newShards {
		dn.AddOrUpdateEcShard(newShard)
	}

	for _, deletedShard := range deletedShards {
		dn.DeleteEcShard(deletedShard)
	}

}

func (dn *DataNode) AddOrUpdateEcShard(s *erasure_coding.EcVolumeInfo) {
	dn.ecShardsLock.Lock()
	defer dn.ecShardsLock.Unlock()

	delta := 0
	if existing, ok := dn.ecShards[s.VolumeId]; !ok {
		dn.ecShards[s.VolumeId] = s
		delta = s.ShardBits.ShardIdCount()
	} else {
		oldCount := existing.ShardBits.ShardIdCount()
		existing.ShardBits = existing.ShardBits.Plus(s.ShardBits)
		delta = existing.ShardBits.ShardIdCount() - oldCount
	}

	dn.UpAdjustEcShardCountDelta(int64(delta))

}

func (dn *DataNode) DeleteEcShard(s *erasure_coding.EcVolumeInfo) {
	dn.ecShardsLock.Lock()
	defer dn.ecShardsLock.Unlock()

	if existing, ok := dn.ecShards[s.VolumeId]; ok {
		oldCount := existing.ShardBits.ShardIdCount()
		existing.ShardBits = existing.ShardBits.Minus(s.ShardBits)
		delta := existing.ShardBits.ShardIdCount() - oldCount
		dn.UpAdjustEcShardCountDelta(int64(delta))
		if existing.ShardBits.ShardIdCount() == 0 {
			delete(dn.ecShards, s.VolumeId)
		}
	}

}

func (dn *DataNode) HasVolumesById(id needle.VolumeId) (hasVolumeId bool) {

	// check whether normal volumes has this volume id
	dn.RLock()
	_, ok := dn.volumes[id]
	if ok {
		hasVolumeId = true
	}
	dn.RUnlock()

	if hasVolumeId {
		return
	}

	// check whether ec shards has this volume id
	dn.ecShardsLock.RLock()
	_, ok = dn.ecShards[id]
	if ok {
		hasVolumeId = true
	}
	dn.ecShardsLock.RUnlock()

	return

}
<commit_msg>fix shard count reporting<commit_after>package topology

import (
	"github.com/chrislusf/seaweedfs/weed/storage/erasure_coding"
	"github.com/chrislusf/seaweedfs/weed/storage/needle"
)

func (dn *DataNode) GetEcShards() (ret []*erasure_coding.EcVolumeInfo) {
	dn.RLock()
	for _, ecVolumeInfo := range dn.ecShards {
		ret = append(ret, ecVolumeInfo)
	}
	dn.RUnlock()
	return ret
}

func (dn *DataNode) UpdateEcShards(actualShards []*erasure_coding.EcVolumeInfo) (newShards, deletedShards []*erasure_coding.EcVolumeInfo) {
	// prepare the new ec shard map
	actualEcShardMap := make(map[needle.VolumeId]*erasure_coding.EcVolumeInfo)
	for _, ecShards := range actualShards {
		actualEcShardMap[ecShards.VolumeId] = ecShards
	}

	// found out the newShards and deletedShards
	var newShardCount, deletedShardCount int
	dn.ecShardsLock.RLock()
	for vid, ecShards := range dn.ecShards {
		if actualEcShards, ok := actualEcShardMap[vid]; !ok {
			// dn registered ec shards not found in the new set of ec shards
			deletedShards = append(deletedShards, ecShards)
			deletedShardCount += ecShards.ShardIdCount()
		} else {
			// found, but maybe the actual shard could be missing
			a := actualEcShards.Minus(ecShards)
			if a.ShardIdCount() > 0 {
				newShards = append(newShards, a)
				newShardCount += a.ShardIdCount()
			}
			d := ecShards.Minus(actualEcShards)
			if d.ShardIdCount() > 0 {
				deletedShards = append(deletedShards, d)
				deletedShardCount += d.ShardIdCount()
			}
		}
	}
	for _, ecShards := range actualShards {
		if _, found := dn.ecShards[ecShards.VolumeId]; !found {
			newShards = append(newShards, ecShards)
			newShardCount += ecShards.ShardIdCount()
		}
	}
	dn.ecShardsLock.RUnlock()

	if len(newShards) > 0 || len(deletedShards) > 0 {
		// if changed, set to the new ec shard map
		dn.ecShardsLock.Lock()
		dn.ecShards = actualEcShardMap
		dn.UpAdjustEcShardCountDelta(int64(newShardCount - deletedShardCount))
		dn.ecShardsLock.Unlock()
	}

	return
}

func (dn *DataNode) DeltaUpdateEcShards(newShards, deletedShards []*erasure_coding.EcVolumeInfo) {

	for _, newShard := range newShards {
		dn.AddOrUpdateEcShard(newShard)
	}

	for _, deletedShard := range deletedShards {
		dn.DeleteEcShard(deletedShard)
	}

}

func (dn *DataNode) AddOrUpdateEcShard(s *erasure_coding.EcVolumeInfo) {
	dn.ecShardsLock.Lock()
	defer dn.ecShardsLock.Unlock()

	delta := 0
	if existing, ok := dn.ecShards[s.VolumeId]; !ok {
		dn.ecShards[s.VolumeId] = s
		delta = s.ShardBits.ShardIdCount()
	} else {
		oldCount := existing.ShardBits.ShardIdCount()
		existing.ShardBits = existing.ShardBits.Plus(s.ShardBits)
		delta = existing.ShardBits.ShardIdCount() - oldCount
	}

	dn.UpAdjustEcShardCountDelta(int64(delta))

}

func (dn *DataNode) DeleteEcShard(s *erasure_coding.EcVolumeInfo) {
	dn.ecShardsLock.Lock()
	defer dn.ecShardsLock.Unlock()

	if existing, ok := dn.ecShards[s.VolumeId]; ok {
		oldCount := existing.ShardBits.ShardIdCount()
		existing.ShardBits = existing.ShardBits.Minus(s.ShardBits)
		delta := existing.ShardBits.ShardIdCount() - oldCount
		dn.UpAdjustEcShardCountDelta(int64(delta))
		if existing.ShardBits.ShardIdCount() == 0 {
			delete(dn.ecShards, s.VolumeId)
		}
	}

}

func (dn *DataNode) HasVolumesById(id needle.VolumeId) (hasVolumeId bool) {

	// check whether normal volumes has this volume id
	dn.RLock()
	_, ok := dn.volumes[id]
	if ok {
		hasVolumeId = true
	}
	dn.RUnlock()

	if hasVolumeId {
		return
	}

	// check whether ec shards has this volume id
	dn.ecShardsLock.RLock()
	_, ok = dn.ecShards[id]
	if ok {
		hasVolumeId = true
	}
	dn.ecShardsLock.RUnlock()

	return

}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Knative 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 fake

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

	container "google.golang.org/api/container/v1beta1"
	"knative.dev/pkg/test/gke"
)

// Timeout for fake client.
// Need to be changed dynamically in the tests, so make them public.
var (
	CreationTimeout = 1000 * time.Millisecond
	DeletionTimeout = 10 * time.Minute
)

// GKESDKClient is a fake client for unit tests.
type GKESDKClient struct {
	// map of parent: clusters slice
	clusters map[string][]*container.Cluster
	// map of operationID: operation
	ops map[string]*container.Operation

	// An incremental number for new ops
	opNumber int
	// A lookup table for determining ops statuses
	OpStatus map[string]string
}

// NewGKESDKClient returns a new fake gkeSDKClient that can be used in unit tests.
func NewGKESDKClient() *GKESDKClient {
	return &GKESDKClient{
		clusters: make(map[string][]*container.Cluster),
		ops:      make(map[string]*container.Operation),
		OpStatus: make(map[string]string),
	}
}

// automatically registers new ops, and mark it "DONE" by default. Update
// fgsc.opStatus by fgsc.opStatus[string(fgsc.opNumber+1)]="PENDING" to make the
// next operation pending
func (fgsc *GKESDKClient) newOp() *container.Operation {
	opName := strconv.Itoa(fgsc.opNumber)
	op := &container.Operation{
		Name:   opName,
		Status: "DONE",
	}
	if status, ok := fgsc.OpStatus[opName]; ok {
		op.Status = status
	}
	fgsc.opNumber++
	fgsc.ops[opName] = op
	return op
}

// CreateCluster creates a new cluster, and wait until it finishes or timeout or there is an error.
func (fgsc *GKESDKClient) CreateCluster(
	project, region, zone string,
	rb *container.CreateClusterRequest,
) error {
	op, err := fgsc.CreateClusterAsync(project, region, zone, rb)
	if err == nil {
		err = gke.Wait(fgsc, project, region, zone, op.Name, CreationTimeout)
	}
	return err
}

// CreateClusterAsync creates a new cluster asynchronously.
func (fgsc *GKESDKClient) CreateClusterAsync(
	project, region, zone string,
	rb *container.CreateClusterRequest,
) (*container.Operation, error) {
	location := gke.GetClusterLocation(region, zone)
	parent := fmt.Sprintf("projects/%s/locations/%s", project, location)
	name := rb.Cluster.Name
	if cls, ok := fgsc.clusters[parent]; ok {
		for _, cl := range cls {
			if cl.Name == name {
				return nil, errors.New("cluster already exist")
			}
		}
	} else {
		fgsc.clusters[parent] = make([]*container.Cluster, 0)
	}
	cluster := &container.Cluster{
		Name:         name,
		Location:     location,
		Status:       "RUNNING",
		AddonsConfig: rb.Cluster.AddonsConfig,
		NodePools:    rb.Cluster.NodePools,
	}
	if rb.Cluster.NodePools != nil {
		cluster.NodePools = rb.Cluster.NodePools
	}
	if rb.Cluster.MasterAuth != nil {
		cluster.MasterAuth = &container.MasterAuth{
			Username: rb.Cluster.MasterAuth.Username,
		}
	}

	fgsc.clusters[parent] = append(fgsc.clusters[parent], cluster)
	return fgsc.newOp(), nil
}

// DeleteCluster deletes the cluster, and wait until it finishes or timeout or there is an error.
func (fgsc *GKESDKClient) DeleteCluster(
	project, region, zone, clusterName string,
) error {
	op, err := fgsc.DeleteClusterAsync(project, region, zone, clusterName)
	if err == nil {
		err = gke.Wait(fgsc, project, region, zone, op.Name, DeletionTimeout)
	}
	return err
}

// DeleteClusterAsync deletes the cluster asynchronously.
func (fgsc *GKESDKClient) DeleteClusterAsync(
	project, region, zone, clusterName string,
) (*container.Operation, error) {
	location := gke.GetClusterLocation(region, zone)
	parent := fmt.Sprintf("projects/%s/locations/%s", project, location)
	found := -1
	if clusters, ok := fgsc.clusters[parent]; ok {
		for i, cluster := range clusters {
			if cluster.Name == clusterName {
				found = i
			}
		}
	}
	if found == -1 {
		return nil, fmt.Errorf("cluster %q not found for deletion", clusterName)
	}
	// Delete this cluster
	fgsc.clusters[parent] = append(fgsc.clusters[parent][:found], fgsc.clusters[parent][found+1:]...)
	return fgsc.newOp(), nil
}

// GetCluster gets the cluster with the given settings.
func (fgsc *GKESDKClient) GetCluster(project, region, zone, cluster string) (*container.Cluster, error) {
	location := gke.GetClusterLocation(region, zone)
	parent := fmt.Sprintf("projects/%s/locations/%s", project, location)
	if cls, ok := fgsc.clusters[parent]; ok {
		for _, cl := range cls {
			if cl.Name == cluster {
				return cl, nil
			}
		}
	}
	return nil, fmt.Errorf("cluster not found")
}

// ListClustersInProject lists all the GKE clusters created in the given project.
func (fgsc *GKESDKClient) ListClustersInProject(project string) ([]*container.Cluster, error) {
	allClusters := make([]*container.Cluster, 0)
	projectPath := fmt.Sprintf("projects/%s", project)
	for location, cls := range fgsc.clusters {
		// If the clusters are under this project
		if strings.HasPrefix(location, projectPath) {
			allClusters = append(allClusters, cls...)
		}
	}
	return allClusters, nil
}

// GetOperation gets the operation with the given settings.
func (fgsc *GKESDKClient) GetOperation(project, region, zone, opName string) (*container.Operation, error) {
	if op, ok := fgsc.ops[opName]; ok {
		return op, nil
	}
	return nil, fmt.Errorf("op not found")
}
<commit_msg>Modify GKE fake client to make the operations thread-safe (#771)<commit_after>/*
Copyright 2019 The Knative 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 fake

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

	container "google.golang.org/api/container/v1beta1"
	"knative.dev/pkg/test/gke"
)

// Timeout for fake client.
// Need to be changed dynamically in the tests, so make them public.
var (
	CreationTimeout = 1000 * time.Millisecond
	DeletionTimeout = 10 * time.Minute
)

// GKESDKClient is a fake client for unit tests.
type GKESDKClient struct {
	// map of parent: clusters slice
	clusters map[string][]*container.Cluster
	// map of operationID: operation
	ops map[string]*container.Operation

	// An incremental number for new ops
	opNumber int
	// A lookup table for determining ops statuses
	OpStatus map[string]string

	mutex sync.Mutex
}

// NewGKESDKClient returns a new fake gkeSDKClient that can be used in unit tests.
func NewGKESDKClient() *GKESDKClient {
	return &GKESDKClient{
		clusters: make(map[string][]*container.Cluster),
		ops:      make(map[string]*container.Operation),
		OpStatus: make(map[string]string),
	}
}

// automatically registers new ops, and mark it "DONE" by default. Update
// fgsc.opStatus by fgsc.opStatus[string(fgsc.opNumber+1)]="PENDING" to make the
// next operation pending
func (fgsc *GKESDKClient) newOp() *container.Operation {
	opName := strconv.Itoa(fgsc.opNumber)
	op := &container.Operation{
		Name:   opName,
		Status: "DONE",
	}
	if status, ok := fgsc.OpStatus[opName]; ok {
		op.Status = status
	}
	fgsc.opNumber++
	fgsc.ops[opName] = op
	return op
}

// CreateCluster creates a new cluster, and wait until it finishes or timeout or there is an error.
func (fgsc *GKESDKClient) CreateCluster(
	project, region, zone string,
	rb *container.CreateClusterRequest,
) error {
	op, err := fgsc.CreateClusterAsync(project, region, zone, rb)
	if err == nil {
		err = gke.Wait(fgsc, project, region, zone, op.Name, CreationTimeout)
	}
	return err
}

// CreateClusterAsync creates a new cluster asynchronously.
func (fgsc *GKESDKClient) CreateClusterAsync(
	project, region, zone string,
	rb *container.CreateClusterRequest,
) (*container.Operation, error) {
	fgsc.mutex.Lock()
	defer fgsc.mutex.Unlock()
	location := gke.GetClusterLocation(region, zone)
	parent := fmt.Sprintf("projects/%s/locations/%s", project, location)
	name := rb.Cluster.Name
	if cls, ok := fgsc.clusters[parent]; ok {
		for _, cl := range cls {
			if cl.Name == name {
				return nil, errors.New("cluster already exist")
			}
		}
	} else {
		fgsc.clusters[parent] = make([]*container.Cluster, 0)
	}
	cluster := &container.Cluster{
		Name:         name,
		Location:     location,
		Status:       "RUNNING",
		AddonsConfig: rb.Cluster.AddonsConfig,
		NodePools:    rb.Cluster.NodePools,
	}
	if rb.Cluster.NodePools != nil {
		cluster.NodePools = rb.Cluster.NodePools
	}
	if rb.Cluster.MasterAuth != nil {
		cluster.MasterAuth = &container.MasterAuth{
			Username: rb.Cluster.MasterAuth.Username,
		}
	}

	fgsc.clusters[parent] = append(fgsc.clusters[parent], cluster)
	return fgsc.newOp(), nil
}

// DeleteCluster deletes the cluster, and wait until it finishes or timeout or there is an error.
func (fgsc *GKESDKClient) DeleteCluster(
	project, region, zone, clusterName string,
) error {
	op, err := fgsc.DeleteClusterAsync(project, region, zone, clusterName)
	if err == nil {
		err = gke.Wait(fgsc, project, region, zone, op.Name, DeletionTimeout)
	}
	return err
}

// DeleteClusterAsync deletes the cluster asynchronously.
func (fgsc *GKESDKClient) DeleteClusterAsync(
	project, region, zone, clusterName string,
) (*container.Operation, error) {
	fgsc.mutex.Lock()
	defer fgsc.mutex.Unlock()
	location := gke.GetClusterLocation(region, zone)
	parent := fmt.Sprintf("projects/%s/locations/%s", project, location)
	found := -1
	if clusters, ok := fgsc.clusters[parent]; ok {
		for i, cluster := range clusters {
			if cluster.Name == clusterName {
				found = i
			}
		}
	}
	if found == -1 {
		return nil, fmt.Errorf("cluster %q not found for deletion", clusterName)
	}
	// Delete this cluster
	fgsc.clusters[parent] = append(fgsc.clusters[parent][:found], fgsc.clusters[parent][found+1:]...)
	return fgsc.newOp(), nil
}

// GetCluster gets the cluster with the given settings.
func (fgsc *GKESDKClient) GetCluster(project, region, zone, cluster string) (*container.Cluster, error) {
	fgsc.mutex.Lock()
	defer fgsc.mutex.Unlock()
	location := gke.GetClusterLocation(region, zone)
	parent := fmt.Sprintf("projects/%s/locations/%s", project, location)
	if cls, ok := fgsc.clusters[parent]; ok {
		for _, cl := range cls {
			if cl.Name == cluster {
				return cl, nil
			}
		}
	}
	return nil, fmt.Errorf("cluster not found")
}

// ListClustersInProject lists all the GKE clusters created in the given project.
func (fgsc *GKESDKClient) ListClustersInProject(project string) ([]*container.Cluster, error) {
	fgsc.mutex.Lock()
	defer fgsc.mutex.Unlock()
	allClusters := make([]*container.Cluster, 0)
	projectPath := fmt.Sprintf("projects/%s", project)
	for location, cls := range fgsc.clusters {
		// If the clusters are under this project
		if strings.HasPrefix(location, projectPath) {
			allClusters = append(allClusters, cls...)
		}
	}
	return allClusters, nil
}

// GetOperation gets the operation with the given settings.
func (fgsc *GKESDKClient) GetOperation(project, region, zone, opName string) (*container.Operation, error) {
	fgsc.mutex.Lock()
	op, ok := fgsc.ops[opName]
	fgsc.mutex.Unlock()
	if ok {
		return op, nil
	}
	return nil, errors.New(opName + " operation not found")
}
<|endoftext|>


<commit_before>package routing

import (
	"errors"
	"math/rand"

	log "github.com/Sirupsen/logrus"
)

var (
	ErrorCouldNotSelect = errors.New("could not select a plugin (round robin strategy)")
)

type RoundRobinStrategy struct {
}

func (r *RoundRobinStrategy) String() string {
	return "round-robin"
}

func (r *RoundRobinStrategy) Select(spp SelectablePluginPool, spa []SelectablePlugin) (SelectablePlugin, error) {
	var h int = -1
	var index int = -1
	for i, sp := range spa {
		// look for the lowest hit count
		if sp.HitCount() < h || h == -1 {
			index = i
			h = sp.HitCount()
		}
		// on a hitcount tie we randomly choose one
		if sp.HitCount() == h {
			if rand.Intn(1) == 1 {
				index = i
				h = sp.HitCount()
			}
		}
	}
	if index > -1 {
		log.WithFields(log.Fields{
			"_module":   "control-routing",
			"block":     "select",
			"strategy":  "round-robin",
			"pool size": len(spa),
			"index":     spa[index].String(),
			"hitcount":  spa[index].HitCount(),
		}).Debug("plugin selected")
		return spa[index], nil
	}
	log.WithFields(log.Fields{
		"_module":  "control-routing",
		"block":    "select",
		"strategy": "round-robin",
		"error":    ErrorCouldNotSelect,
	}).Debug("error selecting")
	return nil, ErrorCouldNotSelect
}
<commit_msg>Fixes #376. Switches debug message to error message<commit_after>package routing

import (
	"errors"
	"math/rand"

	log "github.com/Sirupsen/logrus"
)

var (
	ErrorCouldNotSelect = errors.New("could not select a plugin (round robin strategy)")
)

type RoundRobinStrategy struct {
}

func (r *RoundRobinStrategy) String() string {
	return "round-robin"
}

func (r *RoundRobinStrategy) Select(spp SelectablePluginPool, spa []SelectablePlugin) (SelectablePlugin, error) {
	var h int = -1
	var index int = -1
	for i, sp := range spa {
		// look for the lowest hit count
		if sp.HitCount() < h || h == -1 {
			index = i
			h = sp.HitCount()
		}
		// on a hitcount tie we randomly choose one
		if sp.HitCount() == h {
			if rand.Intn(1) == 1 {
				index = i
				h = sp.HitCount()
			}
		}
	}
	if index > -1 {
		log.WithFields(log.Fields{
			"_module":   "control-routing",
			"block":     "select",
			"strategy":  "round-robin",
			"pool size": len(spa),
			"index":     spa[index].String(),
			"hitcount":  spa[index].HitCount(),
		}).Debug("plugin selected")
		return spa[index], nil
	}
	log.WithFields(log.Fields{
		"_module":  "control-routing",
		"block":    "select",
		"strategy": "round-robin",
		"error":    ErrorCouldNotSelect,
	}).Error("error selecting")
	return nil, ErrorCouldNotSelect
}
<|endoftext|>


<commit_before>package config

import (
	"fmt"
	"log"
	"os/user"
	"path/filepath"
	"strings"

	"os"

	"github.com/spf13/viper"
)

// TablesConf informations
type TablesConf struct {
	Name        string   `mapstructure:"name"`
	Permissions []string `mapstructure:"permissions"`
	Fields      []string `mapstructure:"fields"`
}

// AccessConf informations
type AccessConf struct {
	Restrict bool
	Tables   []TablesConf
}

// Prest basic config
type Prest struct {
	// HTTPPort Declare which http port the PREST used
	HTTPPort        int
	PGHost          string
	PGPort          int
	PGUser          string
	PGPass          string
	PGDatabase      string
	PGMaxIdleConn   int
	PGMAxOpenConn   int
	JWTKey          string
	MigrationsPath  string
	QueriesPath     string
	AccessConf      AccessConf
	CORSAllowOrigin []string
}

// PrestConf config variable
var PrestConf *Prest

func init() {
	viperCfg()
}

func viperCfg() {
	filePath := os.Getenv("PREST_CONF")
	if filePath == "" {
		filePath = "prest.toml"
	}
	replacer := strings.NewReplacer(".", "_")
	viper.SetEnvPrefix("PREST")
	viper.AutomaticEnv()
	viper.SetEnvKeyReplacer(replacer)
	viper.SetConfigFile(filePath)
	viper.SetConfigType("toml")
	viper.SetDefault("http.port", 3000)
	viper.SetDefault("pg.host", "127.0.0.1")
	viper.SetDefault("pg.port", 5432)
	viper.SetDefault("pg.maxidleconn", 10)
	viper.SetDefault("pg.maxopenconn", 10)

	user, err := user.Current()
	if err != nil {
		log.Println("{viperCfg}", err)
	}

	viper.SetDefault("queries.location", filepath.Join(user.HomeDir, "queries"))
}

// Parse pREST config
func Parse(cfg *Prest) (err error) {
	err = viper.ReadInConfig()
	if err != nil {
		return
	}
	cfg.HTTPPort = viper.GetInt("http.port")
	cfg.PGHost = viper.GetString("pg.host")
	cfg.PGPort = viper.GetInt("pg.port")
	cfg.PGUser = viper.GetString("pg.user")
	cfg.PGPass = viper.GetString("pg.pass")
	cfg.PGDatabase = viper.GetString("pg.database")
	cfg.PGMaxIdleConn = viper.GetInt("pg.maxidleconn")
	cfg.PGMAxOpenConn = viper.GetInt("pg.maxopenconn")
	cfg.JWTKey = viper.GetString("jwt.key")
	cfg.MigrationsPath = viper.GetString("migrations")
	cfg.AccessConf.Restrict = viper.GetBool("access.restrict")
	cfg.QueriesPath = viper.GetString("queries.location")
	cfg.CORSAllowOrigin = viper.GetStringSlice("cors.alloworigin")

	var t []TablesConf
	err = viper.UnmarshalKey("access.tables", &t)
	if err != nil {
		return err
	}

	cfg.AccessConf.Tables = t

	return
}

// InitConf initialize config
func InitConf() {
	viperCfg()
	prestConfig := Prest{}
	Parse(&prestConfig)
	PrestConf = &prestConfig

	if !prestConfig.AccessConf.Restrict {
		fmt.Println("You are running pREST in public mode.")
	}

	if _, err := os.Stat(PrestConf.QueriesPath); os.IsNotExist(err) {
		os.MkdirAll(PrestConf.QueriesPath, 0777)
	}
}
<commit_msg>connection timeout configuration (#127)<commit_after>package config

import (
	"fmt"
	"log"
	"os/user"
	"path/filepath"
	"strings"

	"os"

	"github.com/spf13/viper"
)

// TablesConf informations
type TablesConf struct {
	Name        string   `mapstructure:"name"`
	Permissions []string `mapstructure:"permissions"`
	Fields      []string `mapstructure:"fields"`
}

// AccessConf informations
type AccessConf struct {
	Restrict bool
	Tables   []TablesConf
}

// Prest basic config
type Prest struct {
	// HTTPPort Declare which http port the PREST used
	HTTPPort        int
	PGHost          string
	PGPort          int
	PGUser          string
	PGPass          string
	PGDatabase      string
	PGMaxIdleConn   int
	PGMAxOpenConn   int
	PGConnTimeout   int
	JWTKey          string
	MigrationsPath  string
	QueriesPath     string
	AccessConf      AccessConf
	CORSAllowOrigin []string
}

// PrestConf config variable
var PrestConf *Prest

func init() {
	viperCfg()
}

func viperCfg() {
	filePath := os.Getenv("PREST_CONF")
	if filePath == "" {
		filePath = "prest.toml"
	}
	replacer := strings.NewReplacer(".", "_")
	viper.SetEnvPrefix("PREST")
	viper.AutomaticEnv()
	viper.SetEnvKeyReplacer(replacer)
	viper.SetConfigFile(filePath)
	viper.SetConfigType("toml")
	viper.SetDefault("http.port", 3000)
	viper.SetDefault("pg.host", "127.0.0.1")
	viper.SetDefault("pg.port", 5432)
	viper.SetDefault("pg.maxidleconn", 10)
	viper.SetDefault("pg.maxopenconn", 10)
	viper.SetDefault("pg.conntimeout", 10)

	user, err := user.Current()
	if err != nil {
		log.Println("{viperCfg}", err)
	}

	viper.SetDefault("queries.location", filepath.Join(user.HomeDir, "queries"))
}

// Parse pREST config
func Parse(cfg *Prest) (err error) {
	err = viper.ReadInConfig()
	if err != nil {
		return
	}
	cfg.HTTPPort = viper.GetInt("http.port")
	cfg.PGHost = viper.GetString("pg.host")
	cfg.PGPort = viper.GetInt("pg.port")
	cfg.PGUser = viper.GetString("pg.user")
	cfg.PGPass = viper.GetString("pg.pass")
	cfg.PGDatabase = viper.GetString("pg.database")
	cfg.PGMaxIdleConn = viper.GetInt("pg.maxidleconn")
	cfg.PGMAxOpenConn = viper.GetInt("pg.maxopenconn")
	cfg.PGConnTimeout = viper.GetInt("pg.conntimeout")
	cfg.JWTKey = viper.GetString("jwt.key")
	cfg.MigrationsPath = viper.GetString("migrations")
	cfg.AccessConf.Restrict = viper.GetBool("access.restrict")
	cfg.QueriesPath = viper.GetString("queries.location")
	cfg.CORSAllowOrigin = viper.GetStringSlice("cors.alloworigin")

	var t []TablesConf
	err = viper.UnmarshalKey("access.tables", &t)
	if err != nil {
		return err
	}

	cfg.AccessConf.Tables = t

	return
}

// InitConf initialize config
func InitConf() {
	viperCfg()
	prestConfig := Prest{}
	Parse(&prestConfig)
	PrestConf = &prestConfig

	if !prestConfig.AccessConf.Restrict {
		fmt.Println("You are running pREST in public mode.")
	}

	if _, err := os.Stat(PrestConf.QueriesPath); os.IsNotExist(err) {
		os.MkdirAll(PrestConf.QueriesPath, 0777)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"testing"
)

func TestPascalCaseToSnakeCase(t *testing.T) {
	tests := []struct {
		in  string
		out string
	}{
		{
			"TestString",
			"test_string",
		},
		{
			"Teststring",
			"teststring",
		},
	}

	for i, test := range tests {
		out := PascalCaseToSnakeCase(test.in)

		if out != test.out {
			t.Errorf("Test %d: Expected %s, but got %s", i, test.out, out)
		}
	}
}
<commit_msg>Add an ApplicationCommand registration test.<commit_after>// Copyright 2014 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package backend

import (
	"fmt"
	"testing"
)

type (
	DummyApplicationCommand struct {
		DefaultCommand
	}
)

func (c *DummyApplicationCommand) Run() error {
	return fmt.Errorf("Ran")
}

func (c *DummyApplicationCommand) IsChecked() bool {
	return false
}

func TestPascalCaseToSnakeCase(t *testing.T) {
	tests := []struct {
		in  string
		out string
	}{
		{
			"TestString",
			"test_string",
		},
		{
			"Teststring",
			"teststring",
		},
	}

	for i, test := range tests {
		out := PascalCaseToSnakeCase(test.in)

		if out != test.out {
			t.Errorf("Test %d: Expected %s, but got %s", i, test.out, out)
		}
	}
}

func TestRegisterApplicationCommand(t *testing.T) {
	name := "app_test_command"
	ac := DummyApplicationCommand{}
	ch := GetEditor().CommandHandler()

	err := ch.Register(name, &ac)

	if err != nil {
		t.Errorf("Got error while registering: %s", err)
	}

	err = ch.RunApplicationCommand(name, Args{})

	if err == nil {
		t.Errorf("Expected %s to run, but it didn't", name)
	} else if err.Error() != "Ran" {
		t.Errorf("Expected %s to run, but it got an error: %v", name, err)
	}
}
<|endoftext|>