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

package cmd

import (
	"encoding/json"
	"log"
	"net/http"
	"time"

	"github.com/Mirantis/northshore/blueprint"
	"github.com/Mirantis/northshore/fsm"
	"github.com/Mirantis/northshore/server"
	"github.com/gorilla/mux"
	"github.com/satori/go.uuid"
	"github.com/spf13/cobra"
)

var demoBlueprintPath string
var demoBp blueprint.BP

// demoBlueprintCmd represents the "demo-blueprint" command
var demoBlueprintCmd = &cobra.Command{
	Use:   "demo-blueprint",
	Short: "Run execution of blueprint",
	Long:  `This command read, parse and process blueprint.`,
	Run: func(cmd *cobra.Command, args []string) {
		log.Println("Run Blueprint")
		log.Printf("PATH -> %s", demoBlueprintPath)
		bp, err := blueprint.ParseBlueprint(demoBlueprintPath)
		if err != nil {
			log.Fatalf("Parsing error: %s", err)
		}
		log.Printf("BLUEPRINT -> %+v", bp)
	},
}

// demoFSMCmd represents the "demo-fsm" command
var demoFSMCmd = &cobra.Command{
	Use:   "demo-fsm",
	Short: "Demo FSM",
	Long:  `Run the Blueprint Pipeline thru states`,
	Run: func(cmd *cobra.Command, args []string) {

		stages := []string{"Stage A", "Stage B"}
		pl := fsm.NewBlueprintPipeline(stages)

		pl.Start()
		pl.Update(map[string]fsm.StageState{"Stage B": fsm.StageStateRunning})
		pl.Update(map[string]fsm.StageState{"Stage A": fsm.StageStateRunning, "Stage B": fsm.StageStatePaused})
		pl.Update(map[string]fsm.StageState{"Stage B": fsm.StageStateRunning})

	},
}

// demoCmd represents the "demo" command
var demoCmd = &cobra.Command{
	Use:   "demo",
	Short: "Run demo",
	Long: `Run demo on local server.

The local server binds localhost:8998.
Demo Blueprint Pipeline goes thru states.`,
	Run: func(cmd *cobra.Command, args []string) {

		/* Run Blueprint */
		log.Println("#run_blueprint")
		log.Printf("PATH -> %s \n", demoBlueprintPath)
		bp, err := blueprint.ParseBlueprint(demoBlueprintPath)
		if err != nil {
			log.Printf("Parsing error: %s \n", err)
			return
		}
		log.Printf("BLUEPRINT -> %+v \n", bp)

		/* Run States */
		log.Println("#run_states")
		var stages []string
		for k := range bp.Stages {
			stages = append(stages, k)
		}

		ss := []map[string]fsm.StageState{
			{stages[0]: fsm.StageStatePaused},
			{stages[0]: fsm.StageStateRunning, stages[1]: fsm.StageStatePaused},
			{stages[1]: fsm.StageStateRunning},
		}

		go func() {
			uuid := uuid.NewV4()
			for {
				pl := fsm.NewBlueprintPipeline(stages)
				demoBp = blueprint.BP{&bp, pl, uuid}
				demoBp.Start()

				time.Sleep(time.Second * 9)

				for _, s := range stages {
					time.Sleep(time.Second * 3)
					v := map[string]fsm.StageState{s: fsm.StageStateCreated}
					log.Println("#pl-update", v)
					demoBp.Update(v)
				}
				for _, s := range stages {
					time.Sleep(time.Second * 3)
					v := map[string]fsm.StageState{s: fsm.StageStateRunning}
					log.Println("#pl-update", v)
					demoBp.Update(v)
				}
				for _, v := range ss {
					time.Sleep(time.Second * 3)
					log.Println("#pl-update", v)
					demoBp.Update(v)
				}
			}
		}()

		/* Run local server */
		log.Println("#run_local_server")
		r := mux.NewRouter()

		uiAPI1 := r.PathPrefix("/ui/api/v1").Subrouter().StrictSlash(true)
		uiAPI1.HandleFunc("/", server.UIAPI1RootHandler).Methods("GET")

		uiAPI1.HandleFunc("/action", demouiAPI1ActionHandler).Methods("GET", "POST")
		uiAPI1.HandleFunc("/blueprints", demouiAPI1BlueprintsHandler).Methods("GET", "POST")
		uiAPI1.HandleFunc("/errors", demouiAPI1ErrorsHandler).Methods("GET", "POST")

		ui := r.PathPrefix("/ui").Subrouter().StrictSlash(true)
		ui.PathPrefix("/{uiDir:(app)|(assets)|(node_modules)}").Handler(http.StripPrefix("/ui", server.NoDirListing(http.FileServer(http.Dir("ui/")))))
		ui.HandleFunc("/{_:.*}", server.UIIndexHandler)

		r.HandleFunc("/{_:.*}", server.UIIndexHandler)

		log.Println("Listening at port 8998")
		http.ListenAndServe(":8998", r)

	},
}

func init() {
	demoBlueprintCmd.Flags().StringVarP(&demoBlueprintPath, "file", "f", "", "Path to blueprint yaml")
	demoCmd.Flags().StringVarP(&demoBlueprintPath, "file", "f", "", "Path to blueprint yaml")
	runCmd.AddCommand(demoBlueprintCmd)
	runCmd.AddCommand(demoFSMCmd)
	runCmd.AddCommand(demoCmd)
}

func demouiAPI1ActionHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/vnd.api+json")

	o := map[string]interface{}{
		"data": []map[string]interface{}{
			{"details": "Details 1"},
			{"details": "Details 2"},
		},
		"meta": map[string]interface{}{
			"info": "demouiAPI1ActionHandler",
		},
	}

	json.NewEncoder(w).Encode(o)
}

func demouiAPI1BlueprintsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/vnd.api+json")

	o := map[string]interface{}{
		"data": []blueprint.BP{
			demoBp,
		},
		"meta": map[string]interface{}{
			"info": "demouiAPI1BlueprintsHandler",
		},
	}

	json.NewEncoder(w).Encode(o)
}

func demouiAPI1ErrorsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.WriteHeader(500)

	o := map[string]interface{}{
		"data": []map[string]interface{}{},
		"errors": []map[string]interface{}{
			{
				"details": "Error details 1",
				"title":   "Error title 1",
			},
			{
				"details": "Details of Error 2",
				"meta": map[string]interface{}{
					"info": "meta info of Error 2",
				},
			},
		},
		"meta": map[string]interface{}{
			"info": "demouiAPI1ErrorsHandler",
		},
	}

	json.NewEncoder(w).Encode(o)
}
<commit_msg>[db] Demo Store / Load BPs<commit_after>// Copyright 2016 The NorthShore Authors All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
	"encoding/json"
	"log"
	"net/http"
	"os"
	"time"

	"github.com/Mirantis/northshore/blueprint"
	"github.com/Mirantis/northshore/fsm"
	"github.com/Mirantis/northshore/server"
	"github.com/boltdb/bolt"
	"github.com/gorilla/mux"
	"github.com/satori/go.uuid"
	"github.com/spf13/cobra"
)

type demoStore struct {
	db *bolt.DB
}

const dbBucketBlueprints = "blueprints"

var (
	demoBlueprintPath string
	store             demoStore
)

// demoBlueprintCmd represents the "demo-blueprint" command
var demoBlueprintCmd = &cobra.Command{
	Use:   "demo-blueprint",
	Short: "Run execution of blueprint",
	Long:  `This command read, parse and process blueprint.`,
	Run: func(cmd *cobra.Command, args []string) {
		log.Println("Run Blueprint")
		log.Printf("PATH -> %s", demoBlueprintPath)
		bp, err := blueprint.ParseBlueprint(demoBlueprintPath)
		if err != nil {
			log.Fatalf("Parsing error: %s", err)
		}
		log.Printf("BLUEPRINT -> %+v", bp)
	},
}

// demoFSMCmd represents the "demo-fsm" command
var demoFSMCmd = &cobra.Command{
	Use:   "demo-fsm",
	Short: "Demo FSM",
	Long:  `Run the Blueprint Pipeline thru states`,
	Run: func(cmd *cobra.Command, args []string) {

		stages := []string{"Stage A", "Stage B"}
		pl := fsm.NewBlueprintPipeline(stages)

		pl.Start()
		pl.Update(map[string]fsm.StageState{"Stage B": fsm.StageStateRunning})
		pl.Update(map[string]fsm.StageState{"Stage A": fsm.StageStateRunning, "Stage B": fsm.StageStatePaused})
		pl.Update(map[string]fsm.StageState{"Stage B": fsm.StageStateRunning})

	},
}

// demoCmd represents the "demo" command
var demoCmd = &cobra.Command{
	Use:   "demo",
	Short: "Run demo",
	Long: `Run demo on local server.

The local server binds localhost:8998.
Demo Blueprint Pipeline goes thru states.`,
	Run: func(cmd *cobra.Command, args []string) {

		/* Init DB */
		db, err := bolt.Open("demo.db", 0600, nil)
		if err != nil {
			log.Fatal(err)
		}
		defer db.Close()
		defer os.Remove(db.Path())

		if err = db.Update(func(tx *bolt.Tx) error {
			_, err = tx.CreateBucketIfNotExists([]byte(dbBucketBlueprints))
			if err != nil {
				return err
			}
			return nil
		}); err != nil {
			log.Fatal(err)
		}
		store = demoStore{db}

		/* Run Blueprint */
		log.Println("#run_blueprint")
		log.Printf("PATH -> %s \n", demoBlueprintPath)
		bp, err := blueprint.ParseBlueprint(demoBlueprintPath)
		if err != nil {
			log.Printf("Parsing error: %s \n", err)
			return
		}
		log.Printf("BLUEPRINT -> %+v \n", bp)

		/* Run States */
		log.Println("#run_states")
		var stages []string
		for k := range bp.Stages {
			stages = append(stages, k)
		}

		ss := []map[string]fsm.StageState{
			{stages[0]: fsm.StageStatePaused},
			{stages[0]: fsm.StageStateRunning, stages[1]: fsm.StageStatePaused},
			{stages[1]: fsm.StageStateRunning},
		}

		go func() {
			uuid := uuid.NewV4()
			for {
				pl := fsm.NewBlueprintPipeline(stages)
				demoBp := blueprint.BP{&bp, pl, uuid}
				demoBp.Start()
				demoBpStore(demoBp)

				time.Sleep(time.Second * 9)

				for _, s := range stages {
					time.Sleep(time.Second * 3)
					v := map[string]fsm.StageState{s: fsm.StageStateCreated}
					log.Println("#pl-update", v)
					demoBp.Update(v)
					demoBpStore(demoBp)
				}
				for _, s := range stages {
					time.Sleep(time.Second * 3)
					v := map[string]fsm.StageState{s: fsm.StageStateRunning}
					log.Println("#pl-update", v)
					demoBp.Update(v)
					demoBpStore(demoBp)
				}
				for _, v := range ss {
					time.Sleep(time.Second * 3)
					log.Println("#pl-update", v)
					demoBp.Update(v)
					demoBpStore(demoBp)
				}
			}
		}()

		/* Run local server */
		log.Println("#run_local_server")
		r := mux.NewRouter()

		uiAPI1 := r.PathPrefix("/ui/api/v1").Subrouter().StrictSlash(true)
		uiAPI1.HandleFunc("/", server.UIAPI1RootHandler).Methods("GET")

		uiAPI1.HandleFunc("/action", demouiAPI1ActionHandler).Methods("GET", "POST")
		uiAPI1.HandleFunc("/blueprints", demouiAPI1BlueprintsHandler).Methods("GET", "POST")
		uiAPI1.HandleFunc("/errors", demouiAPI1ErrorsHandler).Methods("GET", "POST")

		ui := r.PathPrefix("/ui").Subrouter().StrictSlash(true)
		ui.PathPrefix("/{uiDir:(app)|(assets)|(node_modules)}").Handler(http.StripPrefix("/ui", server.NoDirListing(http.FileServer(http.Dir("ui/")))))
		ui.HandleFunc("/{_:.*}", server.UIIndexHandler)

		r.HandleFunc("/{_:.*}", server.UIIndexHandler)

		log.Println("Listening at port 8998")
		http.ListenAndServe(":8998", r)

	},
}

func init() {
	demoBlueprintCmd.Flags().StringVarP(&demoBlueprintPath, "file", "f", "", "Path to blueprint yaml")
	demoCmd.Flags().StringVarP(&demoBlueprintPath, "file", "f", "", "Path to blueprint yaml")
	runCmd.AddCommand(demoBlueprintCmd)
	runCmd.AddCommand(demoFSMCmd)
	runCmd.AddCommand(demoCmd)
}

func demoBpLoadAll() ([]blueprint.BP, error) {
	var bps []blueprint.BP
	err := store.db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(dbBucketBlueprints))
		b.ForEach(func(k, v []byte) error {
			var bp blueprint.BP
			err := json.Unmarshal(v, &bp)
			if err != nil {
				log.Println("#demoBpLoadAll,#Error", err)
			}
			bps = append(bps, bp)
			return nil
		})

		return nil
	})
	return bps, err
}

func demoBpStore(bp blueprint.BP) error {
	err := store.db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(dbBucketBlueprints))
		bpEncoded, err := json.Marshal(bp)
		if err != nil {
			return err
		}
		if err := b.Put([]byte(bp.Name), bpEncoded); err != nil {
			return err
		}
		return nil
	})
	return err
}

func demouiAPI1ActionHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/vnd.api+json")

	o := map[string]interface{}{
		"data": []map[string]interface{}{
			{"details": "Details 1"},
			{"details": "Details 2"},
		},
		"meta": map[string]interface{}{
			"info": "demouiAPI1ActionHandler",
		},
	}

	json.NewEncoder(w).Encode(o)
}

func demouiAPI1BlueprintsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/vnd.api+json")

	var data []map[string]interface{}
	err := store.db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(dbBucketBlueprints))
		b.ForEach(func(k, v []byte) error {
			var item map[string]interface{}
			if err := json.Unmarshal(v, &item); err != nil {
				log.Println("#Error", err)
				return err
			}
			data = append(data, item)
			return nil
		})
		return nil
	})

	o := map[string]interface{}{
		"data": data,
		"meta": map[string]interface{}{
			"info": "demouiAPI1BlueprintsHandler",
		},
	}

	if err != nil {
		o["errors"] = map[string]interface{}{
			"details": err,
		}
	}

	json.NewEncoder(w).Encode(o)
}

func demouiAPI1ErrorsHandler(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "application/vnd.api+json")
	w.WriteHeader(500)

	o := map[string]interface{}{
		"data": []map[string]interface{}{},
		"errors": []map[string]interface{}{
			{
				"details": "Error details 1",
				"title":   "Error title 1",
			},
			{
				"details": "Details of Error 2",
				"meta": map[string]interface{}{
					"info": "meta info of Error 2",
				},
			},
		},
		"meta": map[string]interface{}{
			"info": "demouiAPI1ErrorsHandler",
		},
	}

	json.NewEncoder(w).Encode(o)
}
<|endoftext|>


<commit_before>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"fmt"
	"os"

	"github.com/digitalocean/godo"
	"github.com/jconard3/docore/client"
	"github.com/jconard3/docore/utils"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func init() {
	RootCmd.AddCommand(dropletCmd)
	dropletCmd.AddCommand(listCmd)
	dropletCmd.AddCommand(createCmd)
	dropletCmd.AddCommand(deleteCmd)
	dropletCmd.AddCommand(getCmd)
}

var dropletCmd = &cobra.Command{
	Use:   "droplet",
	Short: "Interface for DigitalOcean Droplets",
	Long: `Droplet subcommand provides droplet-level interface with the
	provided DigitalOcean account.`,
	Run: func(cmd *cobra.Command, args []string) {
		cmd.Help()
	},
}

var listCmd = &cobra.Command{
	Use:   "list",
	Short: "List all droplets",
	Run: func(cmd *cobra.Command, args []string) {
		my_client, _ := client.CreateClient()
		names := ListDroplets(my_client)
		fmt.Println(names)
	},
}

var createCmd = &cobra.Command{
	Use:   "create",
	Short: "Create a droplet",
	Run: func(cmd *cobra.Command, args []string) {
		if !viper.IsSet("ssh_keys") {
			fmt.Println("No ssh_keys specified in config file. Aborting without creating droplet.")
			os.Exit(-1)
		}

		if cmd.Flag("name").Value.String() == "" {
			fmt.Println("No name specified for creating droplet. Aborting without creating droplet.")
			os.Exit(-1)
		}

		c, _ := client.CreateClient()
		CreateDroplet(c, cmd)
	},
}

var deleteCmd = &cobra.Command{
	Use:   "delete <droplet_name>",
	Short: "Delete a droplet",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) < 1 {
			fmt.Println("No name specified for deleting droplet. Aborting without deleting droplet.")
			cmd.Help()
			os.Exit(-1)
		}

		c, _ := client.CreateClient()
		id, err := utils.NameToID(c, cmd.Flag("name").Value.String())
		if err != nil {
			fmt.Println(err)
			fmt.Println("Failed to look up droplet ID with given name.")
			os.Exit(-1)
		}

		prompt := fmt.Sprintf("Are you sure you want to delete droplet %s, ID: %d ?", cmd.Flag("name").Value.String(), id)
		confirmed, err := utils.AskForConfirmation(prompt)
		if confirmed {
			if err := DeleteDroplet(c, id); err != nil {
				fmt.Println(err)
				fmt.Println("Failed to delete droplet.")
				os.Exit(-1)
			}
		}
	},
}

var getCmd = &cobra.Command{
	Use:   "get <droplet_name>",
	Short: "Get full details of a droplet",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) < 1 {
			fmt.Println("No name specified. Aborting")
			cmd.Help()
			os.Exit(-1)
		}

		c, err := client.CreateClient()
		if err != nil {
			fmt.Println(err)
			fmt.Println("Error creating DO client. Aborting")
			os.Exit(-1)
		}

		droplet, err := GetDroplet(c, args[0])
		if err != nil {
			fmt.Println(err)
			fmt.Println("error retrieving droplet. Aborting")
			os.Exit(-1)
		}
		fmt.Println(droplet)
	},
}

func ListDroplets(client godo.Client) []string {
	opt := &godo.ListOptions{
		Page:    1,
		PerPage: 25,
	}
	var dropletNames []string
	droplets, _, _ := client.Droplets.List(opt)
	for _, element := range droplets {
		dropletNames = append(dropletNames, element.Name)
	}
	return dropletNames
}

func CreateDroplet(client godo.Client, cmd *cobra.Command) {
	ssh_keys := viper.GetStringSlice("ssh_keys")
	droplet_keys := make([]godo.DropletCreateSSHKey, len(ssh_keys))
	for i, ssh_key := range ssh_keys {
		droplet_keys[i].Fingerprint = ssh_key
	}

	createRequest := &godo.DropletCreateRequest{
		Name:   cmd.Flag("name").Value.String(),
		Region: cmd.Flag("region").Value.String(),
		Size:   cmd.Flag("size").Value.String(),
		Image: godo.DropletCreateImage{
			Slug: cmd.Flag("image").Value.String(),
		},
		SSHKeys: droplet_keys,
	}

	fmt.Println(createRequest)
	c, _ := utils.AskForConfirmation("Are you sure you want to create this droplet")
	if !c {
		os.Exit(-1)
	}

	droplet, _, err := client.Droplets.Create(createRequest)
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
	fmt.Println("Droplet ", droplet.Name, " created. Currently provisioning...")
}

func DeleteDroplet(client godo.Client, id int) error {
	_, err := client.Droplets.Delete(id)
	return err
}

func GetDroplet(client godo.Client, name string) (*godo.Droplet, error) {
	id, err := utils.NameToID(client, name)
	if err != nil {
		return nil, err
	}

	droplet, _, err := client.Droplets.Get(id)
	return droplet, err
}
<commit_msg>Refactored droplet create to initialize flags.<commit_after>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"fmt"
	"os"

	"github.com/digitalocean/godo"
	"github.com/jconard3/docore/client"
	"github.com/jconard3/docore/utils"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func init() {
	RootCmd.AddCommand(dropletCmd)
	dropletCmd.AddCommand(dropletlistCmd)

	dropletCmd.AddCommand(dropletcreateCmd)
	dropletcreateCmd.Flags().StringP("name", "n", "", "Name of droplet to be created. Required - no default")
	dropletcreateCmd.Flags().StringP("region", "r", "nyc1", "Region of droplet to be created")
	dropletcreateCmd.Flags().StringP("size", "s", "512mb", "RAM size of droplet to be created")
	dropletcreateCmd.Flags().StringP("image", "i", "coreos-stable", "Image of droplet to be created")

	dropletCmd.AddCommand(dropletdeleteCmd)
	dropletCmd.AddCommand(dropletgetCmd)
}

var dropletCmd = &cobra.Command{
	Use:   "droplet",
	Short: "Interface for DigitalOcean Droplets",
	Long: `Droplet subcommand provides droplet-level interface with the
	provided DigitalOcean account.`,
	Run: func(cmd *cobra.Command, args []string) {
		cmd.Help()
	},
}

var dropletlistCmd = &cobra.Command{
	Use:   "list",
	Short: "List all droplets",
	Run: func(cmd *cobra.Command, args []string) {
		c, _ := client.CreateClient()
		names := ListDroplets(c)
		fmt.Println(names)
	},
}

var dropletcreateCmd = &cobra.Command{
	Use:   "create",
	Short: "Create a droplet",
	Run: func(cmd *cobra.Command, args []string) {
		c, _ := client.CreateClient()
		CreateDroplet(c, cmd)
	},
}

var dropletdeleteCmd = &cobra.Command{
	Use:   "delete <droplet_name>",
	Short: "Delete a droplet",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) < 1 {
			fmt.Println("No name specified for deleting droplet. Aborting without deleting droplet.")
			cmd.Help()
			os.Exit(-1)
		}

		c, _ := client.CreateClient()
		id, err := utils.NameToID(c, cmd.Flag("name").Value.String())
		if err != nil {
			fmt.Println(err)
			fmt.Println("Failed to look up droplet ID with given name.")
			os.Exit(-1)
		}

		prompt := fmt.Sprintf("Are you sure you want to delete droplet %s, ID: %d ?", cmd.Flag("name").Value.String(), id)
		confirmed, err := utils.AskForConfirmation(prompt)
		if confirmed {
			if err := DeleteDroplet(c, id); err != nil {
				fmt.Println(err)
				fmt.Println("Failed to delete droplet.")
				os.Exit(-1)
			}
		}
	},
}

var dropletgetCmd = &cobra.Command{
	Use:   "get <droplet_name>",
	Short: "Get full details of a droplet",
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) < 1 {
			fmt.Println("No name specified. Aborting")
			cmd.Help()
			os.Exit(-1)
		}

		c, err := client.CreateClient()
		if err != nil {
			fmt.Println(err)
			fmt.Println("Error creating DO client. Aborting")
			os.Exit(-1)
		}

		droplet, err := GetDroplet(c, args[0])
		if err != nil {
			fmt.Println(err)
			fmt.Println("error retrieving droplet. Aborting")
			os.Exit(-1)
		}
		fmt.Println(droplet)
	},
}

func ListDroplets(client godo.Client) []string {
	opt := &godo.ListOptions{
		Page:    1,
		PerPage: 25,
	}
	var dropletNames []string
	droplets, _, _ := client.Droplets.List(opt)
	for _, element := range droplets {
		dropletNames = append(dropletNames, element.Name)
	}
	return dropletNames
}

func CreateDroplet(client godo.Client, cmd *cobra.Command) {
	if !viper.IsSet("ssh_keys") {
		fmt.Println("No ssh_keys specified in config file. Aborting without creating droplet.")
		os.Exit(-1)
	}
	ssh_keys := viper.GetStringSlice("ssh_keys")
	droplet_keys := make([]godo.DropletCreateSSHKey, len(ssh_keys))
	for i, ssh_key := range ssh_keys {
		droplet_keys[i].Fingerprint = ssh_key
	}

	if cmd.Flag("name").Value.String() == "" {
		fmt.Println("No name specified for creating droplet. Aborting without creating droplet.")
		os.Exit(-1)
	}

	createRequest := &godo.DropletCreateRequest{
		Name:   cmd.Flag("name").Value.String(),
		Region: cmd.Flag("region").Value.String(),
		Size:   cmd.Flag("size").Value.String(),
		Image: godo.DropletCreateImage{
			Slug: cmd.Flag("image").Value.String(),
		},
		SSHKeys: droplet_keys,
	}

	fmt.Println(createRequest)
	c, _ := utils.AskForConfirmation("Are you sure you want to create this droplet")
	if !c {
		os.Exit(-1)
	}

	droplet, _, err := client.Droplets.Create(createRequest)
	if err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
	fmt.Println("Droplet ", droplet.Name, " created. Currently provisioning...")
}

func DeleteDroplet(client godo.Client, id int) error {
	_, err := client.Droplets.Delete(id)
	return err
}

func GetDroplet(client godo.Client, name string) (*godo.Droplet, error) {
	id, err := utils.NameToID(client, name)
	if err != nil {
		return nil, err
	}

	droplet, _, err := client.Droplets.Get(id)
	return droplet, err
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/jessevdk/go-flags"
	"io"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"time"
)

// Avoid thundering herd problem on remote services used by this command.
// Interval will be 0, if this is not an issue.
func SpreadWait(interval time.Duration) {
	if interval > 0 {
		// Seed random generator with current process ID
		rand.Seed(int64(os.Getpid()))
		// Sleep for random amount of time within interval
		time.Sleep(time.Duration(rand.Int63n(int64(interval))))
	}
}

// Ok states that execution went well. Logs debug output and reports ok to
// monitoring.
func Ok() {
	var message string
	log.Println("OK")
	if firstbytes == nil {
		message = "OK"
	} else {
		message = string(firstbytes.Bytes())
	}
	monitor(monitorOk, message)
}

// NotAvailable states that the command could not be started successfully. It
// might not be installed or has other problems.
func NotAvailable(err error) {
	s := fmt.Sprintln("Cannot start command: ", err)
	log.Println("FATAL:", s)
	monitor(monitorUnknown, s)
}

// TimedOut states that the command took too long and reports failure to the
// monitoring.
func TimedOut() {
	s := "execution took too long"
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

// Busy states that the command hangs and reports failure to the monitoring.
// Those tasks should be automatically killed, if it happens often.
func Busy() {
	s := "previous invocation of command still running"
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

// Failed states that the command didn't execute successfully and reports
// failure to the monitoring. Also Logs error output.
func Failed(err error) {
	var message string
	code, s := error2exit(err)
	log.Println("FATAL:", s)
	if firstbytes == nil {
		message = s
	} else {
		message = string(firstbytes.Bytes())
	}
	monitor(code, message)
}

// LockError states that we could not get the lock.
func LockError(err error) {
	s := fmt.Sprintln("Failed to get lock: ", err)
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

var firstbytes *CapWriter

var opts struct {
	Interval         time.Duration `short:"i" long:"max-start-delay" description:"optional maximum execution start delay for command, e.g. 45s, 2m, 1h30m"`
	Timeout          time.Duration `short:"t" long:"timeout" default:"1m" description:"set execution timeout for command, e.g. 45s, 2m, 1h30m"`
	UseSyslog        bool          `short:"s" long:"use-syslog" description:"log via syslog instead of stderr"`
	WrapNagiosPlugin bool          `short:"n" long:"wrap-nagios-plugin" description:"wrap nagios plugin (pass on return codes, pass first 8KiB of stdout as message)"`
	NoPipeStderr     bool          `long:"no-stream-stderr" description:"do not stream stderr to log"`
	NoPipeStdout     bool          `long:"no-stream-stdout" description:"do not stream stdout to log"`
	MonitoringEvent  string        `short:"E" long:"monitor-event" description:"monitoring event (defaults to check_foo for /path/check_foo.sh)"`
	KillRunning      bool          `short:"k" long:"kill-running" description:"kill already running instance of command"`
}

func parseFlags() []string {
	p := flags.NewParser(&opts, flags.Default)

	// display nice usage message
	p.Usage = "[OPTIONS]... COMMAND\n\nSafely wrap execution of COMMAND in e.g. a cron job"

	args, err := p.Parse()
	if err != nil {
		// --help is not an error
		if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
			return nil
		} else {
			log.Fatal("FATAL: invalid arguments")
		}
	}

	if len(args) < 1 {
		log.Fatal("FATAL: no command to execute")
	}

	if opts.Interval >= opts.Timeout {
		log.Fatal("FATAL: interval >= timeout, no time left for actual command execution")
	}

	return args
}

func main() {
	var cmd *exec.Cmd
	var wg sync.WaitGroup

	log.SetFlags(0)
	args := parseFlags()

	if len(args) == 0 {
		return
	}

	command := args[0]

	monitoringEvent = opts.MonitoringEvent
	if monitoringEvent == "" {
		// event for command /path/check_foo.sh will be check_foo
		monitoringEvent = filepath.Base(command)
		if ext := filepath.Ext(command); ext != "" {
			monitoringEvent = monitoringEvent[0 : len(monitoringEvent)-len("."+ext)+1]
		}
	}

	logger, err := getLogger(opts.UseSyslog)
	if err != nil {
		log.Fatal("FATAL: cannot contact syslog")
		return
	}

	loadMonitoringCommands()

	// FIXME(nightlyone) try two intervals instead of one?
	timer := time.AfterFunc(opts.Timeout, func() {
		TimedOut()
		if cmd != nil && cmd.Process != nil {
			cmd.Process.Kill()
			// FIXME(nightlyone) log the kill
		}
		os.Exit(0)
	})

	SpreadWait(opts.Interval)

	lock, err := createLock(opts.KillRunning)
	if err != nil {
		timer.Stop()
		LockError(err)
		return
	}
	defer lock.Unlock()

	cmd = exec.Command(command, args[1:]...)

	if !opts.NoPipeStdout {
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		if opts.WrapNagiosPlugin {
			firstbytes = NewCapWriter(8192)
			stdout := io.TeeReader(stdout, firstbytes)
			logStream(stdout, logger, &wg)
		} else {
			logStream(stdout, logger, &wg)
		}
	} else if opts.WrapNagiosPlugin {
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		firstbytes = NewCapWriter(8192)
		go io.Copy(firstbytes, stdout)
	}

	if !opts.NoPipeStderr {
		stderr, err := cmd.StderrPipe()
		if err != nil {
			log.Fatal(err)
		}
		logStream(stderr, logger, &wg)
	}

	if err := cmd.Start(); err != nil {
		timer.Stop()
		NotAvailable(err)
		return
	}

	if err := cmd.Wait(); err != nil {
		timer.Stop()
		Failed(err)
	} else {
		timer.Stop()
		Ok()
	}

	wg.Wait()
}
<commit_msg>Rename interval to max delay for consistency<commit_after>package main

import (
	"fmt"
	"github.com/jessevdk/go-flags"
	"io"
	"log"
	"math/rand"
	"os"
	"os/exec"
	"path/filepath"
	"sync"
	"time"
)

// Avoid thundering herd problem on remote services used by this command.
// maxDelay will be 0 if this is not an issue.
func SpreadWait(maxDelay time.Duration) {
	if maxDelay > 0 {
		// Seed random generator with current process ID
		rand.Seed(int64(os.Getpid()))
		// Sleep for random amount of time within maxDelay
		time.Sleep(time.Duration(rand.Int63n(int64(maxDelay))))
	}
}

// Ok states that execution went well. Logs debug output and reports ok to
// monitoring.
func Ok() {
	var message string
	log.Println("OK")
	if firstbytes == nil {
		message = "OK"
	} else {
		message = string(firstbytes.Bytes())
	}
	monitor(monitorOk, message)
}

// NotAvailable states that the command could not be started successfully. It
// might not be installed or has other problems.
func NotAvailable(err error) {
	s := fmt.Sprintln("Cannot start command: ", err)
	log.Println("FATAL:", s)
	monitor(monitorUnknown, s)
}

// TimedOut states that the command took too long and reports failure to the
// monitoring.
func TimedOut() {
	s := "execution took too long"
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

// Busy states that the command hangs and reports failure to the monitoring.
// Those tasks should be automatically killed, if it happens often.
func Busy() {
	s := "previous invocation of command still running"
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

// Failed states that the command didn't execute successfully and reports
// failure to the monitoring. Also Logs error output.
func Failed(err error) {
	var message string
	code, s := error2exit(err)
	log.Println("FATAL:", s)
	if firstbytes == nil {
		message = s
	} else {
		message = string(firstbytes.Bytes())
	}
	monitor(code, message)
}

// LockError states that we could not get the lock.
func LockError(err error) {
	s := fmt.Sprintln("Failed to get lock: ", err)
	log.Println("FATAL:", s)
	monitor(monitorCritical, s)
}

var firstbytes *CapWriter

var opts struct {
	MaxDelay         time.Duration `short:"d" long:"max-start-delay" description:"optional maximum execution start delay for command, e.g. 45s, 2m, 1h30m"`
	Timeout          time.Duration `short:"t" long:"timeout" default:"1m" description:"set execution timeout for command, e.g. 45s, 2m, 1h30m"`
	UseSyslog        bool          `short:"s" long:"use-syslog" description:"log via syslog instead of stderr"`
	WrapNagiosPlugin bool          `short:"n" long:"wrap-nagios-plugin" description:"wrap nagios plugin (pass on return codes, pass first 8KiB of stdout as message)"`
	NoPipeStderr     bool          `long:"no-stream-stderr" description:"do not stream stderr to log"`
	NoPipeStdout     bool          `long:"no-stream-stdout" description:"do not stream stdout to log"`
	MonitoringEvent  string        `short:"E" long:"monitor-event" description:"monitoring event (defaults to check_foo for /path/check_foo.sh)"`
	KillRunning      bool          `short:"k" long:"kill-running" description:"kill already running instance of command"`
}

func parseFlags() []string {
	p := flags.NewParser(&opts, flags.Default)

	// display nice usage message
	p.Usage = "[OPTIONS]... COMMAND\n\nSafely wrap execution of COMMAND in e.g. a cron job"

	args, err := p.Parse()
	if err != nil {
		// --help is not an error
		if e, ok := err.(*flags.Error); ok && e.Type == flags.ErrHelp {
			return nil
		} else {
			log.Fatal("FATAL: invalid arguments")
		}
	}

	if len(args) < 1 {
		log.Fatal("FATAL: no command to execute")
	}

	if opts.MaxDelay >= opts.Timeout {
		log.Fatal("FATAL: max delay >= timeout, no time left for actual command execution")
	}

	return args
}

func main() {
	var cmd *exec.Cmd
	var wg sync.WaitGroup

	log.SetFlags(0)
	args := parseFlags()

	if len(args) == 0 {
		return
	}

	command := args[0]

	monitoringEvent = opts.MonitoringEvent
	if monitoringEvent == "" {
		// event for command /path/check_foo.sh will be check_foo
		monitoringEvent = filepath.Base(command)
		if ext := filepath.Ext(command); ext != "" {
			monitoringEvent = monitoringEvent[0 : len(monitoringEvent)-len("."+ext)+1]
		}
	}

	logger, err := getLogger(opts.UseSyslog)
	if err != nil {
		log.Fatal("FATAL: cannot contact syslog")
		return
	}

	loadMonitoringCommands()

	// FIXME(nightlyone) try two intervals instead of one?
	timer := time.AfterFunc(opts.Timeout, func() {
		TimedOut()
		if cmd != nil && cmd.Process != nil {
			cmd.Process.Kill()
			// FIXME(nightlyone) log the kill
		}
		os.Exit(0)
	})

	SpreadWait(opts.MaxDelay)

	lock, err := createLock(opts.KillRunning)
	if err != nil {
		timer.Stop()
		LockError(err)
		return
	}
	defer lock.Unlock()

	cmd = exec.Command(command, args[1:]...)

	if !opts.NoPipeStdout {
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		if opts.WrapNagiosPlugin {
			firstbytes = NewCapWriter(8192)
			stdout := io.TeeReader(stdout, firstbytes)
			logStream(stdout, logger, &wg)
		} else {
			logStream(stdout, logger, &wg)
		}
	} else if opts.WrapNagiosPlugin {
		stdout, err := cmd.StdoutPipe()
		if err != nil {
			log.Fatal(err)
		}
		firstbytes = NewCapWriter(8192)
		go io.Copy(firstbytes, stdout)
	}

	if !opts.NoPipeStderr {
		stderr, err := cmd.StderrPipe()
		if err != nil {
			log.Fatal(err)
		}
		logStream(stderr, logger, &wg)
	}

	if err := cmd.Start(); err != nil {
		timer.Stop()
		NotAvailable(err)
		return
	}

	if err := cmd.Wait(); err != nil {
		timer.Stop()
		Failed(err)
	} else {
		timer.Stop()
		Ok()
	}

	wg.Wait()
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"

	flags "github.com/jessevdk/go-flags"
	"github.com/monochromegane/terminal"
	pt "github.com/monochromegane/the_platinum_searcher"
)

const version = "1.7.6"

var opts pt.Option

func init() {
	if cpu := runtime.NumCPU(); cpu == 1 {
		runtime.GOMAXPROCS(2)
	} else {
		runtime.GOMAXPROCS(cpu)
	}
}

func main() {
	opts.Color = opts.SetEnableColor
	opts.NoColor = opts.SetDisableColor
	opts.EnableColor = true
	opts.SkipVcsIgnore = opts.SkipVcsIgnores

	parser := flags.NewParser(&opts, flags.Default)
	parser.Name = "pt"
	parser.Usage = "[OPTIONS] PATTERN [PATH]"

	args, err := parser.Parse()
	if err != nil {
		os.Exit(1)
	}

	if opts.Version {
		fmt.Printf("%s\n", version)
		os.Exit(0)
	}

	if len(args) == 0 && opts.FilesWithRegexp == "" {
		parser.WriteHelp(os.Stdout)
		os.Exit(1)
	}

	opts.SearchStream = false
	if len(args) == 1 {
		fi, err := os.Stdin.Stat()
		if runtime.GOOS == "windows" {
			if err == nil {
				opts.SearchStream = true
				opts.NoGroup = true
			}
		} else {
			if err != nil {
				os.Exit(1)
			}

			mode := fi.Mode()
			if (mode & os.ModeNamedPipe != 0) || mode.IsRegular() {
				opts.SearchStream = true
				opts.NoGroup = true
			}
		}
	}

	var roots = []string{"."}
	if len(args) >= 2 {
		roots = []string{}
		for _, root := range args[1:] {
			root = strings.TrimRight(root, "\"")
			_, err := os.Lstat(root)
			if err != nil {
				fmt.Fprintf(os.Stderr, "%s\n", err)
				os.Exit(1)
			}
			roots = append(roots, root)
		}
	}

	opts.Proc = runtime.NumCPU()

	if !terminal.IsTerminal(os.Stdout) {
		if !opts.ForceColor {
			opts.EnableColor = false
		}
		opts.NoGroup = true
	}

	if opts.Context > 0 {
		opts.Before = opts.Context
		opts.After = opts.Context
	}

	pattern := ""
	if len(args) > 0 {
		pattern = args[0]
	}

	if opts.WordRegexp {
		opts.Regexp = true
		pattern = "\\b" + pattern + "\\b"
	}

	start := time.Now()

	searcher := pt.PlatinumSearcher{roots, pattern, &opts}
	err = searcher.Search()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
	if opts.Stats {
		elapsed := time.Since(start)
		fmt.Printf("%d Files Searched\n", pt.FilesSearched)
		fmt.Printf("%s Elapsed\n", elapsed)
	}

	if pt.FileMatchCount == 0 && pt.MatchCount == 0 {
		os.Exit(1)
	}
}
<commit_msg>gofmt<commit_after>package main

import (
	"fmt"
	"os"
	"runtime"
	"strings"
	"time"

	flags "github.com/jessevdk/go-flags"
	"github.com/monochromegane/terminal"
	pt "github.com/monochromegane/the_platinum_searcher"
)

const version = "1.7.6"

var opts pt.Option

func init() {
	if cpu := runtime.NumCPU(); cpu == 1 {
		runtime.GOMAXPROCS(2)
	} else {
		runtime.GOMAXPROCS(cpu)
	}
}

func main() {
	opts.Color = opts.SetEnableColor
	opts.NoColor = opts.SetDisableColor
	opts.EnableColor = true
	opts.SkipVcsIgnore = opts.SkipVcsIgnores

	parser := flags.NewParser(&opts, flags.Default)
	parser.Name = "pt"
	parser.Usage = "[OPTIONS] PATTERN [PATH]"

	args, err := parser.Parse()
	if err != nil {
		os.Exit(1)
	}

	if opts.Version {
		fmt.Printf("%s\n", version)
		os.Exit(0)
	}

	if len(args) == 0 && opts.FilesWithRegexp == "" {
		parser.WriteHelp(os.Stdout)
		os.Exit(1)
	}

	opts.SearchStream = false
	if len(args) == 1 {
		fi, err := os.Stdin.Stat()
		if runtime.GOOS == "windows" {
			if err == nil {
				opts.SearchStream = true
				opts.NoGroup = true
			}
		} else {
			if err != nil {
				os.Exit(1)
			}

			mode := fi.Mode()
			if (mode&os.ModeNamedPipe != 0) || mode.IsRegular() {
				opts.SearchStream = true
				opts.NoGroup = true
			}
		}
	}

	var roots = []string{"."}
	if len(args) >= 2 {
		roots = []string{}
		for _, root := range args[1:] {
			root = strings.TrimRight(root, "\"")
			_, err := os.Lstat(root)
			if err != nil {
				fmt.Fprintf(os.Stderr, "%s\n", err)
				os.Exit(1)
			}
			roots = append(roots, root)
		}
	}

	opts.Proc = runtime.NumCPU()

	if !terminal.IsTerminal(os.Stdout) {
		if !opts.ForceColor {
			opts.EnableColor = false
		}
		opts.NoGroup = true
	}

	if opts.Context > 0 {
		opts.Before = opts.Context
		opts.After = opts.Context
	}

	pattern := ""
	if len(args) > 0 {
		pattern = args[0]
	}

	if opts.WordRegexp {
		opts.Regexp = true
		pattern = "\\b" + pattern + "\\b"
	}

	start := time.Now()

	searcher := pt.PlatinumSearcher{roots, pattern, &opts}
	err = searcher.Search()
	if err != nil {
		fmt.Fprintf(os.Stderr, "%s\n", err)
		os.Exit(1)
	}
	if opts.Stats {
		elapsed := time.Since(start)
		fmt.Printf("%d Files Searched\n", pt.FilesSearched)
		fmt.Printf("%s Elapsed\n", elapsed)
	}

	if pt.FileMatchCount == 0 && pt.MatchCount == 0 {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"strings"
)

var (
	autocomplete = flag.Bool("c", false, "for bash autocomplete")
	showVer      = flag.Bool("version", false, "show version")
	showColors   = flag.Bool("colors-true", false, "show terminal true colors")
)

func initAutocomplete() {
	what := `complete -C "tb -c" tb`
	u, err := user.Current()
	if err != nil {
		panic(err)
	}

	bashrc := u.HomeDir + "/.bashrc"

	cmd := exec.Command("grep", "-e", what, bashrc)
	_, err = cmd.Output()
	if err != nil {
		f, err := os.OpenFile(bashrc, os.O_RDWR|os.O_APPEND, 0660)
		if err != nil {
			panic(err)
		}

		fmt.Fprintf(f, "\n%s\n", what)
		f.Close()
		fmt.Println("autocomplete clause has added to .bashrc. Run source ~/.bashrc now")
	}
}

func printAutocomplete() {
	visitFunc := func(f *flag.Flag) {
		if f.Name == "c" {
			return
		}
		if strings.HasPrefix("-"+f.Name, flag.Arg(1)) {
			fmt.Println("-" + f.Name)
		}
	}
	flag.VisitAll(visitFunc)
}

func main() {
	initAutocomplete()
	flag.Parse()

	if *autocomplete {
		printAutocomplete()
		return
	}

	if flag.NFlag() == 0 {
		flag.Usage()
		return
	}

	if *showColors {
		printTerminalColors()
		return
	}
}

func printTerminalColors() {
	for colnum := 0; colnum < 256; colnum++ {
		r := 255 - (colnum * 255 / 255)
		g := (colnum * 510 / 255)
		b := (colnum * 255 / 255)
		if g > 255 {
			g = 510 - g
		}
		fmt.Printf("\033[48;2;%d;%d;%dm", r, g, b)
		fmt.Printf("\033[38;2;%d;%d;%dm", 255-r, 255-g, 255-b)
		fmt.Printf("%s\033[0m", " ")
		if colnum%64 == 63 {
			fmt.Println()
		}
	}
}
<commit_msg>Add rebuild option<commit_after>package main

import (
	"flag"
	"time"
	"fmt"
	"os"
	"os/exec"
	"os/user"
	"strings"
)

var (
	version string
	date string
	u *user.User
)

var (
	autocomplete = flag.Bool("c", false, "for bash autocomplete")
	rebuild = flag.Bool("rebuild", false, "rebuild tb")
	showVer      = flag.Bool("version", false, "show version")
	showColors   = flag.Bool("colors-true", false, "show terminal true colors")
)

func init() {
	var err error
	u, err = user.Current()
	if err != nil {
		panic(err)
	}
}

func initAutocomplete() {
	what := `complete -C "tb -c" tb`

	bashrc := u.HomeDir + "/.bashrc"

	cmd := exec.Command("grep", "-e", what, bashrc)
	_, err := cmd.Output()
	if err != nil {
		f, err := os.OpenFile(bashrc, os.O_RDWR|os.O_APPEND, 0660)
		if err != nil {
			panic(err)
		}

		fmt.Fprintf(f, "\n%s\n", what)
		f.Close()
		fmt.Println("autocomplete clause has added to .bashrc. Run source ~/.bashrc now")
	}
}

func printAutocomplete() {
	visitFunc := func(f *flag.Flag) {
		if f.Name == "c" {
			return
		}
		if strings.HasPrefix("-"+f.Name, flag.Arg(1)) {
			fmt.Println("-" + f.Name)
		}
	}
	flag.VisitAll(visitFunc)
}

func printVersion() {
	fmt.Println("version:", version)
	fmt.Println("date:   ", date)
}

func rebuildToolbox() {
	gopath := u.HomeDir + "/go"

	args := []string {
		"install",
		"-ldflags", "-X main.date="+time.Now().Format(time.RFC3339),
		"github.com/serge-v/toolbox/..."}

	cmd := exec.Command("go", args...)
	cmd.Env = os.Environ()
	cmd.Env = append(cmd.Env, "GOPATH=" + gopath)
	fmt.Println("run: go", args)
	out, err := cmd.CombinedOutput()
	if err != nil {
		println(string(out))
	}
}

func main() {
	initAutocomplete()
	flag.Parse()

	if *autocomplete {
		printAutocomplete()
		return
	}

	if flag.NFlag() == 0 {
		flag.Usage()
		return
	}

	if *rebuild {
		rebuildToolbox()
	}

	if *showVer {
		printVersion()
		return
	}

	if *showColors {
		printTerminalColors()
		return
	}
}

func printTerminalColors() {
	for colnum := 0; colnum < 256; colnum++ {
		r := 255 - (colnum * 255 / 255)
		g := (colnum * 510 / 255)
		b := (colnum * 255 / 255)
		if g > 255 {
			g = 510 - g
		}
		fmt.Printf("\033[48;2;%d;%d;%dm", r, g, b)
		fmt.Printf("\033[38;2;%d;%d;%dm", 255-r, 255-g, 255-b)
		fmt.Printf("%s\033[0m", " ")
		if colnum%64 == 63 {
			fmt.Println()
		}
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"github.com/spf13/cobra"
)

var (
	version = "1.1.0"
	githash = "HEAD"
)

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Printf("haproxy-exporter %s (%s)\n", version, githash)
	},
}
<commit_msg>chore: bump to 1.2.0<commit_after>package cmd

import (
	"fmt"
	"github.com/spf13/cobra"
)

var (
	version = "1.2.0"
	githash = "HEAD"
)

func init() {
	RootCmd.AddCommand(versionCmd)
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Printf("haproxy-exporter %s (%s)\n", version, githash)
	},
}
<|endoftext|>


<commit_before>// Copyright © 2022 ezbuy & LITB Team
//
// 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 cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
)

var CommitHash string

func version(commit string) string {
	if commit == "" {
		return fmt.Sprintf("ezorm v%d.%d.%d", vMajor, vMinor, vPatch)
	}
	return fmt.Sprintf("ezorm v%d.%d.%d-%s", vMajor, vMinor, vPatch, commit)
}

const (
	vMajor = 2
	vMinor = 3
	vPatch = 2
)

// versionCmd represents the version command
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "EzOrm 版本信息",
	Long:  `EzOrm 版本信息`,
	Run: func(_ *cobra.Command, _ []string) {
		fmt.Fprintln(os.Stdout, version(CommitHash))
	},
}

func init() {
	RootCmd.AddCommand(versionCmd)
}
<commit_msg>cmd: bump version to v2.4.2<commit_after>// Copyright © 2022 ezbuy & LITB Team
//
// 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 cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
)

var CommitHash string

func version(commit string) string {
	if commit == "" {
		return fmt.Sprintf("ezorm v%d.%d.%d", vMajor, vMinor, vPatch)
	}
	return fmt.Sprintf("ezorm v%d.%d.%d-%s", vMajor, vMinor, vPatch, commit)
}

const (
	vMajor = 2
	vMinor = 4
	vPatch = 2
)

// versionCmd represents the version command
var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "EzOrm 版本信息",
	Long:  `EzOrm 版本信息`,
	Run: func(_ *cobra.Command, _ []string) {
		fmt.Fprintln(os.Stdout, version(CommitHash))
	},
}

func init() {
	RootCmd.AddCommand(versionCmd)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

const version = "v0.8.21"

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of Terraformer",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("Terraformer " + version)
	},
}
<commit_msg>Update version.go (#1460)<commit_after>package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
)

const version = "v0.8.22"

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number of Terraformer",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println("Terraformer " + version)
	},
}
<|endoftext|>


<commit_before>package coal

import (
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// A Tester provides facilities to the test a fire API.
type Tester struct {
	// The store to use for cleaning the database.
	Store *Store

	// The registered models.
	Models []Model
}

// NewTester returns a new tester.
func NewTester(store *Store, models ...Model) *Tester {
	return &Tester{
		Store:  store,
		Models: models,
	}
}

// Clean will remove the collections of models that have been registered and
// reset the header map.
func (t *Tester) Clean() {
	for _, model := range t.Models {
		// remove all is faster than dropping the collection
		_, err := t.Store.C(model).DeleteMany(nil, bson.M{})
		if err != nil {
			panic(err)
		}
	}
}

// Save will save the specified model.
func (t *Tester) Save(model Model) Model {
	// initialize model
	model = Init(model)

	// insert to collection
	_, err := t.Store.C(model).InsertOne(nil, model)
	if err != nil {
		panic(err)
	}

	return model
}

// FindAll will return all saved models.
func (t *Tester) FindAll(model Model) interface{} {
	// initialize model
	model = Init(model)

	// find all documents
	list := model.Meta().MakeSlice()
	cursor, err := t.Store.C(model).Find(nil, bson.M{}, options.Find().SetSort(Sort("_id")))
	if err != nil {
		panic(err)
	}

	// get all results
	err = cursor.All(nil, list)
	if err != nil {
		panic(err)
	}

	// close cursor
	err = cursor.Close(nil)
	if err != nil {
		panic(err)
	}

	// initialize list
	InitSlice(list)

	return list
}

// FindLast will return the last saved model.
func (t *Tester) FindLast(model Model) Model {
	// find last document
	err := t.Store.C(model).FindOne(nil, bson.M{}, options.FindOne().SetSort(Sort("-_id"))).Decode(model)
	if err != nil {
		panic(err)
	}

	// initialize model
	Init(model)

	return model
}

// Fetch will return the saved model.
func (t *Tester) Fetch(model Model, id primitive.ObjectID) Model {
	// find specific document
	err := t.Store.C(model).FindOne(nil, bson.M{
		"_id": id,
	}).Decode(model)
	if err != nil {
		panic(err)
	}

	// initialize model
	Init(model)

	return model
}

// Update will update the specified model.
func (t *Tester) Update(model Model) Model {
	// initialize model
	model = Init(model)

	// insert to collection
	_, err := t.Store.C(model).ReplaceOne(nil, bson.M{
		"_id": model.ID(),
	}, model)
	if err != nil {
		panic(err)
	}

	return model
}

// Delete will delete the specified model.
func (t *Tester) Delete(model Model) {
	// initialize model
	model = Init(model)

	// insert to collection
	_, err := t.Store.C(model).DeleteOne(nil, bson.M{
		"_id": model.ID(),
	})
	if err != nil {
		panic(err)
	}
}
<commit_msg>added count helper<commit_after>package coal

import (
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"
)

// A Tester provides facilities to the test a fire API.
type Tester struct {
	// The store to use for cleaning the database.
	Store *Store

	// The registered models.
	Models []Model
}

// NewTester returns a new tester.
func NewTester(store *Store, models ...Model) *Tester {
	return &Tester{
		Store:  store,
		Models: models,
	}
}

// Clean will remove the collections of models that have been registered and
// reset the header map.
func (t *Tester) Clean() {
	for _, model := range t.Models {
		// remove all is faster than dropping the collection
		_, err := t.Store.C(model).DeleteMany(nil, bson.M{})
		if err != nil {
			panic(err)
		}
	}
}

// Save will save the specified model.
func (t *Tester) Save(model Model) Model {
	// initialize model
	model = Init(model)

	// insert to collection
	_, err := t.Store.C(model).InsertOne(nil, model)
	if err != nil {
		panic(err)
	}

	return model
}

// FindAll will return all saved models.
func (t *Tester) FindAll(model Model) interface{} {
	// initialize model
	model = Init(model)

	// find all documents
	list := model.Meta().MakeSlice()
	cursor, err := t.Store.C(model).Find(nil, bson.M{}, options.Find().SetSort(Sort("_id")))
	if err != nil {
		panic(err)
	}

	// get all results
	err = cursor.All(nil, list)
	if err != nil {
		panic(err)
	}

	// close cursor
	err = cursor.Close(nil)
	if err != nil {
		panic(err)
	}

	// initialize list
	InitSlice(list)

	return list
}

// FindLast will return the last saved model.
func (t *Tester) FindLast(model Model) Model {
	// find last document
	err := t.Store.C(model).FindOne(nil, bson.M{}, options.FindOne().SetSort(Sort("-_id"))).Decode(model)
	if err != nil {
		panic(err)
	}

	// initialize model
	Init(model)

	return model
}

// Count will count all saved models.
func (t *Tester) Count(model Model) int {
	// count all documents
	n, err := t.Store.C(model).CountDocuments(nil, bson.M{})
	if err != nil {
		panic(err)
	}

	return int(n)
}

// Fetch will return the saved model.
func (t *Tester) Fetch(model Model, id primitive.ObjectID) Model {
	// find specific document
	err := t.Store.C(model).FindOne(nil, bson.M{
		"_id": id,
	}).Decode(model)
	if err != nil {
		panic(err)
	}

	// initialize model
	Init(model)

	return model
}

// Update will update the specified model.
func (t *Tester) Update(model Model) Model {
	// initialize model
	model = Init(model)

	// insert to collection
	_, err := t.Store.C(model).ReplaceOne(nil, bson.M{
		"_id": model.ID(),
	}, model)
	if err != nil {
		panic(err)
	}

	return model
}

// Delete will delete the specified model.
func (t *Tester) Delete(model Model) {
	// initialize model
	model = Init(model)

	// insert to collection
	_, err := t.Store.C(model).DeleteOne(nil, bson.M{
		"_id": model.ID(),
	})
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>package hbot

import (
	"os"
	"encoding/json"
	"fmt"
)

//User Mode Flags
const (
	UMAway = uint32(1) << iota
	UMInvisibility
	UMWallops
	UMRestricted
	UMOperator
	UMLocalOp
	UMRecNotices
)

var UserModeMap = map[string]uint32{
	"a" : UMAway,
	"i" : UMInvisibility,
	"w" : UMWallops,
	"r" : UMRestricted,
	"o" : UMOperator,
	"O" : UMLocalOp,
	"s" : UMRecNotices,
}

// Currently Unused
type IrcUser struct {
	Nick string
	User string
	Host string

	Perms uint32
}

type IrcChannel struct {
	Name string
	con *IrcCon
	Counts map[string]int
	Perms uint32

	istream chan *Message
	//ostream chan *Message

	// Currently Unused
	Users map[string]*IrcUser
}

// Attempt to load chat frequency stats from a file
func (c *IrcChannel) TryLoadStats(finame string) bool {
	fi,err := os.Open(finame)
	if err != nil {
		return false
	}
	defer fi.Close()

	dec := json.NewDecoder(fi)

	err = dec.Decode(&c.Counts)
	if err != nil {
		fmt.Println(err)
		return false
	}
	return true
}

// Write chat frequencies to a file
func (c *IrcChannel) SaveStats(finame string) {
	fi,err := os.Create(finame)
	if err != nil {
		panic(err)
	}
	defer fi.Close()

	enc := json.NewEncoder(fi)
	enc.Encode(c.Counts)
}

//Take note of joins, parts, and mode changes
func (c *IrcChannel) handleMessages() {
	for mes := range c.istream {
		switch mes.Command {
		case "JOIN":
			u := new(IrcUser)
			u.Host = mes.Host
			u.Nick = mes.Name
			u.User = mes.User
			c.Users[mes.Name] = u
		case "MODE":
			ch := mes.Params[1][0]
			u := c.Users[mes.Params[2]]
			if ch == '+' {
				u.Perms |= UserModeMap[mes.Params[1][1:]]
			} else if ch == '-' {
				u.Perms &= ^UserModeMap[mes.Params[1][1:]]
			}
		case "PART":
			delete(c.Users, mes.Name)
		case "NICK":
			newnick := mes.Content
			u := c.Users[mes.From]
			delete(c.Users, mes.From)
			c.Users[newnick] = u
			u.Nick = newnick
		}
	}
}

// Send a message to this irc channel
func (c *IrcChannel) Say(text string) {
	if c == nil {
		fmt.Println("tried to send to channel youre not in...")
		return
	}
	c.con.Send(fmt.Sprintf("PRIVMSG %s :%s\r\n", c.Name, text))
}

// Sets the channels topic (requires bot has proper permissions)
func (c *IrcChannel) Topic(topic string) {
	str := fmt.Sprintf("TOPIC %s :%s", c.Name, topic)
	c.con.Send(str)
}

// Kick a user in this channel, reason optional (requires permissions)
func (c *IrcChannel) Kick(user, reason string) {
	c.con.Send(fmt.Sprintf("KICK %s %s :%s", c.Name, user, reason))
}

/* Commented out until i have a clever way of making it threadsafe

// Returns a channel that will contain messages sent to
// the channel represented by this IrcChannel
func (c *IrcChannel) GetMessageStream() chan *Message {
	if c.ostream == nil {
		c.ostream = make(chan *Message, 16)
	}
	return c.ostream
}

// Closes out the message stream for this channel
func (c *IrcChannel) CloseMessageStream() {
	close(c.ostream)
	c.ostream = nil
}

*/
<commit_msg>Added notice command (and let gofmt do its job)<commit_after>package hbot

import (
	"encoding/json"
	"fmt"
	"os"
)

//User Mode Flags
const (
	UMAway = uint32(1) << iota
	UMInvisibility
	UMWallops
	UMRestricted
	UMOperator
	UMLocalOp
	UMRecNotices
)

var UserModeMap = map[string]uint32{
	"a": UMAway,
	"i": UMInvisibility,
	"w": UMWallops,
	"r": UMRestricted,
	"o": UMOperator,
	"O": UMLocalOp,
	"s": UMRecNotices,
}

// Currently Unused
type IrcUser struct {
	Nick string
	User string
	Host string

	Perms uint32
}

type IrcChannel struct {
	Name   string
	con    *IrcCon
	Counts map[string]int
	Perms  uint32

	istream chan *Message
	//ostream chan *Message

	// Currently Unused
	Users map[string]*IrcUser
}

// Attempt to load chat frequency stats from a file
func (c *IrcChannel) TryLoadStats(finame string) bool {
	fi, err := os.Open(finame)
	if err != nil {
		return false
	}
	defer fi.Close()

	dec := json.NewDecoder(fi)

	err = dec.Decode(&c.Counts)
	if err != nil {
		fmt.Println(err)
		return false
	}
	return true
}

// Write chat frequencies to a file
func (c *IrcChannel) SaveStats(finame string) {
	fi, err := os.Create(finame)
	if err != nil {
		panic(err)
	}
	defer fi.Close()

	enc := json.NewEncoder(fi)
	enc.Encode(c.Counts)
}

//Take note of joins, parts, and mode changes
func (c *IrcChannel) handleMessages() {
	for mes := range c.istream {
		switch mes.Command {
		case "JOIN":
			u := new(IrcUser)
			u.Host = mes.Host
			u.Nick = mes.Name
			u.User = mes.User
			c.Users[mes.Name] = u
		case "MODE":
			ch := mes.Params[1][0]
			u := c.Users[mes.Params[2]]
			if ch == '+' {
				u.Perms |= UserModeMap[mes.Params[1][1:]]
			} else if ch == '-' {
				u.Perms &= ^UserModeMap[mes.Params[1][1:]]
			}
		case "PART":
			delete(c.Users, mes.Name)
		case "NICK":
			newnick := mes.Content
			u := c.Users[mes.From]
			delete(c.Users, mes.From)
			c.Users[newnick] = u
			u.Nick = newnick
		}
	}
}

// Send a message to this irc channel
func (c *IrcChannel) Say(text string) {
	if c == nil {
		fmt.Println("tried to send to channel youre not in...")
		return
	}
	c.con.Send(fmt.Sprintf("PRIVMSG %s :%s\r\n", c.Name, text))
}

// Notice performs an action in the channel
func (c *IrcChannel) Notice(text string) {
	msg := fmt.Sprintf("\u0001ACTION %s\u0001", text)
	c.Say(msg)
}

// Sets the channels topic (requires bot has proper permissions)
func (c *IrcChannel) Topic(topic string) {
	str := fmt.Sprintf("TOPIC %s :%s", c.Name, topic)
	c.con.Send(str)
}

// Kick a user in this channel, reason optional (requires permissions)
func (c *IrcChannel) Kick(user, reason string) {
	c.con.Send(fmt.Sprintf("KICK %s %s :%s", c.Name, user, reason))
}

/* Commented out until i have a clever way of making it threadsafe

// Returns a channel that will contain messages sent to
// the channel represented by this IrcChannel
func (c *IrcChannel) GetMessageStream() chan *Message {
	if c.ostream == nil {
		c.ostream = make(chan *Message, 16)
	}
	return c.ostream
}

// Closes out the message stream for this channel
func (c *IrcChannel) CloseMessageStream() {
	close(c.ostream)
	c.ostream = nil
}

*/
<|endoftext|>


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

// TODO: remove hard-coded versions when we have implemented fractional weights.
// The current implementation is incompatible with later CLDR versions.
//go:generate go run maketables.go -cldr=23 -unicode=6.2.0

// Package collate contains types for comparing and sorting Unicode strings
// according to a given collation order.  Package locale provides a high-level
// interface to collation. Users should typically use that package instead.
package collate // import "golang.org/x/text/collate"

import (
	"bytes"
	"strings"

	"golang.org/x/text/internal/colltab"
	"golang.org/x/text/language"
)

// Collator provides functionality for comparing strings for a given
// collation order.
type Collator struct {
	options

	sorter sorter

	_iter [2]iter
}

func (c *Collator) iter(i int) *iter {
	// TODO: evaluate performance for making the second iterator optional.
	return &c._iter[i]
}

// Supported returns the list of languages for which collating differs from its parent.
func Supported() []language.Tag {
	// TODO: use language.Coverage instead.

	t := make([]language.Tag, len(tags))
	copy(t, tags)
	return t
}

func init() {
	ids := strings.Split(availableLocales, ",")
	tags = make([]language.Tag, len(ids))
	for i, s := range ids {
		tags[i] = language.Raw.MustParse(s)
	}
}

var tags []language.Tag

// New returns a new Collator initialized for the given locale.
func New(t language.Tag, o ...Option) *Collator {
	index := colltab.MatchLang(t, tags)
	c := newCollator(getTable(locales[index]))

	// Set options from the user-supplied tag.
	c.setFromTag(t)

	// Set the user-supplied options.
	c.setOptions(o)

	c.init()
	return c
}

// NewFromTable returns a new Collator for the given Weighter.
func NewFromTable(w colltab.Weighter, o ...Option) *Collator {
	c := newCollator(w)
	c.setOptions(o)
	c.init()
	return c
}

func (c *Collator) init() {
	if c.numeric {
		c.t = colltab.NewNumericWeighter(c.t)
	}
	c._iter[0].init(c)
	c._iter[1].init(c)
}

// Buffer holds keys generated by Key and KeyString.
type Buffer struct {
	buf [4096]byte
	key []byte
}

func (b *Buffer) init() {
	if b.key == nil {
		b.key = b.buf[:0]
	}
}

// Reset clears the buffer from previous results generated by Key and KeyString.
func (b *Buffer) Reset() {
	b.key = b.key[:0]
}

// Compare returns an integer comparing the two byte slices.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (c *Collator) Compare(a, b []byte) int {
	// TODO: skip identical prefixes once we have a fast way to detect if a rune is
	// part of a contraction. This would lead to roughly a 10% speedup for the colcmp regtest.
	c.iter(0).SetInput(a)
	c.iter(1).SetInput(b)
	if res := c.compare(); res != 0 {
		return res
	}
	if !c.ignore[colltab.Identity] {
		return bytes.Compare(a, b)
	}
	return 0
}

// CompareString returns an integer comparing the two strings.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (c *Collator) CompareString(a, b string) int {
	// TODO: skip identical prefixes once we have a fast way to detect if a rune is
	// part of a contraction. This would lead to roughly a 10% speedup for the colcmp regtest.
	c.iter(0).SetInputString(a)
	c.iter(1).SetInputString(b)
	if res := c.compare(); res != 0 {
		return res
	}
	if !c.ignore[colltab.Identity] {
		if a < b {
			return -1
		} else if a > b {
			return 1
		}
	}
	return 0
}

func compareLevel(f func(i *iter) int, a, b *iter) int {
	a.pce = 0
	b.pce = 0
	for {
		va := f(a)
		vb := f(b)
		if va != vb {
			if va < vb {
				return -1
			}
			return 1
		} else if va == 0 {
			break
		}
	}
	return 0
}

func (c *Collator) compare() int {
	ia, ib := c.iter(0), c.iter(1)
	// Process primary level
	if c.alternate != altShifted {
		// TODO: implement script reordering
		if res := compareLevel((*iter).nextPrimary, ia, ib); res != 0 {
			return res
		}
	} else {
		// TODO: handle shifted
	}
	if !c.ignore[colltab.Secondary] {
		f := (*iter).nextSecondary
		if c.backwards {
			f = (*iter).prevSecondary
		}
		if res := compareLevel(f, ia, ib); res != 0 {
			return res
		}
	}
	// TODO: special case handling (Danish?)
	if !c.ignore[colltab.Tertiary] || c.caseLevel {
		if res := compareLevel((*iter).nextTertiary, ia, ib); res != 0 {
			return res
		}
		if !c.ignore[colltab.Quaternary] {
			if res := compareLevel((*iter).nextQuaternary, ia, ib); res != 0 {
				return res
			}
		}
	}
	return 0
}

// Key returns the collation key for str.
// Passing the buffer buf may avoid memory allocations.
// The returned slice will point to an allocation in Buffer and will remain
// valid until the next call to buf.Reset().
func (c *Collator) Key(buf *Buffer, str []byte) []byte {
	// See http://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
	buf.init()
	return c.key(buf, c.getColElems(str))
}

// KeyFromString returns the collation key for str.
// Passing the buffer buf may avoid memory allocations.
// The returned slice will point to an allocation in Buffer and will retain
// valid until the next call to buf.ResetKeys().
func (c *Collator) KeyFromString(buf *Buffer, str string) []byte {
	// See http://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
	buf.init()
	return c.key(buf, c.getColElemsString(str))
}

func (c *Collator) key(buf *Buffer, w []colltab.Elem) []byte {
	processWeights(c.alternate, c.t.Top(), w)
	kn := len(buf.key)
	c.keyFromElems(buf, w)
	return buf.key[kn:]
}

func (c *Collator) getColElems(str []byte) []colltab.Elem {
	i := c.iter(0)
	i.SetInput(str)
	for i.Next() {
	}
	return i.Elems
}

func (c *Collator) getColElemsString(str string) []colltab.Elem {
	i := c.iter(0)
	i.SetInputString(str)
	for i.Next() {
	}
	return i.Elems
}

type iter struct {
	wa [512]colltab.Elem

	colltab.Iter
	pce int
}

func (i *iter) init(c *Collator) {
	i.Weighter = c.t
	i.Elems = i.wa[:0]
}

func (i *iter) nextPrimary() int {
	for {
		for ; i.pce < i.N; i.pce++ {
			if v := i.Elems[i.pce].Primary(); v != 0 {
				i.pce++
				return v
			}
		}
		if !i.Next() {
			return 0
		}
	}
	panic("should not reach here")
}

func (i *iter) nextSecondary() int {
	for ; i.pce < len(i.Elems); i.pce++ {
		if v := i.Elems[i.pce].Secondary(); v != 0 {
			i.pce++
			return v
		}
	}
	return 0
}

func (i *iter) prevSecondary() int {
	for ; i.pce < len(i.Elems); i.pce++ {
		if v := i.Elems[len(i.Elems)-i.pce-1].Secondary(); v != 0 {
			i.pce++
			return v
		}
	}
	return 0
}

func (i *iter) nextTertiary() int {
	for ; i.pce < len(i.Elems); i.pce++ {
		if v := i.Elems[i.pce].Tertiary(); v != 0 {
			i.pce++
			return int(v)
		}
	}
	return 0
}

func (i *iter) nextQuaternary() int {
	for ; i.pce < len(i.Elems); i.pce++ {
		if v := i.Elems[i.pce].Quaternary(); v != 0 {
			i.pce++
			return v
		}
	}
	return 0
}

func appendPrimary(key []byte, p int) []byte {
	// Convert to variable length encoding; supports up to 23 bits.
	if p <= 0x7FFF {
		key = append(key, uint8(p>>8), uint8(p))
	} else {
		key = append(key, uint8(p>>16)|0x80, uint8(p>>8), uint8(p))
	}
	return key
}

// keyFromElems converts the weights ws to a compact sequence of bytes.
// The result will be appended to the byte buffer in buf.
func (c *Collator) keyFromElems(buf *Buffer, ws []colltab.Elem) {
	for _, v := range ws {
		if w := v.Primary(); w > 0 {
			buf.key = appendPrimary(buf.key, w)
		}
	}
	if !c.ignore[colltab.Secondary] {
		buf.key = append(buf.key, 0, 0)
		// TODO: we can use one 0 if we can guarantee that all non-zero weights are > 0xFF.
		if !c.backwards {
			for _, v := range ws {
				if w := v.Secondary(); w > 0 {
					buf.key = append(buf.key, uint8(w>>8), uint8(w))
				}
			}
		} else {
			for i := len(ws) - 1; i >= 0; i-- {
				if w := ws[i].Secondary(); w > 0 {
					buf.key = append(buf.key, uint8(w>>8), uint8(w))
				}
			}
		}
	} else if c.caseLevel {
		buf.key = append(buf.key, 0, 0)
	}
	if !c.ignore[colltab.Tertiary] || c.caseLevel {
		buf.key = append(buf.key, 0, 0)
		for _, v := range ws {
			if w := v.Tertiary(); w > 0 {
				buf.key = append(buf.key, uint8(w))
			}
		}
		// Derive the quaternary weights from the options and other levels.
		// Note that we represent MaxQuaternary as 0xFF. The first byte of the
		// representation of a primary weight is always smaller than 0xFF,
		// so using this single byte value will compare correctly.
		if !c.ignore[colltab.Quaternary] && c.alternate >= altShifted {
			if c.alternate == altShiftTrimmed {
				lastNonFFFF := len(buf.key)
				buf.key = append(buf.key, 0)
				for _, v := range ws {
					if w := v.Quaternary(); w == colltab.MaxQuaternary {
						buf.key = append(buf.key, 0xFF)
					} else if w > 0 {
						buf.key = appendPrimary(buf.key, w)
						lastNonFFFF = len(buf.key)
					}
				}
				buf.key = buf.key[:lastNonFFFF]
			} else {
				buf.key = append(buf.key, 0)
				for _, v := range ws {
					if w := v.Quaternary(); w == colltab.MaxQuaternary {
						buf.key = append(buf.key, 0xFF)
					} else if w > 0 {
						buf.key = appendPrimary(buf.key, w)
					}
				}
			}
		}
	}
}

func processWeights(vw alternateHandling, top uint32, wa []colltab.Elem) {
	ignore := false
	vtop := int(top)
	switch vw {
	case altShifted, altShiftTrimmed:
		for i := range wa {
			if p := wa[i].Primary(); p <= vtop && p != 0 {
				wa[i] = colltab.MakeQuaternary(p)
				ignore = true
			} else if p == 0 {
				if ignore {
					wa[i] = colltab.Ignore
				}
			} else {
				ignore = false
			}
		}
	case altBlanked:
		for i := range wa {
			if p := wa[i].Primary(); p <= vtop && (ignore || p != 0) {
				wa[i] = colltab.Ignore
				ignore = true
			} else {
				ignore = false
			}
		}
	}
}
<commit_msg>collate: remove misleading incorrect comment.<commit_after>// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// TODO: remove hard-coded versions when we have implemented fractional weights.
// The current implementation is incompatible with later CLDR versions.
//go:generate go run maketables.go -cldr=23 -unicode=6.2.0

// Package collate contains types for comparing and sorting Unicode strings
// according to a given collation order.
package collate // import "golang.org/x/text/collate"

import (
	"bytes"
	"strings"

	"golang.org/x/text/internal/colltab"
	"golang.org/x/text/language"
)

// Collator provides functionality for comparing strings for a given
// collation order.
type Collator struct {
	options

	sorter sorter

	_iter [2]iter
}

func (c *Collator) iter(i int) *iter {
	// TODO: evaluate performance for making the second iterator optional.
	return &c._iter[i]
}

// Supported returns the list of languages for which collating differs from its parent.
func Supported() []language.Tag {
	// TODO: use language.Coverage instead.

	t := make([]language.Tag, len(tags))
	copy(t, tags)
	return t
}

func init() {
	ids := strings.Split(availableLocales, ",")
	tags = make([]language.Tag, len(ids))
	for i, s := range ids {
		tags[i] = language.Raw.MustParse(s)
	}
}

var tags []language.Tag

// New returns a new Collator initialized for the given locale.
func New(t language.Tag, o ...Option) *Collator {
	index := colltab.MatchLang(t, tags)
	c := newCollator(getTable(locales[index]))

	// Set options from the user-supplied tag.
	c.setFromTag(t)

	// Set the user-supplied options.
	c.setOptions(o)

	c.init()
	return c
}

// NewFromTable returns a new Collator for the given Weighter.
func NewFromTable(w colltab.Weighter, o ...Option) *Collator {
	c := newCollator(w)
	c.setOptions(o)
	c.init()
	return c
}

func (c *Collator) init() {
	if c.numeric {
		c.t = colltab.NewNumericWeighter(c.t)
	}
	c._iter[0].init(c)
	c._iter[1].init(c)
}

// Buffer holds keys generated by Key and KeyString.
type Buffer struct {
	buf [4096]byte
	key []byte
}

func (b *Buffer) init() {
	if b.key == nil {
		b.key = b.buf[:0]
	}
}

// Reset clears the buffer from previous results generated by Key and KeyString.
func (b *Buffer) Reset() {
	b.key = b.key[:0]
}

// Compare returns an integer comparing the two byte slices.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (c *Collator) Compare(a, b []byte) int {
	// TODO: skip identical prefixes once we have a fast way to detect if a rune is
	// part of a contraction. This would lead to roughly a 10% speedup for the colcmp regtest.
	c.iter(0).SetInput(a)
	c.iter(1).SetInput(b)
	if res := c.compare(); res != 0 {
		return res
	}
	if !c.ignore[colltab.Identity] {
		return bytes.Compare(a, b)
	}
	return 0
}

// CompareString returns an integer comparing the two strings.
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
func (c *Collator) CompareString(a, b string) int {
	// TODO: skip identical prefixes once we have a fast way to detect if a rune is
	// part of a contraction. This would lead to roughly a 10% speedup for the colcmp regtest.
	c.iter(0).SetInputString(a)
	c.iter(1).SetInputString(b)
	if res := c.compare(); res != 0 {
		return res
	}
	if !c.ignore[colltab.Identity] {
		if a < b {
			return -1
		} else if a > b {
			return 1
		}
	}
	return 0
}

func compareLevel(f func(i *iter) int, a, b *iter) int {
	a.pce = 0
	b.pce = 0
	for {
		va := f(a)
		vb := f(b)
		if va != vb {
			if va < vb {
				return -1
			}
			return 1
		} else if va == 0 {
			break
		}
	}
	return 0
}

func (c *Collator) compare() int {
	ia, ib := c.iter(0), c.iter(1)
	// Process primary level
	if c.alternate != altShifted {
		// TODO: implement script reordering
		if res := compareLevel((*iter).nextPrimary, ia, ib); res != 0 {
			return res
		}
	} else {
		// TODO: handle shifted
	}
	if !c.ignore[colltab.Secondary] {
		f := (*iter).nextSecondary
		if c.backwards {
			f = (*iter).prevSecondary
		}
		if res := compareLevel(f, ia, ib); res != 0 {
			return res
		}
	}
	// TODO: special case handling (Danish?)
	if !c.ignore[colltab.Tertiary] || c.caseLevel {
		if res := compareLevel((*iter).nextTertiary, ia, ib); res != 0 {
			return res
		}
		if !c.ignore[colltab.Quaternary] {
			if res := compareLevel((*iter).nextQuaternary, ia, ib); res != 0 {
				return res
			}
		}
	}
	return 0
}

// Key returns the collation key for str.
// Passing the buffer buf may avoid memory allocations.
// The returned slice will point to an allocation in Buffer and will remain
// valid until the next call to buf.Reset().
func (c *Collator) Key(buf *Buffer, str []byte) []byte {
	// See http://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
	buf.init()
	return c.key(buf, c.getColElems(str))
}

// KeyFromString returns the collation key for str.
// Passing the buffer buf may avoid memory allocations.
// The returned slice will point to an allocation in Buffer and will retain
// valid until the next call to buf.ResetKeys().
func (c *Collator) KeyFromString(buf *Buffer, str string) []byte {
	// See http://www.unicode.org/reports/tr10/#Main_Algorithm for more details.
	buf.init()
	return c.key(buf, c.getColElemsString(str))
}

func (c *Collator) key(buf *Buffer, w []colltab.Elem) []byte {
	processWeights(c.alternate, c.t.Top(), w)
	kn := len(buf.key)
	c.keyFromElems(buf, w)
	return buf.key[kn:]
}

func (c *Collator) getColElems(str []byte) []colltab.Elem {
	i := c.iter(0)
	i.SetInput(str)
	for i.Next() {
	}
	return i.Elems
}

func (c *Collator) getColElemsString(str string) []colltab.Elem {
	i := c.iter(0)
	i.SetInputString(str)
	for i.Next() {
	}
	return i.Elems
}

type iter struct {
	wa [512]colltab.Elem

	colltab.Iter
	pce int
}

func (i *iter) init(c *Collator) {
	i.Weighter = c.t
	i.Elems = i.wa[:0]
}

func (i *iter) nextPrimary() int {
	for {
		for ; i.pce < i.N; i.pce++ {
			if v := i.Elems[i.pce].Primary(); v != 0 {
				i.pce++
				return v
			}
		}
		if !i.Next() {
			return 0
		}
	}
	panic("should not reach here")
}

func (i *iter) nextSecondary() int {
	for ; i.pce < len(i.Elems); i.pce++ {
		if v := i.Elems[i.pce].Secondary(); v != 0 {
			i.pce++
			return v
		}
	}
	return 0
}

func (i *iter) prevSecondary() int {
	for ; i.pce < len(i.Elems); i.pce++ {
		if v := i.Elems[len(i.Elems)-i.pce-1].Secondary(); v != 0 {
			i.pce++
			return v
		}
	}
	return 0
}

func (i *iter) nextTertiary() int {
	for ; i.pce < len(i.Elems); i.pce++ {
		if v := i.Elems[i.pce].Tertiary(); v != 0 {
			i.pce++
			return int(v)
		}
	}
	return 0
}

func (i *iter) nextQuaternary() int {
	for ; i.pce < len(i.Elems); i.pce++ {
		if v := i.Elems[i.pce].Quaternary(); v != 0 {
			i.pce++
			return v
		}
	}
	return 0
}

func appendPrimary(key []byte, p int) []byte {
	// Convert to variable length encoding; supports up to 23 bits.
	if p <= 0x7FFF {
		key = append(key, uint8(p>>8), uint8(p))
	} else {
		key = append(key, uint8(p>>16)|0x80, uint8(p>>8), uint8(p))
	}
	return key
}

// keyFromElems converts the weights ws to a compact sequence of bytes.
// The result will be appended to the byte buffer in buf.
func (c *Collator) keyFromElems(buf *Buffer, ws []colltab.Elem) {
	for _, v := range ws {
		if w := v.Primary(); w > 0 {
			buf.key = appendPrimary(buf.key, w)
		}
	}
	if !c.ignore[colltab.Secondary] {
		buf.key = append(buf.key, 0, 0)
		// TODO: we can use one 0 if we can guarantee that all non-zero weights are > 0xFF.
		if !c.backwards {
			for _, v := range ws {
				if w := v.Secondary(); w > 0 {
					buf.key = append(buf.key, uint8(w>>8), uint8(w))
				}
			}
		} else {
			for i := len(ws) - 1; i >= 0; i-- {
				if w := ws[i].Secondary(); w > 0 {
					buf.key = append(buf.key, uint8(w>>8), uint8(w))
				}
			}
		}
	} else if c.caseLevel {
		buf.key = append(buf.key, 0, 0)
	}
	if !c.ignore[colltab.Tertiary] || c.caseLevel {
		buf.key = append(buf.key, 0, 0)
		for _, v := range ws {
			if w := v.Tertiary(); w > 0 {
				buf.key = append(buf.key, uint8(w))
			}
		}
		// Derive the quaternary weights from the options and other levels.
		// Note that we represent MaxQuaternary as 0xFF. The first byte of the
		// representation of a primary weight is always smaller than 0xFF,
		// so using this single byte value will compare correctly.
		if !c.ignore[colltab.Quaternary] && c.alternate >= altShifted {
			if c.alternate == altShiftTrimmed {
				lastNonFFFF := len(buf.key)
				buf.key = append(buf.key, 0)
				for _, v := range ws {
					if w := v.Quaternary(); w == colltab.MaxQuaternary {
						buf.key = append(buf.key, 0xFF)
					} else if w > 0 {
						buf.key = appendPrimary(buf.key, w)
						lastNonFFFF = len(buf.key)
					}
				}
				buf.key = buf.key[:lastNonFFFF]
			} else {
				buf.key = append(buf.key, 0)
				for _, v := range ws {
					if w := v.Quaternary(); w == colltab.MaxQuaternary {
						buf.key = append(buf.key, 0xFF)
					} else if w > 0 {
						buf.key = appendPrimary(buf.key, w)
					}
				}
			}
		}
	}
}

func processWeights(vw alternateHandling, top uint32, wa []colltab.Elem) {
	ignore := false
	vtop := int(top)
	switch vw {
	case altShifted, altShiftTrimmed:
		for i := range wa {
			if p := wa[i].Primary(); p <= vtop && p != 0 {
				wa[i] = colltab.MakeQuaternary(p)
				ignore = true
			} else if p == 0 {
				if ignore {
					wa[i] = colltab.Ignore
				}
			} else {
				ignore = false
			}
		}
	case altBlanked:
		for i := range wa {
			if p := wa[i].Primary(); p <= vtop && (ignore || p != 0) {
				wa[i] = colltab.Ignore
				ignore = true
			} else {
				ignore = false
			}
		}
	}
}
<|endoftext|>


<commit_before>package collections
import "fmt"

type Set struct {
	data     map[interface{}]bool
	values   []interface{}
	initSize int
}

func (s Set) Size() int {
	return len(s.values)
}

func NewSet(size int, values ...interface{}) *Set {
	set := &Set{}
	set.initSize = size
	set.data = make(map[interface{}]bool)
	for _, val := range values {
		set.Add(val)
	}

	return set
}

// add a value into set,
// if this set already has the value it will return false,
// else return true
func (s *Set) Add(val interface{}) bool {
	if s.data[val] {
		return false
	}

	s.data[val] = true
	s.values = append(s.values, val)
	return true
}

//return true if this set contains the value,
//otherwise will return false
func (s *Set) Contains(val interface{}) bool {
	if s.data[val] {
		return true
	}

	return false
}

// if contains the value then delete the value and return ture
// otherwise will return false
func (s *Set) Remove(val interface{}) bool {
	if s.data[val] {
		delete(s.data, val)
		tmpSet := make([]interface{}, 0, len(s.data))
		for k, _ := range s.data {
			tmpSet = append(tmpSet, k)
		}

		s.values = tmpSet
		return true
	}

	return false
}

// get values from the set
func (s *Set) Values() []interface{} {
	return s.values
}

//values len is 0 will return true
// otherwise will return false
func (s *Set) IsEmpty() bool {
	return len(s.values) == 0
}

func (s *Set) String() string {
	var result string
	for v, _ := range s.data {
		result += fmt.Sprintf("%v", v)
	}

	return result
}

func (s *Set) Clear() *Set {
	s.values = make([]interface{}, 0, s.initSize)
	return s
}<commit_msg>修改 set string<commit_after>package collections
import "fmt"

type Set struct {
	data     map[interface{}]bool
	values   []interface{}
	initSize int
}

func (s Set) Size() int {
	return len(s.values)
}

func NewSet(size int, values ...interface{}) *Set {
	set := &Set{}
	set.initSize = size
	set.data = make(map[interface{}]bool)
	for _, val := range values {
		set.Add(val)
	}

	return set
}

// add a value into set,
// if this set already has the value it will return false,
// else return true
func (s *Set) Add(val interface{}) bool {
	if s.data[val] {
		return false
	}

	s.data[val] = true
	s.values = append(s.values, val)
	return true
}

//return true if this set contains the value,
//otherwise will return false
func (s *Set) Contains(val interface{}) bool {
	if s.data[val] {
		return true
	}

	return false
}

// if contains the value then delete the value and return ture
// otherwise will return false
func (s *Set) Remove(val interface{}) bool {
	if s.data[val] {
		delete(s.data, val)
		tmpSet := make([]interface{}, 0, len(s.data))
		for k, _ := range s.data {
			tmpSet = append(tmpSet, k)
		}

		s.values = tmpSet
		return true
	}

	return false
}

// get values from the set
func (s *Set) Values() []interface{} {
	return s.values
}

//values len is 0 will return true
// otherwise will return false
func (s *Set) IsEmpty() bool {
	return len(s.values) == 0
}

func (s *Set) String() string {
	return fmt.Sprint(s.values)
}

func (s *Set) Clear() *Set {
	s.values = make([]interface{}, 0, s.initSize)
	return s
}<|endoftext|>


<commit_before>package commands

import (
	kvexpress "../kvexpress/"
	"fmt"
	"github.com/spf13/cobra"
	"log"
	"os"
)

var inCmd = &cobra.Command{
	Use:   "in",
	Short: "Put configuration into Consul.",
	Long:  `in is for putting data into a Consul key so that you can write it on another networked node.`,
	Run:   inRun,
}

func inRun(cmd *cobra.Command, args []string) {
	var Direction = "in"
	checkInFlags(Direction)

	KeyStop := kvexpress.KeyStopPath(KeyInLocation, PrefixLocation, Direction)
	KeyData := kvexpress.KeyDataPath(KeyInLocation, PrefixLocation, Direction)
	KeyChecksum := kvexpress.KeyChecksumPath(KeyInLocation, PrefixLocation, Direction)

	CompareFile := kvexpress.CompareFilename(FiletoRead, Direction)
	LastFile := kvexpress.LastFilename(FiletoRead, Direction)

	StopKeyData := kvexpress.Get(KeyStop, ConsulServer, Token, Direction)

	if StopKeyData != "" {
		log.Print(Direction, ": Stop Key is present - stopping. Reason: ", StopKeyData)
		os.Exit(1)
	} else {
		log.Print(Direction, ": Stop Key is NOT present - continuing.")
	}

	// Read the file - if it's to be sorted - then make sure to sort.
	FileString := kvexpress.ReadFile(FiletoRead)

	// Sorting also removes any blank lines.
	if Sorted {
		FileString = kvexpress.SortFile(FileString)
	}

	// Is it long enough?
	longEnough := kvexpress.LengthCheck(FileString, MinFileLength, Direction)

	if !longEnough {
		log.Print(Direction, ": File is NOT long enough. Stopping.")
		os.Exit(1)
	}

	// Write the .compare file.
	kvexpress.WriteFile(FileString, CompareFile, FilePermissions, Direction)

	// Check for the .last file - touch if it doesn't exist.
	kvexpress.CheckLastFile(LastFile, FilePermissions)

	// Read compare and last files into string.
	CompareData := kvexpress.ReadFile(CompareFile)
	LastData := kvexpress.ReadFile(LastFile)

	if CompareData != "" && LastData != "" {
		log.Print(Direction, ": We have data - let's do the thing.")
	} else {
		log.Print(Direction, ": We do NOT have data. This should never happen.")
		os.Exit(1)
	}

	// Get SHA256 values for each string.
	CompareChecksum := kvexpress.ComputeChecksum(CompareData, Direction)
	LastChecksum := kvexpress.ComputeChecksum(LastData, Direction)

	// If they're different - let's update things.
	if CompareChecksum != LastChecksum {
		log.Print(Direction, ": file checksums are different - let's update some stuff!")
	} else {
		log.Print(Direction, ": checksums='match' saved='false'")
		os.Exit(0)
	}

	// Diff the file data.
	// html_diff := kvexpress.HTMLDiff(LastData, CompareData)

	// TODO: To be removed.
	// fmt.Printf("%v", html_diff)

	// Get the checksum from Consul.
	CurrentChecksum := kvexpress.Get(KeyChecksum, ConsulServer, Token, Direction)

	if CurrentChecksum != CompareChecksum {
		log.Print(Direction, ": current and previous Consul checksum are different - let's update the KV store.")
		saved := kvexpress.Set(KeyData, CompareData, ConsulServer, Token, Direction)
		if saved {
			CompareDataBytes := len(CompareData)
			log.Print(Direction, ": KeyData='", KeyData, "' saved='true' size='", CompareDataBytes, "'")
			kvexpress.Set(KeyChecksum, CompareChecksum, ConsulServer, Token, Direction)

			if DogStatsd {
				kvexpress.StatsdIn(KeyInLocation, CompareDataBytes, CompareData)
			}

			// Copy the CompareData to the .last file.
			kvexpress.WriteFile(CompareData, LastFile, FilePermissions, Direction)
		} else {
			log.Print(Direction, ": KeyData='", KeyData, "' saved='false'")
			os.Exit(1)
		}

	}

	// Run this command after the data is input.
	if PostExec != "" {
		log.Print(Direction, ": exec='", PostExec, "'")
		kvexpress.RunCommand(PostExec)
	}
}

func checkInFlags(direction string) {
	log.Print(direction, ": Checking cli flags.")
	if KeyInLocation == "" {
		fmt.Println(direction, ": Need a key location in -k")
		os.Exit(1)
	}
	if FiletoRead == "" {
		fmt.Println(direction, ": Need a file to read in -f")
		os.Exit(1)
	}
	if _, err := os.Stat(FiletoRead); err != nil {
		fmt.Println(direction, ": File ", FiletoRead, " does not exist.")
		os.Exit(1)
	}
	if DogStatsd {
		log.Print(direction, ": Enabling Dogstatsd metrics.")
	}
	log.Print(direction, ": Required cli flags present.")
}

var (
	KeyInLocation string
	FiletoRead    string
	Sorted        bool
)

func init() {
	RootCmd.AddCommand(inCmd)
	inCmd.Flags().StringVarP(&KeyInLocation, "key", "k", "", "key to push data to")
	inCmd.Flags().StringVarP(&FiletoRead, "file", "f", "", "filename to read data from")
	inCmd.Flags().BoolVarP(&Sorted, "sorted", "S", false, "sort the input file")
}
<commit_msg>Always write the .last file once we get this far. Closes #33.<commit_after>package commands

import (
	kvexpress "../kvexpress/"
	"fmt"
	"github.com/spf13/cobra"
	"log"
	"os"
)

var inCmd = &cobra.Command{
	Use:   "in",
	Short: "Put configuration into Consul.",
	Long:  `in is for putting data into a Consul key so that you can write it on another networked node.`,
	Run:   inRun,
}

func inRun(cmd *cobra.Command, args []string) {
	var Direction = "in"
	checkInFlags(Direction)

	KeyStop := kvexpress.KeyStopPath(KeyInLocation, PrefixLocation, Direction)
	KeyData := kvexpress.KeyDataPath(KeyInLocation, PrefixLocation, Direction)
	KeyChecksum := kvexpress.KeyChecksumPath(KeyInLocation, PrefixLocation, Direction)

	CompareFile := kvexpress.CompareFilename(FiletoRead, Direction)
	LastFile := kvexpress.LastFilename(FiletoRead, Direction)

	StopKeyData := kvexpress.Get(KeyStop, ConsulServer, Token, Direction)

	if StopKeyData != "" {
		log.Print(Direction, ": Stop Key is present - stopping. Reason: ", StopKeyData)
		os.Exit(1)
	} else {
		log.Print(Direction, ": Stop Key is NOT present - continuing.")
	}

	// Read the file - if it's to be sorted - then make sure to sort.
	FileString := kvexpress.ReadFile(FiletoRead)

	// Sorting also removes any blank lines.
	if Sorted {
		FileString = kvexpress.SortFile(FileString)
	}

	// Is it long enough?
	longEnough := kvexpress.LengthCheck(FileString, MinFileLength, Direction)

	if !longEnough {
		log.Print(Direction, ": File is NOT long enough. Stopping.")
		os.Exit(1)
	}

	// Write the .compare file.
	kvexpress.WriteFile(FileString, CompareFile, FilePermissions, Direction)

	// Check for the .last file - touch if it doesn't exist.
	kvexpress.CheckLastFile(LastFile, FilePermissions)

	// Read compare and last files into string.
	CompareData := kvexpress.ReadFile(CompareFile)
	LastData := kvexpress.ReadFile(LastFile)

	if CompareData != "" && LastData != "" {
		log.Print(Direction, ": We have data - let's do the thing.")
	} else {
		log.Print(Direction, ": We do NOT have data. This should never happen.")
		os.Exit(1)
	}

	// Get SHA256 values for each string.
	CompareChecksum := kvexpress.ComputeChecksum(CompareData, Direction)
	LastChecksum := kvexpress.ComputeChecksum(LastData, Direction)

	// If they're different - let's update things.
	if CompareChecksum != LastChecksum {
		log.Print(Direction, ": file checksums are different - let's update some stuff!")
	} else {
		log.Print(Direction, ": checksums='match' saved='false'")
		os.Exit(0)
	}

	// If we get this far - copy the CompareData to the .last file.
	// This handles the case detailed in https://github.com/darron/kvexpress/issues/33
	kvexpress.WriteFile(CompareData, LastFile, FilePermissions, Direction)

	// Diff the file data.
	// html_diff := kvexpress.HTMLDiff(LastData, CompareData)

	// TODO: To be removed.
	// fmt.Printf("%v", html_diff)

	// Get the checksum from Consul.
	CurrentChecksum := kvexpress.Get(KeyChecksum, ConsulServer, Token, Direction)

	if CurrentChecksum != CompareChecksum {
		log.Print(Direction, ": current and previous Consul checksum are different - let's update the KV store.")
		saved := kvexpress.Set(KeyData, CompareData, ConsulServer, Token, Direction)
		if saved {
			CompareDataBytes := len(CompareData)
			log.Print(Direction, ": KeyData='", KeyData, "' saved='true' size='", CompareDataBytes, "'")
			kvexpress.Set(KeyChecksum, CompareChecksum, ConsulServer, Token, Direction)

			if DogStatsd {
				kvexpress.StatsdIn(KeyInLocation, CompareDataBytes, CompareData)
			}

		} else {
			log.Print(Direction, ": KeyData='", KeyData, "' saved='false'")
			os.Exit(0)
		}

	}
	// Run this command after the data is input.
	if PostExec != "" {
		log.Print(Direction, ": exec='", PostExec, "'")
		kvexpress.RunCommand(PostExec)
	}
}

func checkInFlags(direction string) {
	log.Print(direction, ": Checking cli flags.")
	if KeyInLocation == "" {
		fmt.Println(direction, ": Need a key location in -k")
		os.Exit(1)
	}
	if FiletoRead == "" {
		fmt.Println(direction, ": Need a file to read in -f")
		os.Exit(1)
	}
	if _, err := os.Stat(FiletoRead); err != nil {
		fmt.Println(direction, ": File ", FiletoRead, " does not exist.")
		os.Exit(1)
	}
	if DogStatsd {
		log.Print(direction, ": Enabling Dogstatsd metrics.")
	}
	log.Print(direction, ": Required cli flags present.")
}

var (
	KeyInLocation string
	FiletoRead    string
	Sorted        bool
)

func init() {
	RootCmd.AddCommand(inCmd)
	inCmd.Flags().StringVarP(&KeyInLocation, "key", "k", "", "key to push data to")
	inCmd.Flags().StringVarP(&FiletoRead, "file", "f", "", "filename to read data from")
	inCmd.Flags().BoolVarP(&Sorted, "sorted", "S", false, "sort the input file")
}
<|endoftext|>