<commit_before>package main

import (
	"flag"
	"fmt"
	"github.com/the42/ogdat/ckan"
	"github.com/the42/ogdat/ogdatv21"
	"github.com/the42/ogdat/schedule"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

const AppID = "a6545f8f-e0c9-4917-83c7-3e47bd1e0247"

var logger *log.Logger
var db *DBConn
var portal *ckan.Portal

var resettdb = flag.Bool("resetdb", false, "Delete the tracking database. You will be prompted before actual deletion. Process will terminate afterwards.")
var servetdb = flag.Bool("serve", false, "Start in watchdog mode. Process will continue to run until it receives a (clean shutdown) or gets killed")

func gotyesonprompt() bool {
	var prompt string
	fmt.Scanf("%s", &prompt)
	prompt = strings.ToLower(strings.TrimSpace(prompt))
	if len(prompt) > 0 {
		return prompt[0] == 'y'
	}
	return false
}

func getheartbeatinterval() int {

	if i, err := strconv.Atoi(os.Getenv("HEARTBEAT_INTERVAL")); err == nil {
		return i
	}
	return 10 // Minutes
}

func getnumworkers() int {
	if i, err := strconv.Atoi(os.Getenv("PARALLEL_FETCHNO")); err == nil {
		return i
	}
	return 4 // process four IDs in parallel
}

func getckanurl() (url string) {

	const CKAN_URL = "http://www.data.gv.at/katalog/api/"

	url = os.Getenv("CKAN_URL")
	if url == "" {
		url = CKAN_URL
	}
	return
}

func resetdb() {
	logger.Println("Warning: Requesting database reset")
	fmt.Print("\n\nALL RECORDED DATA IN DATABASE  WILL BE DELETED.\nDO YOU REALLY WANT TO PROCEED? [N,y]\n")
	if !gotyesonprompt() {
		fmt.Print("\nABORTING\n\n")
		logger.Println("Info: Database reset canceled")
	} else {
		if err := db.ResetDatabase(); err != nil {
			s := fmt.Sprintf("Database reset failed: %s", err)
			fmt.Println(s)
			logger.Panic(s)
		}
	}
}

func stringslicetoiface(ss []string) []interface{} {
	slice := make([]interface{}, len(ss))
	for i, v := range ss {
		slice[i] = v
	}
	return slice
}

func ifaceslicetostring(ifs []interface{}) []string {
	slice := make([]string, len(ifs))
	for i, v := range ifs {
		s, ok := v.(string)
		if !ok {
			panic("Interface value not of string type")
		}
		slice[i] = s
	}
	return slice
}

func processmetadataids(conn *DBConn, processids []string) error {

	nums := len(processids)
	for idx, id := range processids {

		logger.Printf("%4d / %4d : processing %v\n", idx+1, nums, id)

		mdjson, err := portal.GetDatasetStreamforID(id, true)
		if err != nil {
			return fmt.Errorf("Cannot fetch JSON for ID %v: %s", id, err)
		}

		md, err := ogdatv21.MetadatafromJSONStream(mdjson)
		if err != nil {
			return fmt.Errorf("Cannot access metadata for ID %v: %s", id, err)
		}

		dbdatasetid, isnew, err := conn.InsertOrUpdateMetadataInfo(id, md)
		if err != nil {
			return fmt.Errorf("InsertOrUpdateMetadataInfo: database error at id %v: %s", id, err)
		}

		messages, err := md.Check(true)
		if err != nil {
			return fmt.Errorf("Metadata check error for id %v: %s", id, err)
		}

		if err = conn.ProtocollCheck(dbdatasetid, isnew, messages); err != nil {
			return fmt.Errorf("ProtocollCheck: database error at id %v: %s", id, err)
		}
	}
	logger.Printf("Worker finished processing %d entries", nums)
	return nil
}

func heartbeat(interval int) {
	for {
		dbconn := GetDatabaseConnection()
		db := &DBConn{dbconn, AppID}
		if err := db.HeartBeat(); err != nil {
			logger.Panicln(err)
		}
		dbconn.Close()
		logger.Println("Watchdog alive")
		time.Sleep(time.Duration(interval) * time.Minute)
	}
}

func mymain() int {

	if flag.NFlag() == 0 {
		fmt.Println("No command line flags given. Usage:")
		flag.PrintDefaults()
		logger.Panicln("Fatal: No command line flags given")
	}

	lockfile := NewLockfile(lockfilename)
	defer lockfile.Delete()
	lockfile.WriteInfo()

	// When the process gets killed, try to delete the lock file
	interrupt := make(chan os.Signal)
	signal.Notify(interrupt, os.Interrupt)
	go func() {
		<-interrupt
		logger.Println("Terminate requested")
		lockfile.Delete()
		os.Exit(10)
	}()

	dbconnection := GetDatabaseConnection()
	db = &DBConn{dbconnection, AppID}
	defer dbconnection.Close()

	if *resettdb {
		resetdb()
		logger.Println("Info: Earyl exit due to maintainance switches")
		return 2
	}

	if *servetdb {

		portal = ckan.NewDataPortalAPIEndpoint(getckanurl(), "2/")
		heartbeatinterval := getheartbeatinterval()
		numworkers := getnumworkers()

		logger.Printf("Doing %d jobs in parallel\n", numworkers)
		go heartbeat(heartbeatinterval)

		for {
			hit, err := db.GetLastHit()
			if err != nil {
				s := fmt.Sprintf("Cannot read last DBHit: %s", err)
				fmt.Println(s)
				logger.Panic(s)
			}

			var processids []string
			if hit == nil {
				logger.Println("No checkpoint in database found, getting all datasets")
				processids, err = portal.GetAllMetaDataIDs()
			} else {
				logger.Printf("Getting changed datasets since %s\n", hit)
				processids, err = portal.GetChangedPackageIDsSince(*hit, numworkers)
			}

			if err != nil {
				fmt.Println(err)
				logger.Panic(err)

			}

			if anzids := len(processids); anzids > 0 {

				tx, err := dbconnection.Begin()
				if err != nil {
					logger.Panicln("Cannot create database transaction")
				}
				scheduler := schedule.New(numworkers)
				conn := &DBConn{DBer: tx, appid: AppID}
				f := func(slice []interface{}) error {
					if err := processmetadataids(conn, ifaceslicetostring(slice)); err != nil {
						return err
					}
					return nil
				}

				db.LogMessage(fmt.Sprintf("%d Medadaten werden verarbeitet", anzids), StateOk, true)
				workchannel := scheduler.Schedule(f, stringslicetoiface(processids))
				select {
				case workreply := <-workchannel:
					if err := workreply.Err; err != nil {
						logger.Panicln("Scheduler didn't return success:", err)
					} else if workreply.Code == schedule.StateFinish {
						tx.Commit()
						db.LogMessage("Idle", StateOk, true)
						logger.Printf("Finished processing %d datasets\n", anzids)
					}
				}

			} else {
				// When there was nothing to do, wait for heartbeatinterval time
				logger.Printf("Nothing to do, sleeping for %d minutes\n", heartbeatinterval)
				time.Sleep(time.Duration(heartbeatinterval) * time.Minute)
			}
		}
	}
	return 0
}

func main() {
	os.Exit(mymain())
}

func init() {
	logger = log.New(os.Stderr, filepath.Base(os.Args[0])+": ", log.LstdFlags)
	flag.Parse()
}
<commit_msg>log to self: what to do about links<commit_after>package main

import (
	"flag"
	"fmt"
	"github.com/the42/ogdat/ckan"
	"github.com/the42/ogdat/ogdatv21"
	"github.com/the42/ogdat/schedule"
	"log"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

const AppID = "a6545f8f-e0c9-4917-83c7-3e47bd1e0247"

var logger *log.Logger
var db *DBConn
var portal *ckan.Portal

var resettdb = flag.Bool("resetdb", false, "Delete the tracking database. You will be prompted before actual deletion. Process will terminate afterwards.")
var servetdb = flag.Bool("serve", false, "Start in watchdog mode. Process will continue to run until it receives a (clean shutdown) or gets killed")

func gotyesonprompt() bool {
	var prompt string
	fmt.Scanf("%s", &prompt)
	prompt = strings.ToLower(strings.TrimSpace(prompt))
	if len(prompt) > 0 {
		return prompt[0] == 'y'
	}
	return false
}

func getheartbeatinterval() int {

	if i, err := strconv.Atoi(os.Getenv("HEARTBEAT_INTERVAL")); err == nil {
		return i
	}
	return 60 // Minutes
}

func getnumworkers() int {
	if i, err := strconv.Atoi(os.Getenv("PARALLEL_FETCHNO")); err == nil {
		return i
	}
	return 4 // process four IDs in parallel
}

func getckanurl() (url string) {

	const CKAN_URL = "http://www.data.gv.at/katalog/api/"

	url = os.Getenv("CKAN_URL")
	if url == "" {
		url = CKAN_URL
	}
	return
}

func resetdb() {
	logger.Println("Warning: Requesting database reset")
	fmt.Print("\n\nALL RECORDED DATA IN DATABASE  WILL BE DELETED.\nDO YOU REALLY WANT TO PROCEED? [N,y]\n")
	if !gotyesonprompt() {
		fmt.Print("\nABORTING\n\n")
		logger.Println("Info: Database reset canceled")
	} else {
		if err := db.ResetDatabase(); err != nil {
			s := fmt.Sprintf("Database reset failed: %s", err)
			fmt.Println(s)
			logger.Panic(s)
		}
	}
}

func stringslicetoiface(ss []string) []interface{} {
	slice := make([]interface{}, len(ss))
	for i, v := range ss {
		slice[i] = v
	}
	return slice
}

func ifaceslicetostring(ifs []interface{}) []string {
	slice := make([]string, len(ifs))
	for i, v := range ifs {
		s, ok := v.(string)
		if !ok {
			panic("Interface value not of string type")
		}
		slice[i] = s
	}
	return slice
}

func processmetadataids(conn *DBConn, processids []string) error {

	nums := len(processids)
	for idx, id := range processids {

		logger.Printf("%4d / %4d : processing %v\n", idx+1, nums, id)

		mdjson, err := portal.GetDatasetStreamforID(id, true)
		if err != nil {
			return fmt.Errorf("Cannot fetch JSON for ID %v: %s", id, err)
		}

		md, err := ogdatv21.MetadatafromJSONStream(mdjson)
		if err != nil {
			return fmt.Errorf("Cannot access metadata for ID %v: %s", id, err)
		}

		dbdatasetid, isnew, err := conn.InsertOrUpdateMetadataInfo(id, md)
		if err != nil {
			return fmt.Errorf("InsertOrUpdateMetadataInfo: database error at id %v: %s", id, err)
		}

		messages, err := md.Check(true)
		if err != nil {
			return fmt.Errorf("Metadata check error for id %v: %s", id, err)
		}

		if err = conn.ProtocollCheck(dbdatasetid, isnew, messages); err != nil {
			return fmt.Errorf("ProtocollCheck: database error at id %v: %s", id, err)
		}
	}
	logger.Printf("Worker finished processing %d entries", nums)
	return nil
}

func heartbeat(interval int) {
	for {
		dbconn := GetDatabaseConnection()
		db := &DBConn{dbconn, AppID}
		if err := db.HeartBeat(); err != nil {
			logger.Panicln(err)
		}
		dbconn.Close()
		logger.Println("Watchdog alive")
		time.Sleep(time.Duration(interval) * time.Minute)
	}
}

func mymain() int {

	if flag.NFlag() == 0 {
		fmt.Println("No command line flags given. Usage:")
		flag.PrintDefaults()
		logger.Panicln("Fatal: No command line flags given")
	}

	lockfile := NewLockfile(lockfilename)
	defer lockfile.Delete()
	lockfile.WriteInfo()

	// When the process gets killed, try to delete the lock file
	interrupt := make(chan os.Signal)
	signal.Notify(interrupt, os.Interrupt)
	go func() {
		<-interrupt
		logger.Println("Terminate requested")
		lockfile.Delete()
		os.Exit(10)
	}()

	dbconnection := GetDatabaseConnection()
	db = &DBConn{dbconnection, AppID}
	defer dbconnection.Close()

	if *resettdb {
		resetdb()
		logger.Println("Info: Earyl exit due to maintainance switches")
		return 2
	}

	if *servetdb {

		portal = ckan.NewDataPortalAPIEndpoint(getckanurl(), "2/")
		heartbeatinterval := getheartbeatinterval()
		numworkers := getnumworkers()

		logger.Printf("Doing %d jobs in parallel\n", numworkers)
		go heartbeat(heartbeatinterval)

		urlcheckpointchan := time.Tick(1 * time.Hour * 24)

		for {
			hit, err := db.GetLastHit()
			if err != nil {
				s := fmt.Sprintf("Cannot read last DBHit: %s", err)
				fmt.Println(s)
				logger.Panic(s)
			}

			var processids []string
			if hit == nil {
				logger.Println("No checkpoint in database found, getting all datasets")
				processids, err = portal.GetAllMetaDataIDs()
			} else {
				logger.Printf("Getting changed datasets since %s\n", hit)
				processids, err = portal.GetChangedPackageIDsSince(*hit, numworkers)
			}

			if err != nil {
				fmt.Println(err)
				logger.Panic(err)

			}

			if anzids := len(processids); anzids > 0 {

				tx, err := dbconnection.Begin()
				if err != nil {
					logger.Panicln("Cannot create database transaction")
				}
				scheduler := schedule.New(numworkers)
				conn := &DBConn{DBer: tx, appid: AppID}
				f := func(slice []interface{}) error {
					if err := processmetadataids(conn, ifaceslicetostring(slice)); err != nil {
						return err
					}
					return nil
				}

				db.LogMessage(fmt.Sprintf("%d Medadaten werden verarbeitet", anzids), StateOk, true)
				workchannel := scheduler.Schedule(f, stringslicetoiface(processids))
				select {
				case workreply := <-workchannel:
					if err := workreply.Err; err != nil {
						logger.Panicln("Scheduler didn't return success:", err)
					} else if workreply.Code == schedule.StateFinish {
						tx.Commit()
						db.LogMessage("Idle", StateOk, true)
						logger.Printf("Finished processing %d datasets\n", anzids)
					}
				}

			} else {
				// When there was nothing to do, wait for heartbeatinterval time
				logger.Printf("Nothing to do, sleeping for %d minutes\n", heartbeatinterval)
				time.Sleep(time.Duration(heartbeatinterval) * time.Minute)
			}

			// Check urls once a day, and when there is an error, report
			for _ = range urlcheckpointchan {
				// get all urls to check
				// = jene, die als fetchable eingestuft sind nicht mit einem strukturellen Problem belegt sind
				// = und die im bezug auf den datensatz am aktuellesten im statusrecord sind (group by time)

				// schedule check:
				// getable: OK <-- what to do, when last check was 'not getable'?
				// report result
			}
		}
	}
	return 0
}

func main() {
	os.Exit(mymain())
}

func init() {
	logger = log.New(os.Stderr, filepath.Base(os.Args[0])+": ", log.LstdFlags)
	flag.Parse()
}
<|endoftext|>


<commit_before>package cloudcontroller_test

import (
	"time"

	. "code.cloudfoundry.org/cli/api/cloudcontroller"
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Minimum Version Check", func() {
	Describe("MinimumAPIVersionCheck", func() {
		minimumVersion := "1.0.0"
		Context("current version is greater than min", func() {
			It("does not return an error", func() {
				currentVersion := "1.0.1"
				err := MinimumAPIVersionCheck(currentVersion, minimumVersion)
				Expect(err).ToNot(HaveOccurred())
			})
		})

		Context("current version is less than min", func() {
			It("does return an error", func() {
				currentVersion := "1.0.0-alpha.5"
				err := MinimumAPIVersionCheck(currentVersion, minimumVersion)
				Expect(err).To(MatchError(ccerror.MinimumAPIVersionNotMetError{
					CurrentVersion: currentVersion,
					MinimumVersion: minimumVersion,
				}))
			})
		})

		Context("minimum version is empty", func() {
			It("does not return an error", func() {
				err := MinimumAPIVersionCheck("2.0.0", "")
				Expect(err).ToNot(HaveOccurred())
			})
		})
	})

	Describe("Minimum version numbers", func() {
		It("are up to date", func() {
			expirationDate, err := time.Parse(time.RFC3339, "2020-01-01T00:00:00Z")
			Expect(err).ToNot(HaveOccurred())
			Expect(time.Now().Before(expirationDate)).To(BeTrue(), "Check https://github.com/cloudfoundry/cli/wiki/Versioning-Policy#cf-cli-minimum-supported-version and update versions if necessary")
		})
	})
})
<commit_msg>Disable "time bomb" test<commit_after>package cloudcontroller_test

import (
	"time"

	. "code.cloudfoundry.org/cli/api/cloudcontroller"
	"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Minimum Version Check", func() {
	Describe("MinimumAPIVersionCheck", func() {
		minimumVersion := "1.0.0"
		Context("current version is greater than min", func() {
			It("does not return an error", func() {
				currentVersion := "1.0.1"
				err := MinimumAPIVersionCheck(currentVersion, minimumVersion)
				Expect(err).ToNot(HaveOccurred())
			})
		})

		Context("current version is less than min", func() {
			It("does return an error", func() {
				currentVersion := "1.0.0-alpha.5"
				err := MinimumAPIVersionCheck(currentVersion, minimumVersion)
				Expect(err).To(MatchError(ccerror.MinimumAPIVersionNotMetError{
					CurrentVersion: currentVersion,
					MinimumVersion: minimumVersion,
				}))
			})
		})

		Context("minimum version is empty", func() {
			It("does not return an error", func() {
				err := MinimumAPIVersionCheck("2.0.0", "")
				Expect(err).ToNot(HaveOccurred())
			})
		})
	})

	XDescribe("Minimum version numbers", func() {
		It("are up to date", func() {
			expirationDate, err := time.Parse(time.RFC3339, "2020-01-01T00:00:00Z")
			Expect(err).ToNot(HaveOccurred())
			Expect(time.Now().Before(expirationDate)).To(BeTrue(), "Check https://github.com/cloudfoundry/cli/wiki/Versioning-Policy#cf-cli-minimum-supported-version and update versions if necessary")
		})
	})
})
<|endoftext|>


<commit_before>package deepcopier

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

	"github.com/guregu/null"
	"github.com/lib/pq"
	"github.com/oleiade/reflections"
)

const (
	// TagName is struct field tag name.
	TagName = "deepcopier"

	// FieldOptionName is the from field option name for struct tag.
	FieldOptionName = "field"

	// ContextOptionName is the context option name for struct tag.
	ContextOptionName = "context"

	// SkipOptionName is the skip option name for struct tag.
	SkipOptionName = "skip"
)

// DeepCopier deep copies a struct to/from a struct.
type DeepCopier struct {
	Source      interface{}
	Destination interface{}
	Tagged      interface{}
	Context     map[string]interface{}
	Reversed    bool
}

// FieldOptions contains options passed to SetField method.
type FieldOptions struct {
	SourceField      string
	DestinationField string
	WithContext      bool
	Skip             bool
}

// NewFieldOptions returns a FieldOptions instance for the given instance's field.
func NewFieldOptions(instance interface{}, field string, reversed bool) *FieldOptions {
	fieldOptions := &FieldOptions{
		SourceField:      field,
		DestinationField: field,
		WithContext:      false,
		Skip:             false,
	}

	tagOptions, _ := reflections.GetFieldTag(instance, field, TagName)

	if tagOptions == "" {
		return fieldOptions
	}

	opts := GetTagOptions(tagOptions)

	if _, ok := opts[FieldOptionName]; ok {
		fieldName := opts[FieldOptionName]

		if !reversed {
			fieldOptions.SourceField = fieldName
		} else {
			fieldOptions.DestinationField = fieldName
		}
	}

	if _, ok := opts[ContextOptionName]; ok {
		fieldOptions.WithContext = true
	}

	if _, ok := opts[SkipOptionName]; ok {
		fieldOptions.Skip = true
	}

	return fieldOptions
}

// Copy sets the source.
func Copy(source interface{}) *DeepCopier {
	return &DeepCopier{
		Source:   source,
		Reversed: false,
	}
}

// To sets the given tagged struct as destination struct.
// Source -> Destination
func (dc *DeepCopier) To(tagged interface{}) error {
	dc.Destination = tagged
	dc.Tagged = tagged

	return dc.ProcessCopy()
}

// From sets the given tagged struct as source and the current source as destination.
// Source <- Destination
func (dc *DeepCopier) From(tagged interface{}) error {
	dc.Destination = dc.Source
	dc.Source = tagged
	dc.Tagged = tagged
	dc.Reversed = true

	return dc.ProcessCopy()
}

// ProcessCopy processes copy.
func (dc *DeepCopier) ProcessCopy() error {
	var (
		fields      = []string{}
		taggedValue = reflect.ValueOf(dc.Tagged).Elem()
		taggedType  = taggedValue.Type()
	)

	for i := 0; i < taggedValue.NumField(); i++ {
		var (
			fv = taggedValue.Field(i)
			ft = taggedType.Field(i)
		)

		// Embedded struct
		if ft.Anonymous {
			f, _ := reflections.Fields(fv.Interface())
			fields = append(fields, f...)
		} else {
			fields = append(fields, ft.Name)
		}
	}

	for _, field := range fields {
		if err := dc.SetField(NewFieldOptions(dc.Tagged, field, dc.Reversed)); err != nil {
			return err
		}
	}

	return nil
}

// -----------------------------------------------------------------------------
// Options
// -----------------------------------------------------------------------------

// WithContext injects the given context into the builder instance.
func (dc *DeepCopier) WithContext(context map[string]interface{}) *DeepCopier {
	dc.Context = context
	return dc
}

// -----------------------------------------------------------------------------
// Struct tags
// -----------------------------------------------------------------------------

// GetTagOptions parses deepcopier tag field and returns options.
func GetTagOptions(value string) map[string]string {
	options := map[string]string{}

	for _, opt := range strings.Split(value, ";") {
		o := strings.Split(opt, ":")

		// deepcopier:"keyword; without; value;"
		if len(o) == 1 {
			k := o[0]
			options[k] = ""
		}

		// deepcopier:"key:value; anotherkey:anothervalue"
		if len(o) == 2 {
			k, v := o[0], o[1]
			k = strings.TrimSpace(k)
			v = strings.TrimSpace(v)
			options[k] = v
		}
	}
	return options
}

// -----------------------------------------------------------------------------
// Field Setters
// -----------------------------------------------------------------------------

// SetField sets the value of the given field.
func (dc *DeepCopier) SetField(options *FieldOptions) error {
	if options.Skip {
		return nil
	}

	if dc.Reversed {
		has, _ := reflections.HasField(dc.Destination, options.DestinationField)
		if !has {
			return nil
		}
	}

	has, _ := reflections.HasField(dc.Source, options.SourceField)
	if !has {
		err := dc.HandleMethod(options)
		if err != nil {
			has, _ = reflections.HasField(dc.Destination, options.DestinationField)
			if has {
				return nil
			}
		}
		return nil
	}

	kind, _ := reflections.GetFieldKind(dc.Source, options.SourceField)
	if kind == reflect.Struct {
		if err := dc.HandleStructField(options); err != nil {
			return err
		}
		return nil
	}

	if err := dc.HandleField(options); err != nil {
		return err
	}

	return nil
}

// SetFieldValue Sets the given value to the given field.
func (dc *DeepCopier) SetFieldValue(entity interface{}, name string, value reflect.Value) error {
	kind := value.Kind()

	if kind == reflect.Ptr {
		if value.IsNil() {
			return nil
		}
		value = value.Elem()
		kind = value.Kind()
	}

	// Maps
	if kind == reflect.Map {
		switch v := value.Interface().(type) {
		case map[string]interface{}, map[string]string, map[string]map[string]string, map[string]map[string]map[string]string:
			if err := reflections.SetField(entity, name, v); err != nil {
				return err
			}
			return nil
		}
	}

	// Structs
	if kind == reflect.Struct {
		switch v := value.Interface().(type) {
		case time.Time, pq.NullTime, null.String:
			if err := reflections.SetField(entity, name, v); err != nil {
				return err
			}
			return nil
		}
	}

	// Slices
	if kind == reflect.Slice {
		switch v := value.Interface().(type) {
		case []int8, []int16, []int32, []int64, []int, []uint8, []uint16, []uint32, []uint64, []uint, []float32, []float64, []string, []bool:
			if err := reflections.SetField(entity, name, v); err != nil {
				return err
			}
			return nil
		}
	}

	// Reflect
	switch kind {
	case reflect.Int8:
		if err := reflections.SetField(entity, name, int8(value.Int())); err != nil {
			return err
		}
		return nil
	case reflect.Int16:
		if err := reflections.SetField(entity, name, int16(value.Int())); err != nil {
			return err
		}
		return nil
	case reflect.Int32:
		if err := reflections.SetField(entity, name, int32(value.Int())); err != nil {
			return err
		}
		return nil
	case reflect.Int64:
		if err := reflections.SetField(entity, name, value.Int()); err != nil {
			return err
		}
		return nil
	case reflect.Int:
		if err := reflections.SetField(entity, name, int(value.Int())); err != nil {
			return err
		}
		return nil
	case reflect.Uint8:
		if err := reflections.SetField(entity, name, uint8(value.Uint())); err != nil {
			return err
		}
		return nil
	case reflect.Uint16:
		if err := reflections.SetField(entity, name, uint16(value.Uint())); err != nil {
			return err
		}
		return nil
	case reflect.Uint32:
		if err := reflections.SetField(entity, name, uint32(value.Uint())); err != nil {
			return err
		}
		return nil
	case reflect.Uint64:
		if err := reflections.SetField(entity, name, value.Uint()); err != nil {
			return err
		}
		return nil
	case reflect.Uint:
		if err := reflections.SetField(entity, name, uint(value.Uint())); err != nil {
			return err
		}
		return nil
	case reflect.Float32:
		if err := reflections.SetField(entity, name, float32(value.Float())); err != nil {
			return err
		}
		return nil
	case reflect.Float64:
		if err := reflections.SetField(entity, name, value.Float()); err != nil {
			return err
		}
		return nil
	case reflect.String:
		if err := reflections.SetField(entity, name, value.String()); err != nil {
			return err
		}
		return nil
	case reflect.Bool:
		if err := reflections.SetField(entity, name, value.Bool()); err != nil {
			return err
		}
		return nil
	}

	return nil
}

// -----------------------------------------------------------------------------
// Field Type Handlers
// -----------------------------------------------------------------------------

// HandleStructField sets the value for the given supported struct field.
func (dc *DeepCopier) HandleStructField(options *FieldOptions) error {
	f, err := reflections.GetField(dc.Source, options.SourceField)
	if err != nil {
		return err
	}

	switch v := f.(type) {
	case pq.NullTime:
		if v.Valid {
			if err := reflections.SetField(dc.Destination, options.DestinationField, &v.Time); err != nil {
				return err
			}
		}
	case time.Time:
		if err := reflections.SetField(dc.Destination, options.DestinationField, v); err != nil {
			return err
		}
	}

	return nil
}

// HandleField sets value for the given field.
func (dc *DeepCopier) HandleField(options *FieldOptions) error {
	v, err := reflections.GetField(dc.Source, options.SourceField)
	if err != nil {
		return err
	}

	value := reflect.ValueOf(v)
	if err := dc.SetFieldValue(dc.Destination, options.DestinationField, value); err != nil {
		return err
	}

	return nil
}

// HandleMethod tries to call method on model and sets result in resource field.
func (dc *DeepCopier) HandleMethod(options *FieldOptions) error {
	if dc.Reversed {
		return nil
	}

	method := reflect.ValueOf(dc.Source).MethodByName(options.SourceField)
	if !method.IsValid() {
		return fmt.Errorf("Method %s does not exist", options.SourceField)
	}

	var results []reflect.Value
	if options.WithContext {
		results = method.Call([]reflect.Value{reflect.ValueOf(dc.Context)})
	} else {
		results = method.Call([]reflect.Value{})
	}

	if err := dc.SetFieldValue(dc.Destination, options.DestinationField, results[0]); err != nil {
		return err
	}

	return nil
}

// -----------------------------------------------------------------------------
// Refacto
// -----------------------------------------------------------------------------

// Options are copier options.
type Options struct {
	// Context given to WithContext() method.
	Context map[string]interface{}
}

func getMethods(t reflect.Type) []string {
	var methods []string
	for i := 0; i < t.NumMethod(); i++ {
		methods = append(methods, t.Method(i).Name)
	}
	return methods
}

// InStringSlice checks if the given string is in the given slice of string
func InStringSlice(haystack []string, needle string) bool {
	for _, str := range haystack {
		if needle == str {
			return true
		}
	}
	return false
}

// Copier is the brand new way to process copy.
func Copier(dst interface{}, src interface{}, args ...Options) error {
	var (
		options    = Options{}
		srcValue   = reflect.Indirect(reflect.ValueOf(src))
		srcType    = srcValue.Type()
		srcMethods = getMethods(srcType)
		dstValue   = reflect.Indirect(reflect.ValueOf(dst))
	)

	// Pointer only for receiver
	if !dstValue.CanAddr() {
		return errors.New("dst value is unaddressable")
	}

	if len(args) > 0 {
		options = args[0]
	}

	for i := 0; i < srcValue.NumField(); i++ {
		var (
			srcFieldValue = srcValue.Field(i)
			srcFieldType  = srcValue.Type().Field(i)
			srcFieldName  = srcFieldType.Name
		)

		if !srcFieldValue.IsValid() {
			continue
		}

		for ii := 0; ii < dstValue.NumField(); ii++ {
			var (
				dstFieldValue = dstValue.Field(ii)
				dstFieldType  = dstValue.Type().Field(ii)
				dstFieldName  = dstFieldType.Name
				dstFieldTag   = dstFieldType.Tag.Get(TagName)
				// Options
				fieldName   = dstFieldName
				withContext = false
			)

			tagOptions := GetTagOptions(dstFieldTag)

			// If skip option is set, bypass copy.
			if v, ok := tagOptions[SkipOptionName]; ok && v != "" {
				continue
			}

			// Get real source field / method name src struct tag.
			if v, ok := tagOptions[FieldOptionName]; ok && v != "" {
				fieldName = v
			}

			// Give context as function argument?
			if v, ok := tagOptions[ContextOptionName]; ok && v != "" {
				withContext = true
			}

			// Method() -> field -- TODO: handle WithContext
			if InStringSlice(srcMethods, fieldName) {
				method := reflect.ValueOf(src).MethodByName(fieldName)

				if !method.IsValid() {
					return fmt.Errorf("method %v in source is not valid", fieldName)
				}

				var results []reflect.Value

				if withContext {
					results = method.Call([]reflect.Value{reflect.ValueOf(options.Context)})
				} else {
					results = method.Call([]reflect.Value{})
				}

				dstFieldValue.Set(results[0])

				continue
			}

			if fieldName != srcFieldName {
				continue
			}

			// Ptr -> Value
			if srcFieldType.Type.Kind() == reflect.Ptr && !srcFieldValue.IsNil() && dstFieldType.Type.Kind() != reflect.Ptr {
				dstFieldValue.Set(reflect.Indirect(srcFieldValue))
				continue
			}

			if srcFieldType.Type.AssignableTo(dstFieldType.Type) {
				dstFieldValue.Set(srcFieldValue)
			}
		}
	}

	return nil
}
<commit_msg>Refacto: remove obsolete comment.<commit_after>package deepcopier

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

	"github.com/guregu/null"
	"github.com/lib/pq"
	"github.com/oleiade/reflections"
)

const (
	// TagName is struct field tag name.
	TagName = "deepcopier"

	// FieldOptionName is the from field option name for struct tag.
	FieldOptionName = "field"

	// ContextOptionName is the context option name for struct tag.
	ContextOptionName = "context"

	// SkipOptionName is the skip option name for struct tag.
	SkipOptionName = "skip"
)

// DeepCopier deep copies a struct to/from a struct.
type DeepCopier struct {
	Source      interface{}
	Destination interface{}
	Tagged      interface{}
	Context     map[string]interface{}
	Reversed    bool
}

// FieldOptions contains options passed to SetField method.
type FieldOptions struct {
	SourceField      string
	DestinationField string
	WithContext      bool
	Skip             bool
}

// NewFieldOptions returns a FieldOptions instance for the given instance's field.
func NewFieldOptions(instance interface{}, field string, reversed bool) *FieldOptions {
	fieldOptions := &FieldOptions{
		SourceField:      field,
		DestinationField: field,
		WithContext:      false,
		Skip:             false,
	}

	tagOptions, _ := reflections.GetFieldTag(instance, field, TagName)

	if tagOptions == "" {
		return fieldOptions
	}

	opts := GetTagOptions(tagOptions)

	if _, ok := opts[FieldOptionName]; ok {
		fieldName := opts[FieldOptionName]

		if !reversed {
			fieldOptions.SourceField = fieldName
		} else {
			fieldOptions.DestinationField = fieldName
		}
	}

	if _, ok := opts[ContextOptionName]; ok {
		fieldOptions.WithContext = true
	}

	if _, ok := opts[SkipOptionName]; ok {
		fieldOptions.Skip = true
	}

	return fieldOptions
}

// Copy sets the source.
func Copy(source interface{}) *DeepCopier {
	return &DeepCopier{
		Source:   source,
		Reversed: false,
	}
}

// To sets the given tagged struct as destination struct.
// Source -> Destination
func (dc *DeepCopier) To(tagged interface{}) error {
	dc.Destination = tagged
	dc.Tagged = tagged

	return dc.ProcessCopy()
}

// From sets the given tagged struct as source and the current source as destination.
// Source <- Destination
func (dc *DeepCopier) From(tagged interface{}) error {
	dc.Destination = dc.Source
	dc.Source = tagged
	dc.Tagged = tagged
	dc.Reversed = true

	return dc.ProcessCopy()
}

// ProcessCopy processes copy.
func (dc *DeepCopier) ProcessCopy() error {
	var (
		fields      = []string{}
		taggedValue = reflect.ValueOf(dc.Tagged).Elem()
		taggedType  = taggedValue.Type()
	)

	for i := 0; i < taggedValue.NumField(); i++ {
		var (
			fv = taggedValue.Field(i)
			ft = taggedType.Field(i)
		)

		// Embedded struct
		if ft.Anonymous {
			f, _ := reflections.Fields(fv.Interface())
			fields = append(fields, f...)
		} else {
			fields = append(fields, ft.Name)
		}
	}

	for _, field := range fields {
		if err := dc.SetField(NewFieldOptions(dc.Tagged, field, dc.Reversed)); err != nil {
			return err
		}
	}

	return nil
}

// -----------------------------------------------------------------------------
// Options
// -----------------------------------------------------------------------------

// WithContext injects the given context into the builder instance.
func (dc *DeepCopier) WithContext(context map[string]interface{}) *DeepCopier {
	dc.Context = context
	return dc
}

// -----------------------------------------------------------------------------
// Struct tags
// -----------------------------------------------------------------------------

// GetTagOptions parses deepcopier tag field and returns options.
func GetTagOptions(value string) map[string]string {
	options := map[string]string{}

	for _, opt := range strings.Split(value, ";") {
		o := strings.Split(opt, ":")

		// deepcopier:"keyword; without; value;"
		if len(o) == 1 {
			k := o[0]
			options[k] = ""
		}

		// deepcopier:"key:value; anotherkey:anothervalue"
		if len(o) == 2 {
			k, v := o[0], o[1]
			k = strings.TrimSpace(k)
			v = strings.TrimSpace(v)
			options[k] = v
		}
	}
	return options
}

// -----------------------------------------------------------------------------
// Field Setters
// -----------------------------------------------------------------------------

// SetField sets the value of the given field.
func (dc *DeepCopier) SetField(options *FieldOptions) error {
	if options.Skip {
		return nil
	}

	if dc.Reversed {
		has, _ := reflections.HasField(dc.Destination, options.DestinationField)
		if !has {
			return nil
		}
	}

	has, _ := reflections.HasField(dc.Source, options.SourceField)
	if !has {
		err := dc.HandleMethod(options)
		if err != nil {
			has, _ = reflections.HasField(dc.Destination, options.DestinationField)
			if has {
				return nil
			}
		}
		return nil
	}

	kind, _ := reflections.GetFieldKind(dc.Source, options.SourceField)
	if kind == reflect.Struct {
		if err := dc.HandleStructField(options); err != nil {
			return err
		}
		return nil
	}

	if err := dc.HandleField(options); err != nil {
		return err
	}

	return nil
}

// SetFieldValue Sets the given value to the given field.
func (dc *DeepCopier) SetFieldValue(entity interface{}, name string, value reflect.Value) error {
	kind := value.Kind()

	if kind == reflect.Ptr {
		if value.IsNil() {
			return nil
		}
		value = value.Elem()
		kind = value.Kind()
	}

	// Maps
	if kind == reflect.Map {
		switch v := value.Interface().(type) {
		case map[string]interface{}, map[string]string, map[string]map[string]string, map[string]map[string]map[string]string:
			if err := reflections.SetField(entity, name, v); err != nil {
				return err
			}
			return nil
		}
	}

	// Structs
	if kind == reflect.Struct {
		switch v := value.Interface().(type) {
		case time.Time, pq.NullTime, null.String:
			if err := reflections.SetField(entity, name, v); err != nil {
				return err
			}
			return nil
		}
	}

	// Slices
	if kind == reflect.Slice {
		switch v := value.Interface().(type) {
		case []int8, []int16, []int32, []int64, []int, []uint8, []uint16, []uint32, []uint64, []uint, []float32, []float64, []string, []bool:
			if err := reflections.SetField(entity, name, v); err != nil {
				return err
			}
			return nil
		}
	}

	// Reflect
	switch kind {
	case reflect.Int8:
		if err := reflections.SetField(entity, name, int8(value.Int())); err != nil {
			return err
		}
		return nil
	case reflect.Int16:
		if err := reflections.SetField(entity, name, int16(value.Int())); err != nil {
			return err
		}
		return nil
	case reflect.Int32:
		if err := reflections.SetField(entity, name, int32(value.Int())); err != nil {
			return err
		}
		return nil
	case reflect.Int64:
		if err := reflections.SetField(entity, name, value.Int()); err != nil {
			return err
		}
		return nil
	case reflect.Int:
		if err := reflections.SetField(entity, name, int(value.Int())); err != nil {
			return err
		}
		return nil
	case reflect.Uint8:
		if err := reflections.SetField(entity, name, uint8(value.Uint())); err != nil {
			return err
		}
		return nil
	case reflect.Uint16:
		if err := reflections.SetField(entity, name, uint16(value.Uint())); err != nil {
			return err
		}
		return nil
	case reflect.Uint32:
		if err := reflections.SetField(entity, name, uint32(value.Uint())); err != nil {
			return err
		}
		return nil
	case reflect.Uint64:
		if err := reflections.SetField(entity, name, value.Uint()); err != nil {
			return err
		}
		return nil
	case reflect.Uint:
		if err := reflections.SetField(entity, name, uint(value.Uint())); err != nil {
			return err
		}
		return nil
	case reflect.Float32:
		if err := reflections.SetField(entity, name, float32(value.Float())); err != nil {
			return err
		}
		return nil
	case reflect.Float64:
		if err := reflections.SetField(entity, name, value.Float()); err != nil {
			return err
		}
		return nil
	case reflect.String:
		if err := reflections.SetField(entity, name, value.String()); err != nil {
			return err
		}
		return nil
	case reflect.Bool:
		if err := reflections.SetField(entity, name, value.Bool()); err != nil {
			return err
		}
		return nil
	}

	return nil
}

// -----------------------------------------------------------------------------
// Field Type Handlers
// -----------------------------------------------------------------------------

// HandleStructField sets the value for the given supported struct field.
func (dc *DeepCopier) HandleStructField(options *FieldOptions) error {
	f, err := reflections.GetField(dc.Source, options.SourceField)
	if err != nil {
		return err
	}

	switch v := f.(type) {
	case pq.NullTime:
		if v.Valid {
			if err := reflections.SetField(dc.Destination, options.DestinationField, &v.Time); err != nil {
				return err
			}
		}
	case time.Time:
		if err := reflections.SetField(dc.Destination, options.DestinationField, v); err != nil {
			return err
		}
	}

	return nil
}

// HandleField sets value for the given field.
func (dc *DeepCopier) HandleField(options *FieldOptions) error {
	v, err := reflections.GetField(dc.Source, options.SourceField)
	if err != nil {
		return err
	}

	value := reflect.ValueOf(v)
	if err := dc.SetFieldValue(dc.Destination, options.DestinationField, value); err != nil {
		return err
	}

	return nil
}

// HandleMethod tries to call method on model and sets result in resource field.
func (dc *DeepCopier) HandleMethod(options *FieldOptions) error {
	if dc.Reversed {
		return nil
	}

	method := reflect.ValueOf(dc.Source).MethodByName(options.SourceField)
	if !method.IsValid() {
		return fmt.Errorf("Method %s does not exist", options.SourceField)
	}

	var results []reflect.Value
	if options.WithContext {
		results = method.Call([]reflect.Value{reflect.ValueOf(dc.Context)})
	} else {
		results = method.Call([]reflect.Value{})
	}

	if err := dc.SetFieldValue(dc.Destination, options.DestinationField, results[0]); err != nil {
		return err
	}

	return nil
}

// -----------------------------------------------------------------------------
// Refacto
// -----------------------------------------------------------------------------

// Options are copier options.
type Options struct {
	// Context given to WithContext() method.
	Context map[string]interface{}
}

func getMethods(t reflect.Type) []string {
	var methods []string
	for i := 0; i < t.NumMethod(); i++ {
		methods = append(methods, t.Method(i).Name)
	}
	return methods
}

// InStringSlice checks if the given string is in the given slice of string
func InStringSlice(haystack []string, needle string) bool {
	for _, str := range haystack {
		if needle == str {
			return true
		}
	}
	return false
}

// Copier is the brand new way to process copy.
func Copier(dst interface{}, src interface{}, args ...Options) error {
	var (
		options    = Options{}
		srcValue   = reflect.Indirect(reflect.ValueOf(src))
		srcType    = srcValue.Type()
		srcMethods = getMethods(srcType)
		dstValue   = reflect.Indirect(reflect.ValueOf(dst))
	)

	// Pointer only for receiver
	if !dstValue.CanAddr() {
		return errors.New("dst value is unaddressable")
	}

	if len(args) > 0 {
		options = args[0]
	}

	for i := 0; i < srcValue.NumField(); i++ {
		var (
			srcFieldValue = srcValue.Field(i)
			srcFieldType  = srcValue.Type().Field(i)
			srcFieldName  = srcFieldType.Name
		)

		if !srcFieldValue.IsValid() {
			continue
		}

		for ii := 0; ii < dstValue.NumField(); ii++ {
			var (
				dstFieldValue = dstValue.Field(ii)
				dstFieldType  = dstValue.Type().Field(ii)
				dstFieldName  = dstFieldType.Name
				dstFieldTag   = dstFieldType.Tag.Get(TagName)
				// Options
				fieldName   = dstFieldName
				withContext = false
			)

			tagOptions := GetTagOptions(dstFieldTag)

			// If skip option is set, bypass copy.
			if v, ok := tagOptions[SkipOptionName]; ok && v != "" {
				continue
			}

			// Get real source field / method name src struct tag.
			if v, ok := tagOptions[FieldOptionName]; ok && v != "" {
				fieldName = v
			}

			// Give context as function argument?
			if v, ok := tagOptions[ContextOptionName]; ok && v != "" {
				withContext = true
			}

			if InStringSlice(srcMethods, fieldName) {
				method := reflect.ValueOf(src).MethodByName(fieldName)

				if !method.IsValid() {
					return fmt.Errorf("method %v in source is not valid", fieldName)
				}

				var results []reflect.Value

				if withContext {
					results = method.Call([]reflect.Value{reflect.ValueOf(options.Context)})
				} else {
					results = method.Call([]reflect.Value{})
				}

				dstFieldValue.Set(results[0])

				continue
			}

			if fieldName != srcFieldName {
				continue
			}

			// Ptr -> Value
			if srcFieldType.Type.Kind() == reflect.Ptr && !srcFieldValue.IsNil() && dstFieldType.Type.Kind() != reflect.Ptr {
				dstFieldValue.Set(reflect.Indirect(srcFieldValue))
				continue
			}

			if srcFieldType.Type.AssignableTo(dstFieldType.Type) {
				dstFieldValue.Set(srcFieldValue)
			}
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"runtime"
	"src/todo"
	"strings"
	"time"
)

/*
REVISION HISTORY
-------- -------
11 Jan 22 -- Started copying out of "Powerful Command-Line Applications in Go" by Ricardo Gerardi
15 Jan 22 -- Modifying the output for the -h flag using the book code.  I don't need -v flag anymore.
             Then added the String method, but that had to be a value receiver to work as like in the book.
             Then added use of TODO_FILENAME environment variable.
16 Jan 22 -- Added stdin as a source.  And changed name of string task flag to a boolean add flag.
17 Jan 22 -- Added default actions if no switch is provided.  If there are arguments then add as a task, if not list tasks.
 8 Feb 22 -- Will show a timestamp of adding a task, and will use a network file if available.
*/

const lastModified = "9 Feb 2022"
const linuxNetworkPrefix = "/mnt/docs/"
const windowsNetworkPrefix = "z:/"

var todoFilename = "todo.json" // now a var instead of a const so can use environment variable if set.
var todoFileBin = "todo.gob"   // now a var instead of a const so can use environment variable if set.
var fileExists bool

var verboseFlag = flag.Bool("v", false, "Set verbose mode.")

//                                                                                var task = flag.String("task", "", "Task to be added to the ToDo list.")
var add = flag.Bool("add", false, "Add task to the ToDo list.")
var complete = flag.Int("complete", 0, "Item to be completed.") // here, 0 means NTD.  That's why we have to start at 1 for item numbers.
var listFlag = flag.Bool("list", false, "List all tasks to the display.")

func main() {
	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), " %s last modified %s. \n", os.Args[0], lastModified)
		fmt.Fprintf(flag.CommandLine.Output(), " Usage information:\n")
		flag.PrintDefaults()
	}
	flag.Parse()
	if *verboseFlag {
		fmt.Printf(" todo last modified %s.  It will display and manage a todo list.\n", lastModified)
		fmt.Printf(" Default file root is todo for todo.json and todo.gob.  TODO_FILENAME environment variable is read.\n")

	}

	homeDir, err := os.UserHomeDir()
	if err != nil {
		fmt.Fprintf(os.Stderr, " Error from os.UserHomeDir is %v.\n", err)
	}

	if runtime.GOOS == "linux" {

	} else { // must be on Windows.

	}

	envValue, ok := os.LookupEnv("TODO_FILENAME")
	if ok {
		todoFilename = envValue + ".json"
		//todoFileBin = filepath.Base(envValue) + ".gob"
		todoFileBin = envValue + ".gob"
	}
	if *verboseFlag {
		fmt.Printf(" todoFilename = %s, todoFileBin = %s\n", todoFilename, todoFileBin)
	}

	var fullFilenameJson, fullFilenameBin string
	if ok {
		fullFilenameJson, fullFilenameBin = todoFilename, todoFileBin
	} else {
		fullFilenameJson = filepath.Join(homeDir, todoFilename)
		fullFilenameBin = filepath.Join(homeDir, todoFileBin)
	}
	if *verboseFlag {
		fmt.Printf(" fullFilenameJson = %s, fullFilenameBin = %s\n", fullFilenameJson, fullFilenameBin)
	}

	_, err = os.Stat(fullFilenameJson)
	if err != nil {
		//fmt.Fprintf(os.Stderr, " %s got error from os.Stat of %v.\n", fullFilenameJson, err)
		fileExists = false
	} else {
		fileExists = true
	}
	_, err = os.Stat(fullFilenameBin)
	if err != nil {
		//fmt.Fprintf(os.Stderr, " %s got error from os.Stat of %v.\n", fullFilenameBin, err)
	}

	l := todo.ListType{}
	err = l.LoadJSON(fullFilenameJson) // if file doesn't exist, this doesn't return an error.
	if err != nil {
		fmt.Fprintf(os.Stderr, " Error returned while reading %s is %v\n", fullFilenameJson, err)
		er := l.LoadBinary(fullFilenameBin)
		if er != nil {
			fmt.Fprintf(os.Stderr, " Error returned while reading %s is %v\n", fullFilenameBin, er)
			fmt.Print(" Should I exit? ")
			var ans string
			fmt.Scanln(&ans)
			if strings.HasPrefix(strings.ToLower(ans), "y") {
				os.Exit(1)
			}
			fmt.Println()
			fileExists = false
		}
	}

	if *verboseFlag {
		for i, t := range l {
			fmt.Printf(" %d: %s, %t, %s, %s\n", i+1, t.Task, t.Done, t.CreatedAt.Format(time.RFC822), t.CompletedAt.Format(time.RFC822))
		}
		fmt.Println()
	}
	switch {
	case *listFlag:
		/* Replaced by the stringer interface
		for _, item := range l {
			if !item.Done {
				fmt.Printf(" Not done: %s\n", item.Task)
			}
		}
		fmt.Println()
		for _, item := range l {
			if item.Done {
				fmt.Printf(" Done: %s was completed on %s\n", item.Task, item.CompletedAt.Format("Jan-02-2006 15:04:05"))
			}
		}
		*/

		// This should invoke the stringer interface from the fmt package.  IE, call the String method I defined in todo.  But it's not working.
		// I kept playing w/ it and I read the docs at golang.org.  I concluded that the stringer interface required a value receiver.  I had
		// followed the book that defined it as a pointer receiver.  So I defined it in todo.go as a value receiver, and it started to work.
		if fileExists {
			fmt.Println(l)
		} else {
			fmt.Fprintf(os.Stderr, " Cannot list todo files (%s or %s) as they cannot be found.\n", fullFilenameJson, fullFilenameBin)
		}

		//fmt.Printf("%s", l)   // this does not work.
		//fmt.Print(l.String()) // this works.  But I figured out why it didn't work at first like the book said it should.  See the above comment.
	case *complete > 0:
		if !fileExists {
			fmt.Fprintf(os.Stderr, " Cannot complete todo entries because files (%s or %s) cannot be found.\n", fullFilenameJson, fullFilenameBin)
			os.Exit(1)
		}
		err = l.Complete(*complete)
		if err != nil {
			fmt.Fprintf(os.Stderr, " Item number %d cannot be completed because %v\n", *complete, err)
		}

		err = l.SaveJSON(fullFilenameJson)
		if err != nil {
			fmt.Fprintf(os.Stderr, " List could not be saved in json because %v\n", err)
		}
		err = l.SaveBinary(fullFilenameBin)
		if err != nil {
			fmt.Fprintf(os.Stderr, " List could not be saved in binary format because %v\n", err)
		}
	case *add:
		task, err := getTask(os.Stdin, flag.Args()...)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		l.Add(task)
		err = l.SaveJSON(fullFilenameJson)
		if err != nil {
			fmt.Fprintf(os.Stderr, " List could not be saved in JSON because %v \n", err)
		}
		err = l.SaveBinary(fullFilenameBin)
		if err != nil {
			fmt.Fprintf(os.Stderr, " List could not be saved in binary format because %v \n", err)
		}
	default: // task add
		if flag.NArg() > 0 {
			tsk := strings.Join(flag.Args(), " ")
			l.Add(tsk)
			err = l.SaveJSON(fullFilenameJson)
			if err != nil {
				fmt.Fprintf(os.Stderr, " List could not be saved in JSON because %v \n", err)
			}
			err = l.SaveBinary(fullFilenameBin)
			if err != nil {
				fmt.Fprintf(os.Stderr, " List could not be saved in binary format because %v \n", err)
			}
		} else {
			if fileExists {
				fmt.Println(l)
			} else {
				fmt.Fprintf(os.Stderr, " Cannot list todo files (%s or %s) as they cannot be found.\n", fullFilenameJson, fullFilenameBin)
			}
		}
	}
}

func getTask(r io.Reader, args ...string) (string, error) { // decides where to get task string, from args or stdin.
	if len(args) > 0 {
		return strings.Join(args, " "), nil
	}

	scnr := bufio.NewScanner(r)
	scnr.Scan()
	if err := scnr.Err(); err != nil {
		return "", err
	}

	if len(scnr.Text()) == 0 {
		return "", fmt.Errorf("Task to add cannot be blank.")
	}

	return scnr.Text(), nil
}
<commit_msg>02/09/2022 07:31:05 AM todo/cmd/todo/main.go<commit_after>package main

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

/*
REVISION HISTORY
-------- -------
11 Jan 22 -- Started copying out of "Powerful Command-Line Applications in Go" by Ricardo Gerardi
15 Jan 22 -- Modifying the output for the -h flag using the book code.  I don't need -v flag anymore.
             Then added the String method, but that had to be a value receiver to work as like in the book.
             Then added use of TODO_FILENAME environment variable.
16 Jan 22 -- Added stdin as a source.  And changed name of string task flag to a boolean add flag.
17 Jan 22 -- Added default actions if no switch is provided.  If there are arguments then add as a task, if not list tasks.
 8 Feb 22 -- Will show a timestamp of adding a task, done by updating the stringer method in todo.go.  I changed how the
               filename is constructed.  I am considering adding another environment variable, called TODO_PREFIX to more easily cover the networking prefix.
*/

const lastModified = "9 Feb 2022"

var todoFilename = "todo.json" // now a var instead of a const so can use environment variable if set.
var todoFileBin = "todo.gob"   // now a var instead of a const so can use environment variable if set.
var prefix string
var fileExists bool

var verboseFlag = flag.Bool("v", false, "Set verbose mode.")

//                                                                                var task = flag.String("task", "", "Task to be added to the ToDo list.")
var add = flag.Bool("add", false, "Add task to the ToDo list.")
var complete = flag.Int("complete", 0, "Item to be completed.") // here, 0 means NTD.  That's why we have to start at 1 for item numbers.
var listFlag = flag.Bool("list", false, "List all tasks to the display.")

func main() {
	flag.Usage = func() {
		fmt.Fprintf(flag.CommandLine.Output(), " %s last modified %s. \n", os.Args[0], lastModified)
		fmt.Fprintf(flag.CommandLine.Output(), "TODO_PREFIX and TODO_FILENAME are the environment variables used.  Do not use an extension for TODO_FILENAME")
		fmt.Fprintf(flag.CommandLine.Output(), " Usage information:\n")
		flag.PrintDefaults()
	}
	flag.Parse()
	if *verboseFlag {
		fmt.Printf(" todo last modified %s.  It will display and manage a todo list.\n", lastModified)
		fmt.Printf(" Default filename root is todo for todo.json and todo.gob.  TODO_FILENAME environment variable is read, and should not have an extension.\n")
	}

	homeDir, err := os.UserHomeDir()
	if err != nil {
		fmt.Fprintf(os.Stderr, " Error from os.UserHomeDir is %v.\n", err)
	}

	var fullFilenameJson, fullFilenameBin string
	envFN, ok := os.LookupEnv("TODO_FILENAME")
	if ok {
		todoFilename = envFN + ".json"
		todoFileBin = filepath.Base(envFN) + ".gob"
	}
	if *verboseFlag {
		fmt.Printf(" todoFilename = %s, todoFileBin = %s\n", todoFilename, todoFileBin)
	}

	prefix, ok = os.LookupEnv("TODO_PREFIX")
	if ok {
		fullFilenameJson = filepath.Join(prefix, todoFilename)
		fullFilenameBin = filepath.Join(prefix, todoFileBin)
	} else {
		fullFilenameJson = filepath.Join(homeDir, todoFilename)
		fullFilenameBin = filepath.Join(homeDir, todoFileBin)
	}

	if *verboseFlag {
		fmt.Printf(" fullFilenameJson = %s, fullFilenameBin = %s\n", fullFilenameJson, fullFilenameBin)
	}

	_, err = os.Stat(fullFilenameJson)
	if err != nil {
		//fmt.Fprintf(os.Stderr, " %s got error from os.Stat of %v.\n", fullFilenameJson, err)
		fileExists = false
	} else {
		fileExists = true
	}
	_, err = os.Stat(fullFilenameBin)
	if err != nil {
		//fmt.Fprintf(os.Stderr, " %s got error from os.Stat of %v.\n", fullFilenameBin, err)
	}

	l := todo.ListType{}
	err = l.LoadJSON(fullFilenameJson) // if file doesn't exist, this doesn't return an error.
	if err != nil {
		fmt.Fprintf(os.Stderr, " Error returned while reading %s is %v\n", fullFilenameJson, err)
		er := l.LoadBinary(fullFilenameBin)
		if er != nil {
			fmt.Fprintf(os.Stderr, " Error returned while reading %s is %v\n", fullFilenameBin, er)
			fmt.Print(" Should I exit? ")
			var ans string
			fmt.Scanln(&ans)
			if strings.HasPrefix(strings.ToLower(ans), "y") {
				os.Exit(1)
			}
			fmt.Println()
			fileExists = false
		}
	}

	if *verboseFlag {
		for i, t := range l {
			fmt.Printf(" %d: %s, %t, %s, %s\n", i+1, t.Task, t.Done, t.CreatedAt.Format(time.RFC822), t.CompletedAt.Format(time.RFC822))
		}
		fmt.Println()
	}
	switch {
	case *listFlag:
		/* Replaced by the stringer interface
		for _, item := range l {
			if !item.Done {
				fmt.Printf(" Not done: %s\n", item.Task)
			}
		}
		fmt.Println()
		for _, item := range l {
			if item.Done {
				fmt.Printf(" Done: %s was completed on %s\n", item.Task, item.CompletedAt.Format("Jan-02-2006 15:04:05"))
			}
		}
		*/

		// This should invoke the stringer interface from the fmt package.  IE, call the String method I defined in todo.  But it's not working.
		// I kept playing w/ it and I read the docs at golang.org.  I concluded that the stringer interface required a value receiver.  I had
		// followed the book that defined it as a pointer receiver.  So I defined it in todo.go as a value receiver, and it started to work.
		if fileExists {
			fmt.Println(l)
		} else {
			fmt.Fprintf(os.Stderr, " Cannot list todo files (%s or %s) as they cannot be found.\n", fullFilenameJson, fullFilenameBin)
		}

		//fmt.Printf("%s", l)   // this does not work.
		//fmt.Print(l.String()) // this works.  But I figured out why it didn't work at first like the book said it should.  See the above comment.
	case *complete > 0:
		if !fileExists {
			fmt.Fprintf(os.Stderr, " Cannot complete todo entries because files (%s or %s) cannot be found.\n", fullFilenameJson, fullFilenameBin)
			os.Exit(1)
		}
		err = l.Complete(*complete)
		if err != nil {
			fmt.Fprintf(os.Stderr, " Item number %d cannot be completed because %v\n", *complete, err)
		}

		err = l.SaveJSON(fullFilenameJson)
		if err != nil {
			fmt.Fprintf(os.Stderr, " List could not be saved in json because %v\n", err)
		}
		err = l.SaveBinary(fullFilenameBin)
		if err != nil {
			fmt.Fprintf(os.Stderr, " List could not be saved in binary format because %v\n", err)
		}
	case *add:
		task, err := getTask(os.Stdin, flag.Args()...)
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
		l.Add(task)
		err = l.SaveJSON(fullFilenameJson)
		if err != nil {
			fmt.Fprintf(os.Stderr, " List could not be saved in JSON because %v \n", err)
		}
		err = l.SaveBinary(fullFilenameBin)
		if err != nil {
			fmt.Fprintf(os.Stderr, " List could not be saved in binary format because %v \n", err)
		}
	default: // task add
		if flag.NArg() > 0 {
			tsk := strings.Join(flag.Args(), " ")
			l.Add(tsk)
			err = l.SaveJSON(fullFilenameJson)
			if err != nil {
				fmt.Fprintf(os.Stderr, " List could not be saved in JSON because %v \n", err)
			}
			err = l.SaveBinary(fullFilenameBin)
			if err != nil {
				fmt.Fprintf(os.Stderr, " List could not be saved in binary format because %v \n", err)
			}
		} else {
			if fileExists {
				fmt.Println(l)
			} else {
				fmt.Fprintf(os.Stderr, " Cannot list todo files (%s or %s) as they cannot be found.\n", fullFilenameJson, fullFilenameBin)
			}
		}
	}
}

func getTask(r io.Reader, args ...string) (string, error) { // decides where to get task string, from args or stdin.
	if len(args) > 0 {
		return strings.Join(args, " "), nil
	}

	scnr := bufio.NewScanner(r)
	scnr.Scan()
	if err := scnr.Err(); err != nil {
		return "", err
	}

	if len(scnr.Text()) == 0 {
		return "", fmt.Errorf("Task to add cannot be blank.")
	}

	return scnr.Text(), nil
}
<|endoftext|>


<commit_before>package api

import (
	"cf"
	"cf/configuration"
	"cf/net"
	"fmt"
	"strings"
)

type ApplicationSummaries struct {
	Apps []ApplicationFromSummary
}

func (resource ApplicationSummaries) ToModels() (apps []cf.ApplicationFields) {
	for _, appSummary := range resource.Apps {
		apps = append(apps, appSummary.ToFields())
	}
	return
}

type ApplicationFromSummary struct {
	Guid             string
	Name             string
	Routes           []RouteSummary
	RunningInstances int `json:"running_instances"`
	Memory           uint64
	Instances        int
	DiskQuota        uint64 `json:"disk_quota"`
	Urls             []string
	State            string
}

func (resource ApplicationFromSummary) ToFields() (app cf.ApplicationFields) {
	app = cf.ApplicationFields{}
	app.Guid = resource.Guid
	app.Name = resource.Name
	app.State = strings.ToLower(resource.State)
	app.InstanceCount = resource.Instances
	app.DiskQuota = resource.DiskQuota
	app.RunningInstances = resource.RunningInstances
	app.Memory = resource.Memory

	return
}

func (resource ApplicationFromSummary) ToModel() (app cf.AppSummary) {
	app.ApplicationFields = resource.ToFields()
	routes := []cf.RouteSummary{}
	for _, route := range resource.Routes {
		routes = append(routes, route.ToModel())
	}
	app.RouteSummaries = routes

	return
}

type RouteSummary struct {
	Guid   string
	Host   string
	Domain DomainSummary
}

func (resource RouteSummary) ToModel() (route cf.RouteSummary) {
	domain := cf.DomainFields{}
	domain.Guid = resource.Domain.Guid
	domain.Name = resource.Domain.Name
	domain.Shared = resource.Domain.OwningOrganizationGuid != ""

	route.Guid = resource.Guid
	route.Host = resource.Host
	route.Domain = domain
	return
}

type DomainSummary struct {
	Guid                   string
	Name                   string
	OwningOrganizationGuid string
}

type AppSummaryRepository interface {
	GetSummariesInCurrentSpace() (apps []cf.AppSummary, apiResponse net.ApiResponse)
	GetSummary(appGuid string) (summary cf.AppSummary, apiResponse net.ApiResponse)
}

type CloudControllerAppSummaryRepository struct {
	config  *configuration.Configuration
	gateway net.Gateway
}

func NewCloudControllerAppSummaryRepository(config *configuration.Configuration, gateway net.Gateway) (repo CloudControllerAppSummaryRepository) {
	repo.config = config
	repo.gateway = gateway
	return
}

func (repo CloudControllerAppSummaryRepository) GetSummariesInCurrentSpace() (apps []cf.AppSummary, apiResponse net.ApiResponse) {
	resources := new(ApplicationSummaries)

	path := fmt.Sprintf("%s/v2/spaces/%s/summary", repo.config.Target, repo.config.SpaceFields.Guid)
	apiResponse = repo.gateway.GetResource(path, repo.config.AccessToken, resources)
	if apiResponse.IsNotSuccessful() {
		return
	}

	for _, resource := range resources.Apps {
		var app cf.AppSummary
		app, apiResponse = repo.createSummary(&resource)
		if apiResponse.IsNotSuccessful() {
			return
		}
		apps = append(apps, app)
	}
	return
}

func (repo CloudControllerAppSummaryRepository) GetSummary(appGuid string) (summary cf.AppSummary, apiResponse net.ApiResponse) {
	path := fmt.Sprintf("%s/v2/apps/%s/summary", repo.config.Target, appGuid)
	summaryResponse := new(ApplicationFromSummary)
	apiResponse = repo.gateway.GetResource(path, repo.config.AccessToken, summaryResponse)
	if apiResponse.IsNotSuccessful() {
		return
	}

	return repo.createSummary(summaryResponse)
}

func (repo CloudControllerAppSummaryRepository) createSummary(resource *ApplicationFromSummary) (summary cf.AppSummary, apiResponse net.ApiResponse) {
	summary = resource.ToModel()
	return
}
<commit_msg>cleaning up app summary, removing unused apiResponse [finishes #61009376]<commit_after>package api

import (
	"cf"
	"cf/configuration"
	"cf/net"
	"fmt"
	"strings"
)

type ApplicationSummaries struct {
	Apps []ApplicationFromSummary
}

func (resource ApplicationSummaries) ToModels() (apps []cf.ApplicationFields) {
	for _, appSummary := range resource.Apps {
		apps = append(apps, appSummary.ToFields())
	}
	return
}

type ApplicationFromSummary struct {
	Guid             string
	Name             string
	Routes           []RouteSummary
	RunningInstances int `json:"running_instances"`
	Memory           uint64
	Instances        int
	DiskQuota        uint64 `json:"disk_quota"`
	Urls             []string
	State            string
}

func (resource ApplicationFromSummary) ToFields() (app cf.ApplicationFields) {
	app = cf.ApplicationFields{}
	app.Guid = resource.Guid
	app.Name = resource.Name
	app.State = strings.ToLower(resource.State)
	app.InstanceCount = resource.Instances
	app.DiskQuota = resource.DiskQuota
	app.RunningInstances = resource.RunningInstances
	app.Memory = resource.Memory

	return
}

func (resource ApplicationFromSummary) ToModel() (app cf.AppSummary) {
	app.ApplicationFields = resource.ToFields()
	routes := []cf.RouteSummary{}
	for _, route := range resource.Routes {
		routes = append(routes, route.ToModel())
	}
	app.RouteSummaries = routes

	return
}

type RouteSummary struct {
	Guid   string
	Host   string
	Domain DomainSummary
}

func (resource RouteSummary) ToModel() (route cf.RouteSummary) {
	domain := cf.DomainFields{}
	domain.Guid = resource.Domain.Guid
	domain.Name = resource.Domain.Name
	domain.Shared = resource.Domain.OwningOrganizationGuid != ""

	route.Guid = resource.Guid
	route.Host = resource.Host
	route.Domain = domain
	return
}

type DomainSummary struct {
	Guid                   string
	Name                   string
	OwningOrganizationGuid string
}

type AppSummaryRepository interface {
	GetSummariesInCurrentSpace() (apps []cf.AppSummary, apiResponse net.ApiResponse)
	GetSummary(appGuid string) (summary cf.AppSummary, apiResponse net.ApiResponse)
}

type CloudControllerAppSummaryRepository struct {
	config  *configuration.Configuration
	gateway net.Gateway
}

func NewCloudControllerAppSummaryRepository(config *configuration.Configuration, gateway net.Gateway) (repo CloudControllerAppSummaryRepository) {
	repo.config = config
	repo.gateway = gateway
	return
}

func (repo CloudControllerAppSummaryRepository) GetSummariesInCurrentSpace() (apps []cf.AppSummary, apiResponse net.ApiResponse) {
	resources := new(ApplicationSummaries)

	path := fmt.Sprintf("%s/v2/spaces/%s/summary", repo.config.Target, repo.config.SpaceFields.Guid)
	apiResponse = repo.gateway.GetResource(path, repo.config.AccessToken, resources)
	if apiResponse.IsNotSuccessful() {
		return
	}

	for _, resource := range resources.Apps {
		apps = append(apps, resource.ToModel())
	}
	return
}

func (repo CloudControllerAppSummaryRepository) GetSummary(appGuid string) (summary cf.AppSummary, apiResponse net.ApiResponse) {
	path := fmt.Sprintf("%s/v2/apps/%s/summary", repo.config.Target, appGuid)
	summaryResponse := new(ApplicationFromSummary)
	apiResponse = repo.gateway.GetResource(path, repo.config.AccessToken, summaryResponse)
	if apiResponse.IsNotSuccessful() {
		return
	}

	summary = summaryResponse.ToModel()
	return
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import (
	`regexp`
)

func (p *Position) NewMove(from, to int) Move {
	piece, capture := p.pieces[from], p.pieces[to]

	if p.enpassant != 0 && to == p.enpassant {
		capture = pawn(piece.color() ^ 1)
	}

	return Move(from | (to << 8) | (int(piece) << 16) | (int(capture) << 20))
}

func (p *Position) NewCastle(from, to int) Move {
	return Move(from | (to << 8) | (int(p.pieces[from]) << 16) | isCastle)
}

func (p *Position) NewEnpassant(from, to int) Move {
	return Move(from | (to << 8) | (int(p.pieces[from]) << 16) | isEnpassant)
}

// Returns true if *non-evasion* move is valid, i.e. it is possible to make
// the move in current position without violating chess rules. If the king is
// in check the generator is expected to generate valid evasions where extra
// validation is not needed.
func (p *Position) isValid(move Move, pins Bitmask) bool {
	color := move.color() // TODO: make color part of move split.
	from, to, piece, capture := move.split()

	// For rare en-passant pawn captures we validate the move by actually
	// making it, and then taking it back.
	if p.enpassant != 0 && to == p.enpassant && capture.isPawn() {
		if position := p.MakeMove(move); position != nil {
			position.UndoLastMove()
			return true
		}
		return false
	}

	// King's move is valid when a) the move is a castle or b) the destination
	// square is not being attacked by the opponent.
	if piece.isKing() {
		return (move & isCastle != 0) || !p.isAttacked(to, color^1)
	}

	// For all other peices the move is valid when it doesn't cause a
	// check. For pinned sliders this includes moves along the pinning
	// file, rank, or diagonal.
	return pins == 0 || pins.isClear(from) || IsBetween(from, to, p.king[color])
}

// Returns a bitmask of all pinned pieces preventing a check for the king on
// given square. The color of the pieces match the color of the king.
func (p *Position) pinnedMask(square int) (mask Bitmask) {
	color := p.pieces[square].color()
	enemy := color ^ 1
	attackers := (p.outposts[bishop(enemy)] | p.outposts[queen(enemy)]) & bishopMagicMoves[square][0]
	attackers |= (p.outposts[rook(enemy)] | p.outposts[queen(enemy)]) & rookMagicMoves[square][0]

	for attackers != 0 {
		attackSquare := attackers.pop()
		blockers := maskBlock[square][attackSquare] & ^bit[attackSquare] & p.board

		if blockers.count() == 1 {
			mask |= blockers & p.outposts[color] // Only friendly pieces are pinned.
		}
	}
	return
}

func (p *Position) pawnMove(square, target int) Move {
	if RelRow(square, p.color) == 1 && RelRow(target, p.color) == 3 {
		if p.causesEnpassant(target) {
			return p.NewEnpassant(square, target)
		} else {
			return p.NewMove(square, target)
		}
	}

	return p.NewMove(square, target)
}

func (p *Position) pawnPromotion(square, target int) (Move, Move, Move, Move) {
	return p.NewMove(square, target).promote(Queen),
		p.NewMove(square, target).promote(Rook),
		p.NewMove(square, target).promote(Bishop),
		p.NewMove(square, target).promote(Knight)
}

func (p *Position) causesEnpassant(target int) bool {
	pawns := p.outposts[pawn(p.color^1)] // Opposite color pawns.
	switch col := Col(target); col {
	case 0:
		return pawns.isSet(target + 1)
	case 7:
		return pawns.isSet(target - 1)
	default:
		return pawns.isSet(target+1) || pawns.isSet(target-1)
	}
	return false
}

func (p *Position) NewMoveFromString(e2e4 string) (move Move) {
	re := regexp.MustCompile(`([KkQqRrBbNn]?)([a-h])([1-8])-?([a-h])([1-8])([QqRrBbNn]?)`)
	arr := re.FindStringSubmatch(e2e4)

	if len(arr) > 0 {
		name := arr[1]
		from := Square(int(arr[3][0]-'1'), int(arr[2][0]-'a'))
		to := Square(int(arr[5][0]-'1'), int(arr[4][0]-'a'))
		promo := arr[6]

		var piece Piece
		switch name {
		case `K`, `k`:
			piece = king(p.color)
		case `Q`, `q`:
			piece = queen(p.color)
		case `R`, `r`:
			piece = rook(p.color)
		case `B`, `b`:
			piece = bishop(p.color)
		case `N`, `n`:
			piece = knight(p.color)
		default:
			piece = p.pieces[from] // <-- Makes piece character optional.
		}
		if (p.pieces[from] != piece) || (p.targets(from)&bit[to] == 0) {
			move = 0 // Invalid move.
		} else {
			move = p.NewMove(from, to)
			if len(promo) > 0 {
				switch promo {
				case `Q`, `q`:
					move = move.promote(Queen)
				case `R`, `r`:
					move = move.promote(Rook)
				case `B`, `b`:
					move = move.promote(Bishop)
				case `N`, `n`:
					move = move.promote(Knight)
				default:
					move = 0
				}
			}
		}
	} else if e2e4 == `0-0` || e2e4 == `0-0-0` {
		from := p.king[p.color]
		to := G1
		if e2e4 == `0-0-0` {
			to = C1
		}
		if p.color == Black {
			to += 56
		}
		move = p.NewCastle(from, to)
		if !move.isCastle() {
			move = 0
		}
	}
	return
}
<commit_msg>Faster pawn move and en-passant detection<commit_after>// Copyright (c) 2013-2014 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package donna

import (
	`regexp`
)

func (p *Position) NewMove(from, to int) Move {
	piece, capture := p.pieces[from], p.pieces[to]

	if p.enpassant != 0 && to == p.enpassant {
		capture = pawn(piece.color() ^ 1)
	}

	return Move(from | (to << 8) | (int(piece) << 16) | (int(capture) << 20))
}

func (p *Position) NewCastle(from, to int) Move {
	return Move(from | (to << 8) | (int(p.pieces[from]) << 16) | isCastle)
}

func (p *Position) NewEnpassant(from, to int) Move {
	return Move(from | (to << 8) | (int(p.pieces[from]) << 16) | isEnpassant)
}

// Returns true if *non-evasion* move is valid, i.e. it is possible to make
// the move in current position without violating chess rules. If the king is
// in check the generator is expected to generate valid evasions where extra
// validation is not needed.
func (p *Position) isValid(move Move, pins Bitmask) bool {
	color := move.color() // TODO: make color part of move split.
	from, to, piece, capture := move.split()

	// For rare en-passant pawn captures we validate the move by actually
	// making it, and then taking it back.
	if p.enpassant != 0 && to == p.enpassant && capture.isPawn() {
		if position := p.MakeMove(move); position != nil {
			position.UndoLastMove()
			return true
		}
		return false
	}

	// King's move is valid when a) the move is a castle or b) the destination
	// square is not being attacked by the opponent.
	if piece.isKing() {
		return (move & isCastle != 0) || !p.isAttacked(to, color^1)
	}

	// For all other peices the move is valid when it doesn't cause a
	// check. For pinned sliders this includes moves along the pinning
	// file, rank, or diagonal.
	return pins == 0 || pins.isClear(from) || IsBetween(from, to, p.king[color])
}

// Returns a bitmask of all pinned pieces preventing a check for the king on
// given square. The color of the pieces match the color of the king.
func (p *Position) pinnedMask(square int) (mask Bitmask) {
	color := p.pieces[square].color()
	enemy := color ^ 1
	attackers := (p.outposts[bishop(enemy)] | p.outposts[queen(enemy)]) & bishopMagicMoves[square][0]
	attackers |= (p.outposts[rook(enemy)] | p.outposts[queen(enemy)]) & rookMagicMoves[square][0]

	for attackers != 0 {
		attackSquare := attackers.pop()
		blockers := maskBlock[square][attackSquare] & ^bit[attackSquare] & p.board

		if blockers.count() == 1 {
			mask |= blockers & p.outposts[color] // Only friendly pieces are pinned.
		}
	}
	return
}

func (p *Position) pawnMove(square, target int) Move {
	if Abs(square - target) == 16 && p.causesEnpassant(target) {
		return p.NewEnpassant(square, target)
	}

	return p.NewMove(square, target)
}

func (p *Position) pawnPromotion(square, target int) (Move, Move, Move, Move) {
	return p.NewMove(square, target).promote(Queen),
		p.NewMove(square, target).promote(Rook),
		p.NewMove(square, target).promote(Bishop),
		p.NewMove(square, target).promote(Knight)
}

// Returns true if a pawn jump causes en-passant. This is done by checking whether
// the enemy pawns occupy squares ajacent to the target square.
func (p *Position) causesEnpassant(target int) bool {
	pawns := p.outposts[pawn(p.color^1)] // Opposite color pawns.

	return maskIsolated[Col(target)] & maskRank[Row(target)] & pawns != 0
}

func (p *Position) NewMoveFromString(e2e4 string) (move Move) {
	re := regexp.MustCompile(`([KkQqRrBbNn]?)([a-h])([1-8])-?([a-h])([1-8])([QqRrBbNn]?)`)
	arr := re.FindStringSubmatch(e2e4)

	if len(arr) > 0 {
		name := arr[1]
		from := Square(int(arr[3][0]-'1'), int(arr[2][0]-'a'))
		to := Square(int(arr[5][0]-'1'), int(arr[4][0]-'a'))
		promo := arr[6]

		var piece Piece
		switch name {
		case `K`, `k`:
			piece = king(p.color)
		case `Q`, `q`:
			piece = queen(p.color)
		case `R`, `r`:
			piece = rook(p.color)
		case `B`, `b`:
			piece = bishop(p.color)
		case `N`, `n`:
			piece = knight(p.color)
		default:
			piece = p.pieces[from] // <-- Makes piece character optional.
		}
		if (p.pieces[from] != piece) || (p.targets(from)&bit[to] == 0) {
			move = 0 // Invalid move.
		} else {
			move = p.NewMove(from, to)
			if len(promo) > 0 {
				switch promo {
				case `Q`, `q`:
					move = move.promote(Queen)
				case `R`, `r`:
					move = move.promote(Rook)
				case `B`, `b`:
					move = move.promote(Bishop)
				case `N`, `n`:
					move = move.promote(Knight)
				default:
					move = 0
				}
			}
		}
	} else if e2e4 == `0-0` || e2e4 == `0-0-0` {
		from := p.king[p.color]
		to := G1
		if e2e4 == `0-0-0` {
			to = C1
		}
		if p.color == Black {
			to += 56
		}
		move = p.NewCastle(from, to)
		if !move.isCastle() {
			move = 0
		}
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

// Parsing of Mach-O executables (OS X).

package objfile

import (
	"debug/macho"
	"fmt"
	"os"
	"sort"
)

type machoFile struct {
	macho *macho.File
}

func openMacho(r *os.File) (rawFile, error) {
	f, err := macho.NewFile(r)
	if err != nil {
		return nil, err
	}
	return &machoFile{f}, nil
}

func (f *machoFile) symbols() ([]Sym, error) {
	if f.macho.Symtab == nil {
		return nil, fmt.Errorf("missing symbol table")
	}

	// Build sorted list of addresses of all symbols.
	// We infer the size of a symbol by looking at where the next symbol begins.
	var addrs []uint64
	for _, s := range f.macho.Symtab.Syms {
		addrs = append(addrs, s.Value)
	}
	sort.Sort(uint64s(addrs))

	var syms []Sym
	for _, s := range f.macho.Symtab.Syms {
		sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
		i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
		if i < len(addrs) {
			sym.Size = int64(addrs[i] - s.Value)
		}
		if s.Sect == 0 {
			sym.Code = 'U'
		} else if int(s.Sect) <= len(f.macho.Sections) {
			sect := f.macho.Sections[s.Sect-1]
			switch sect.Seg {
			case "__TEXT":
				sym.Code = 'R'
			case "__DATA":
				sym.Code = 'D'
			}
			switch sect.Seg + " " + sect.Name {
			case "__TEXT __text":
				sym.Code = 'T'
			case "__DATA __bss", "__DATA __noptrbss":
				sym.Code = 'B'
			}
		}
		syms = append(syms, sym)
	}

	return syms, nil
}

func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
	if sect := f.macho.Section("__text"); sect != nil {
		textStart = sect.Addr
	}
	if sect := f.macho.Section("__gosymtab"); sect != nil {
		if symtab, err = sect.Data(); err != nil {
			return 0, nil, nil, err
		}
	}
	if sect := f.macho.Section("__gopclntab"); sect != nil {
		if pclntab, err = sect.Data(); err != nil {
			return 0, nil, nil, err
		}
	}
	return textStart, symtab, pclntab, nil
}

func (f *machoFile) text() (textStart uint64, text []byte, err error) {
	sect := f.macho.Section("__text")
	if sect == nil {
		return 0, nil, fmt.Errorf("text section not found")
	}
	textStart = sect.Addr
	text, err = sect.Data()
	return
}

func (f *machoFile) goarch() string {
	switch f.macho.Cpu {
	case macho.Cpu386:
		return "386"
	case macho.CpuAmd64:
		return "amd64"
	case macho.CpuArm:
		return "arm"
	case macho.CpuPpc64:
		return "ppc64"
	}
	return ""
}

type uint64s []uint64

func (x uint64s) Len() int           { return len(x) }
func (x uint64s) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
func (x uint64s) Less(i, j int) bool { return x[i] < x[j] }
<commit_msg>cmd/internal/objfile: Skip mach-o debug symbols.<commit_after>// Copyright 2013 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.

// Parsing of Mach-O executables (OS X).

package objfile

import (
	"debug/macho"
	"fmt"
	"os"
	"sort"
)

const stabTypeMask = 0xe0

type machoFile struct {
	macho *macho.File
}

func openMacho(r *os.File) (rawFile, error) {
	f, err := macho.NewFile(r)
	if err != nil {
		return nil, err
	}
	return &machoFile{f}, nil
}

func (f *machoFile) symbols() ([]Sym, error) {
	if f.macho.Symtab == nil {
		return nil, fmt.Errorf("missing symbol table")
	}

	// Build sorted list of addresses of all symbols.
	// We infer the size of a symbol by looking at where the next symbol begins.
	var addrs []uint64
	for _, s := range f.macho.Symtab.Syms {
		// Skip stab debug info.
		if s.Type&stabTypeMask == 0 {
			addrs = append(addrs, s.Value)
		}
	}
	sort.Sort(uint64s(addrs))

	var syms []Sym
	for _, s := range f.macho.Symtab.Syms {
		if s.Type&stabTypeMask != 0 {
			// Skip stab debug info.
			continue
		}
		sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
		i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
		if i < len(addrs) {
			sym.Size = int64(addrs[i] - s.Value)
		}
		if s.Sect == 0 {
			sym.Code = 'U'
		} else if int(s.Sect) <= len(f.macho.Sections) {
			sect := f.macho.Sections[s.Sect-1]
			switch sect.Seg {
			case "__TEXT":
				sym.Code = 'R'
			case "__DATA":
				sym.Code = 'D'
			}
			switch sect.Seg + " " + sect.Name {
			case "__TEXT __text":
				sym.Code = 'T'
			case "__DATA __bss", "__DATA __noptrbss":
				sym.Code = 'B'
			}
		}
		syms = append(syms, sym)
	}

	return syms, nil
}

func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) {
	if sect := f.macho.Section("__text"); sect != nil {
		textStart = sect.Addr
	}
	if sect := f.macho.Section("__gosymtab"); sect != nil {
		if symtab, err = sect.Data(); err != nil {
			return 0, nil, nil, err
		}
	}
	if sect := f.macho.Section("__gopclntab"); sect != nil {
		if pclntab, err = sect.Data(); err != nil {
			return 0, nil, nil, err
		}
	}
	return textStart, symtab, pclntab, nil
}

func (f *machoFile) text() (textStart uint64, text []byte, err error) {
	sect := f.macho.Section("__text")
	if sect == nil {
		return 0, nil, fmt.Errorf("text section not found")
	}
	textStart = sect.Addr
	text, err = sect.Data()
	return
}

func (f *machoFile) goarch() string {
	switch f.macho.Cpu {
	case macho.Cpu386:
		return "386"
	case macho.CpuAmd64:
		return "amd64"
	case macho.CpuArm:
		return "arm"
	case macho.CpuPpc64:
		return "ppc64"
	}
	return ""
}

type uint64s []uint64

func (x uint64s) Len() int           { return len(x) }
func (x uint64s) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
func (x uint64s) Less(i, j int) bool { return x[i] < x[j] }
<|endoftext|>


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

package main

const adapterTemplate = `// Code generated by adapter-generator. DO NOT EDIT.

package adapter

import (
	"fmt"
	"github.com/gogo/protobuf/proto"
	"github.com/ligato/cn-infra/datasync"
	. "github.com/ligato/cn-infra/kvscheduler/api"

    {{- range $i, $path := .Imports }}
	"{{ $path }}"
	{{- end }}
)

////////// type-safe key-value pair with metadata //////////

type {{ .DescriptorName }}KVWithMetadata struct {
	Key      string
	Value    {{ .ValueT }}
	Metadata {{ .MetadataT }}
	Origin   ValueOrigin
}

////////// type-safe Descriptor structure //////////

type {{ .DescriptorName }}Descriptor struct {
	Name               string
	KeySelector        KeySelector
	ValueTypeName      string
	KeyLabel           func(key string) string
	ValueComparator    func(key string, v1, v2 {{ .ValueT }}) bool
	NBKeyPrefix        string
	WithMetadata       bool
	MetadataMapFactory MetadataMapFactory
	Add                func(key string, value {{ .ValueT }}) (metadata {{ .MetadataT }}, err error)
	Delete             func(key string, value {{ .ValueT }}, metadata {{ .MetadataT }}) error
	Modify             func(key string, oldValue, newValue {{ .ValueT }}, oldMetadata {{ .MetadataT }}) (newMetadata {{ .MetadataT }}, err error)
	ModifyWithRecreate func(key string, oldValue, newValue {{ .ValueT }}, metadata {{ .MetadataT }}) bool
	Update             func(key string, value {{ .ValueT }}, metadata {{ .MetadataT }}) error
	IsRetriableFailure func(err error) bool
	Dependencies       func(key string, value {{ .ValueT }}) []Dependency
	DerivedValues      func(key string, value {{ .ValueT }}) []KeyValuePair
	Dump               func(correlate []{{ .DescriptorName }}KVWithMetadata) ([]{{ .DescriptorName }}KVWithMetadata, error)
	DumpDependencies   []string /* descriptor name */
}

////////// Descriptor adapter //////////

type {{ .DescriptorName }}DescriptorAdapter struct {
	descriptor *{{ .DescriptorName }}Descriptor
}

func New{{ .DescriptorName }}Descriptor(typedDescriptor *{{ .DescriptorName }}Descriptor) *KVDescriptor {
	adapter := &{{ .DescriptorName }}DescriptorAdapter{descriptor: typedDescriptor}
	descriptor := &KVDescriptor{
		Name:               typedDescriptor.Name,
        KeySelector:        typedDescriptor.KeySelector,
        ValueTypeName:      typedDescriptor.ValueTypeName,
		KeyLabel:           typedDescriptor.KeyLabel,
		NBKeyPrefix:        typedDescriptor.NBKeyPrefix,
		WithMetadata:       typedDescriptor.WithMetadata,
        MetadataMapFactory: typedDescriptor.MetadataMapFactory,
		IsRetriableFailure: typedDescriptor.IsRetriableFailure,
		DumpDependencies:   typedDescriptor.DumpDependencies,
	}
	if typedDescriptor.ValueComparator != nil {
		descriptor.ValueComparator = adapter.ValueComparator
	}
	if typedDescriptor.Add != nil {
		descriptor.Add = adapter.Add
	}
	if typedDescriptor.Delete != nil {
		descriptor.Delete = adapter.Delete
	}
	if typedDescriptor.Modify != nil {
		descriptor.Modify = adapter.Modify
	}
	if typedDescriptor.ModifyWithRecreate != nil {
		descriptor.ModifyWithRecreate = adapter.ModifyWithRecreate
	}
	if typedDescriptor.Update != nil {
		descriptor.Update = adapter.Update
	}
	if typedDescriptor.Dependencies != nil {
		descriptor.Dependencies = adapter.Dependencies
	}
	if typedDescriptor.DerivedValues != nil {
		descriptor.DerivedValues = adapter.DerivedValues
	}
	if typedDescriptor.Dump != nil {
		descriptor.Dump = adapter.Dump
	}
	return descriptor
}

func (da *{{ .DescriptorName }}DescriptorAdapter) ValueComparator(key string, v1, v2 proto.Message) bool {
	typedV1, err1 := cast{{ .DescriptorName }}Value(key, v1)
	typedV2, err1 := cast{{ .DescriptorName }}Value(key, v2)
	if err1 != nil || err2 != nil {
		return false
	}
	return da.descriptor.ValueComparator(key, typedV1, typedV2)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Add(key string, value proto.Message) (metadata Metadata, err error) {
	typedValue, err := cast{{ .DescriptorName }}Value(key, value)
	if err != nil {
		return nil, err
	}
	return da.descriptor.Add(key, typedValue)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Modify(key string, oldValue, newValue proto.Message, oldMetadata Metadata) (newMetadata Metadata, err error) {
	oldTypedValue, err := cast{{ .DescriptorName }}Value(key, oldValue)
	if err != nil {
		return nil, err
	}
	newTypedValue, err := cast{{ .DescriptorName }}Value(key, newValue)
	if err != nil {
		return nil, err
	}
	typedOldMetadata, err := cast{{ .DescriptorName }}Metadata(key, oldMetadata)
	if err != nil {
		return nil, err
	}
	return da.descriptor.Modify(key, oldTypedValue, newTypedValue, typedOldMetadata)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Delete(key string, value proto.Message, metadata Metadata) error {
	typedValue, err := cast{{ .DescriptorName }}Value(key, value)
	if err != nil {
		return err
	}
	typedMetadata, err := cast{{ .DescriptorName }}Metadata(key, metadata)
	if err != nil {
		return err
	}
	return da.descriptor.Delete(key, typedValue, typedMetadata)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) ModifyWithRecreate(key string, oldValue, newValue proto.Message, metadata Metadata) bool {
	oldTypedValue, err := cast{{ .DescriptorName }}Value(key, oldValue)
	if err != nil {
		return true
	}
	newTypedValue, err := cast{{ .DescriptorName }}Value(key, newValue)
	if err != nil {
		return true
	}
	typedMetadata, err := cast{{ .DescriptorName }}Metadata(key, metadata)
	if err != nil {
		return true
	}
	return da.descriptor.ModifyWithRecreate(key, oldTypedValue, newTypedValue, typedMetadata)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Update(key string, value proto.Message, metadata Metadata) error {
	typedValue, err := cast{{ .DescriptorName }}Value(key, value)
	if err != nil {
		return err
	}
	typedMetadata, err := cast{{ .DescriptorName }}Metadata(key, metadata)
	if err != nil {
		return err
	}
	return da.descriptor.Update(key, typedValue, typedMetadata)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Dependencies(key string, value proto.Message) []Dependency {
	typedValue, err := cast{{ .DescriptorName }}Value(key, value)
	if err != nil {
		return nil
	}
	return da.descriptor.Dependencies(key, typedValue)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) DerivedValues(key string, value proto.Message) []KeyValuePair {
	typedValue, err := cast{{ .DescriptorName }}Value(key, value)
	if err != nil {
		return nil
	}
	return da.descriptor.DerivedValues(key, typedValue)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Dump(correlate []KVWithMetadata) ([]KVWithMetadata, error) {
	var correlateWithType []{{ .DescriptorName }}KVWithMetadata
	for _, kvpair := range correlate {
		typedValue, err := cast{{ .DescriptorName }}Value(kvpair.Key, kvpair.Value)
		if err != nil {
			continue
		}
		typedMetadata, err := cast{{ .DescriptorName }}Metadata(kvpair.Key, kvpair.Metadata)
		if err != nil {
			continue
		}
		correlateWithType = append(correlateWithType,
			{{ .DescriptorName }}KVWithMetadata{
				Key:      kvpair.Key,
				Value:    typedValue,
				Metadata: typedMetadata,
				Origin:   kvpair.Origin,
			})
	}

	typedDump, err := da.descriptor.Dump(correlateWithType)
	if err != nil {
		return nil, err
	}
	var dump []KVWithMetadata
	for _, typedKVWithMetadata := range typedDump {
		kvWithMetadata := KVWithMetadata{
			Key:      typedKVWithMetadata.Key,
			Metadata: typedKVWithMetadata.Metadata,
			Origin:   typedKVWithMetadata.Origin,
			}
		kvWithMetadata.Value = typedKVWithMetadata.Value
		dump = append(dump, kvWithMetadata)
	}
	return dump, err
}

////////// Helper methods //////////

func cast{{ .DescriptorName }}Value(key string, value proto.Message) ({{ .ValueT }}, error) {
	typedValue, ok := value.({{ .ValueT }})
	if !ok {
		return nil, ErrInvalidValueType(key, value)
	}
	return typedValue, nil
}

func cast{{ .DescriptorName }}Metadata(key string, metadata Metadata) ({{ .MetadataT }}, error) {
	if metadata == nil {
		return nil, nil
	}
	typedMetadata, ok := metadata.({{ .MetadataT }})
	if !ok {
		return nil, ErrInvalidMetadataType(key)
	}
	return typedMetadata, nil
}
`
<commit_msg>One more descriptor adapter template fix.<commit_after>// Copyright (c) 2018 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

const adapterTemplate = `// Code generated by adapter-generator. DO NOT EDIT.

package adapter

import (
	"github.com/gogo/protobuf/proto"
	. "github.com/ligato/cn-infra/kvscheduler/api"

    {{- range $i, $path := .Imports }}
	"{{ $path }}"
	{{- end }}
)

////////// type-safe key-value pair with metadata //////////

type {{ .DescriptorName }}KVWithMetadata struct {
	Key      string
	Value    {{ .ValueT }}
	Metadata {{ .MetadataT }}
	Origin   ValueOrigin
}

////////// type-safe Descriptor structure //////////

type {{ .DescriptorName }}Descriptor struct {
	Name               string
	KeySelector        KeySelector
	ValueTypeName      string
	KeyLabel           func(key string) string
	ValueComparator    func(key string, v1, v2 {{ .ValueT }}) bool
	NBKeyPrefix        string
	WithMetadata       bool
	MetadataMapFactory MetadataMapFactory
	Add                func(key string, value {{ .ValueT }}) (metadata {{ .MetadataT }}, err error)
	Delete             func(key string, value {{ .ValueT }}, metadata {{ .MetadataT }}) error
	Modify             func(key string, oldValue, newValue {{ .ValueT }}, oldMetadata {{ .MetadataT }}) (newMetadata {{ .MetadataT }}, err error)
	ModifyWithRecreate func(key string, oldValue, newValue {{ .ValueT }}, metadata {{ .MetadataT }}) bool
	Update             func(key string, value {{ .ValueT }}, metadata {{ .MetadataT }}) error
	IsRetriableFailure func(err error) bool
	Dependencies       func(key string, value {{ .ValueT }}) []Dependency
	DerivedValues      func(key string, value {{ .ValueT }}) []KeyValuePair
	Dump               func(correlate []{{ .DescriptorName }}KVWithMetadata) ([]{{ .DescriptorName }}KVWithMetadata, error)
	DumpDependencies   []string /* descriptor name */
}

////////// Descriptor adapter //////////

type {{ .DescriptorName }}DescriptorAdapter struct {
	descriptor *{{ .DescriptorName }}Descriptor
}

func New{{ .DescriptorName }}Descriptor(typedDescriptor *{{ .DescriptorName }}Descriptor) *KVDescriptor {
	adapter := &{{ .DescriptorName }}DescriptorAdapter{descriptor: typedDescriptor}
	descriptor := &KVDescriptor{
		Name:               typedDescriptor.Name,
        KeySelector:        typedDescriptor.KeySelector,
        ValueTypeName:      typedDescriptor.ValueTypeName,
		KeyLabel:           typedDescriptor.KeyLabel,
		NBKeyPrefix:        typedDescriptor.NBKeyPrefix,
		WithMetadata:       typedDescriptor.WithMetadata,
        MetadataMapFactory: typedDescriptor.MetadataMapFactory,
		IsRetriableFailure: typedDescriptor.IsRetriableFailure,
		DumpDependencies:   typedDescriptor.DumpDependencies,
	}
	if typedDescriptor.ValueComparator != nil {
		descriptor.ValueComparator = adapter.ValueComparator
	}
	if typedDescriptor.Add != nil {
		descriptor.Add = adapter.Add
	}
	if typedDescriptor.Delete != nil {
		descriptor.Delete = adapter.Delete
	}
	if typedDescriptor.Modify != nil {
		descriptor.Modify = adapter.Modify
	}
	if typedDescriptor.ModifyWithRecreate != nil {
		descriptor.ModifyWithRecreate = adapter.ModifyWithRecreate
	}
	if typedDescriptor.Update != nil {
		descriptor.Update = adapter.Update
	}
	if typedDescriptor.Dependencies != nil {
		descriptor.Dependencies = adapter.Dependencies
	}
	if typedDescriptor.DerivedValues != nil {
		descriptor.DerivedValues = adapter.DerivedValues
	}
	if typedDescriptor.Dump != nil {
		descriptor.Dump = adapter.Dump
	}
	return descriptor
}

func (da *{{ .DescriptorName }}DescriptorAdapter) ValueComparator(key string, v1, v2 proto.Message) bool {
	typedV1, err1 := cast{{ .DescriptorName }}Value(key, v1)
	typedV2, err2 := cast{{ .DescriptorName }}Value(key, v2)
	if err1 != nil || err2 != nil {
		return false
	}
	return da.descriptor.ValueComparator(key, typedV1, typedV2)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Add(key string, value proto.Message) (metadata Metadata, err error) {
	typedValue, err := cast{{ .DescriptorName }}Value(key, value)
	if err != nil {
		return nil, err
	}
	return da.descriptor.Add(key, typedValue)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Modify(key string, oldValue, newValue proto.Message, oldMetadata Metadata) (newMetadata Metadata, err error) {
	oldTypedValue, err := cast{{ .DescriptorName }}Value(key, oldValue)
	if err != nil {
		return nil, err
	}
	newTypedValue, err := cast{{ .DescriptorName }}Value(key, newValue)
	if err != nil {
		return nil, err
	}
	typedOldMetadata, err := cast{{ .DescriptorName }}Metadata(key, oldMetadata)
	if err != nil {
		return nil, err
	}
	return da.descriptor.Modify(key, oldTypedValue, newTypedValue, typedOldMetadata)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Delete(key string, value proto.Message, metadata Metadata) error {
	typedValue, err := cast{{ .DescriptorName }}Value(key, value)
	if err != nil {
		return err
	}
	typedMetadata, err := cast{{ .DescriptorName }}Metadata(key, metadata)
	if err != nil {
		return err
	}
	return da.descriptor.Delete(key, typedValue, typedMetadata)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) ModifyWithRecreate(key string, oldValue, newValue proto.Message, metadata Metadata) bool {
	oldTypedValue, err := cast{{ .DescriptorName }}Value(key, oldValue)
	if err != nil {
		return true
	}
	newTypedValue, err := cast{{ .DescriptorName }}Value(key, newValue)
	if err != nil {
		return true
	}
	typedMetadata, err := cast{{ .DescriptorName }}Metadata(key, metadata)
	if err != nil {
		return true
	}
	return da.descriptor.ModifyWithRecreate(key, oldTypedValue, newTypedValue, typedMetadata)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Update(key string, value proto.Message, metadata Metadata) error {
	typedValue, err := cast{{ .DescriptorName }}Value(key, value)
	if err != nil {
		return err
	}
	typedMetadata, err := cast{{ .DescriptorName }}Metadata(key, metadata)
	if err != nil {
		return err
	}
	return da.descriptor.Update(key, typedValue, typedMetadata)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Dependencies(key string, value proto.Message) []Dependency {
	typedValue, err := cast{{ .DescriptorName }}Value(key, value)
	if err != nil {
		return nil
	}
	return da.descriptor.Dependencies(key, typedValue)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) DerivedValues(key string, value proto.Message) []KeyValuePair {
	typedValue, err := cast{{ .DescriptorName }}Value(key, value)
	if err != nil {
		return nil
	}
	return da.descriptor.DerivedValues(key, typedValue)
}

func (da *{{ .DescriptorName }}DescriptorAdapter) Dump(correlate []KVWithMetadata) ([]KVWithMetadata, error) {
	var correlateWithType []{{ .DescriptorName }}KVWithMetadata
	for _, kvpair := range correlate {
		typedValue, err := cast{{ .DescriptorName }}Value(kvpair.Key, kvpair.Value)
		if err != nil {
			continue
		}
		typedMetadata, err := cast{{ .DescriptorName }}Metadata(kvpair.Key, kvpair.Metadata)
		if err != nil {
			continue
		}
		correlateWithType = append(correlateWithType,
			{{ .DescriptorName }}KVWithMetadata{
				Key:      kvpair.Key,
				Value:    typedValue,
				Metadata: typedMetadata,
				Origin:   kvpair.Origin,
			})
	}

	typedDump, err := da.descriptor.Dump(correlateWithType)
	if err != nil {
		return nil, err
	}
	var dump []KVWithMetadata
	for _, typedKVWithMetadata := range typedDump {
		kvWithMetadata := KVWithMetadata{
			Key:      typedKVWithMetadata.Key,
			Metadata: typedKVWithMetadata.Metadata,
			Origin:   typedKVWithMetadata.Origin,
			}
		kvWithMetadata.Value = typedKVWithMetadata.Value
		dump = append(dump, kvWithMetadata)
	}
	return dump, err
}

////////// Helper methods //////////

func cast{{ .DescriptorName }}Value(key string, value proto.Message) ({{ .ValueT }}, error) {
	typedValue, ok := value.({{ .ValueT }})
	if !ok {
		return nil, ErrInvalidValueType(key, value)
	}
	return typedValue, nil
}

func cast{{ .DescriptorName }}Metadata(key string, metadata Metadata) ({{ .MetadataT }}, error) {
	if metadata == nil {
		return nil, nil
	}
	typedMetadata, ok := metadata.({{ .MetadataT }})
	if !ok {
		return nil, ErrInvalidMetadataType(key)
	}
	return typedMetadata, nil
}
`
<|endoftext|>