<commit_before>/*
 *   Copyright 2016 Manik Surtani
 *
 *   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 redis

import (
	"github.com/maniksurtani/quotaservice/configs"
	"github.com/maniksurtani/quotaservice/buckets"
	"time"
	"sync"
	"gopkg.in/redis.v3"
	"fmt"
	"github.com/maniksurtani/quotaservice/logging"
	"strconv"
)

const (
	TOKENS_NEXT_AVBL_NANOS_SUFFIX = "TNA"
	ACCUMULATED_TOKENS_SUFFIX = "AT"
)

type redisBucket struct {
	cfg                         *configs.BucketConfig
	namespace                   string
	name                        string
	factory                     *BucketFactory
	nanosBetweenTokens          int64
	maxTokensToAccumulate       int64
	tokensNextAvblNanosRedisKey string
	accumulatedTokensRedisKey   string
	buckets.ActivityChannel
}

type BucketFactory struct {
	m           *sync.RWMutex // Embed a lock.
	client      *redis.Client
	initialized bool
}

func NewBucketFactory() *BucketFactory {
	return &BucketFactory{initialized: false, m: &sync.RWMutex{}}
}

func (bf *BucketFactory) Init(cfg *configs.ServiceConfig) {
	if !bf.initialized {
		bf.m.Lock()
		defer bf.m.Unlock()

		if !bf.initialized {
			bf.initialized = true
			logging.Print("Establishing connection to Redis")
			// Set up connection to Redis
			// TODO(manik) read cfgs from config
			bf.client = redis.NewClient(&redis.Options{
				Addr:     "localhost:6379",
				Password: "", // no password set
				DB:       0, // use default DB
			})

			logging.Printf("Connection established. Time on server: %v", time.Unix(toInt64(bf.client.Time().Val()[0], 0) / 1000, 0))
		}
	}
}

func (bf *BucketFactory) NewBucket(namespace, bucketName string, cfg *configs.BucketConfig) buckets.Bucket {
	return &redisBucket{
		cfg,
		namespace,
		bucketName,
		bf,
		int64(1e9 / cfg.FillRate),
		int64(cfg.Size),
		toRedisKey(namespace, bucketName, TOKENS_NEXT_AVBL_NANOS_SUFFIX),
		toRedisKey(namespace, bucketName, ACCUMULATED_TOKENS_SUFFIX),
		buckets.NewActivityChannel()}
}

func toRedisKey(namespace, bucketName, suffix string) string {
	return fmt.Sprintf("%v:%v:%v", namespace, bucketName, suffix)
}

func (b *redisBucket) Take(requested int, maxWaitTime time.Duration) (waitTime time.Duration) {
	tokensRequested := int64(requested)
	// Start a Redis "transaction"
	client := b.factory.client
	m := client.Multi()
	defer m.Exec(func() error {
		return nil
	})

	currentTimeNanos := time.Now().UnixNano()
	cachedVals := m.MGet(b.tokensNextAvblNanosRedisKey, b.accumulatedTokensRedisKey)

	tokensNextAvailableNanos := toInt64(cachedVals.Val()[0], 0)
	accumulatedTokens := toInt64(cachedVals.Val()[1], 0)

	if currentTimeNanos > tokensNextAvailableNanos {
		// Accumulate fresh tokens.
		freshTokens := (currentTimeNanos - tokensNextAvailableNanos) / b.nanosBetweenTokens

		// Never exceed maxTokensToAccumulate
		accumulatedTokens = min(b.maxTokensToAccumulate, accumulatedTokens + freshTokens)
		tokensNextAvailableNanos = currentTimeNanos
	}

	waitTime = time.Duration(tokensNextAvailableNanos - currentTimeNanos) * time.Nanosecond
	accumulatedTokensUsed := min(accumulatedTokens, tokensRequested)
	tokensToWaitFor := int64(tokensRequested) - accumulatedTokensUsed
	futureWaitNanos := tokensToWaitFor * b.nanosBetweenTokens

	// Is waitTime too long?
	if waitTime > 0 && waitTime > maxWaitTime && maxWaitTime > 0 {
		// Don't "claim" any tokens.
		waitTime = time.Duration(-1)
	} else {
		tokensNextAvailableNanos = tokensNextAvailableNanos + futureWaitNanos
		accumulatedTokens = accumulatedTokens - accumulatedTokensUsed

		// TODO(manik) see if we can re-implement using INCR?

		// "Claim" tokens by writing variables back to Redis and releasing lock.
		expiry := time.Duration(b.cfg.MaxIdleMillis) * time.Millisecond
		m.Set(b.tokensNextAvblNanosRedisKey, tokensNextAvailableNanos, expiry)
		m.Set(b.accumulatedTokensRedisKey, accumulatedTokens, expiry)
	}

	return
}

func min(x, y int64) int64 {
	if x < y {
		return x
	}
	return y
}
func max(x, y int64) int64 {
	if x > y {
		return x
	}
	return y
}

func toInt64(s interface{}, defaultValue int64) (v int64) {
	if s != nil {
		var err error
		v, err = strconv.ParseInt(s.(string), 10, 64)
		if err != nil {
			logging.Printf("Cannot convert '%v' to int64", s)
		}
	}
	return
}

func (b *redisBucket) GetConfig() *configs.BucketConfig {
	return b.cfg
}
<commit_msg>Add TODO<commit_after>/*
 *   Copyright 2016 Manik Surtani
 *
 *   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 redis

import (
	"github.com/maniksurtani/quotaservice/configs"
	"github.com/maniksurtani/quotaservice/buckets"
	"time"
	"sync"
	"gopkg.in/redis.v3"
	"fmt"
	"github.com/maniksurtani/quotaservice/logging"
	"strconv"
)

const (
	TOKENS_NEXT_AVBL_NANOS_SUFFIX = "TNA"
	ACCUMULATED_TOKENS_SUFFIX = "AT"
)

type redisBucket struct {
	cfg                         *configs.BucketConfig
	namespace                   string
	name                        string
	factory                     *BucketFactory
	nanosBetweenTokens          int64
	maxTokensToAccumulate       int64
	tokensNextAvblNanosRedisKey string
	accumulatedTokensRedisKey   string
	buckets.ActivityChannel
}

type BucketFactory struct {
	m           *sync.RWMutex // Embed a lock.
	client      *redis.Client
	initialized bool
}

func NewBucketFactory() *BucketFactory {
	return &BucketFactory{initialized: false, m: &sync.RWMutex{}}
}

func (bf *BucketFactory) Init(cfg *configs.ServiceConfig) {
	if !bf.initialized {
		bf.m.Lock()
		defer bf.m.Unlock()

		if !bf.initialized {
			bf.initialized = true
			logging.Print("Establishing connection to Redis")
			// Set up connection to Redis
			// TODO(manik) read cfgs from config
			bf.client = redis.NewClient(&redis.Options{
				Addr:     "localhost:6379",
				Password: "", // no password set
				DB:       0, // use default DB
			})

			logging.Printf("Connection established. Time on server: %v", time.Unix(toInt64(bf.client.Time().Val()[0], 0) / 1000, 0))
		}
	}
}

func (bf *BucketFactory) NewBucket(namespace, bucketName string, cfg *configs.BucketConfig) buckets.Bucket {
	return &redisBucket{
		cfg,
		namespace,
		bucketName,
		bf,
		int64(1e9 / cfg.FillRate),
		int64(cfg.Size),
		toRedisKey(namespace, bucketName, TOKENS_NEXT_AVBL_NANOS_SUFFIX),
		toRedisKey(namespace, bucketName, ACCUMULATED_TOKENS_SUFFIX),
		buckets.NewActivityChannel()}
}

func toRedisKey(namespace, bucketName, suffix string) string {
	return fmt.Sprintf("%v:%v:%v", namespace, bucketName, suffix)
}

func (b *redisBucket) Take(requested int, maxWaitTime time.Duration) (waitTime time.Duration) {
	tokensRequested := int64(requested)
	// Start a Redis "transaction"
	client := b.factory.client
	// TODO(manik) detect failed clients and reconnect
	m := client.Multi()
	defer m.Exec(func() error {
		return nil
	})

	currentTimeNanos := time.Now().UnixNano()
	cachedVals := m.MGet(b.tokensNextAvblNanosRedisKey, b.accumulatedTokensRedisKey)

	tokensNextAvailableNanos := toInt64(cachedVals.Val()[0], 0)
	accumulatedTokens := toInt64(cachedVals.Val()[1], 0)

	if currentTimeNanos > tokensNextAvailableNanos {
		// Accumulate fresh tokens.
		freshTokens := (currentTimeNanos - tokensNextAvailableNanos) / b.nanosBetweenTokens

		// Never exceed maxTokensToAccumulate
		accumulatedTokens = min(b.maxTokensToAccumulate, accumulatedTokens + freshTokens)
		tokensNextAvailableNanos = currentTimeNanos
	}

	waitTime = time.Duration(tokensNextAvailableNanos - currentTimeNanos) * time.Nanosecond
	accumulatedTokensUsed := min(accumulatedTokens, tokensRequested)
	tokensToWaitFor := int64(tokensRequested) - accumulatedTokensUsed
	futureWaitNanos := tokensToWaitFor * b.nanosBetweenTokens

	// Is waitTime too long?
	if waitTime > 0 && waitTime > maxWaitTime && maxWaitTime > 0 {
		// Don't "claim" any tokens.
		waitTime = time.Duration(-1)
	} else {
		tokensNextAvailableNanos = tokensNextAvailableNanos + futureWaitNanos
		accumulatedTokens = accumulatedTokens - accumulatedTokensUsed

		// TODO(manik) see if we can re-implement using INCR?

		// "Claim" tokens by writing variables back to Redis and releasing lock.
		expiry := time.Duration(b.cfg.MaxIdleMillis) * time.Millisecond
		m.Set(b.tokensNextAvblNanosRedisKey, tokensNextAvailableNanos, expiry)
		m.Set(b.accumulatedTokensRedisKey, accumulatedTokens, expiry)
	}

	return
}

func min(x, y int64) int64 {
	if x < y {
		return x
	}
	return y
}
func max(x, y int64) int64 {
	if x > y {
		return x
	}
	return y
}

func toInt64(s interface{}, defaultValue int64) (v int64) {
	if s != nil {
		var err error
		v, err = strconv.ParseInt(s.(string), 10, 64)
		if err != nil {
			logging.Printf("Cannot convert '%v' to int64", s)
		}
	}
	return
}

func (b *redisBucket) GetConfig() *configs.BucketConfig {
	return b.cfg
}
<|endoftext|>


<commit_before>package eval

var valueTests = []evalTest{
	// Compounding
	// -----------
	{"put {fi,elvi}sh{1.0,1.1}",
		want{out: strs("fish1.0", "fish1.1", "elvish1.0", "elvish1.1")}},

	// List, Map and Indexing
	// ----------------------

	{"echo [a b c] [&key=value] | each put",
		want{out: strs("[a b c] [&key=value]")}},
	{"put [a b c][2]", want{out: strs("c")}},
	{"put [&key=value][key]", want{out: strs("value")}},

	// String Literals
	// ---------------
	{`put 'such \"''literal'`, want{out: strs(`such \"'literal`)}},
	{`put "much \n\033[31;1m$cool\033[m"`,
		want{out: strs("much \n\033[31;1m$cool\033[m")}},

	// Captures
	// ---------

	// Output capture
	{"put (put lorem ipsum)", want{out: strs("lorem", "ipsum")}},
	{"put (print \"lorem\nipsum\")", want{out: strs("lorem", "ipsum")}},

	// Exception capture
	{"bool ?(nop); bool ?(e:false)", want{out: bools(true, false)}},

	// Variable Use
	// ------------

	// Compounding
	{"x='SHELL'\nput 'WOW, SUCH '$x', MUCH COOL'\n",
		want{out: strs("WOW, SUCH SHELL, MUCH COOL")}},
	// Splicing
	{"x=[elvish rules]; put $@x", want{out: strs("elvish", "rules")}},

	// Wildcard
	// --------

	{"put *", want{out: strs(filesToCreate...)}},
	{"put a/b/nonexistent*", want{err: ErrWildcardNoMatch}},
	{"put a/b/nonexistent*[nomatch-ok]", wantNothing},

	// Tilde
	// -----
	{"h=$E:HOME; E:HOME=/foo; put ~ ~/src; E:HOME=$h",
		want{out: strs("/foo", "/foo/src")}},

	// Closure
	// -------

	{"[]{ }", wantNothing},
	{"[x]{put $x} foo", want{out: strs("foo")}},

	// Variable capture
	{"x=lorem; []{x=ipsum}; put $x", want{out: strs("ipsum")}},
	{"x=lorem; []{ put $x; x=ipsum }; put $x",
		want{out: strs("lorem", "ipsum")}},

	// Shadowing
	{"x=ipsum; []{ local:x=lorem; put $x }; put $x",
		want{out: strs("lorem", "ipsum")}},

	// Shadowing by argument
	{"x=ipsum; [x]{ put $x; x=BAD } lorem; put $x",
		want{out: strs("lorem", "ipsum")}},

	// Closure captures new local variables every time
	{`fn f []{ x=0; put []{x=(+ $x 1)} []{put $x} }
		      {inc1,put1}=(f); $put1; $inc1; $put1
			  {inc2,put2}=(f); $put2; $inc2; $put2`,
		want{out: strs("0", "1", "0", "1")}},

	// fn.
	{"fn f [x]{ put x=$x'.' }; f lorem; f ipsum",
		want{out: strs("x=lorem.", "x=ipsum.")}},
	// return.
	{"fn f []{ put a; return; put b }; f", want{out: strs("a")}},

	// Rest argument.
	{"[x @xs]{ put $x $xs } a b c",
		want{out: []Value{String("a"), NewList(String("b"), String("c"))}}},
	// Options.
	{"[a &k=v]{ put $a $k } foo &k=bar", want{out: strs("foo", "bar")}},
	// Option default value.
	{"[a &k=v]{ put $a $k } foo", want{out: strs("foo", "v")}},
}

func init() {
	addToEvalTests(valueTests)
}
<commit_msg>Remove some duplicate test cases.<commit_after>package eval

var valueTests = []evalTest{
	// Compounding
	// -----------
	{"put {fi,elvi}sh{1.0,1.1}",
		want{out: strs("fish1.0", "fish1.1", "elvish1.0", "elvish1.1")}},

	// List, Map and Indexing
	// ----------------------

	{"echo [a b c] [&key=value] | each put",
		want{out: strs("[a b c] [&key=value]")}},
	{"put [a b c][2]", want{out: strs("c")}},
	{"put [&key=value][key]", want{out: strs("value")}},

	// String Literals
	// ---------------
	{`put 'such \"''literal'`, want{out: strs(`such \"'literal`)}},
	{`put "much \n\033[31;1m$cool\033[m"`,
		want{out: strs("much \n\033[31;1m$cool\033[m")}},

	// Captures
	// ---------

	// Output capture
	{"put (put lorem ipsum)", want{out: strs("lorem", "ipsum")}},
	{"put (print \"lorem\nipsum\")", want{out: strs("lorem", "ipsum")}},

	// Exception capture
	{"bool ?(nop); bool ?(e:false)", want{out: bools(true, false)}},

	// Variable Use
	// ------------

	// Compounding
	{"x='SHELL'\nput 'WOW, SUCH '$x', MUCH COOL'\n",
		want{out: strs("WOW, SUCH SHELL, MUCH COOL")}},
	// Splicing
	{"x=[elvish rules]; put $@x", want{out: strs("elvish", "rules")}},

	// Wildcard
	// --------

	{"put *", want{out: strs(filesToCreate...)}},
	{"put a/b/nonexistent*", want{err: ErrWildcardNoMatch}},
	{"put a/b/nonexistent*[nomatch-ok]", wantNothing},

	// Tilde
	// -----
	{"h=$E:HOME; E:HOME=/foo; put ~ ~/src; E:HOME=$h",
		want{out: strs("/foo", "/foo/src")}},

	// Closure
	// -------

	{"[]{ }", wantNothing},
	{"[x]{put $x} foo", want{out: strs("foo")}},

	// Variable capture
	{"x=lorem; []{x=ipsum}; put $x", want{out: strs("ipsum")}},
	{"x=lorem; []{ put $x; x=ipsum }; put $x",
		want{out: strs("lorem", "ipsum")}},

	// Shadowing
	{"x=ipsum; []{ local:x=lorem; put $x }; put $x",
		want{out: strs("lorem", "ipsum")}},

	// Shadowing by argument
	{"x=ipsum; [x]{ put $x; x=BAD } lorem; put $x",
		want{out: strs("lorem", "ipsum")}},

	// Closure captures new local variables every time
	{`fn f []{ x=0; put []{x=(+ $x 1)} []{put $x} }
		      {inc1,put1}=(f); $put1; $inc1; $put1
			  {inc2,put2}=(f); $put2; $inc2; $put2`,
		want{out: strs("0", "1", "0", "1")}},

	// Rest argument.
	{"[x @xs]{ put $x $xs } a b c",
		want{out: []Value{String("a"), NewList(String("b"), String("c"))}}},
	// Options.
	{"[a &k=v]{ put $a $k } foo &k=bar", want{out: strs("foo", "bar")}},
	// Option default value.
	{"[a &k=v]{ put $a $k } foo", want{out: strs("foo", "v")}},
}

func init() {
	addToEvalTests(valueTests)
}
<|endoftext|>


<commit_before><commit_msg>Address comments: remove random spanName, stop server<commit_after><|endoftext|>


<commit_before>package fs

import (
	"errors"
	"fmt"
	"github.com/dotcloud/docker/future"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
)

type LayerStore struct {
	Root string
}

func NewLayerStore(root string) (*LayerStore, error) {
	abspath, err := filepath.Abs(root)
	if err != nil {
		return nil, err
	}
	// Create the root directory if it doesn't exists
	if err := os.Mkdir(root, 0700); err != nil && !os.IsExist(err) {
		return nil, err
	}
	return &LayerStore{
		Root: abspath,
	}, nil
}

func (store *LayerStore) List() []string {
	files, err := ioutil.ReadDir(store.Root)
	if err != nil {
		return []string{}
	}
	var layers []string
	for _, st := range files {
		if st.IsDir() {
			layers = append(layers, path.Join(store.Root, st.Name()))
		}
	}
	return layers
}

func (store *LayerStore) Get(id string) string {
	if !store.Exists(id) {
		return ""
	}
	return store.layerPath(id)
}

func (store *LayerStore) rootExists() (bool, error) {
	if stat, err := os.Stat(store.Root); err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	} else if !stat.IsDir() {
		return false, errors.New("Not a directory: " + store.Root)
	}
	return true, nil
}

func (store *LayerStore) Init() error {
	if exists, err := store.rootExists(); err != nil {
		return err
	} else if exists {
		return nil
	}
	return os.Mkdir(store.Root, 0700)
}

func (store *LayerStore) Mktemp() (string, error) {
	tmpName := future.RandomId()
	tmpPath := path.Join(store.Root, "tmp-"+tmpName)
	if err := os.Mkdir(tmpPath, 0700); err != nil {
		return "", err
	}
	return tmpPath, nil
}

func (store *LayerStore) layerPath(id string) string {
	return path.Join(store.Root, id)
}

func (store *LayerStore) AddLayer(id string, archive Archive) (string, error) {
	if _, err := os.Stat(store.layerPath(id)); err == nil {
		return "", fmt.Errorf("Layer already exists: %v", id)
	}
	tmp, err := store.Mktemp()
	defer os.RemoveAll(tmp)
	if err != nil {
		return "", fmt.Errorf("Mktemp failed: %s", err)
	}
	if err := Untar(archive, tmp); err != nil {
		return "", nil
	}
	layer := store.layerPath(id)
	if !store.Exists(id) {
		if err := os.Rename(tmp, layer); err != nil {
			return "", fmt.Errorf("Could not rename temp dir to layer %s: %s", layer, err)
		}
	}
	return layer, nil
}

func (store *LayerStore) Exists(id string) bool {
	st, err := os.Stat(store.layerPath(id))
	if err != nil {
		return false
	}
	return st.IsDir()
}
<commit_msg>Fixed a bug which causes 'docker import' to fail silently when bsdtar is not installed<commit_after>package fs

import (
	"errors"
	"fmt"
	"github.com/dotcloud/docker/future"
	"io/ioutil"
	"os"
	"path"
	"path/filepath"
)

type LayerStore struct {
	Root string
}

func NewLayerStore(root string) (*LayerStore, error) {
	abspath, err := filepath.Abs(root)
	if err != nil {
		return nil, err
	}
	// Create the root directory if it doesn't exists
	if err := os.Mkdir(root, 0700); err != nil && !os.IsExist(err) {
		return nil, err
	}
	return &LayerStore{
		Root: abspath,
	}, nil
}

func (store *LayerStore) List() []string {
	files, err := ioutil.ReadDir(store.Root)
	if err != nil {
		return []string{}
	}
	var layers []string
	for _, st := range files {
		if st.IsDir() {
			layers = append(layers, path.Join(store.Root, st.Name()))
		}
	}
	return layers
}

func (store *LayerStore) Get(id string) string {
	if !store.Exists(id) {
		return ""
	}
	return store.layerPath(id)
}

func (store *LayerStore) rootExists() (bool, error) {
	if stat, err := os.Stat(store.Root); err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err
	} else if !stat.IsDir() {
		return false, errors.New("Not a directory: " + store.Root)
	}
	return true, nil
}

func (store *LayerStore) Init() error {
	if exists, err := store.rootExists(); err != nil {
		return err
	} else if exists {
		return nil
	}
	return os.Mkdir(store.Root, 0700)
}

func (store *LayerStore) Mktemp() (string, error) {
	tmpName := future.RandomId()
	tmpPath := path.Join(store.Root, "tmp-"+tmpName)
	if err := os.Mkdir(tmpPath, 0700); err != nil {
		return "", err
	}
	return tmpPath, nil
}

func (store *LayerStore) layerPath(id string) string {
	return path.Join(store.Root, id)
}

func (store *LayerStore) AddLayer(id string, archive Archive) (string, error) {
	if _, err := os.Stat(store.layerPath(id)); err == nil {
		return "", fmt.Errorf("Layer already exists: %v", id)
	}
	tmp, err := store.Mktemp()
	defer os.RemoveAll(tmp)
	if err != nil {
		return "", fmt.Errorf("Mktemp failed: %s", err)
	}
	if err := Untar(archive, tmp); err != nil {
		return "", err
	}
	layer := store.layerPath(id)
	if !store.Exists(id) {
		if err := os.Rename(tmp, layer); err != nil {
			return "", fmt.Errorf("Could not rename temp dir to layer %s: %s", layer, err)
		}
	}
	return layer, nil
}

func (store *LayerStore) Exists(id string) bool {
	st, err := os.Stat(store.layerPath(id))
	if err != nil {
		return false
	}
	return st.IsDir()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
	"os"
)

func main() {

	var (
		ClientOV       *ov.OVClient
		new_volume     = "TestVolume"
		name_to_update = "UpdatedName"
	)

	ovc := ClientOV.NewOVClient(
		os.Getenv("ONEVIEW_OV_USER"),
		os.Getenv("ONEVIEW_OV_PASSWORD"),
		os.Getenv("ONEVIEW_OV_DOMAIN"),
		os.Getenv("ONEVIEW_OV_ENDPOINT"),
		false,
		1800,
		"*")

	// Create storage volume with name <new_volume>
	properties := &ov.Properties{
		Name:                new_volume,
		Storagepool:         utils.NewNstring("/rest/storage-pools/7D2A17CD-414A-45EF-B221-ABF1006D6F44"),
		Size:                268435456,
		ProvisioningType:    "Thin",
		DataProtectionLevel: "NetworkRaid10Mirror2Way",
	}
	trueVal := true
	storageVolume := ov.StorageVolume{TemplateURI: utils.NewNstring("/rest/storage-volume-templates/798f3224-8f8d-43b1-a02f-abf100736549"), Properties: properties, IsPermanent: &trueVal}

	err := ovc.CreateStorageVolume(storageVolume)
	if err != nil {
		fmt.Println("Could not create the volume", err)
	}

	// Update the given storage volume
	update_vol, _ := ovc.GetStorageVolumeByName(new_volume)

	updated_storage_volume := ov.StorageVolume{
		ProvisioningTypeForUpdate: update_vol.ProvisioningTypeForUpdate,
		IsPermanent:               update_vol.IsPermanent,
		IsShareable:               update_vol.IsShareable,
		Name:                      name_to_update,
		ProvisionedCapacity:       "107374741824",
		DeviceSpecificAttributes:  update_vol.DeviceSpecificAttributes,
		URI:                       update_vol.URI,
		ETAG:                      update_vol.ETAG,
		Description:               "empty",
		TemplateVersion:           "1.1",
		VolumeTemplateUri:         update_vol.VolumeTemplateUri,
	}

	err = ovc.UpdateStorageVolume(updated_storage_volume)
	if err != nil {
		fmt.Println("Could not update the volume", err)
	}

	// Get All the volumes present
	fmt.Println("\nGetting all the storage volumes present in the system: \n")
	sort := "name:desc"
	vol_list, err := ovc.GetStorageVolumes("", sort)
	if err != nil {
		fmt.Println("Error Getting the storage volumes ", err)
	}
	for i := 0; i < len(vol_list.Members); i++ {
		fmt.Println(vol_list.Members[i].Name)
	}

	// Get volume by name
	fmt.Println("\nGetting details of volume with name: ", name_to_update)
	vol_by_name, _ := ovc.GetStorageVolumeByName(name_to_update)
	fmt.Println(vol_by_name)

	// Delete the created volume
	fmt.Println("\nDeleting the volume with name : UpdatedName")
	err = ovc.DeleteStorageVolume(name_to_update)
	if err != nil {
		fmt.Println("Delete Unsuccessful", err)
	}
}
<commit_msg>gofmt fix<commit_after>package main

import (
	"fmt"
	"github.com/HewlettPackard/oneview-golang/ov"
	"github.com/HewlettPackard/oneview-golang/utils"
	"os"
)

func main() {

	var (
		ClientOV       *ov.OVClient
		new_volume     = "TestVolume"
		name_to_update = "UpdatedName"
	)

	ovc := ClientOV.NewOVClient(
		os.Getenv("ONEVIEW_OV_USER"),
		os.Getenv("ONEVIEW_OV_PASSWORD"),
		os.Getenv("ONEVIEW_OV_DOMAIN"),
		os.Getenv("ONEVIEW_OV_ENDPOINT"),
		false,
		1800,
		"*")

	// Create storage volume with name <new_volume>
	properties := &ov.Properties{
		Name:                new_volume,
		Storagepool:         utils.NewNstring("/rest/storage-pools/7D2A17CD-414A-45EF-B221-ABF1006D6F44"),
		Size:                268435456,
		ProvisioningType:    "Thin",
		DataProtectionLevel: "NetworkRaid10Mirror2Way",
	}
	trueVal := true
	storageVolume := ov.StorageVolume{TemplateURI: utils.NewNstring("/rest/storage-volume-templates/798f3224-8f8d-43b1-a02f-abf100736549"), Properties: properties, IsPermanent: &trueVal}

	err := ovc.CreateStorageVolume(storageVolume)
	if err != nil {
		fmt.Println("Could not create the volume", err)
	}

	// Update the given storage volume
	update_vol, _ := ovc.GetStorageVolumeByName(new_volume)

	updated_storage_volume := ov.StorageVolume{
		ProvisioningTypeForUpdate: update_vol.ProvisioningTypeForUpdate,
		IsPermanent:               update_vol.IsPermanent,
		IsShareable:               update_vol.IsShareable,
		Name:                      name_to_update,
		ProvisionedCapacity:       "107374741824",
		DeviceSpecificAttributes:  update_vol.DeviceSpecificAttributes,
		URI:               update_vol.URI,
		ETAG:              update_vol.ETAG,
		Description:       "empty",
		TemplateVersion:   "1.1",
		VolumeTemplateUri: update_vol.VolumeTemplateUri,
	}

	err = ovc.UpdateStorageVolume(updated_storage_volume)
	if err != nil {
		fmt.Println("Could not update the volume", err)
	}

	// Get All the volumes present
	fmt.Println("\nGetting all the storage volumes present in the system: \n")
	sort := "name:desc"
	vol_list, err := ovc.GetStorageVolumes("", sort)
	if err != nil {
		fmt.Println("Error Getting the storage volumes ", err)
	}
	for i := 0; i < len(vol_list.Members); i++ {
		fmt.Println(vol_list.Members[i].Name)
	}

	// Get volume by name
	fmt.Println("\nGetting details of volume with name: ", name_to_update)
	vol_by_name, _ := ovc.GetStorageVolumeByName(name_to_update)
	fmt.Println(vol_by_name)

	// Delete the created volume
	fmt.Println("\nDeleting the volume with name : UpdatedName")
	err = ovc.DeleteStorageVolume(name_to_update)
	if err != nil {
		fmt.Println("Delete Unsuccessful", err)
	}
}
<|endoftext|>


<commit_before>package registry

import (
	"path"
	"strings"

	"github.com/coreos/fleet/third_party/github.com/coreos/go-etcd/etcd"
	log "github.com/coreos/fleet/third_party/github.com/golang/glog"

	"github.com/coreos/fleet/event"
	"github.com/coreos/fleet/job"
	"github.com/coreos/fleet/machine"
)

const (
	jobPrefix	= "/job/"
	payloadPrefix	= "/payload/"
)

func (r *Registry) GetAllPayloads() []job.JobPayload {
	var payloads []job.JobPayload

	key := path.Join(keyPrefix, payloadPrefix)
	resp, err := r.etcd.Get(key, true, true)

	if err != nil {
		return payloads
	}

	for _, node := range resp.Node.Nodes {
		var jp job.JobPayload
		//TODO: Handle the error generated by unmarshal
		unmarshal(node.Value, &jp)

		if err != nil {
			log.Errorf(err.Error())
			continue
		}

		payloads = append(payloads, jp)
	}

	return payloads
}

// List the jobs all Machines are scheduled to run
func (r *Registry) GetAllJobs() []job.Job {
	var jobs []job.Job

	key := path.Join(keyPrefix, jobPrefix)
	resp, err := r.etcd.Get(key, true, true)

	if err != nil {
		return jobs
	}

	for _, node := range resp.Node.Nodes {
		if j := r.GetJob(path.Base(node.Key)); j != nil {
			jobs = append(jobs, *j)
		}
	}

	return jobs
}

func (r *Registry) GetAllJobsByMachine(machBootId string) []job.Job {
	var jobs []job.Job

	key := path.Join(keyPrefix, jobPrefix)
	resp, err := r.etcd.Get(key, true, true)

	if err != nil {
		log.Errorf(err.Error())
		return jobs
	}

	for _, node := range resp.Node.Nodes {
		if j := r.GetJob(path.Base(node.Key)); j != nil {
			tgt := r.GetJobTarget(j.Name)
			if tgt != nil && tgt.BootId == machBootId {
				jobs = append(jobs, *j)
			}
		}
	}

	return jobs
}

func (r *Registry) GetJobTarget(jobName string) *machine.MachineState {
	// Figure out to which Machine this Job is scheduled
	key := path.Join(keyPrefix, jobPrefix, jobName, "target")
	resp, err := r.etcd.Get(key, false, true)
	if err != nil {
		return nil
	}

	return &machine.MachineState{resp.Node.Value, "", make(map[string]string, 0)}
}

func (r *Registry) GetJob(jobName string) *job.Job {
	key := path.Join(keyPrefix, jobPrefix, jobName, "object")
	resp, err := r.etcd.Get(key, false, true)

	// Assume the error was KeyNotFound and return an empty data structure
	if err != nil {
		return nil
	}

	var j job.Job
	//TODO: Handle the error generated by unmarshal
	unmarshal(resp.Node.Value, &j)

	return &j
}

func (r *Registry) CreatePayload(jp *job.JobPayload) error {
	key := path.Join(keyPrefix, payloadPrefix, jp.Name)
	json, _ := marshal(jp)
	_, err := r.etcd.Set(key, json, 0)
	return err
}

func (r *Registry) GetPayload(payloadName string) *job.JobPayload {
	key := path.Join(keyPrefix, payloadPrefix, payloadName)
	resp, err := r.etcd.Get(key, false, true)

	// Assume the error was KeyNotFound and return an empty data structure
	if err != nil {
		return nil
	}

	var jp job.JobPayload
	//TODO: Handle the error generated by unmarshal
	unmarshal(resp.Node.Value, &jp)

	return &jp
}

func (r *Registry) DestroyPayload(payloadName string) {
	key := path.Join(keyPrefix, payloadPrefix, payloadName)
	r.etcd.Delete(key, false)
}

func (r *Registry) CreateJob(j *job.Job) error {
	key := path.Join(keyPrefix, jobPrefix, j.Name, "object")
	json, _ := marshal(j)
	_, err := r.etcd.Create(key, json, 0)
	return err
}

func (r *Registry) ScheduleJob(jobName string, machBootId string) {
	key := path.Join(keyPrefix, jobPrefix, jobName, "target")
	r.etcd.Set(key, machBootId, 0)
}

func (r *Registry) UnscheduleJob(jobName string) {
	key := path.Join(keyPrefix, jobPrefix, jobName, "target")
	r.etcd.Delete(key, true)
}

func (r *Registry) StopJob(jobName string) {
	key := path.Join(keyPrefix, jobPrefix, jobName)
	r.etcd.Delete(key, true)
}

func (r *Registry) LockJob(jobName, context string) *TimedResourceMutex {
	return r.lockResource("job", jobName, context)
}

func filterEventJobCreated(resp *etcd.Response) *event.Event {
	if resp.Action != "create" {
		return nil
	}

	baseName := path.Base(resp.Node.Key)
	if baseName != "object" {
		return nil
	}

	var j job.Job
	err := unmarshal(resp.Node.Value, &j)
	if err != nil {
		log.V(1).Infof("Failed to deserialize Job: %s", err)
		return nil
	}

	return &event.Event{"EventJobCreated", j, nil}
}

func filterEventJobScheduled(resp *etcd.Response) *event.Event {
	if resp.Action != "set" {
		return nil
	}

	dir, baseName := path.Split(resp.Node.Key)
	if baseName != "target" {
		return nil
	}

	mach := machine.MachineState{resp.Node.Value, "", make(map[string]string, 0)}
	jobName := path.Base(strings.TrimSuffix(dir, "/"))

	return &event.Event{"EventJobScheduled", jobName, mach}
}

func filterEventJobStopped(resp *etcd.Response) *event.Event {
	if resp.Action != "delete" && resp.Action != "expire" {
		return nil
	}

	dir, jobName := path.Split(resp.Node.Key)
	dir = strings.TrimSuffix(dir, "/")
	dir, prefixName := path.Split(dir)

	if prefixName != "job" {
		return nil
	}

	return &event.Event{"EventJobStopped", jobName, nil}
}
<commit_msg>fix(registry): Use go-etcd Create in CreatePayload<commit_after>package registry

import (
	"path"
	"strings"

	"github.com/coreos/fleet/third_party/github.com/coreos/go-etcd/etcd"
	log "github.com/coreos/fleet/third_party/github.com/golang/glog"

	"github.com/coreos/fleet/event"
	"github.com/coreos/fleet/job"
	"github.com/coreos/fleet/machine"
)

const (
	jobPrefix	= "/job/"
	payloadPrefix	= "/payload/"
)

func (r *Registry) GetAllPayloads() []job.JobPayload {
	var payloads []job.JobPayload

	key := path.Join(keyPrefix, payloadPrefix)
	resp, err := r.etcd.Get(key, true, true)

	if err != nil {
		return payloads
	}

	for _, node := range resp.Node.Nodes {
		var jp job.JobPayload
		//TODO: Handle the error generated by unmarshal
		unmarshal(node.Value, &jp)

		if err != nil {
			log.Errorf(err.Error())
			continue
		}

		payloads = append(payloads, jp)
	}

	return payloads
}

// List the jobs all Machines are scheduled to run
func (r *Registry) GetAllJobs() []job.Job {
	var jobs []job.Job

	key := path.Join(keyPrefix, jobPrefix)
	resp, err := r.etcd.Get(key, true, true)

	if err != nil {
		return jobs
	}

	for _, node := range resp.Node.Nodes {
		if j := r.GetJob(path.Base(node.Key)); j != nil {
			jobs = append(jobs, *j)
		}
	}

	return jobs
}

func (r *Registry) GetAllJobsByMachine(machBootId string) []job.Job {
	var jobs []job.Job

	key := path.Join(keyPrefix, jobPrefix)
	resp, err := r.etcd.Get(key, true, true)

	if err != nil {
		log.Errorf(err.Error())
		return jobs
	}

	for _, node := range resp.Node.Nodes {
		if j := r.GetJob(path.Base(node.Key)); j != nil {
			tgt := r.GetJobTarget(j.Name)
			if tgt != nil && tgt.BootId == machBootId {
				jobs = append(jobs, *j)
			}
		}
	}

	return jobs
}

func (r *Registry) GetJobTarget(jobName string) *machine.MachineState {
	// Figure out to which Machine this Job is scheduled
	key := path.Join(keyPrefix, jobPrefix, jobName, "target")
	resp, err := r.etcd.Get(key, false, true)
	if err != nil {
		return nil
	}

	return &machine.MachineState{resp.Node.Value, "", make(map[string]string, 0)}
}

func (r *Registry) GetJob(jobName string) *job.Job {
	key := path.Join(keyPrefix, jobPrefix, jobName, "object")
	resp, err := r.etcd.Get(key, false, true)

	// Assume the error was KeyNotFound and return an empty data structure
	if err != nil {
		return nil
	}

	var j job.Job
	//TODO: Handle the error generated by unmarshal
	unmarshal(resp.Node.Value, &j)

	return &j
}

func (r *Registry) CreatePayload(jp *job.JobPayload) error {
	key := path.Join(keyPrefix, payloadPrefix, jp.Name)
	json, _ := marshal(jp)
	_, err := r.etcd.Create(key, json, 0)
	return err
}

func (r *Registry) GetPayload(payloadName string) *job.JobPayload {
	key := path.Join(keyPrefix, payloadPrefix, payloadName)
	resp, err := r.etcd.Get(key, false, true)

	// Assume the error was KeyNotFound and return an empty data structure
	if err != nil {
		return nil
	}

	var jp job.JobPayload
	//TODO: Handle the error generated by unmarshal
	unmarshal(resp.Node.Value, &jp)

	return &jp
}

func (r *Registry) DestroyPayload(payloadName string) {
	key := path.Join(keyPrefix, payloadPrefix, payloadName)
	r.etcd.Delete(key, false)
}

func (r *Registry) CreateJob(j *job.Job) error {
	key := path.Join(keyPrefix, jobPrefix, j.Name, "object")
	json, _ := marshal(j)
	_, err := r.etcd.Create(key, json, 0)
	return err
}

func (r *Registry) ScheduleJob(jobName string, machBootId string) {
	key := path.Join(keyPrefix, jobPrefix, jobName, "target")
	r.etcd.Set(key, machBootId, 0)
}

func (r *Registry) UnscheduleJob(jobName string) {
	key := path.Join(keyPrefix, jobPrefix, jobName, "target")
	r.etcd.Delete(key, true)
}

func (r *Registry) StopJob(jobName string) {
	key := path.Join(keyPrefix, jobPrefix, jobName)
	r.etcd.Delete(key, true)
}

func (r *Registry) LockJob(jobName, context string) *TimedResourceMutex {
	return r.lockResource("job", jobName, context)
}

func filterEventJobCreated(resp *etcd.Response) *event.Event {
	if resp.Action != "create" {
		return nil
	}

	baseName := path.Base(resp.Node.Key)
	if baseName != "object" {
		return nil
	}

	var j job.Job
	err := unmarshal(resp.Node.Value, &j)
	if err != nil {
		log.V(1).Infof("Failed to deserialize Job: %s", err)
		return nil
	}

	return &event.Event{"EventJobCreated", j, nil}
}

func filterEventJobScheduled(resp *etcd.Response) *event.Event {
	if resp.Action != "set" {
		return nil
	}

	dir, baseName := path.Split(resp.Node.Key)
	if baseName != "target" {
		return nil
	}

	mach := machine.MachineState{resp.Node.Value, "", make(map[string]string, 0)}
	jobName := path.Base(strings.TrimSuffix(dir, "/"))

	return &event.Event{"EventJobScheduled", jobName, mach}
}

func filterEventJobStopped(resp *etcd.Response) *event.Event {
	if resp.Action != "delete" && resp.Action != "expire" {
		return nil
	}

	dir, jobName := path.Split(resp.Node.Key)
	dir = strings.TrimSuffix(dir, "/")
	dir, prefixName := path.Split(dir)

	if prefixName != "job" {
		return nil
	}

	return &event.Event{"EventJobStopped", jobName, nil}
}
<|endoftext|>


<commit_before>/*
renamer.go

Renaming files script on various patterns

Author: Gianluca Fiore <forod.g@gmail.com> © 2013-2015
*/

package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

var usageMessage = `
renamer.go (-p <prefix>|-s <suffix>|-i <indexname> -I <num>|-e|-l|-u) [-x <regexp>] [-t <target_dir>] -[cnr]

renamer.go will rename all files matching a regexp or all files in the
given directory (and optionally in all its subdirectories) by the flag
chosen. It can add a prefix/suffix, rename according to a
<name><numeric_index> pattern, make all low/uppercase, lowercase the
extension and copy files somewhere else leaving the originals untouched.

Arguments:

	-prefix|-p <prefix>
		Renames matching files by adding a prefix

	-suffix|-s <suffix>
		Renames matching files by adding a suffix

	-index|-i <name>
		Renames matching files to <name><num>. Requires '-I'

	-startnumber|-I <num>
		The <num> to start renaming in index mode. Requires '-i'

	-regexp|-x <regexp>
		The regular expression for matching files. Use double quotes
		around it

	-target-dir|-t <path>
		The directory where to rename/copy the files. Default is the
		current directory

	-copy|-c
		Copy instead of renaming

	-lower-extension|-e
		Lowercase the extension

	-lowercase|-l
		Lowercase the new filename. It is mutually exclusive with
		'-u'

	-uppercase|-u
		Uppercase the new filename. It is mutually exclusive with
		'-l'

	-dry-run|-n
		List files but don't actually perform any action

	-force|-f
		Overwrite existing files. The default is to not copy/rename
		if the target file already exists

	-recursive|-r
		Operate recursively on all subdirectories of target-dir
`

var regexpArg string         // the regexp argument
var fileRegex *regexp.Regexp // the files matching the regexp
var prefixArg string         // the prefix
var suffixArg string         // the suffix
var indexArg string          // the <name> in the <name><num> pattern
var numArg int               // the <num> in the <name><num> pattern
var targetArg string         // the target directory
var lowerExtArg bool         // the lower extension switch
var lowerArg bool            // the lowercase switch
var upperArg bool            // the uppercase switch
var copyArg bool             // the copy switch
var dryrunArg bool           // the dry-run switch
var forceArg bool            // the force switch
var recursiveArg bool        // the recursive switch

var operationSuccessful int // numeric flag to keep trace of what went
// wrong during the renaming

// Print a message and the usage instructions
func printUsage(msg string) {
	fmt.Fprintf(os.Stderr, msg+"\n")
	fmt.Fprintf(os.Stderr, usageMessage)
	os.Exit(2)
}

// Parse flags ("arguments")
func flagsInit() {
	// Use our custom usageMessage to print usage instructions
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usageMessage)
	}

	const (
		defRegexp    = ""
		defPrefix    = ""
		defSuffix    = ""
		defIndex     = ""
		defNum       = 1
		defTarget    = "."
		defLowerext  = false
		defLowercase = false
		defUppercase = false
		defCopy      = false
		defDryrun    = false
		defForce     = false
		defRecursive = false
	)

	flag.StringVar(&regexpArg, "regexp", defRegexp, "")
	flag.StringVar(&regexpArg, "x", defRegexp, "")
	flag.StringVar(&prefixArg, "prefix", defPrefix, "")
	flag.StringVar(&prefixArg, "p", defPrefix, "")
	flag.StringVar(&suffixArg, "suffix", defSuffix, "")
	flag.StringVar(&suffixArg, "s", defSuffix, "")
	flag.StringVar(&indexArg, "index", defIndex, "")
	flag.StringVar(&indexArg, "i", defIndex, "")
	flag.IntVar(&numArg, "startnumber", defNum, "")
	flag.IntVar(&numArg, "I", defNum, "")
	flag.StringVar(&targetArg, "target", defTarget, "")
	flag.StringVar(&targetArg, "t", defTarget, "")
	flag.BoolVar(&lowerExtArg, "lower-extension", defLowerext, "")
	flag.BoolVar(&lowerExtArg, "e", defLowerext, "")
	flag.BoolVar(&lowerArg, "lowercase", defLowercase, "")
	flag.BoolVar(&lowerArg, "l", defLowercase, "")
	flag.BoolVar(&upperArg, "uppercase", defUppercase, "")
	flag.BoolVar(&upperArg, "u", defUppercase, "")
	flag.BoolVar(&copyArg, "copy", defCopy, "")
	flag.BoolVar(&copyArg, "c", defCopy, "")
	flag.BoolVar(&dryrunArg, "dry-run", defDryrun, "")
	flag.BoolVar(&dryrunArg, "n", defDryrun, "")
	flag.BoolVar(&forceArg, "force", defForce, "")
	flag.BoolVar(&forceArg, "f", defForce, "")
	flag.BoolVar(&recursiveArg, "recursive", defRecursive, "")
	flag.BoolVar(&recursiveArg, "r", defRecursive, "")

	flag.Parse()

	if regexpArg == "" && prefixArg == "" && suffixArg == "" && indexArg == "" && lowerExtArg == false && lowerArg == false && upperArg == false {
		printUsage("At least one of the mandatory actions must be given, nothing to do...")
	}
}

// Write a renamed or a copy of a file to disk
func writeFile(oldname, newname string) {
	// check if the new filename is already present
	_, lstatErr := os.Lstat(newname)
	if lstatErr == nil && forceArg == false {
		fmt.Fprintf(os.Stderr, "File %s already exist! Use -force to override it\n", newname)
		operationSuccessful = operationSuccessful + 1
	}
	if dryrunArg {
		// if dry-run was given, just output the renaming operation
		fmt.Fprintf(os.Stdout, "Renaming %s to %s (dry-run)\n", oldname, newname)
		operationSuccessful = operationSuccessful + 0
	} else {
		if copyArg {
			copyf, createErr := os.Create(newname)
			if createErr != nil {
				fmt.Fprintf(os.Stderr, createErr.Error())
				operationSuccessful = operationSuccessful + 1
			}
			originalf, openErr := os.Open(oldname)
			if openErr != nil {
				fmt.Fprintf(os.Stderr, openErr.Error())
				operationSuccessful = operationSuccessful + 1
			}
			_, copyErr := io.Copy(copyf, originalf)
			if copyErr != nil {
				fmt.Fprintf(os.Stderr, "An error occurred during the copy of %s to %s\n", oldname, newname)
				fmt.Fprintf(os.Stderr, copyErr.Error())
				operationSuccessful = operationSuccessful + 1
			} else {
				fmt.Fprintf(os.Stdout, "Copying %s to %s\n", oldname, newname)
			}
		} else {
			renameErr := os.Rename(oldname, newname)
			if renameErr != nil {
				fmt.Fprintf(os.Stderr, "An error occurred during the renaming of %s to %s\n", oldname, newname)
				fmt.Fprintf(os.Stderr, renameErr.Error())
				operationSuccessful = operationSuccessful + 1
			} else {
				fmt.Fprintf(os.Stdout, "Renaming %s to %s\n", oldname, newname)
			}
		}
	}
}

// Add a prefix string to a name
func addPrefix(names []string, prefix string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f)
		finalname = filepath.Join(dirname, prefix+filepath.Base(f))
		writeFile(f, finalname)
	}
	return 0
}

// Add a suffix string to a name
func addSuffix(names []string, suffix string) int {
	var finalname, dirname, justname, ext string
	for _, f := range names {
		ext = filepath.Ext(f)
		dirname = filepath.Dir(f)
		justname = strings.TrimSuffix(filepath.Base(f), ext)
		finalname = filepath.Join(dirname, justname+suffix+ext)
		writeFile(f, finalname)
	}
	return 0
}

// Rename a slice of filenames to <newname><count>.<extension>
func indexName(names []string, newname string, count int) int {
	var finalname, dirname, ext string
	for _, f := range names {
		ext = filepath.Ext(f)
		dirname = filepath.Dir(f)
		finalname = fmt.Sprintf("%s/%s%03d%s", dirname, newname, count, ext)
		writeFile(f, finalname)
		count++
	}
	return 0
}

// Make extensions lowercase
func lowercaseExtension(names []string) int {
	var finalname, dirname, basename, ext string
	for _, f := range names {
		dirname = filepath.Dir(f)
		basename = filepath.Base(f)
		ext = filepath.Ext(f)
		finalname = filepath.Join(dirname, strings.TrimSuffix(basename, ext)+strings.ToLower(strings.TrimSuffix(ext, basename)))
		writeFile(f, finalname)
	}
	return 0
}

// Make filenames all lowercase
func lowercaseFiles(names []string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f)
		finalname = filepath.Join(dirname, strings.ToLower(filepath.Base(f)))
		writeFile(f, finalname)
	}
	return 0
}

// Make filenames all uppercase
func uppercaseFiles(names []string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f)
		finalname = filepath.Join(dirname, strings.ToUpper(filepath.Base(f)))
		writeFile(f, finalname)
	}
	return 0
}

// Get all files and directories
func getFilesFromDir(dirname string) ([]string, []string) {
	var completePath string                // final, absolute, path
	var filesindir = make([]os.FileInfo, 0) // files & directories found in path
	var allfiles = make([]string, 0)
	var alldirectories = make([]string, 0)

	dirinfo, lerr := os.Lstat(dirname)
	if lerr != nil {
		fmt.Fprintf(os.Stderr, lerr.Error())
		return alldirectories, allfiles
	}

	// check whether targetArg is an absolute path AND a directory
	if filepath.IsAbs(dirname) && dirinfo.IsDir() {
		completePath = dirname
	} else {
		absPath, err := filepath.Abs(dirname)
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
		}
		completePath = absPath
	}
	dir, err := os.Open(completePath)
	defer dir.Close()
	if err != nil {
		err = fmt.Errorf("Target directory %s is not a directory or can't be accessed\n", completePath)
		fmt.Fprintf(os.Stderr, err.Error())
		return alldirectories, allfiles
	}

	// scan for files/directories in path
	filesindir, readErr := dir.Readdir(0)
	if readErr != nil {
		fmt.Fprintf(os.Stderr, readErr.Error())
		return alldirectories, allfiles
	}

	// check in filesindir slice and separate directories from files in
	// 2 different slices
	for _, f := range filesindir {
		if f.IsDir() {
			alldirectories = append(alldirectories, filepath.Join(completePath, f.Name()))
		} else {
			allfiles = append(allfiles, filepath.Join(completePath, f.Name()))
		}
	}

	return alldirectories, allfiles
}

func renameFiles(dir, files []string) int {
	var basename string
	var matchingfiles []string // a slice containing only the files
	// matching the regexp passed as argument (if)
	var result int // the integer returned by each functions,
	// signaling success or failure

	// recursively search on every directory in dir for other
	// files/directories if recursiveArg switch has been enabled
	if dir != nil && recursiveArg == true {
		for _, d := range dir {
			nd, nf := getFilesFromDir(d)
			// if it's a dir, append to []dir
			if len(nd) > 0 {
				for _, i := range nd {
					dir = append(dir, i)
				}
			}
			// if it's a file, append to []files
			if len(nf) > 0 {
				for _, i := range nf {
					files = append(files, i)
				}
			}
		}
	}

	// check if the files should match a given regexp
	if regexpArg != "" {
		for _, f := range files {
			basename = filepath.Base(f)
			// Compile and check if the regexp is a valid one
			compRegexp, err := regexp.Compile(regexpArg)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Invalid regexp: %s\n", regexpArg)
				printUsage("You must give a valid regexp (or none, to operate on all files). Alternatively, add -force to force renaming all files, whether they match the regexp or not")
				return 1

			if compRegexp.MatchString(basename) == false {
				continue
			} else {
				matchingfiles = append(matchingfiles, f)
			}
			}
		}
	}

	// if matchingfiles contains something, iterate over it.
	// Otherwise, we simply use the generic files slice
	if len(matchingfiles) >= 1 {
		files = matchingfiles
	} else {
		// different messages whether we have forceArg == true or false
		if regexpArg != "" {
			if forceArg {
				fmt.Fprintf(os.Stdout, "No files matched, including all files anyway (-force enabled)\n")
			} else {
				fmt.Fprintf(os.Stderr, "No files matched, check the correctness of your regexp\n")
				return 1
			}
		}
	}

	if prefixArg != "" {
		result = addPrefix(files, prefixArg)
	}
	if suffixArg != "" {
		result = addSuffix(files, suffixArg)
	}
	if indexArg != "" {
		result = indexName(files, indexArg, numArg)
	}
	if lowerArg == true && upperArg == true {
		// can't use both
		printUsage("Can't use both lowercase and uppercase, choose one only!")
		return 1
	}
	if lowerExtArg == true {
		result = lowercaseExtension(files)
	}
	if lowerArg == true {
		result = lowercaseFiles(files)
	}
	if upperArg == true {
		result = uppercaseFiles(files)
	}

	return result
}

func main() {
	var successRename int
	var directories, files []string

	flagsInit()

	directories, files = getFilesFromDir(targetArg)

	successRename = renameFiles(directories, files)

	// check that everything went smoothly
	if successRename == 0 && operationSuccessful == 0 {
		fmt.Fprintf(os.Stdout, "\nRenaming complete\n")
	} else {
		fmt.Fprintf(os.Stdout, "\nNot all files were correctly renamed, check the previous error messages")
	}
}
<commit_msg>update copyright years<commit_after>/*
renamer.go

Renaming files script on various patterns

Author: Gianluca Fiore <forod.g@gmail.com> © 2013-2020
*/

package main

import (
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

var usageMessage = `
renamer.go (-p <prefix>|-s <suffix>|-i <indexname> -I <num>|-e|-l|-u) [-x <regexp>] [-t <target_dir>] -[cnr]

renamer.go will rename all files matching a regexp or all files in the
given directory (and optionally in all its subdirectories) by the flag
chosen. It can add a prefix/suffix, rename according to a
<name><numeric_index> pattern, make all low/uppercase, lowercase the
extension and copy files somewhere else leaving the originals untouched.

Arguments:

	-prefix|-p <prefix>
		Renames matching files by adding a prefix

	-suffix|-s <suffix>
		Renames matching files by adding a suffix

	-index|-i <name>
		Renames matching files to <name><num>. Requires '-I'

	-startnumber|-I <num>
		The <num> to start renaming in index mode. Requires '-i'

	-regexp|-x <regexp>
		The regular expression for matching files. Use double quotes
		around it

	-target-dir|-t <path>
		The directory where to rename/copy the files. Default is the
		current directory

	-copy|-c
		Copy instead of renaming

	-lower-extension|-e
		Lowercase the extension

	-lowercase|-l
		Lowercase the new filename. It is mutually exclusive with
		'-u'

	-uppercase|-u
		Uppercase the new filename. It is mutually exclusive with
		'-l'

	-dry-run|-n
		List files but don't actually perform any action

	-force|-f
		Overwrite existing files. The default is to not copy/rename
		if the target file already exists

	-recursive|-r
		Operate recursively on all subdirectories of target-dir
`

var regexpArg string         // the regexp argument
var fileRegex *regexp.Regexp // the files matching the regexp
var prefixArg string         // the prefix
var suffixArg string         // the suffix
var indexArg string          // the <name> in the <name><num> pattern
var numArg int               // the <num> in the <name><num> pattern
var targetArg string         // the target directory
var lowerExtArg bool         // the lower extension switch
var lowerArg bool            // the lowercase switch
var upperArg bool            // the uppercase switch
var copyArg bool             // the copy switch
var dryrunArg bool           // the dry-run switch
var forceArg bool            // the force switch
var recursiveArg bool        // the recursive switch

var operationSuccessful int // numeric flag to keep trace of what went
// wrong during the renaming

// Print a message and the usage instructions
func printUsage(msg string) {
	fmt.Fprintf(os.Stderr, msg+"\n")
	fmt.Fprintf(os.Stderr, usageMessage)
	os.Exit(2)
}

// Parse flags ("arguments")
func flagsInit() {
	// Use our custom usageMessage to print usage instructions
	flag.Usage = func() {
		fmt.Fprintf(os.Stderr, usageMessage)
	}

	const (
		defRegexp    = ""
		defPrefix    = ""
		defSuffix    = ""
		defIndex     = ""
		defNum       = 1
		defTarget    = "."
		defLowerext  = false
		defLowercase = false
		defUppercase = false
		defCopy      = false
		defDryrun    = false
		defForce     = false
		defRecursive = false
	)

	flag.StringVar(&regexpArg, "regexp", defRegexp, "")
	flag.StringVar(&regexpArg, "x", defRegexp, "")
	flag.StringVar(&prefixArg, "prefix", defPrefix, "")
	flag.StringVar(&prefixArg, "p", defPrefix, "")
	flag.StringVar(&suffixArg, "suffix", defSuffix, "")
	flag.StringVar(&suffixArg, "s", defSuffix, "")
	flag.StringVar(&indexArg, "index", defIndex, "")
	flag.StringVar(&indexArg, "i", defIndex, "")
	flag.IntVar(&numArg, "startnumber", defNum, "")
	flag.IntVar(&numArg, "I", defNum, "")
	flag.StringVar(&targetArg, "target", defTarget, "")
	flag.StringVar(&targetArg, "t", defTarget, "")
	flag.BoolVar(&lowerExtArg, "lower-extension", defLowerext, "")
	flag.BoolVar(&lowerExtArg, "e", defLowerext, "")
	flag.BoolVar(&lowerArg, "lowercase", defLowercase, "")
	flag.BoolVar(&lowerArg, "l", defLowercase, "")
	flag.BoolVar(&upperArg, "uppercase", defUppercase, "")
	flag.BoolVar(&upperArg, "u", defUppercase, "")
	flag.BoolVar(&copyArg, "copy", defCopy, "")
	flag.BoolVar(&copyArg, "c", defCopy, "")
	flag.BoolVar(&dryrunArg, "dry-run", defDryrun, "")
	flag.BoolVar(&dryrunArg, "n", defDryrun, "")
	flag.BoolVar(&forceArg, "force", defForce, "")
	flag.BoolVar(&forceArg, "f", defForce, "")
	flag.BoolVar(&recursiveArg, "recursive", defRecursive, "")
	flag.BoolVar(&recursiveArg, "r", defRecursive, "")

	flag.Parse()

	if regexpArg == "" && prefixArg == "" && suffixArg == "" && indexArg == "" && lowerExtArg == false && lowerArg == false && upperArg == false {
		printUsage("At least one of the mandatory actions must be given, nothing to do...")
	}
}

// Write a renamed or a copy of a file to disk
func writeFile(oldname, newname string) {
	// check if the new filename is already present
	_, lstatErr := os.Lstat(newname)
	if lstatErr == nil && forceArg == false {
		fmt.Fprintf(os.Stderr, "File %s already exist! Use -force to override it\n", newname)
		operationSuccessful = operationSuccessful + 1
	}
	if dryrunArg {
		// if dry-run was given, just output the renaming operation
		fmt.Fprintf(os.Stdout, "Renaming %s to %s (dry-run)\n", oldname, newname)
		operationSuccessful = operationSuccessful + 0
	} else {
		if copyArg {
			copyf, createErr := os.Create(newname)
			if createErr != nil {
				fmt.Fprintf(os.Stderr, createErr.Error())
				operationSuccessful = operationSuccessful + 1
			}
			originalf, openErr := os.Open(oldname)
			if openErr != nil {
				fmt.Fprintf(os.Stderr, openErr.Error())
				operationSuccessful = operationSuccessful + 1
			}
			_, copyErr := io.Copy(copyf, originalf)
			if copyErr != nil {
				fmt.Fprintf(os.Stderr, "An error occurred during the copy of %s to %s\n", oldname, newname)
				fmt.Fprintf(os.Stderr, copyErr.Error())
				operationSuccessful = operationSuccessful + 1
			} else {
				fmt.Fprintf(os.Stdout, "Copying %s to %s\n", oldname, newname)
			}
		} else {
			renameErr := os.Rename(oldname, newname)
			if renameErr != nil {
				fmt.Fprintf(os.Stderr, "An error occurred during the renaming of %s to %s\n", oldname, newname)
				fmt.Fprintf(os.Stderr, renameErr.Error())
				operationSuccessful = operationSuccessful + 1
			} else {
				fmt.Fprintf(os.Stdout, "Renaming %s to %s\n", oldname, newname)
			}
		}
	}
}

// Add a prefix string to a name
func addPrefix(names []string, prefix string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f)
		finalname = filepath.Join(dirname, prefix+filepath.Base(f))
		writeFile(f, finalname)
	}
	return 0
}

// Add a suffix string to a name
func addSuffix(names []string, suffix string) int {
	var finalname, dirname, justname, ext string
	for _, f := range names {
		ext = filepath.Ext(f)
		dirname = filepath.Dir(f)
		justname = strings.TrimSuffix(filepath.Base(f), ext)
		finalname = filepath.Join(dirname, justname+suffix+ext)
		writeFile(f, finalname)
	}
	return 0
}

// Rename a slice of filenames to <newname><count>.<extension>
func indexName(names []string, newname string, count int) int {
	var finalname, dirname, ext string
	for _, f := range names {
		ext = filepath.Ext(f)
		dirname = filepath.Dir(f)
		finalname = fmt.Sprintf("%s/%s%03d%s", dirname, newname, count, ext)
		writeFile(f, finalname)
		count++
	}
	return 0
}

// Make extensions lowercase
func lowercaseExtension(names []string) int {
	var finalname, dirname, basename, ext string
	for _, f := range names {
		dirname = filepath.Dir(f)
		basename = filepath.Base(f)
		ext = filepath.Ext(f)
		finalname = filepath.Join(dirname, strings.TrimSuffix(basename, ext)+strings.ToLower(strings.TrimSuffix(ext, basename)))
		writeFile(f, finalname)
	}
	return 0
}

// Make filenames all lowercase
func lowercaseFiles(names []string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f)
		finalname = filepath.Join(dirname, strings.ToLower(filepath.Base(f)))
		writeFile(f, finalname)
	}
	return 0
}

// Make filenames all uppercase
func uppercaseFiles(names []string) int {
	var finalname, dirname string
	for _, f := range names {
		dirname = filepath.Dir(f)
		finalname = filepath.Join(dirname, strings.ToUpper(filepath.Base(f)))
		writeFile(f, finalname)
	}
	return 0
}

// Get all files and directories
func getFilesFromDir(dirname string) ([]string, []string) {
	var completePath string                // final, absolute, path
	var filesindir = make([]os.FileInfo, 0) // files & directories found in path
	var allfiles = make([]string, 0)
	var alldirectories = make([]string, 0)

	dirinfo, lerr := os.Lstat(dirname)
	if lerr != nil {
		fmt.Fprintf(os.Stderr, lerr.Error())
		return alldirectories, allfiles
	}

	// check whether targetArg is an absolute path AND a directory
	if filepath.IsAbs(dirname) && dirinfo.IsDir() {
		completePath = dirname
	} else {
		absPath, err := filepath.Abs(dirname)
		if err != nil {
			fmt.Fprintf(os.Stderr, err.Error())
		}
		completePath = absPath
	}
	dir, err := os.Open(completePath)
	defer dir.Close()
	if err != nil {
		err = fmt.Errorf("Target directory %s is not a directory or can't be accessed\n", completePath)
		fmt.Fprintf(os.Stderr, err.Error())
		return alldirectories, allfiles
	}

	// scan for files/directories in path
	filesindir, readErr := dir.Readdir(0)
	if readErr != nil {
		fmt.Fprintf(os.Stderr, readErr.Error())
		return alldirectories, allfiles
	}

	// check in filesindir slice and separate directories from files in
	// 2 different slices
	for _, f := range filesindir {
		if f.IsDir() {
			alldirectories = append(alldirectories, filepath.Join(completePath, f.Name()))
		} else {
			allfiles = append(allfiles, filepath.Join(completePath, f.Name()))
		}
	}

	return alldirectories, allfiles
}

func renameFiles(dir, files []string) int {
	var basename string
	var matchingfiles []string // a slice containing only the files
	// matching the regexp passed as argument (if)
	var result int // the integer returned by each functions,
	// signaling success or failure

	// recursively search on every directory in dir for other
	// files/directories if recursiveArg switch has been enabled
	if dir != nil && recursiveArg == true {
		for _, d := range dir {
			nd, nf := getFilesFromDir(d)
			// if it's a dir, append to []dir
			if len(nd) > 0 {
				for _, i := range nd {
					dir = append(dir, i)
				}
			}
			// if it's a file, append to []files
			if len(nf) > 0 {
				for _, i := range nf {
					files = append(files, i)
				}
			}
		}
	}

	// check if the files should match a given regexp
	if regexpArg != "" {
		for _, f := range files {
			basename = filepath.Base(f)
			// Compile and check if the regexp is a valid one
			compRegexp, err := regexp.Compile(regexpArg)
			if err != nil {
				fmt.Fprintf(os.Stderr, "Invalid regexp: %s\n", regexpArg)
				printUsage("You must give a valid regexp (or none, to operate on all files). Alternatively, add -force to force renaming all files, whether they match the regexp or not")
				return 1

			if compRegexp.MatchString(basename) == false {
				continue
			} else {
				matchingfiles = append(matchingfiles, f)
			}
			}
		}
	}

	// if matchingfiles contains something, iterate over it.
	// Otherwise, we simply use the generic files slice
	if len(matchingfiles) >= 1 {
		files = matchingfiles
	} else {
		// different messages whether we have forceArg == true or false
		if regexpArg != "" {
			if forceArg {
				fmt.Fprintf(os.Stdout, "No files matched, including all files anyway (-force enabled)\n")
			} else {
				fmt.Fprintf(os.Stderr, "No files matched, check the correctness of your regexp\n")
				return 1
			}
		}
	}

	if prefixArg != "" {
		result = addPrefix(files, prefixArg)
	}
	if suffixArg != "" {
		result = addSuffix(files, suffixArg)
	}
	if indexArg != "" {
		result = indexName(files, indexArg, numArg)
	}
	if lowerArg == true && upperArg == true {
		// can't use both
		printUsage("Can't use both lowercase and uppercase, choose one only!")
		return 1
	}
	if lowerExtArg == true {
		result = lowercaseExtension(files)
	}
	if lowerArg == true {
		result = lowercaseFiles(files)
	}
	if upperArg == true {
		result = uppercaseFiles(files)
	}

	return result
}

func main() {
	var successRename int
	var directories, files []string

	flagsInit()

	directories, files = getFilesFromDir(targetArg)

	successRename = renameFiles(directories, files)

	// check that everything went smoothly
	if successRename == 0 && operationSuccessful == 0 {
		fmt.Fprintf(os.Stdout, "\nRenaming complete\n")
	} else {
		fmt.Fprintf(os.Stdout, "\nNot all files were correctly renamed, check the previous error messages")
	}
}
<|endoftext|>


<commit_before>// Copyright Kozyrev Yury
// MIT license.
package generator

import (
	"encoding/json"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

//func main() {
//	s := &Document{}
//	s.Read(&domain.Order{})
//	fmt.Println(s)
//}

const DEFAULT_SCHEMA = "http://json-schema.org/schema#"

type Document struct {
	Schema string `json:"$schema,omitempty"`
	property
}

func Generate(v interface{}) string {
	return new(Document).Read(v).String()
}

// Reads the variable structure into the JSON-Schema Document
func (d *Document) Read(variable interface{}) *Document {
	d.setDefaultSchema()

	value := reflect.ValueOf(variable)
	d.read(value.Type())
	return d
}

func (d *Document) setDefaultSchema() {
	if d.Schema == "" {
		d.Schema = DEFAULT_SCHEMA
	}
}

// String return the JSON encoding of the Document as a string
func (d *Document) String() string {
	json, _ := json.MarshalIndent(d, "", "    ")
	return string(json)
}

type property struct {
	Type                 string               `json:"type,omitempty"`
	Format               string               `json:"format,omitempty"`
	Items                *property            `json:"items,omitempty"`
	Properties           map[string]*property `json:"properties,omitempty"`
	Required             []string             `json:"required,omitempty"`
	AdditionalProperties bool                 `json:"additionalProperties,omitempty"`
	Description          string               `json:"description,omitempty"`
	AnyOf                []*property          `json:"anyOf,omitempty"`

	// validation keywords:
	// For any number-valued fields, we're making them pointers, because
	// we want empty values to be omitted, but for numbers, 0 is seen as empty.

	// numbers validators
	MultipleOf       *float64 `json:"multipleOf,omitempty"`
	Maximum          *float64 `json:"maximum,omitempty"`
	Minimum          *float64 `json:"minimum,omitempty"`
	ExclusiveMaximum *float64 `json:"exclusiveMaximum,omitempty"`
	ExclusiveMinimum *float64 `json:"exclusiveMinimum,omitempty"`
	// string validators
	MaxLength *int64 `json:"maxLength,omitempty"`
	MinLength *int64 `json:"minLength,omitempty"`
	Pattern   string `json:"pattern,omitempty"`
	// Enum is defined for arbitrary types, but I'm currently just implementing it for strings.
	Enum []string `json:"enum,omitempty"`

	// Implemented for strings and numbers
	Const interface{} `json:"const,omitempty"`
}

func (p *property) read(t reflect.Type) {
	jsType, format, kind := getTypeFromMapping(t)
	if jsType != "" {
		p.Type = jsType
	}
	if format != "" {
		p.Format = format
	}

	switch kind {
	case reflect.Slice:
		p.readFromSlice(t)
	case reflect.Map:
		p.readFromMap(t)
	case reflect.Struct:
		p.readFromStruct(t)
	case reflect.Ptr:
		p.read(t.Elem())
	}

	// say we have *int
	if kind == reflect.Ptr && isPrimitive(t.Elem().Kind()) {
		p.AnyOf = []*property{
			{Type: p.Type},
			{Type: "null"},
		}
		p.Type = ""
	}
}

func (p *property) readFromSlice(t reflect.Type) {
	jsType, _, kind := getTypeFromMapping(t.Elem())
	if kind == reflect.Uint8 {
		p.Type = "string"
	} else if jsType != "" || kind == reflect.Ptr {
		p.Items = &property{}
		p.Items.read(t.Elem())
	}
}

func (p *property) readFromMap(t reflect.Type) {
	jsType, format, _ := getTypeFromMapping(t.Elem())

	if jsType != "" {
		p.Properties = make(map[string]*property, 0)
		p.Properties[".*"] = &property{Type: jsType, Format: format}
	} else {
		p.AdditionalProperties = true
	}
}

func (p *property) readFromStruct(t reflect.Type) {
	p.Type = "object"
	p.Properties = make(map[string]*property, 0)
	p.AdditionalProperties = false

	count := t.NumField()
	for i := 0; i < count; i++ {
		field := t.Field(i)

		tag := field.Tag.Get("json")
		_, required := field.Tag.Lookup("required")
		name, opts := parseTag(tag)
		if name == "" {
			name = field.Name
		}
		if name == "-" {
			continue
		}

		p.Properties[name] = &property{}
		p.Properties[name].read(field.Type)
		p.Properties[name].Description = field.Tag.Get("description")
		p.Properties[name].addValidatorsFromTags(&field.Tag)

		if opts.Contains("omitempty") || !required {
			continue
		}
		p.Required = append(p.Required, name)
	}
}

func (p *property) addValidatorsFromTags(tag *reflect.StructTag) {
	switch p.Type {
	case "string":
		p.addStringValidators(tag)
	case "number", "integer":
		p.addNumberValidators(tag)
	}
}

// Some helper functions for not having to create temp variables all over the place
func int64ptr(i interface{}) *int64 {
	j := reflect.ValueOf(i).Convert(reflect.TypeOf(int64(0))).Interface().(int64)
	return &j
}

func float64ptr(i interface{}) *float64 {
	j := reflect.ValueOf(i).Convert(reflect.TypeOf(float64(0))).Interface().(float64)
	return &j
}

func (p *property) addStringValidators(tag *reflect.StructTag) {
	// min length
	mls := tag.Get("minLength")
	ml, err := strconv.ParseInt(mls, 10, 64)
	if err == nil {
		p.MinLength = int64ptr(ml)
	}
	// max length
	mls = tag.Get("maxLength")
	ml, err = strconv.ParseInt(mls, 10, 64)
	if err == nil {
		p.MaxLength = int64ptr(ml)
	}
	// pattern
	pat := tag.Get("pattern")
	if pat != "" {
		p.Pattern = pat
	}
	// enum
	en := tag.Get("enum")
	if en != "" {
		p.Enum = strings.Split(en, "|")
	}
	//const
	c := tag.Get("const")
	if c != "" {
		p.Const = c
	}
}

func (p *property) addNumberValidators(tag *reflect.StructTag) {
	m, err := strconv.ParseFloat(tag.Get("multipleOf"), 64)
	if err == nil {
		p.MultipleOf = float64ptr(m)
	}
	m, err = strconv.ParseFloat(tag.Get("min"), 64)
	if err == nil {
		p.Minimum = float64ptr(m)
	}
	m, err = strconv.ParseFloat(tag.Get("max"), 64)
	if err == nil {
		p.Maximum = float64ptr(m)
	}
	m, err = strconv.ParseFloat(tag.Get("exclusiveMin"), 64)
	if err == nil {
		p.ExclusiveMinimum = float64ptr(m)
	}
	m, err = strconv.ParseFloat(tag.Get("exclusiveMax"), 64)
	if err == nil {
		p.ExclusiveMaximum = float64ptr(m)
	}
	c, err := parseType(tag.Get("const"), p.Type)
	if err == nil {
		p.Const = c
	}
}

func parseType(str, ty string) (interface{}, error) {
	var v interface{}
	var err error
	if ty == "number" {
		v, err = strconv.ParseFloat(str, 64)
	} else {
		v, err = strconv.ParseInt(str, 10, 64)
	}
	return v, err
}

var formatMapping = map[string][]string{
	"time.Time": []string{"string", "date-time"},
}

var kindMapping = map[reflect.Kind]string{
	reflect.Bool:    "boolean",
	reflect.Int:     "integer",
	reflect.Int8:    "integer",
	reflect.Int16:   "integer",
	reflect.Int32:   "integer",
	reflect.Int64:   "integer",
	reflect.Uint:    "integer",
	reflect.Uint8:   "integer",
	reflect.Uint16:  "integer",
	reflect.Uint32:  "integer",
	reflect.Uint64:  "integer",
	reflect.Float32: "number",
	reflect.Float64: "number",
	reflect.String:  "string",
	reflect.Slice:   "array",
	reflect.Struct:  "object",
	reflect.Map:     "object",
}

func isPrimitive(k reflect.Kind) bool {
	if v, ok := kindMapping[k]; ok {
		switch v {
		case "boolean":
		case "integer":
		case "number":
		case "string":
			return true
		}
	}
	return false
}

func getTypeFromMapping(t reflect.Type) (string, string, reflect.Kind) {
	if v, ok := formatMapping[t.String()]; ok {
		return v[0], v[1], reflect.String
	}

	if v, ok := kindMapping[t.Kind()]; ok {
		return v, "", t.Kind()
	}

	return "", "", t.Kind()
}

type structTag string

func parseTag(tag string) (string, structTag) {
	if idx := strings.Index(tag, ","); idx != -1 {
		return tag[:idx], structTag(tag[idx+1:])
	}
	return tag, structTag("")
}

func (o structTag) Contains(optionName string) bool {
	if len(o) == 0 {
		return false
	}

	s := string(o)
	for s != "" {
		var next string
		i := strings.Index(s, ",")
		if i >= 0 {
			s, next = s[:i], s[i+1:]
		}
		if s == optionName {
			return true
		}
		s = next
	}
	return false
}

var _ fmt.Stringer = (*Document)(nil)
<commit_msg>Improve int64ptr and float64ptr functions<commit_after>// Copyright Kozyrev Yury
// MIT license.
package generator

import (
	"encoding/json"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

//func main() {
//	s := &Document{}
//	s.Read(&domain.Order{})
//	fmt.Println(s)
//}

const DEFAULT_SCHEMA = "http://json-schema.org/schema#"

var rTypeInt64, rTypeFloat64 = reflect.TypeOf(int64(0)), reflect.TypeOf(float64(0))

type Document struct {
	Schema string `json:"$schema,omitempty"`
	property
}

func Generate(v interface{}) string {
	return new(Document).Read(v).String()
}

// Reads the variable structure into the JSON-Schema Document
func (d *Document) Read(variable interface{}) *Document {
	d.setDefaultSchema()

	value := reflect.ValueOf(variable)
	d.read(value.Type())
	return d
}

func (d *Document) setDefaultSchema() {
	if d.Schema == "" {
		d.Schema = DEFAULT_SCHEMA
	}
}

// String return the JSON encoding of the Document as a string
func (d *Document) String() string {
	json, _ := json.MarshalIndent(d, "", "    ")
	return string(json)
}

type property struct {
	Type                 string               `json:"type,omitempty"`
	Format               string               `json:"format,omitempty"`
	Items                *property            `json:"items,omitempty"`
	Properties           map[string]*property `json:"properties,omitempty"`
	Required             []string             `json:"required,omitempty"`
	AdditionalProperties bool                 `json:"additionalProperties,omitempty"`
	Description          string               `json:"description,omitempty"`
	AnyOf                []*property          `json:"anyOf,omitempty"`

	// validation keywords:
	// For any number-valued fields, we're making them pointers, because
	// we want empty values to be omitted, but for numbers, 0 is seen as empty.

	// numbers validators
	MultipleOf       *float64 `json:"multipleOf,omitempty"`
	Maximum          *float64 `json:"maximum,omitempty"`
	Minimum          *float64 `json:"minimum,omitempty"`
	ExclusiveMaximum *float64 `json:"exclusiveMaximum,omitempty"`
	ExclusiveMinimum *float64 `json:"exclusiveMinimum,omitempty"`
	// string validators
	MaxLength *int64 `json:"maxLength,omitempty"`
	MinLength *int64 `json:"minLength,omitempty"`
	Pattern   string `json:"pattern,omitempty"`
	// Enum is defined for arbitrary types, but I'm currently just implementing it for strings.
	Enum []string `json:"enum,omitempty"`

	// Implemented for strings and numbers
	Const interface{} `json:"const,omitempty"`
}

func (p *property) read(t reflect.Type) {
	jsType, format, kind := getTypeFromMapping(t)
	if jsType != "" {
		p.Type = jsType
	}
	if format != "" {
		p.Format = format
	}

	switch kind {
	case reflect.Slice:
		p.readFromSlice(t)
	case reflect.Map:
		p.readFromMap(t)
	case reflect.Struct:
		p.readFromStruct(t)
	case reflect.Ptr:
		p.read(t.Elem())
	}

	// say we have *int
	if kind == reflect.Ptr && isPrimitive(t.Elem().Kind()) {
		p.AnyOf = []*property{
			{Type: p.Type},
			{Type: "null"},
		}
		p.Type = ""
	}
}

func (p *property) readFromSlice(t reflect.Type) {
	jsType, _, kind := getTypeFromMapping(t.Elem())
	if kind == reflect.Uint8 {
		p.Type = "string"
	} else if jsType != "" || kind == reflect.Ptr {
		p.Items = &property{}
		p.Items.read(t.Elem())
	}
}

func (p *property) readFromMap(t reflect.Type) {
	jsType, format, _ := getTypeFromMapping(t.Elem())

	if jsType != "" {
		p.Properties = make(map[string]*property, 0)
		p.Properties[".*"] = &property{Type: jsType, Format: format}
	} else {
		p.AdditionalProperties = true
	}
}

func (p *property) readFromStruct(t reflect.Type) {
	p.Type = "object"
	p.Properties = make(map[string]*property, 0)
	p.AdditionalProperties = false

	count := t.NumField()
	for i := 0; i < count; i++ {
		field := t.Field(i)

		tag := field.Tag.Get("json")
		_, required := field.Tag.Lookup("required")
		name, opts := parseTag(tag)
		if name == "" {
			name = field.Name
		}
		if name == "-" {
			continue
		}

		p.Properties[name] = &property{}
		p.Properties[name].read(field.Type)
		p.Properties[name].Description = field.Tag.Get("description")
		p.Properties[name].addValidatorsFromTags(&field.Tag)

		if opts.Contains("omitempty") || !required {
			continue
		}
		p.Required = append(p.Required, name)
	}
}

func (p *property) addValidatorsFromTags(tag *reflect.StructTag) {
	switch p.Type {
	case "string":
		p.addStringValidators(tag)
	case "number", "integer":
		p.addNumberValidators(tag)
	}
}

// Some helper functions for not having to create temp variables all over the place
func int64ptr(i interface{}) *int64 {
	v := reflect.ValueOf(i)
	if !v.Type().ConvertibleTo(rTypeInt64) {
		return nil
	}
	j := v.Convert(rTypeInt64).Interface().(int64)
	return &j
}

func float64ptr(i interface{}) *float64 {
	v := reflect.ValueOf(i)
	if !v.Type().ConvertibleTo(rTypeFloat64) {
		return nil
	}
	j := v.Convert(rTypeFloat64).Interface().(float64)
	return &j
}

func (p *property) addStringValidators(tag *reflect.StructTag) {
	// min length
	mls := tag.Get("minLength")
	ml, err := strconv.ParseInt(mls, 10, 64)
	if err == nil {
		p.MinLength = int64ptr(ml)
	}
	// max length
	mls = tag.Get("maxLength")
	ml, err = strconv.ParseInt(mls, 10, 64)
	if err == nil {
		p.MaxLength = int64ptr(ml)
	}
	// pattern
	pat := tag.Get("pattern")
	if pat != "" {
		p.Pattern = pat
	}
	// enum
	en := tag.Get("enum")
	if en != "" {
		p.Enum = strings.Split(en, "|")
	}
	//const
	c := tag.Get("const")
	if c != "" {
		p.Const = c
	}
}

func (p *property) addNumberValidators(tag *reflect.StructTag) {
	m, err := strconv.ParseFloat(tag.Get("multipleOf"), 64)
	if err == nil {
		p.MultipleOf = float64ptr(m)
	}
	m, err = strconv.ParseFloat(tag.Get("min"), 64)
	if err == nil {
		p.Minimum = float64ptr(m)
	}
	m, err = strconv.ParseFloat(tag.Get("max"), 64)
	if err == nil {
		p.Maximum = float64ptr(m)
	}
	m, err = strconv.ParseFloat(tag.Get("exclusiveMin"), 64)
	if err == nil {
		p.ExclusiveMinimum = float64ptr(m)
	}
	m, err = strconv.ParseFloat(tag.Get("exclusiveMax"), 64)
	if err == nil {
		p.ExclusiveMaximum = float64ptr(m)
	}
	c, err := parseType(tag.Get("const"), p.Type)
	if err == nil {
		p.Const = c
	}
}

func parseType(str, ty string) (interface{}, error) {
	var v interface{}
	var err error
	if ty == "number" {
		v, err = strconv.ParseFloat(str, 64)
	} else {
		v, err = strconv.ParseInt(str, 10, 64)
	}
	return v, err
}

var formatMapping = map[string][]string{
	"time.Time": []string{"string", "date-time"},
}

var kindMapping = map[reflect.Kind]string{
	reflect.Bool:    "boolean",
	reflect.Int:     "integer",
	reflect.Int8:    "integer",
	reflect.Int16:   "integer",
	reflect.Int32:   "integer",
	reflect.Int64:   "integer",
	reflect.Uint:    "integer",
	reflect.Uint8:   "integer",
	reflect.Uint16:  "integer",
	reflect.Uint32:  "integer",
	reflect.Uint64:  "integer",
	reflect.Float32: "number",
	reflect.Float64: "number",
	reflect.String:  "string",
	reflect.Slice:   "array",
	reflect.Struct:  "object",
	reflect.Map:     "object",
}

func isPrimitive(k reflect.Kind) bool {
	if v, ok := kindMapping[k]; ok {
		switch v {
		case "boolean":
		case "integer":
		case "number":
		case "string":
			return true
		}
	}
	return false
}

func getTypeFromMapping(t reflect.Type) (string, string, reflect.Kind) {
	if v, ok := formatMapping[t.String()]; ok {
		return v[0], v[1], reflect.String
	}

	if v, ok := kindMapping[t.Kind()]; ok {
		return v, "", t.Kind()
	}

	return "", "", t.Kind()
}

type structTag string

func parseTag(tag string) (string, structTag) {
	if idx := strings.Index(tag, ","); idx != -1 {
		return tag[:idx], structTag(tag[idx+1:])
	}
	return tag, structTag("")
}

func (o structTag) Contains(optionName string) bool {
	if len(o) == 0 {
		return false
	}

	s := string(o)
	for s != "" {
		var next string
		i := strings.Index(s, ",")
		if i >= 0 {
			s, next = s[:i], s[i+1:]
		}
		if s == optionName {
			return true
		}
		s = next
	}
	return false
}

var _ fmt.Stringer = (*Document)(nil)
<|endoftext|>


<commit_before>package jsval

import (
	"bytes"
	"fmt"
	"go/format"
	"io"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"unicode"
)

// Generator is responsible for generating Go code that
// sets up a validator
type Generator struct{}

// NewGenerator creates a new Generator
func NewGenerator() *Generator {
	return &Generator{}
}

// Process takes a validator and prints out Go code to out.
func (g *Generator) Process(out io.Writer, validators ...*JSVal) error {
	ctx := genctx{
		pkgname:  "jsval",
		refnames: make(map[string]string),
		vname:    "V",
	}

	buf := bytes.Buffer{}

	// First get all of the references so we can refer to it later
	refs := map[string]Constraint{}
	refnames := []string{}
	for i, v := range validators {
		for rname, rc := range v.refs {
			if _, ok := refs[rname]; ok {
				continue
			}
			refs[rname] = rc
			refnames = append(refnames, rname)
		}

		if v.Name == "" {
			v.Name = fmt.Sprintf("V%d", i)
		}

		fmt.Fprintf(&buf, "\nvar %s *%s.JSVal", v.Name, ctx.pkgname)
	}

	ctx.refs = refs
	if len(refs) > 0 { // have refs
		ctx.cmname = "M"
		// sort them by reference name
		sort.Strings(refnames)
		fmt.Fprintf(&buf, "\nvar %s *%s.ConstraintMap", ctx.cmname, ctx.pkgname)

		// Generate reference constraint names
		for i, rname := range refnames {
			vname := fmt.Sprintf("R%d", i)
			ctx.refnames[rname] = vname
			fmt.Fprintf(&buf, "\nvar %s %s.Constraint", vname, ctx.pkgname)
		}
	}

	fmt.Fprintf(&buf, "\nfunc init() {")
	if len(refs) > 0 {
		fmt.Fprintf(&buf, "\n%s = &%s.ConstraintMap{}", ctx.cmname, ctx.pkgname)
		// Now generate code for references
		for _, rname := range refnames {
			fmt.Fprintf(&buf, "\n%s = ", ctx.refnames[rname])
			rbuf := bytes.Buffer{}
			if err := generateCode(&ctx, &rbuf, ctx.refs[rname]); err != nil {
				return err
			}
			// Remove indentation here
			rs := rbuf.String()
			for i, r := range rs {
				if !unicode.IsSpace(r) {
					rs = rs[i:]
					break
				}
			}
			fmt.Fprint(&buf, rs)
		}

		for _, rname := range refnames {
			fmt.Fprintf(&buf, "\n%s.SetReference(`%s`, %s)", ctx.cmname, rname, ctx.refnames[rname])
		}
	}

	// Now dump the validators
	for _, v := range validators {
		fmt.Fprintf(&buf, "\n%s = ", v.Name)
		if err := generateCode(&ctx, &buf, v); err != nil {
			return err
		}
	}
	fmt.Fprintf(&buf, "\n}")

	fsrc, err := format.Source(buf.Bytes())
	if err != nil {
		return err
	}
	out.Write(fsrc)
	return nil
}

type genctx struct {
	cmname   string
	pkgname  string
	refs     map[string]Constraint
	refnames map[string]string
	vname    string
}

func generateNilCode(ctx *genctx, out io.Writer, c emptyConstraint) error {
	fmt.Fprintf(out, "%s.EmptyConstraint", ctx.pkgname)
	return nil
}
func generateValidatorCode(ctx *genctx, out io.Writer, v *JSVal) error {
	found := false
	fmt.Fprintf(out, "%s.New()", ctx.pkgname)

	if cmname := ctx.cmname; cmname != "" {
		fmt.Fprintf(out, ".\nSsetConstraintMap(%s)", cmname)
	}

	for rname, rc := range ctx.refs {
		if v.root == rc {
			fmt.Fprintf(out, ".\nSetRoot(%s)", ctx.refnames[rname])
			found = true
			break
		}
	}

	if !found {
		fmt.Fprint(out, ".\nSetRoot(\n")
		if err := generateCode(ctx, out, v.root); err != nil {
			return err
		}
		fmt.Fprint(out, ",\n)\n")
	}

	return nil
}

func generateCode(ctx *genctx, out io.Writer, c interface {
	Validate(interface{}) error
}) error {
	buf := &bytes.Buffer{}

	switch c.(type) {
	case emptyConstraint:
		if err := generateNilCode(ctx, buf, c.(emptyConstraint)); err != nil {
			return err
		}
	case *JSVal:
		if err := generateValidatorCode(ctx, buf, c.(*JSVal)); err != nil {
			return err
		}
	case *AnyConstraint:
		if err := generateAnyCode(ctx, buf, c.(*AnyConstraint)); err != nil {
			return err
		}
	case *AllConstraint:
		if err := generateAllCode(ctx, buf, c.(*AllConstraint)); err != nil {
			return err
		}
	case *ArrayConstraint:
		if err := generateArrayCode(ctx, buf, c.(*ArrayConstraint)); err != nil {
			return err
		}
	case *BooleanConstraint:
		if err := generateBooleanCode(ctx, buf, c.(*BooleanConstraint)); err != nil {
			return err
		}
	case *IntegerConstraint:
		if err := generateIntegerCode(ctx, buf, c.(*IntegerConstraint)); err != nil {
			return err
		}
	case *NotConstraint:
		if err := generateNotCode(ctx, buf, c.(*NotConstraint)); err != nil {
			return err
		}
	case *NumberConstraint:
		if err := generateNumberCode(ctx, buf, c.(*NumberConstraint)); err != nil {
			return err
		}
	case *ObjectConstraint:
		if err := generateObjectCode(ctx, buf, c.(*ObjectConstraint)); err != nil {
			return err
		}
	case *OneOfConstraint:
		if err := generateOneOfCode(ctx, buf, c.(*OneOfConstraint)); err != nil {
			return err
		}
	case *ReferenceConstraint:
		if err := generateReferenceCode(ctx, buf, c.(*ReferenceConstraint)); err != nil {
			return err
		}
	case *StringConstraint:
		if err := generateStringCode(ctx, buf, c.(*StringConstraint)); err != nil {
			return err
		}
	}

	s := buf.String()
	s = strings.TrimSuffix(s, ".\n")
	fmt.Fprintf(out, s)

	return nil
}

func generateReferenceCode(ctx *genctx, out io.Writer, c *ReferenceConstraint) error {
	fmt.Fprintf(out, "%s.Reference(%s).RefersTo(`%s`)", ctx.pkgname, ctx.cmname, c.reference)

	return nil
}

func generateComboCode(ctx *genctx, out io.Writer, name string, clist []Constraint) error {
	if len(clist) == 0 {
		return generateNilCode(ctx, out, EmptyConstraint)
	}
	fmt.Fprintf(out, "%s.%s()", ctx.pkgname, name)
	for _, c1 := range clist {
		fmt.Fprint(out, ".\nAdd(\n")
		if err := generateCode(ctx, out, c1); err != nil {
			return err
		}
		fmt.Fprint(out, ",\n)")
	}
	return nil
}

func generateAnyCode(ctx *genctx, out io.Writer, c *AnyConstraint) error {
	return generateComboCode(ctx, out, "Any", c.constraints)
}

func generateAllCode(ctx *genctx, out io.Writer, c *AllConstraint) error {
	return generateComboCode(ctx, out, "All", c.constraints)
}

func generateOneOfCode(ctx *genctx, out io.Writer, c *OneOfConstraint) error {
	return generateComboCode(ctx, out, "OneOf", c.constraints)
}

func generateIntegerCode(ctx *genctx, out io.Writer, c *IntegerConstraint) error {
	fmt.Fprintf(out, "%s.Integer()", ctx.pkgname)

	if c.applyMinimum {
		fmt.Fprintf(out, ".Minimum(%d)", int(c.minimum))
	}

	if c.applyMaximum {
		fmt.Fprintf(out, ".Maximum(%d)", int(c.maximum))
	}

	return nil
}

func generateNumberCode(ctx *genctx, out io.Writer, c *NumberConstraint) error {
	fmt.Fprintf(out, "%s.Number()", ctx.pkgname)

	if c.applyMinimum {
		fmt.Fprintf(out, ".Minimum(%f)", c.minimum)
	}

	if c.exclusiveMinimum {
		fmt.Fprintf(out, ".ExclusiveMinimum(true)")
	}

	if c.applyMaximum {
		fmt.Fprintf(out, ".Maximum(%f)", c.maximum)
	}

	if c.exclusiveMaximum {
		fmt.Fprintf(out, ".ExclusiveMaximum(true)")
	}

	if c.HasDefault() {
		fmt.Fprintf(out, ".Default(%f)", c.DefaultValue())
	}

	return nil
}

func generateEnumCode(ctx *genctx, out io.Writer, c *EnumConstraint) error {
	fmt.Fprintf(out, "[]interface{}{")
	l := len(c.enums)
	for i, v := range c.enums {
		rv := reflect.ValueOf(v)
		switch rv.Kind() {
		case reflect.String:
			fmt.Fprintf(out, "%s", strconv.Quote(rv.String()))
		}
		if i < l-1 {
			fmt.Fprintf(out, ", ")
		}
	}
	fmt.Fprintf(out, "}")

	return nil
}

func generateStringCode(ctx *genctx, out io.Writer, c *StringConstraint) error {
	fmt.Fprintf(out, "%s.String()", ctx.pkgname)

	if c.maxLength > -1 {
		fmt.Fprintf(out, ".MaxLength(%d)", c.maxLength)
	}

	if c.minLength > 0 {
		fmt.Fprintf(out, ".MinLength(%d)", c.minLength)
	}

	if f := c.format; f != "" {
		fmt.Fprintf(out, ".Format(%s)", strconv.Quote(string(f)))
	}

	if rx := c.regexp; rx != nil {
		fmt.Fprintf(out, ".Regexp(`%s`)", rx.String())
	}

	if enum := c.enums; enum != nil {
		fmt.Fprintf(out, ".Enum(")
		if err := generateEnumCode(ctx, out, enum); err != nil {
			return err
		}
		fmt.Fprintf(out, ",)")
	}

	return nil
}

func generateObjectCode(ctx *genctx, out io.Writer, c *ObjectConstraint) error {
	fmt.Fprintf(out, "%s.Object()", ctx.pkgname)

	if c.HasDefault() {
		fmt.Fprintf(out, ".\nDefault(%s)", c.DefaultValue())
	}

	if len(c.required) > 0 {
		fmt.Fprint(out, ".\nRequired([]string{")
		l := len(c.required)
		pnames := make([]string, 0, l)
		for pname := range c.required {
			pnames = append(pnames, pname)
		}
		sort.Strings(pnames)
		for i, pname := range pnames {
			fmt.Fprint(out, strconv.Quote(pname))
			if i < l-1 {
				fmt.Fprint(out, ", ")
			}
		}
		fmt.Fprint(out, "})")
	}

	if aprop := c.additionalProperties; aprop != nil {
		fmt.Fprintf(out, ".\nAdditionalProperties(\n")
		if err := generateCode(ctx, out, aprop); err != nil {
			return err
		}
		fmt.Fprintf(out, ",\n)")
	}

	pnames := make([]string, 0, len(c.properties))
	for pname := range c.properties {
		pnames = append(pnames, pname)
	}
	sort.Strings(pnames)

	for _, pname := range pnames {
		pdef := c.properties[pname]

		fmt.Fprintf(out, ".\nAddProp(\n`%s`,\n", pname)
		if err := generateCode(ctx, out, pdef); err != nil {
			return err
		}
		fmt.Fprint(out, ",\n)")
	}

	if m := c.propdeps; len(m) > 0 {
		for from, deplist := range m {
			for _, to := range deplist {
				fmt.Fprintf(out, ".\nPropDependency(%s, %s)", strconv.Quote(from), strconv.Quote(to))
			}
		}
	}

	return nil
}

func generateArrayCode(ctx *genctx, out io.Writer, c *ArrayConstraint) error {
	fmt.Fprintf(out, "%s.Array()", ctx.pkgname)

	if cc := c.items; cc != nil {
		fmt.Fprint(out, ".\nItems(\n")
		if err := generateCode(ctx, out, cc); err != nil {
			return err
		}
		fmt.Fprint(out, ",\n)")
	}

	if cc := c.additionalItems; cc != nil {
		fmt.Fprint(out, ".\nAdditionalItems(\n")
		if err := generateCode(ctx, out, cc); err != nil {
			return err
		}
		fmt.Fprintf(out, ",\n)")
	}

	if cc := c.positionalItems; len(cc) > 0 {
		fmt.Fprintf(out, ".\nPositionalItems([]%s.Constraint{\n", ctx.pkgname)
		for _, ccc := range cc {
			if err := generateCode(ctx, out, ccc); err != nil {
			}
			fmt.Fprintf(out, ",\n")
		}
		fmt.Fprint(out, "})")
	}
	if c.minItems > -1 {
		fmt.Fprintf(out, ".\nMinItems(%d)", c.minItems)
	}
	if c.maxItems > -1 {
		fmt.Fprintf(out, ".\nMaxItems(%d)", c.maxItems)
	}
	if c.uniqueItems {
		fmt.Fprint(out, ".\nUniqueItems(true)")
	}
	return nil
}

func generateBooleanCode(ctx *genctx, out io.Writer, c *BooleanConstraint) error {
	fmt.Fprintf(out, "%s.Boolean()", ctx.pkgname)
	if c.HasDefault() {
		fmt.Fprintf(out, ".Default(%t)", c.DefaultValue())
	}
	return nil
}

func generateNotCode(ctx *genctx, out io.Writer, c *NotConstraint) error {
	fmt.Fprintf(out, "%s.Not(\n", ctx.pkgname)
	if err := generateCode(ctx, out, c.child); err != nil {
		return err
	}
	fmt.Fprint(out, "\n)")
	return nil
}
<commit_msg>s/Regexp/RegexpString/<commit_after>package jsval

import (
	"bytes"
	"fmt"
	"go/format"
	"io"
	"reflect"
	"sort"
	"strconv"
	"strings"
	"unicode"
)

// Generator is responsible for generating Go code that
// sets up a validator
type Generator struct{}

// NewGenerator creates a new Generator
func NewGenerator() *Generator {
	return &Generator{}
}

// Process takes a validator and prints out Go code to out.
func (g *Generator) Process(out io.Writer, validators ...*JSVal) error {
	ctx := genctx{
		pkgname:  "jsval",
		refnames: make(map[string]string),
		vname:    "V",
	}

	buf := bytes.Buffer{}

	// First get all of the references so we can refer to it later
	refs := map[string]Constraint{}
	refnames := []string{}
	for i, v := range validators {
		for rname, rc := range v.refs {
			if _, ok := refs[rname]; ok {
				continue
			}
			refs[rname] = rc
			refnames = append(refnames, rname)
		}

		if v.Name == "" {
			v.Name = fmt.Sprintf("V%d", i)
		}

		fmt.Fprintf(&buf, "\nvar %s *%s.JSVal", v.Name, ctx.pkgname)
	}

	ctx.refs = refs
	if len(refs) > 0 { // have refs
		ctx.cmname = "M"
		// sort them by reference name
		sort.Strings(refnames)
		fmt.Fprintf(&buf, "\nvar %s *%s.ConstraintMap", ctx.cmname, ctx.pkgname)

		// Generate reference constraint names
		for i, rname := range refnames {
			vname := fmt.Sprintf("R%d", i)
			ctx.refnames[rname] = vname
			fmt.Fprintf(&buf, "\nvar %s %s.Constraint", vname, ctx.pkgname)
		}
	}

	fmt.Fprintf(&buf, "\nfunc init() {")
	if len(refs) > 0 {
		fmt.Fprintf(&buf, "\n%s = &%s.ConstraintMap{}", ctx.cmname, ctx.pkgname)
		// Now generate code for references
		for _, rname := range refnames {
			fmt.Fprintf(&buf, "\n%s = ", ctx.refnames[rname])
			rbuf := bytes.Buffer{}
			if err := generateCode(&ctx, &rbuf, ctx.refs[rname]); err != nil {
				return err
			}
			// Remove indentation here
			rs := rbuf.String()
			for i, r := range rs {
				if !unicode.IsSpace(r) {
					rs = rs[i:]
					break
				}
			}
			fmt.Fprint(&buf, rs)
		}

		for _, rname := range refnames {
			fmt.Fprintf(&buf, "\n%s.SetReference(`%s`, %s)", ctx.cmname, rname, ctx.refnames[rname])
		}
	}

	// Now dump the validators
	for _, v := range validators {
		fmt.Fprintf(&buf, "\n%s = ", v.Name)
		if err := generateCode(&ctx, &buf, v); err != nil {
			return err
		}
	}
	fmt.Fprintf(&buf, "\n}")

	fsrc, err := format.Source(buf.Bytes())
	if err != nil {
		return err
	}
	out.Write(fsrc)
	return nil
}

type genctx struct {
	cmname   string
	pkgname  string
	refs     map[string]Constraint
	refnames map[string]string
	vname    string
}

func generateNilCode(ctx *genctx, out io.Writer, c emptyConstraint) error {
	fmt.Fprintf(out, "%s.EmptyConstraint", ctx.pkgname)
	return nil
}
func generateValidatorCode(ctx *genctx, out io.Writer, v *JSVal) error {
	found := false
	fmt.Fprintf(out, "%s.New()", ctx.pkgname)

	if cmname := ctx.cmname; cmname != "" {
		fmt.Fprintf(out, ".\nSsetConstraintMap(%s)", cmname)
	}

	for rname, rc := range ctx.refs {
		if v.root == rc {
			fmt.Fprintf(out, ".\nSetRoot(%s)", ctx.refnames[rname])
			found = true
			break
		}
	}

	if !found {
		fmt.Fprint(out, ".\nSetRoot(\n")
		if err := generateCode(ctx, out, v.root); err != nil {
			return err
		}
		fmt.Fprint(out, ",\n)\n")
	}

	return nil
}

func generateCode(ctx *genctx, out io.Writer, c interface {
	Validate(interface{}) error
}) error {
	buf := &bytes.Buffer{}

	switch c.(type) {
	case emptyConstraint:
		if err := generateNilCode(ctx, buf, c.(emptyConstraint)); err != nil {
			return err
		}
	case *JSVal:
		if err := generateValidatorCode(ctx, buf, c.(*JSVal)); err != nil {
			return err
		}
	case *AnyConstraint:
		if err := generateAnyCode(ctx, buf, c.(*AnyConstraint)); err != nil {
			return err
		}
	case *AllConstraint:
		if err := generateAllCode(ctx, buf, c.(*AllConstraint)); err != nil {
			return err
		}
	case *ArrayConstraint:
		if err := generateArrayCode(ctx, buf, c.(*ArrayConstraint)); err != nil {
			return err
		}
	case *BooleanConstraint:
		if err := generateBooleanCode(ctx, buf, c.(*BooleanConstraint)); err != nil {
			return err
		}
	case *IntegerConstraint:
		if err := generateIntegerCode(ctx, buf, c.(*IntegerConstraint)); err != nil {
			return err
		}
	case *NotConstraint:
		if err := generateNotCode(ctx, buf, c.(*NotConstraint)); err != nil {
			return err
		}
	case *NumberConstraint:
		if err := generateNumberCode(ctx, buf, c.(*NumberConstraint)); err != nil {
			return err
		}
	case *ObjectConstraint:
		if err := generateObjectCode(ctx, buf, c.(*ObjectConstraint)); err != nil {
			return err
		}
	case *OneOfConstraint:
		if err := generateOneOfCode(ctx, buf, c.(*OneOfConstraint)); err != nil {
			return err
		}
	case *ReferenceConstraint:
		if err := generateReferenceCode(ctx, buf, c.(*ReferenceConstraint)); err != nil {
			return err
		}
	case *StringConstraint:
		if err := generateStringCode(ctx, buf, c.(*StringConstraint)); err != nil {
			return err
		}
	}

	s := buf.String()
	s = strings.TrimSuffix(s, ".\n")
	fmt.Fprintf(out, s)

	return nil
}

func generateReferenceCode(ctx *genctx, out io.Writer, c *ReferenceConstraint) error {
	fmt.Fprintf(out, "%s.Reference(%s).RefersTo(`%s`)", ctx.pkgname, ctx.cmname, c.reference)

	return nil
}

func generateComboCode(ctx *genctx, out io.Writer, name string, clist []Constraint) error {
	if len(clist) == 0 {
		return generateNilCode(ctx, out, EmptyConstraint)
	}
	fmt.Fprintf(out, "%s.%s()", ctx.pkgname, name)
	for _, c1 := range clist {
		fmt.Fprint(out, ".\nAdd(\n")
		if err := generateCode(ctx, out, c1); err != nil {
			return err
		}
		fmt.Fprint(out, ",\n)")
	}
	return nil
}

func generateAnyCode(ctx *genctx, out io.Writer, c *AnyConstraint) error {
	return generateComboCode(ctx, out, "Any", c.constraints)
}

func generateAllCode(ctx *genctx, out io.Writer, c *AllConstraint) error {
	return generateComboCode(ctx, out, "All", c.constraints)
}

func generateOneOfCode(ctx *genctx, out io.Writer, c *OneOfConstraint) error {
	return generateComboCode(ctx, out, "OneOf", c.constraints)
}

func generateIntegerCode(ctx *genctx, out io.Writer, c *IntegerConstraint) error {
	fmt.Fprintf(out, "%s.Integer()", ctx.pkgname)

	if c.applyMinimum {
		fmt.Fprintf(out, ".Minimum(%d)", int(c.minimum))
	}

	if c.applyMaximum {
		fmt.Fprintf(out, ".Maximum(%d)", int(c.maximum))
	}

	return nil
}

func generateNumberCode(ctx *genctx, out io.Writer, c *NumberConstraint) error {
	fmt.Fprintf(out, "%s.Number()", ctx.pkgname)

	if c.applyMinimum {
		fmt.Fprintf(out, ".Minimum(%f)", c.minimum)
	}

	if c.exclusiveMinimum {
		fmt.Fprintf(out, ".ExclusiveMinimum(true)")
	}

	if c.applyMaximum {
		fmt.Fprintf(out, ".Maximum(%f)", c.maximum)
	}

	if c.exclusiveMaximum {
		fmt.Fprintf(out, ".ExclusiveMaximum(true)")
	}

	if c.HasDefault() {
		fmt.Fprintf(out, ".Default(%f)", c.DefaultValue())
	}

	return nil
}

func generateEnumCode(ctx *genctx, out io.Writer, c *EnumConstraint) error {
	fmt.Fprintf(out, "[]interface{}{")
	l := len(c.enums)
	for i, v := range c.enums {
		rv := reflect.ValueOf(v)
		switch rv.Kind() {
		case reflect.String:
			fmt.Fprintf(out, "%s", strconv.Quote(rv.String()))
		}
		if i < l-1 {
			fmt.Fprintf(out, ", ")
		}
	}
	fmt.Fprintf(out, "}")

	return nil
}

func generateStringCode(ctx *genctx, out io.Writer, c *StringConstraint) error {
	fmt.Fprintf(out, "%s.String()", ctx.pkgname)

	if c.maxLength > -1 {
		fmt.Fprintf(out, ".MaxLength(%d)", c.maxLength)
	}

	if c.minLength > 0 {
		fmt.Fprintf(out, ".MinLength(%d)", c.minLength)
	}

	if f := c.format; f != "" {
		fmt.Fprintf(out, ".Format(%s)", strconv.Quote(string(f)))
	}

	if rx := c.regexp; rx != nil {
		fmt.Fprintf(out, ".RegexpString(`%s`)", rx.String())
	}

	if enum := c.enums; enum != nil {
		fmt.Fprintf(out, ".Enum(")
		if err := generateEnumCode(ctx, out, enum); err != nil {
			return err
		}
		fmt.Fprintf(out, ",)")
	}

	return nil
}

func generateObjectCode(ctx *genctx, out io.Writer, c *ObjectConstraint) error {
	fmt.Fprintf(out, "%s.Object()", ctx.pkgname)

	if c.HasDefault() {
		fmt.Fprintf(out, ".\nDefault(%s)", c.DefaultValue())
	}

	if len(c.required) > 0 {
		fmt.Fprint(out, ".\nRequired([]string{")
		l := len(c.required)
		pnames := make([]string, 0, l)
		for pname := range c.required {
			pnames = append(pnames, pname)
		}
		sort.Strings(pnames)
		for i, pname := range pnames {
			fmt.Fprint(out, strconv.Quote(pname))
			if i < l-1 {
				fmt.Fprint(out, ", ")
			}
		}
		fmt.Fprint(out, "})")
	}

	if aprop := c.additionalProperties; aprop != nil {
		fmt.Fprintf(out, ".\nAdditionalProperties(\n")
		if err := generateCode(ctx, out, aprop); err != nil {
			return err
		}
		fmt.Fprintf(out, ",\n)")
	}

	pnames := make([]string, 0, len(c.properties))
	for pname := range c.properties {
		pnames = append(pnames, pname)
	}
	sort.Strings(pnames)

	for _, pname := range pnames {
		pdef := c.properties[pname]

		fmt.Fprintf(out, ".\nAddProp(\n`%s`,\n", pname)
		if err := generateCode(ctx, out, pdef); err != nil {
			return err
		}
		fmt.Fprint(out, ",\n)")
	}

	if m := c.propdeps; len(m) > 0 {
		for from, deplist := range m {
			for _, to := range deplist {
				fmt.Fprintf(out, ".\nPropDependency(%s, %s)", strconv.Quote(from), strconv.Quote(to))
			}
		}
	}

	return nil
}

func generateArrayCode(ctx *genctx, out io.Writer, c *ArrayConstraint) error {
	fmt.Fprintf(out, "%s.Array()", ctx.pkgname)

	if cc := c.items; cc != nil {
		fmt.Fprint(out, ".\nItems(\n")
		if err := generateCode(ctx, out, cc); err != nil {
			return err
		}
		fmt.Fprint(out, ",\n)")
	}

	if cc := c.additionalItems; cc != nil {
		fmt.Fprint(out, ".\nAdditionalItems(\n")
		if err := generateCode(ctx, out, cc); err != nil {
			return err
		}
		fmt.Fprintf(out, ",\n)")
	}

	if cc := c.positionalItems; len(cc) > 0 {
		fmt.Fprintf(out, ".\nPositionalItems([]%s.Constraint{\n", ctx.pkgname)
		for _, ccc := range cc {
			if err := generateCode(ctx, out, ccc); err != nil {
			}
			fmt.Fprintf(out, ",\n")
		}
		fmt.Fprint(out, "})")
	}
	if c.minItems > -1 {
		fmt.Fprintf(out, ".\nMinItems(%d)", c.minItems)
	}
	if c.maxItems > -1 {
		fmt.Fprintf(out, ".\nMaxItems(%d)", c.maxItems)
	}
	if c.uniqueItems {
		fmt.Fprint(out, ".\nUniqueItems(true)")
	}
	return nil
}

func generateBooleanCode(ctx *genctx, out io.Writer, c *BooleanConstraint) error {
	fmt.Fprintf(out, "%s.Boolean()", ctx.pkgname)
	if c.HasDefault() {
		fmt.Fprintf(out, ".Default(%t)", c.DefaultValue())
	}
	return nil
}

func generateNotCode(ctx *genctx, out io.Writer, c *NotConstraint) error {
	fmt.Fprintf(out, "%s.Not(\n", ctx.pkgname)
	if err := generateCode(ctx, out, c.child); err != nil {
		return err
	}
	fmt.Fprint(out, "\n)")
	return nil
}
<|endoftext|>