<commit_before>// EVH is designed to be a single-use file transfer system.  Its purpose is to replace
// aging methods of sharing files such as FTP.  With the advent of services like
// DropBox, Box, Google Drive and the like, this type of service is becoming more
// commonplace EVH has some differentiating features that make it an especially
// good tool for corporations and/or home use.
//
// EVH runs in two modes: server and client.  Server hosts a web server interface for
// uploading and downloading files.  The Client is for uploading only and runs
// in a terminal.  This app is designed to run on all platforms that Go supports.
package main

import (
	"flag"
	"html/template"
	"log"
	"net/http"
	"os"
)

// Flags
var ConfigFileFlag string
var DstEmailFlag string
var ExpirationFlag string
var FileDescrFlag string
var FilesFieldFlag string
var ProgressFlag bool
var ServerFlag bool
var SrcEmailFlag string
var UrlFlag string
var Evh1ImportFlag bool

// Global Variables
var UploadUrlPath = "/upload/"
var DownloadUrlPath = "/download/"
var Files []string
var HttpProto = "http"
var SiteDown bool
var Templates *template.Template

// Constants
const VERSION = "2.2.2"
const TimeLayout = "Jan 2, 2006 at 3:04pm (MST)"

func init() {
	flag.StringVar(&ConfigFileFlag, "c", "", "Location of the Configuration file")
	flag.BoolVar(&ServerFlag, "server", false, "Listen for incoming file uploads")

	// Client flags
	flag.StringVar(&UrlFlag, "url", "", "Remote server URL to send files to (client only)")
	flag.StringVar(&FilesFieldFlag, "field", "", "Field name of the form (client only)")
	flag.StringVar(&SrcEmailFlag, "from", "", "Email address of uploader (client only)")
	flag.StringVar(&DstEmailFlag, "to", "", "Comma separated set of email address(es) of file recipient(s) (client only)")
	flag.StringVar(&FileDescrFlag, "description", "", "File desription (use quotes) (client only)")
	flag.BoolVar(&ProgressFlag, "progress", true, "Show progress bar during upload (client only)")
	flag.StringVar(&ExpirationFlag, "expires", "", "Example 1:d for 1 day (client only)")
	flag.BoolVar(&Evh1ImportFlag, "import", false, "Import data from EVH1 instance (client only)")
}

func main() {
	flag.Parse()

	// Load in our Config
	Config = NewConfig(ConfigFileFlag)
	Config.ImportFlags()

	if ServerFlag {
		// Final sanity check
		if Config.Server.Assets == "" {
			log.Fatal("ERROR: Cannot continue without specifying assets path")
		}
		if Config.Server.Templates == "" {
			log.Fatal("ERROR: Cannot continue without specifying templates path")
		}
		if Config.Server.ListenAddr == "" {
			log.Fatal("ERROR: Cannot continue without specifying listenaddr value")
		}
		if Config.Server.Mailserver == "" {
			log.Println("WARNING: cannot send emails, mailserver not set")
		}

		// Set so all generated URLs use https if enabled
		if Config.Server.Ssl {
			HttpProto = "https"
		}

		// Setup our assets dir (if it don't already exist)
		err := os.MkdirAll(Config.Server.Assets, 0700)
		if err != nil {
			log.Fatal("Cannot setup assetdir as needed: " + err.Error())
		}

		// Parse our html templates
		go RefreshTemplates()
		go ScrubDownloads()

		// Register our handler functions
		http.HandleFunc(UploadUrlPath, SSLCheck(UploadHandler))
		http.HandleFunc(DownloadUrlPath, SSLCheck(AssetHandler))
		http.HandleFunc("/admin/", BasicAuth(SSLCheck(AdminHandler)))
		http.HandleFunc("/", SSLCheck(HomeHandler))

		// Listen
		log.Println("Listening...")

		// Spawn HTTPS listener in another thread
		go func() {
			if Config.Server.Ssl == false || Config.Server.SslPort == "" {
				return
			}
			var addrSsl = Config.Server.ListenAddr + ":" + Config.Server.SslPort
			listenErrSsl := http.ListenAndServeTLS(addrSsl, Config.Server.CertFile, Config.Server.KeyFile, nil)
			if listenErrSsl != nil {
				log.Fatal("ERROR: ssl listen problem: " + listenErrSsl.Error())
			}
		}()

		// Start non-SSL listener
		var addrNonSsl = Config.Server.ListenAddr + ":" + Config.Server.NonSslPort
		listenErr := http.ListenAndServe(addrNonSsl, nil)
		if listenErr != nil {
			log.Fatal("ERROR: non-ssl listen problem: " + listenErr.Error())
		}
	} else {
		// Run import if requested
		if Evh1ImportFlag {
			SpitSlurp()
			return
		}

		// Final sanity check
		if Config.Client.DestEmail == "" {
			log.Println("WARNING: no -destemail value set, cannot send reciever an email")
		}
		if Config.Client.Email == "" {
			log.Println("WARNING: no -email value set, cannot send email to uploader")
		}
		if Config.Client.Field == "" {
			log.Println("WARNING: no -field value set, using \"file\" instead")
			Config.Client.Field = "file"
		}
		if Config.Client.Url == "" {
			log.Fatal("ERROR: Cannot continue without specifying -url value")
		}

		// All filenames are unflagged arguments, loop through them and uplod the file(s)
		for _, fname := range flag.Args() {
			fi, err := os.Stat(fname)
			if err != nil {
				log.Println("WARNING: Cannot read file, skipping ", fname, ": ", err.Error())
			} else {
				if fi.Mode().IsRegular() {
					Files = append(Files, fname)
				}
			}
		}

		Upload(Files)
	}
}
<commit_msg>Version bump to 2.2.3<commit_after>// EVH is designed to be a single-use file transfer system.  Its purpose is to replace
// aging methods of sharing files such as FTP.  With the advent of services like
// DropBox, Box, Google Drive and the like, this type of service is becoming more
// commonplace EVH has some differentiating features that make it an especially
// good tool for corporations and/or home use.
//
// EVH runs in two modes: server and client.  Server hosts a web server interface for
// uploading and downloading files.  The Client is for uploading only and runs
// in a terminal.  This app is designed to run on all platforms that Go supports.
package main

import (
	"flag"
	"html/template"
	"log"
	"net/http"
	"os"
)

// Flags
var ConfigFileFlag string
var DstEmailFlag string
var ExpirationFlag string
var FileDescrFlag string
var FilesFieldFlag string
var ProgressFlag bool
var ServerFlag bool
var SrcEmailFlag string
var UrlFlag string
var Evh1ImportFlag bool

// Global Variables
var UploadUrlPath = "/upload/"
var DownloadUrlPath = "/download/"
var Files []string
var HttpProto = "http"
var SiteDown bool
var Templates *template.Template

// Constants
const VERSION = "2.2.3"
const TimeLayout = "Jan 2, 2006 at 3:04pm (MST)"

func init() {
	flag.StringVar(&ConfigFileFlag, "c", "", "Location of the Configuration file")
	flag.BoolVar(&ServerFlag, "server", false, "Listen for incoming file uploads")

	// Client flags
	flag.StringVar(&UrlFlag, "url", "", "Remote server URL to send files to (client only)")
	flag.StringVar(&FilesFieldFlag, "field", "", "Field name of the form (client only)")
	flag.StringVar(&SrcEmailFlag, "from", "", "Email address of uploader (client only)")
	flag.StringVar(&DstEmailFlag, "to", "", "Comma separated set of email address(es) of file recipient(s) (client only)")
	flag.StringVar(&FileDescrFlag, "description", "", "File desription (use quotes) (client only)")
	flag.BoolVar(&ProgressFlag, "progress", true, "Show progress bar during upload (client only)")
	flag.StringVar(&ExpirationFlag, "expires", "", "Example 1:d for 1 day (client only)")
	flag.BoolVar(&Evh1ImportFlag, "import", false, "Import data from EVH1 instance (client only)")
}

func main() {
	flag.Parse()

	// Load in our Config
	Config = NewConfig(ConfigFileFlag)
	Config.ImportFlags()

	if ServerFlag {
		// Final sanity check
		if Config.Server.Assets == "" {
			log.Fatal("ERROR: Cannot continue without specifying assets path")
		}
		if Config.Server.Templates == "" {
			log.Fatal("ERROR: Cannot continue without specifying templates path")
		}
		if Config.Server.ListenAddr == "" {
			log.Fatal("ERROR: Cannot continue without specifying listenaddr value")
		}
		if Config.Server.Mailserver == "" {
			log.Println("WARNING: cannot send emails, mailserver not set")
		}

		// Set so all generated URLs use https if enabled
		if Config.Server.Ssl {
			HttpProto = "https"
		}

		// Setup our assets dir (if it don't already exist)
		err := os.MkdirAll(Config.Server.Assets, 0700)
		if err != nil {
			log.Fatal("Cannot setup assetdir as needed: " + err.Error())
		}

		// Parse our html templates
		go RefreshTemplates()
		go ScrubDownloads()

		// Register our handler functions
		http.HandleFunc(UploadUrlPath, SSLCheck(UploadHandler))
		http.HandleFunc(DownloadUrlPath, SSLCheck(AssetHandler))
		http.HandleFunc("/admin/", BasicAuth(SSLCheck(AdminHandler)))
		http.HandleFunc("/", SSLCheck(HomeHandler))

		// Listen
		log.Println("Listening...")

		// Spawn HTTPS listener in another thread
		go func() {
			if Config.Server.Ssl == false || Config.Server.SslPort == "" {
				return
			}
			var addrSsl = Config.Server.ListenAddr + ":" + Config.Server.SslPort
			listenErrSsl := http.ListenAndServeTLS(addrSsl, Config.Server.CertFile, Config.Server.KeyFile, nil)
			if listenErrSsl != nil {
				log.Fatal("ERROR: ssl listen problem: " + listenErrSsl.Error())
			}
		}()

		// Start non-SSL listener
		var addrNonSsl = Config.Server.ListenAddr + ":" + Config.Server.NonSslPort
		listenErr := http.ListenAndServe(addrNonSsl, nil)
		if listenErr != nil {
			log.Fatal("ERROR: non-ssl listen problem: " + listenErr.Error())
		}
	} else {
		// Run import if requested
		if Evh1ImportFlag {
			SpitSlurp()
			return
		}

		// Final sanity check
		if Config.Client.DestEmail == "" {
			log.Println("WARNING: no -destemail value set, cannot send reciever an email")
		}
		if Config.Client.Email == "" {
			log.Println("WARNING: no -email value set, cannot send email to uploader")
		}
		if Config.Client.Field == "" {
			log.Println("WARNING: no -field value set, using \"file\" instead")
			Config.Client.Field = "file"
		}
		if Config.Client.Url == "" {
			log.Fatal("ERROR: Cannot continue without specifying -url value")
		}

		// All filenames are unflagged arguments, loop through them and uplod the file(s)
		for _, fname := range flag.Args() {
			fi, err := os.Stat(fname)
			if err != nil {
				log.Println("WARNING: Cannot read file, skipping ", fname, ": ", err.Error())
			} else {
				if fi.Mode().IsRegular() {
					Files = append(Files, fname)
				}
			}
		}

		Upload(Files)
	}
}
<|endoftext|>


<commit_before>package azurerm

import (
	"fmt"
	"net/http"

	"github.com/Azure/azure-sdk-for-go/arm/dns"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceArmDnsZone() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmDnsZoneCreate,
		Read:   resourceArmDnsZoneRead,
		Update: resourceArmDnsZoneCreate,
		Delete: resourceArmDnsZoneDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"resource_group_name": {
				Type:             schema.TypeString,
				Required:         true,
				ForceNew:         true,
				DiffSuppressFunc: resourceAzurermResourceGroupNameDiffSuppress,
			},

			"number_of_record_sets": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"max_number_of_record_sets": {
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
			},

			"name_servers": {
				Type:     schema.TypeSet,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceArmDnsZoneCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).zonesClient

	name := d.Get("name").(string)
	resGroup := d.Get("resource_group_name").(string)
	location := "global"

	tags := d.Get("tags").(map[string]interface{})

	parameters := dns.Zone{
		Location: &location,
		Tags:     expandTags(tags),
	}

	etag := ""
	ifNoneMatch := "" // set to empty to allow updates to records after creation
	resp, err := client.CreateOrUpdate(resGroup, name, parameters, etag, ifNoneMatch)
	if err != nil {
		return err
	}

	if resp.ID == nil {
		return fmt.Errorf("Cannot read DNS zone %s (resource group %s) ID", name, resGroup)
	}

	d.SetId(*resp.ID)

	return resourceArmDnsZoneRead(d, meta)
}

func resourceArmDnsZoneRead(d *schema.ResourceData, meta interface{}) error {
	zonesClient := meta.(*ArmClient).zonesClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}

	resGroup := id.ResourceGroup
	name := id.Path["dnszones"]

	resp, err := zonesClient.Get(resGroup, name)
	if err != nil {
		return fmt.Errorf("Error reading DNS zone %s (resource group %s): %+v", name, resGroup, err)
	}
	if resp.StatusCode == http.StatusNotFound {
		d.SetId("")
		return nil
	}

	d.Set("name", name)
	d.Set("resource_group_name", resGroup)
	d.Set("number_of_record_sets", resp.NumberOfRecordSets)
	d.Set("max_number_of_record_sets", resp.MaxNumberOfRecordSets)

	nameServers := make([]string, 0, len(*resp.NameServers))
	for _, ns := range *resp.NameServers {
		nameServers = append(nameServers, ns)
	}
	if err := d.Set("name_servers", nameServers); err != nil {
		return err
	}

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmDnsZoneDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).zonesClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}

	resGroup := id.ResourceGroup
	name := id.Path["dnszones"]

	etag := ""
	_, error := client.Delete(resGroup, name, etag, make(chan struct{}))
	err = <-error

	if err != nil {
		return fmt.Errorf("Error deleting DNS zone %s (resource group %s): %+v", name, resGroup, err)
	}

	return nil
}
<commit_msg>These computed fields aren't actually optional<commit_after>package azurerm

import (
	"fmt"
	"net/http"

	"github.com/Azure/azure-sdk-for-go/arm/dns"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceArmDnsZone() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmDnsZoneCreate,
		Read:   resourceArmDnsZoneRead,
		Update: resourceArmDnsZoneCreate,
		Delete: resourceArmDnsZoneDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"resource_group_name": {
				Type:             schema.TypeString,
				Required:         true,
				ForceNew:         true,
				DiffSuppressFunc: resourceAzurermResourceGroupNameDiffSuppress,
			},

			"number_of_record_sets": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"max_number_of_record_sets": {
				Type:     schema.TypeString,
				Computed: true,
			},

			"name_servers": {
				Type:     schema.TypeSet,
				Computed: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set:      schema.HashString,
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceArmDnsZoneCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).zonesClient

	name := d.Get("name").(string)
	resGroup := d.Get("resource_group_name").(string)
	location := "global"

	tags := d.Get("tags").(map[string]interface{})

	parameters := dns.Zone{
		Location: &location,
		Tags:     expandTags(tags),
	}

	etag := ""
	ifNoneMatch := "" // set to empty to allow updates to records after creation
	resp, err := client.CreateOrUpdate(resGroup, name, parameters, etag, ifNoneMatch)
	if err != nil {
		return err
	}

	if resp.ID == nil {
		return fmt.Errorf("Cannot read DNS zone %s (resource group %s) ID", name, resGroup)
	}

	d.SetId(*resp.ID)

	return resourceArmDnsZoneRead(d, meta)
}

func resourceArmDnsZoneRead(d *schema.ResourceData, meta interface{}) error {
	zonesClient := meta.(*ArmClient).zonesClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}

	resGroup := id.ResourceGroup
	name := id.Path["dnszones"]

	resp, err := zonesClient.Get(resGroup, name)
	if err != nil {
		return fmt.Errorf("Error reading DNS zone %s (resource group %s): %+v", name, resGroup, err)
	}
	if resp.StatusCode == http.StatusNotFound {
		d.SetId("")
		return nil
	}

	d.Set("name", name)
	d.Set("resource_group_name", resGroup)
	d.Set("number_of_record_sets", resp.NumberOfRecordSets)
	d.Set("max_number_of_record_sets", resp.MaxNumberOfRecordSets)

	nameServers := make([]string, 0, len(*resp.NameServers))
	for _, ns := range *resp.NameServers {
		nameServers = append(nameServers, ns)
	}
	if err := d.Set("name_servers", nameServers); err != nil {
		return err
	}

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmDnsZoneDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).zonesClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}

	resGroup := id.ResourceGroup
	name := id.Path["dnszones"]

	etag := ""
	_, error := client.Delete(resGroup, name, etag, make(chan struct{}))
	err = <-error

	if err != nil {
		return fmt.Errorf("Error deleting DNS zone %s (resource group %s): %+v", name, resGroup, err)
	}

	return 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.

package url_test

import (
	"fmt"
	"log"
	"net/url"
)

func ExampleValues() {
	v := url.Values{}
	v.Set("name", "Ava")
	v.Add("friend", "Jess")
	v.Add("friend", "Sarah")
	v.Add("friend", "Zoe")
	// v.Encode() == "name=Ava&friend=Jess&friend=Sarah&friend=Zoe"
	fmt.Println(v.Get("name"))
	fmt.Println(v.Get("friend"))
	fmt.Println(v["friend"])
	// Output:
	// Ava
	// Jess
	// [Jess Sarah Zoe]
}

func ExampleURL() {
	u, err := url.Parse("http://bing.com/search?q=dotnet")
	if err != nil {
		log.Fatal(err)
	}
	u.Scheme = "https"
	u.Host = "google.com"
	q := u.Query()
	q.Set("q", "golang")
	u.RawQuery = q.Encode()
	fmt.Println(u)
	// Output: https://google.com/search?q=golang
}
<commit_msg>net/url: add example of using URL.Opaque with http.Request<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.

package url_test

import (
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"strings"
)

func ExampleValues() {
	v := url.Values{}
	v.Set("name", "Ava")
	v.Add("friend", "Jess")
	v.Add("friend", "Sarah")
	v.Add("friend", "Zoe")
	// v.Encode() == "name=Ava&friend=Jess&friend=Sarah&friend=Zoe"
	fmt.Println(v.Get("name"))
	fmt.Println(v.Get("friend"))
	fmt.Println(v["friend"])
	// Output:
	// Ava
	// Jess
	// [Jess Sarah Zoe]
}

func ExampleURL() {
	u, err := url.Parse("http://bing.com/search?q=dotnet")
	if err != nil {
		log.Fatal(err)
	}
	u.Scheme = "https"
	u.Host = "google.com"
	q := u.Query()
	q.Set("q", "golang")
	u.RawQuery = q.Encode()
	fmt.Println(u)
	// Output: https://google.com/search?q=golang
}

func ExampleURL_opaque() {
	// Sending a literal '%' in an HTTP request's Path
	req := &http.Request{
		Method: "GET",
		Host:   "example.com", // takes precendence over URL.Host
		URL: &url.URL{
			Host:   "ignored",
			Scheme: "https",
			Opaque: "/%2f/",
		},
		Header: http.Header{
			"User-Agent": {"godoc-example/0.1"},
		},
	}
	out, err := httputil.DumpRequestOut(req, true)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(strings.Replace(string(out), "\r", "", -1))
	// Output:
	// GET /%2f/ HTTP/1.1
	// Host: example.com
	// User-Agent: godoc-example/0.1
	// Accept-Encoding: gzip
	//
}
<|endoftext|>


<commit_before>package fix

import (
	"os"
	"path/filepath"

	"github.com/ghthor/gospec"
	. "github.com/ghthor/gospec"
	"github.com/ghthor/journal/git"
	"github.com/ghthor/journal/git/gittest"
)

func DescribeAFixableJournal(c gospec.Context) {
	c.Specify("a fixed journal is a", func() {
		// TODO this is a hack to create a fixed journal repo
		d, _, err := newCase0("case_current_spec")
		c.Assume(err, IsNil)

		_, err = Fix(d)
		c.Assume(err, IsNil)

		c.Specify("directory", func() {
			// c.Expect(d, isa, directory)
			c.Specify("inside a git repository", func() {
				// c.Expect(d, isa, gitrepo)
			})

			c.Specify("containing", func() {
				c.Specify("an entry directory", func() {
					// c.Expect(d, contains, "entry/")
					c.Specify("with all entries using the current entry format", func() {
						// c.Expect(d.entries, areCurrentFormat)
					})
				})

				c.Specify("an idea directory store", func() {
					// c.Expect(d.ideas, exists)
					// c.Expect(d.ideas, isEdittable)
				})
			})
		})
	})

	c.Specify("a fixable journal is a", func() {
		d, _, err := newCase0("case_0_is_fixable")
		c.Assume(err, IsNil)

		c.Specify("directory", func() {
			c.Specify("inside a git repository", func() {
				c.Assume(d, gittest.IsAGitRepository)
				c.Assume(git.IsClean(d), IsNil)

				// Case 0
				c.Specify("that contains entries", func() {
					needsFixed, err := NeedsFixed(d)
					c.Expect(needsFixed, IsTrue)

					_, err = Fix(d)
					c.Expect(err, IsNil)

					needsFixed, err = NeedsFixed(d)
					c.Expect(needsFixed, IsFalse)
				})
			})
		})
	})
}
<commit_msg>Specify the directory attributes of a fixed journal<commit_after>package fix

import (
	"os"
	"path/filepath"

	"github.com/ghthor/gospec"
	. "github.com/ghthor/gospec"
	"github.com/ghthor/journal/git"
	"github.com/ghthor/journal/git/gittest"
)

func DescribeAFixableJournal(c gospec.Context) {
	c.Specify("a fixed journal is a", func() {
		// TODO this is a hack to create a fixed journal repo
		d, _, err := newCase0("case_current_spec")
		c.Assume(err, IsNil)

		_, err = Fix(d)
		c.Assume(err, IsNil)

		c.Specify("directory", func() {
			fi, err := os.Stat(d)
			c.Assume(err, IsNil)
			c.Expect(fi.IsDir(), IsTrue)

			c.Specify("inside a git repository", func() {
				c.Expect(d, gittest.IsAGitRepository)
			})

			c.Specify("containing", func() {
				c.Specify("an entry directory", func() {
					// c.Expect(d, contains, "entry/")
					c.Specify("with all entries using the current entry format", func() {
						// c.Expect(d.entries, areCurrentFormat)
					})
				})

				c.Specify("an idea directory store", func() {
					// c.Expect(d.ideas, exists)
					// c.Expect(d.ideas, isEdittable)
				})
			})
		})
	})

	c.Specify("a fixable journal is a", func() {
		d, _, err := newCase0("case_0_is_fixable")
		c.Assume(err, IsNil)

		c.Specify("directory", func() {
			c.Specify("inside a git repository", func() {
				c.Assume(d, gittest.IsAGitRepository)
				c.Assume(git.IsClean(d), IsNil)

				// Case 0
				c.Specify("that contains entries", func() {
					needsFixed, err := NeedsFixed(d)
					c.Expect(needsFixed, IsTrue)

					_, err = Fix(d)
					c.Expect(err, IsNil)

					needsFixed, err = NeedsFixed(d)
					c.Expect(needsFixed, IsFalse)
				})
			})
		})
	})
}
<|endoftext|>


<commit_before>package tasks

import(
	"fmt"
	"net/url"
	"time"

	"golang.org/x/net/context"

	cloudtasks "cloud.google.com/go/cloudtasks/apiv2"
	taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2"
	"github.com/golang/protobuf/ptypes/timestamp"
)

// SubmitAETask submits a new task to your App Engine queue.
func SubmitAETask(ctxIn context.Context, projectID, locationID, queueID string, wait time.Duration, uri string, params url.Values) (*taskspb.Task, error) {
	// Create a new Cloud Tasks client instance.
	// See https://godoc.org/cloud.google.com/go/cloudtasks/apiv2

	ctx,_ := context.WithTimeout(ctxIn, 30 * time.Second) // This is max deadline for cloudtasks API
	client, err := cloudtasks.NewClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("cloudtasks.NewClient: %v", err)
	}

	// Build the Task queue path.
	queuePath := fmt.Sprintf("projects/%s/locations/%s/queues/%s", projectID, locationID, queueID)

	// Build the Task payload.
	// https://godoc.org/google.golang.org/genproto/googleapis/cloud/tasks/v2#CreateTaskRequest
	req := &taskspb.CreateTaskRequest{
		Parent: queuePath,
		Task: &taskspb.Task{
			// https://godoc.org/google.golang.org/genproto/googleapis/cloud/tasks/v2#AppEngineHttpRequest
			MessageType: &taskspb.Task_AppEngineHttpRequest{
				AppEngineHttpRequest: &taskspb.AppEngineHttpRequest{
					// For some reason, POST & body params aren't picked up by the inbound task handler
					HttpMethod:  taskspb.HttpMethod_GET,
					RelativeUri: uri + "?" + params.Encode(),
				},
			},
		},
	}

	// Apply a time delay, if needed
	if wait > 0 {
		when := timestamp.Timestamp{
			Seconds: time.Now().Add(wait).Unix(),
		}
		req.Task.ScheduleTime = &when
	}

	createdTask, err := client.CreateTask(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("cloudtasks.CreateTask: %v", err)
	}

	return createdTask, nil
}
<commit_msg>Allow for task client reuse, in case that's the memory leak<commit_after>package tasks

import(
	"fmt"
	"net/url"
	"time"

	"golang.org/x/net/context"

	cloudtasks "cloud.google.com/go/cloudtasks/apiv2"
	taskspb "google.golang.org/genproto/googleapis/cloud/tasks/v2"
	"github.com/golang/protobuf/ptypes/timestamp"
)

// Create a new Cloud Tasks client instance. Should do this once per submission run,
// not once per task submission
// See https://godoc.org/cloud.google.com/go/cloudtasks/apiv2
func GetClient(ctxIn context.Context) (*cloudtasks.Client, error) {
	ctx,_ := context.WithTimeout(ctxIn, 30 * time.Second) // This is max deadline for cloudtasks API

	if client, err := cloudtasks.NewClient(ctx); err != nil {
		return nil, fmt.Errorf("cloudtasks.NewClient: %v", err)
	} else {
		return client, nil
	}
}

// SubmitAETask submits a new task to your App Engine queue.
func SubmitAETask(ctxIn context.Context, client *cloudtasks.Client, projectID, locationID, queueID string, wait time.Duration, uri string, params url.Values) (*taskspb.Task, error) {
	// Build the Task queue path.
	queuePath := fmt.Sprintf("projects/%s/locations/%s/queues/%s", projectID, locationID, queueID)

	// Build the Task payload.
	// https://godoc.org/google.golang.org/genproto/googleapis/cloud/tasks/v2#CreateTaskRequest
	req := &taskspb.CreateTaskRequest{
		Parent: queuePath,
		Task: &taskspb.Task{
			// https://godoc.org/google.golang.org/genproto/googleapis/cloud/tasks/v2#AppEngineHttpRequest
			MessageType: &taskspb.Task_AppEngineHttpRequest{
				AppEngineHttpRequest: &taskspb.AppEngineHttpRequest{
					// For some reason, POST & body params aren't picked up by the inbound task handler
					HttpMethod:  taskspb.HttpMethod_GET,
					RelativeUri: uri + "?" + params.Encode(),
				},
			},
		},
	}

	// Apply a time delay, if needed
	if wait > 0 {
		when := timestamp.Timestamp{
			Seconds: time.Now().Add(wait).Unix(),
		}
		req.Task.ScheduleTime = &when
	}

	// This needs the context, even though the client already had it - bah
	ctx,_ := context.WithTimeout(ctxIn, 30 * time.Second) // This is max deadline for cloudtasks API
	createdTask, err := client.CreateTask(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("cloudtasks.CreateTask: %v", err)
	}

	return createdTask, nil
}
<|endoftext|>


<commit_before>package godtls

/*
#cgo pkg-config: openssl
#cgo CFLAGS: -Wno-deprecated

#include <stdlib.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/crypto.h>

#define SHA256_FINGERPRINT_SIZE (95 + 1)

static EVP_PKEY *gen_key() {
  EVP_PKEY *pkey = EVP_PKEY_new();
  BIGNUM *exponent = BN_new();
  RSA *rsa = RSA_new();
  if (!pkey || !exponent || !rsa ||
      !BN_set_word(exponent, 0x10001) ||
      !RSA_generate_key_ex(rsa, 1024, exponent, NULL) ||
      !EVP_PKEY_assign_RSA(pkey, rsa)) {
    EVP_PKEY_free(pkey);
    BN_free(exponent);
    RSA_free(rsa);
    return NULL;
  }
  BN_free(exponent);
  return pkey;
}

static X509 *gen_cert(EVP_PKEY* pkey, const char *common, int days) {
  X509 *x509 = NULL;
  BIGNUM *serial_number = NULL;
  X509_NAME *name = NULL;

  if ((x509 = X509_new()) == NULL)
    return NULL;

  if (!X509_set_pubkey(x509, pkey))
    return NULL;

  ASN1_INTEGER* asn1_serial_number;
  if ((serial_number = BN_new()) == NULL ||
      !BN_pseudo_rand(serial_number, 64, 0, 0) ||
      (asn1_serial_number = X509_get_serialNumber(x509)) == NULL ||
      !BN_to_ASN1_INTEGER(serial_number, asn1_serial_number))
    goto cert_err;

  if (!X509_set_version(x509, 0L))
    goto cert_err;

  if ((name = X509_NAME_new()) == NULL ||
      !X509_NAME_add_entry_by_NID(
          name, NID_commonName, MBSTRING_UTF8,
          (unsigned char*)common, -1, -1, 0) ||
      !X509_set_subject_name(x509, name) ||
      !X509_set_issuer_name(x509, name))
    goto cert_err;

  if (!X509_gmtime_adj(X509_get_notBefore(x509), 0) ||
      !X509_gmtime_adj(X509_get_notAfter(x509), days * 24 * 3600))
    goto cert_err;

  if (!X509_sign(x509, pkey, EVP_sha1()))
    goto cert_err;

  if (0) {
cert_err:
    X509_free(x509);
    x509 = NULL;
  }
  BN_free(serial_number);
  X509_NAME_free(name);

  return x509;
}

static int verify_peer_certificate_cb(int ok, X509_STORE_CTX *ctx) {
  return 1;
}

static int ssl_init = 0;

typedef struct {
  SSL_CTX *ctx;
  char fp[SHA256_FINGERPRINT_SIZE];
} dtls_context;

dtls_context *new_dtls_context(const char *common, int days) {
  if (common == NULL)
    return NULL;

  dtls_context *context = (dtls_context *)calloc(1, sizeof *context);
  if (context == NULL)
    return NULL;

  if (!ssl_init) {
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    ssl_init = 1;
  }

  SSL_CTX *ctx = SSL_CTX_new(DTLSv1_method());
  if (ctx == NULL)
    goto ctx_err;
  context->ctx = ctx;

  // ALL:NULL:eNULL:aNULL
  if (SSL_CTX_set_cipher_list(ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") != 1)
    goto ctx_err;

  SSL_CTX_set_read_ahead(ctx, 1); // for DTLS
  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_peer_certificate_cb);

  EVP_PKEY *key = gen_key();
  if (key == NULL)
    goto ctx_err;
  SSL_CTX_use_PrivateKey(ctx, key);

  X509 *cert = gen_cert(key, common, days);
  if (cert == NULL)
    goto ctx_err;
  SSL_CTX_use_certificate(ctx, cert);

  if (SSL_CTX_check_private_key(ctx) != 1)
    goto ctx_err;

  unsigned int len;
  unsigned char buf[1024];
  X509_digest(cert, EVP_sha256(), buf, &len);

  char *p = context->fp;
  for (int i = 0; i < len; ++i) {
    snprintf(p, 4, "%02X:", buf[i]);
    p += 3;
  }
  *(p - 1) = 0;

  if (0) {
ctx_err:
    SSL_CTX_free(ctx);
    free(context);
    context = NULL;
  }

  return context;
}

typedef struct {
  SSL *ssl;
  BIO *ibio;
  BIO *obio;
} dtls_transport;

*/
import "C"

import (
  "errors"
  "unsafe"
)

type DtlsContext struct {
  ctx *C.dtls_context
}

func NewContext(common string, days int) (*DtlsContext, error) {
  s := C.CString(common)
  defer C.free(unsafe.Pointer(s))
  ctx := C.new_dtls_context(s, C.int(days))
  if ctx == nil {
    return nil, errors.New("failed to create DTLS context")
  }
  return &DtlsContext{ctx}, nil
}

func (c *DtlsContext) Destroy() error {
  C.SSL_CTX_free(c.ctx.ctx);
  C.free(unsafe.Pointer(c.ctx));
  return nil
}

type DtlsTransport struct {
  trans *C.dtls_transport
}
<commit_msg>add more bindings<commit_after>package godtls

/*
#cgo pkg-config: openssl
#cgo CFLAGS: -Wno-deprecated

#include <stdlib.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/crypto.h>

#define SHA256_FINGERPRINT_SIZE (95 + 1)

static EVP_PKEY *gen_key() {
  EVP_PKEY *pkey = EVP_PKEY_new();
  BIGNUM *exponent = BN_new();
  RSA *rsa = RSA_new();
  if (!pkey || !exponent || !rsa ||
      !BN_set_word(exponent, 0x10001) ||
      !RSA_generate_key_ex(rsa, 1024, exponent, NULL) ||
      !EVP_PKEY_assign_RSA(pkey, rsa)) {
    EVP_PKEY_free(pkey);
    BN_free(exponent);
    RSA_free(rsa);
    return NULL;
  }
  BN_free(exponent);
  return pkey;
}

static X509 *gen_cert(EVP_PKEY* pkey, const char *common, int days) {
  X509 *x509 = NULL;
  BIGNUM *serial_number = NULL;
  X509_NAME *name = NULL;

  if ((x509 = X509_new()) == NULL)
    return NULL;

  if (!X509_set_pubkey(x509, pkey))
    return NULL;

  ASN1_INTEGER* asn1_serial_number;
  if ((serial_number = BN_new()) == NULL ||
      !BN_pseudo_rand(serial_number, 64, 0, 0) ||
      (asn1_serial_number = X509_get_serialNumber(x509)) == NULL ||
      !BN_to_ASN1_INTEGER(serial_number, asn1_serial_number))
    goto cert_err;

  if (!X509_set_version(x509, 0L))
    goto cert_err;

  if ((name = X509_NAME_new()) == NULL ||
      !X509_NAME_add_entry_by_NID(
          name, NID_commonName, MBSTRING_UTF8,
          (unsigned char*)common, -1, -1, 0) ||
      !X509_set_subject_name(x509, name) ||
      !X509_set_issuer_name(x509, name))
    goto cert_err;

  if (!X509_gmtime_adj(X509_get_notBefore(x509), 0) ||
      !X509_gmtime_adj(X509_get_notAfter(x509), days * 24 * 3600))
    goto cert_err;

  if (!X509_sign(x509, pkey, EVP_sha1()))
    goto cert_err;

  if (0) {
cert_err:
    X509_free(x509);
    x509 = NULL;
  }
  BN_free(serial_number);
  X509_NAME_free(name);

  return x509;
}

static int verify_peer_certificate_cb(int ok, X509_STORE_CTX *ctx) {
  return 1;
}

static int ssl_init = 0;

typedef struct {
  SSL_CTX *ctx;
  char fp[SHA256_FINGERPRINT_SIZE];
} dtls_context;

dtls_context *new_dtls_context(const char *common, int days) {
  if (common == NULL)
    return NULL;

  dtls_context *context = (dtls_context *)calloc(1, sizeof *context);
  if (context == NULL)
    return NULL;

  if (!ssl_init) {
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    ssl_init = 1;
  }

  SSL_CTX *ctx = SSL_CTX_new(DTLSv1_method());
  if (ctx == NULL)
    goto ctx_err;
  context->ctx = ctx;

  // ALL:NULL:eNULL:aNULL
  if (SSL_CTX_set_cipher_list(ctx, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") != 1)
    goto ctx_err;

  SSL_CTX_set_read_ahead(ctx, 1); // for DTLS
  SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_peer_certificate_cb);

  EVP_PKEY *key = gen_key();
  if (key == NULL)
    goto ctx_err;
  SSL_CTX_use_PrivateKey(ctx, key);

  X509 *cert = gen_cert(key, common, days);
  if (cert == NULL)
    goto ctx_err;
  SSL_CTX_use_certificate(ctx, cert);

  if (SSL_CTX_check_private_key(ctx) != 1)
    goto ctx_err;

  unsigned int len;
  unsigned char buf[1024];
  X509_digest(cert, EVP_sha256(), buf, &len);

  char *p = context->fp;
  for (int i = 0; i < len; ++i) {
    snprintf(p, 4, "%02X:", buf[i]);
    p += 3;
  }
  *(p - 1) = 0;

  if (0) {
ctx_err:
    SSL_CTX_free(ctx);
    free(context);
    context = NULL;
  }

  return context;
}

typedef struct {
  SSL *ssl;
  BIO *ibio;
  BIO *obio;
} dtls_transport;

dtls_transport *new_dtls_transport(dtls_context *context)
{
  dtls_transport *dtls = (dtls_transport *)calloc(1, sizeof *dtls);
  if (dtls == NULL)
    return NULL;

  SSL *ssl = SSL_new(context->ctx);
  if (ssl == NULL)
    goto trans_err;
  dtls->ssl = ssl;

  BIO *bio = BIO_new(BIO_s_mem());
  if (bio == NULL)
    goto trans_err;
  BIO_set_mem_eof_return(bio, -1);
  dtls->ibio = bio;

  bio = BIO_new(BIO_s_mem());
  if (bio == NULL)
    goto trans_err;
  BIO_set_mem_eof_return(bio, -1);
  dtls->obio = bio;

  SSL_set_bio(dtls->ssl, dtls->ibio, dtls->obio);

  EC_KEY *ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
  SSL_set_options(dtls->ssl, SSL_OP_SINGLE_ECDH_USE);
  SSL_set_tmp_ecdh(dtls->ssl, ecdh);
  EC_KEY_free(ecdh);

  if (0) {
trans_err:
    SSL_free(ssl);
    free(dtls);
    dtls = NULL;
  }

  return dtls;
}
*/
import "C"

import (
  "errors"
  "unsafe"
  "sync"
  "time"
)

var (
  tryAgainError = errors.New("try again")
  handshakeError = errors.New("failed to handshake")
)

type DtlsContext struct {
  ctx *C.dtls_context
}

func NewContext(common string, days int) (*DtlsContext, error) {
  s := C.CString(common)
  defer C.free(unsafe.Pointer(s))
  ctx := C.new_dtls_context(s, C.int(days))
  if ctx == nil {
    return nil, errors.New("failed to create DTLS context")
  }
  return &DtlsContext{ctx}, nil
}

func (c *DtlsContext) Destroy() {
  C.SSL_CTX_free(c.ctx.ctx)
  C.free(unsafe.Pointer(c.ctx))
}

type DtlsTransport struct {
  dtls *C.dtls_transport
  fingerprint string
  mtx sync.Mutex
}

func (c *DtlsContext) NewTransport() (*DtlsTransport, error) {
  dtls := C.new_dtls_transport(c.ctx)
  if dtls == nil {
    return nil, errors.New("failed to create DTLS transport")
  }
  fingerprint := C.GoString(&c.ctx.fp[0])
  t := &DtlsTransport{dtls: dtls, fingerprint: fingerprint}
  return t, nil
}

func (t *DtlsTransport) Destroy() {
  C.SSL_free(t.dtls.ssl)
  C.free(unsafe.Pointer(t.dtls))
}

func (t *DtlsTransport) Fingerprint() string {
  return t.fingerprint
}

func (t *DtlsTransport) SetConnectState() {
  C.SSL_set_connect_state(t.dtls.ssl)
}

func (t *DtlsTransport) SetAcceptState() {
  C.SSL_set_accept_state(t.dtls.ssl)
}

func (t *DtlsTransport) handshake() error {
  t.mtx.Lock()
  defer t.mtx.Unlock()
  rv := C.SSL_do_handshake(t.dtls.ssl)
  if rv == 1 {
    return nil
  }

  code := C.SSL_get_error(t.dtls.ssl, rv)
  switch code {
    case C.SSL_ERROR_WANT_READ:
      fallthrough
    case C.SSL_ERROR_WANT_WRITE:
      return tryAgainError
  }
  return handshakeError
}

func (t *DtlsTransport) Handshake() error {
  err := tryAgainError
  for err == tryAgainError {
    time.Sleep(4 * time.Millisecond)
    err = t.handshake()
  }
  return err
}

func (t *DtlsTransport) Write(data []byte) (int, error) {
  t.mtx.Lock()
  defer t.mtx.Unlock()
  n := C.SSL_write(t.dtls.ssl, unsafe.Pointer(&data[0]), C.int(len(data)))
  if n < 0 {
    return 0, errors.New("failed to write data")
  }
  return int(n), nil
}

func (t *DtlsTransport) Read(buf []byte) (int, error) {
  t.mtx.Lock()
  defer t.mtx.Unlock()
  n := C.SSL_read(t.dtls.ssl, unsafe.Pointer(&buf[0]), C.int(len(buf)))
  if n < 0 {
    return 0, errors.New("failed to read data")
  }
  return int(n), nil
}

func (t *DtlsTransport) Feed(data []byte) int {
  t.mtx.Lock()
  defer t.mtx.Unlock()
  n := C.BIO_write(t.dtls.ibio, unsafe.Pointer(&data[0]), C.int(len(data)))
  return int(n)
}

func (t *DtlsTransport) Spew(buf []byte) int {
  t.mtx.Lock()
  defer t.mtx.Unlock()
  n := C.BIO_read(t.dtls.obio, unsafe.Pointer(&buf[0]), C.int(len(buf)))
  return int(n)
}
<|endoftext|>


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

package commands

import (
	"bytes"
	"fmt"
	"go/build"
	"runtime"
	"strconv"

	"nvim-go/gb"
	"nvim-go/nvim"

	log "github.com/Sirupsen/logrus"
	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
	"github.com/rogpeppe/godef/go/ast"
	"github.com/rogpeppe/godef/go/parser"
	"github.com/rogpeppe/godef/go/printer"
	"github.com/rogpeppe/godef/go/token"
	"github.com/rogpeppe/godef/go/types"
)

func init() {
	plugin.HandleCommand("Godef", &plugin.CommandOptions{Range: "%", Eval: "expand('%:p:h:h:h:h')"}, Def)
}

func Def(v *vim.Vim, r [2]int, file string) error {
	defer gb.WithGoBuildForPath(file)()

	b, err := v.CurrentBuffer()
	if err != nil {
		return v.WriteErr("cannot get current buffer")
	}

	buf, err := v.BufferLineSlice(b, 0, -1, true, true)
	if err != nil {
		return err
	}
	src := bytes.Join(buf, []byte{'\n'})

	filename, err := v.BufferName(b)
	if err != nil {
		return v.WriteErr("cannot get current buffer name")
	}

	searchpos, err := nvim.ByteOffset(v)
	if err != nil {
		return v.WriteErr("cannot get current buffer byte offset")
	}

	pkgScope := ast.NewScope(parser.Universe)
	f, err := parser.ParseFile(types.FileSet, filename, src, 0, pkgScope)
	if f == nil {
		nvim.Echomsg(v, "Godef: cannot parse %s: %v", filename, err)
	}

	o := findIdentifier(v, f, searchpos)

	switch e := o.(type) {
	case *ast.ImportSpec:
		path := importPath(v, e)
		pkg, err := build.Default.Import(path, "", build.FindOnly)
		if err != nil {
			nvim.Echomsg(v, "Godef: error finding import path for %s: %s", path, err)
		}
		fmt.Println(pkg.Dir)
	case ast.Expr:
		if obj, _ := types.ExprType(e, types.DefaultImporter); obj != nil {
			out := types.FileSet.Position(types.DeclPos(obj))
			log.Debugln("def out.String():", out.String())
			log.Debugln("def out.Filename:", out.Filename)
			log.Debugln("def out.Line:", out.Line)
			log.Debugln("def out.Column:", out.Column)
			log.Debugln("def out.Offset:", out.Offset)
			log.Debugln("def out.IsValid():", out.IsValid())

			v.Command("silent lexpr '" + fmt.Sprintf("%v", out) + "'")
			w, err := v.CurrentWindow()
			if err != nil {
				log.Debugln(err)
			}
			v.SetWindowCursor(w, [2]int{out.Line, out.Column - 1})
			// v.Command("silent lgetexpr '" + fmt.Sprintf("%v", out) + "'")
			// v.Command("sil ll 1")
			// v.Feedkeys("zz", "normal", false)
		}
		nvim.Echomsg(v, "Godef: no declaration found for %v", pretty{e})
	}
	return nil
}

func importPath(v *vim.Vim, n *ast.ImportSpec) string {
	p, err := strconv.Unquote(n.Path.Value)
	if err != nil {
		nvim.Echomsg(v, "Godef: invalid string literal %q in ast.ImportSpec", n.Path.Value)
	}
	return p
}

// findIdentifier looks for an identifier at byte-offset searchpos
// inside the parsed source represented by node.
// If it is part of a selector expression, it returns
// that expression rather than the identifier itself.
//
// As a special case, if it finds an import spec, it returns ImportSpec.
func findIdentifier(v *vim.Vim, f *ast.File, searchpos int) ast.Node {
	ec := make(chan ast.Node)
	found := func(startPos, endPos token.Pos) bool {
		start := types.FileSet.Position(startPos).Offset
		end := start + int(endPos-startPos)
		return start <= searchpos && searchpos <= end
	}
	go func() {
		var visit func(ast.Node) bool
		visit = func(n ast.Node) bool {
			var startPos token.Pos
			switch n := n.(type) {
			default:
				return true
			case *ast.Ident:
				startPos = n.NamePos
			case *ast.SelectorExpr:
				startPos = n.Sel.NamePos
			case *ast.ImportSpec:
				startPos = n.Pos()
			case *ast.StructType:
				// If we find an anonymous bare field in a
				// struct type, its definition points to itself,
				// but we actually want to go elsewhere,
				// so assume (dubiously) that the expression
				// works globally and return a new node for it.
				for _, field := range n.Fields.List {
					if field.Names != nil {
						continue
					}
					t := field.Type
					if pt, ok := field.Type.(*ast.StarExpr); ok {
						t = pt.X
					}
					if id, ok := t.(*ast.Ident); ok {
						if found(id.NamePos, id.End()) {
							ec <- parseExpr(v, f.Scope, id.Name)
							runtime.Goexit()
						}
					}
				}
				return true
			}
			if found(startPos, n.End()) {
				ec <- n
				runtime.Goexit()
			}
			return true
		}
		ast.Walk(FVisitor(visit), f)
		ec <- nil
	}()
	ev := <-ec
	if ev == nil {
		nvim.Echomsg(v, "Godef: no identifier found")
	}
	return ev
}

func typeStr(obj *ast.Object, typ types.Type) string {
	switch obj.Kind {
	case ast.Fun, ast.Var:
		return fmt.Sprintf("%s %v", obj.Name, prettyType{typ})
	case ast.Pkg:
		return fmt.Sprintf("import (%s %s)", obj.Name, typ.Node.(*ast.ImportSpec).Path.Value)
	case ast.Con:
		if decl, ok := obj.Decl.(*ast.ValueSpec); ok {
			return fmt.Sprintf("const %s %v = %s", obj.Name, prettyType{typ}, pretty{decl.Values[0]})
		}
		return fmt.Sprintf("const %s %v", obj.Name, prettyType{typ})
	case ast.Lbl:
		return fmt.Sprintf("label %s", obj.Name)
	case ast.Typ:
		typ = typ.Underlying(false, types.DefaultImporter)
		return fmt.Sprintf("type %s %v", obj.Name, prettyType{typ})
	}
	return fmt.Sprintf("unknown %s %v", obj.Name, typ.Kind)
}

func parseExpr(v *vim.Vim, s *ast.Scope, expr string) ast.Expr {
	n, err := parser.ParseExpr(types.FileSet, "<arg>", expr, s)
	if err != nil {
		nvim.Echomsg(v, "Godef: cannot parse expression: %v", err)
	}
	switch n := n.(type) {
	case *ast.Ident, *ast.SelectorExpr:
		return n
	}
	nvim.Echomsg(v, "Godef: no identifier found in expression")
	return nil
}

type FVisitor func(n ast.Node) bool

func (f FVisitor) Visit(n ast.Node) ast.Visitor {
	if f(n) {
		return f
	}
	return nil
}

// pkgName returns the package name implemented by the go source filename
func pkgName(filename string) string {
	prog, _ := parser.ParseFile(types.FileSet, filename, nil, parser.PackageClauseOnly, nil)
	if prog != nil {
		return prog.Name.Name
	}
	return ""
}

func hasSuffix(s, suff string) bool {
	return len(s) >= len(suff) && s[len(s)-len(suff):] == suff
}

type pretty struct {
	n interface{}
}

func (p pretty) String() string {
	var b bytes.Buffer
	printer.Fprint(&b, types.FileSet, p.n)
	return b.String()
}

type prettyType struct {
	n types.Type
}

func (p prettyType) String() string {
	// TODO print path package when appropriate.
	// Current issues with using p.n.Pkg:
	//	- we should actually print the local package identifier
	//	rather than the package path when possible.
	//	- p.n.Pkg is non-empty even when
	//	the type is not relative to the package.
	return pretty{p.n.Node}.String()
}
<commit_msg>[WIP] Add Godef info and jump commands<commit_after>// Copyright 2016 Koichi Shiraishi. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package commands

import (
	"bytes"
	"fmt"
	"go/build"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"time"

	"nvim-go/gb"
	"nvim-go/nvim"

	log "github.com/Sirupsen/logrus"
	"github.com/garyburd/neovim-go/vim"
	"github.com/garyburd/neovim-go/vim/plugin"
	"github.com/rogpeppe/godef/go/ast"
	"github.com/rogpeppe/godef/go/parser"
	"github.com/rogpeppe/godef/go/printer"
	"github.com/rogpeppe/godef/go/token"
	"github.com/rogpeppe/godef/go/types"
)

func init() {
	plugin.HandleCommand("Godef", &plugin.CommandOptions{NArgs: "1", Eval: "expand('%:p:h:h:h:h')"}, Def)
	// plugin.HandleAutocmd("CursorMoved", &plugin.AutocmdOptions{Pattern: "*.go"}, onCursorMoved)
}

func onCursorMoved(v *vim.Vim) error {
	time.AfterFunc(4*time.Second, func() {
		v.Command("Godef info")
	})
	return nil
}

func Def(v *vim.Vim, args []string, file string) error {
	defer gb.WithGoBuildForPath(file)()

	b, err := v.CurrentBuffer()
	if err != nil {
		return v.WriteErr("cannot get current buffer")
	}

	buf, err := v.BufferLineSlice(b, 0, -1, true, true)
	if err != nil {
		return err
	}
	src := bytes.Join(buf, []byte{'\n'})

	filename, err := v.BufferName(b)
	if err != nil {
		return v.WriteErr("cannot get current buffer name")
	}

	searchpos, err := nvim.ByteOffset(v)
	if err != nil {
		return v.WriteErr("cannot get current buffer byte offset")
	}

	pkgScope := ast.NewScope(parser.Universe)
	f, err := parser.ParseFile(types.FileSet, filename, src, 0, pkgScope)
	if f == nil {
		nvim.Echomsg(v, "Godef: cannot parse %s: %v", filename, err)
	}

	o := findIdentifier(v, f, searchpos)

	switch e := o.(type) {
	case *ast.ImportSpec:
		path := importPath(v, e)
		pkg, err := build.Default.Import(path, "", build.FindOnly)
		if err != nil {
			nvim.Echomsg(v, "Godef: error finding import path for %s: %s", path, err)
		}
		fmt.Println(pkg.Dir)
	case ast.Expr:
		obj, typ := types.ExprType(e, types.DefaultImporter)
		if obj != nil {
			typeMap := typeStrMap(obj, typ)
			switch true {
			case args[0] == "info":
				log.WithFields(log.Fields{"cmd": "Godef info"}).Debugln(typeMap)

				kind := typeMap["Type.Kind"] + " "
				info := typeMap["Type.String()"]
				re, err := regexp.Compile(` func|\n|\t`)
				if err != nil {
					log.Fatal(err)
				}
				switch typeMap["Type.Kind"] {
				case "func":
					pkg := strings.Split(typeMap["Type.Pkg"], "/")
					nvim.Echohl(v, "Godef: ", "Function", fmt.Sprintf(kind+pkg[len(pkg)-1]+"."+re.ReplaceAllString(info, "")))
				case "var":
					nvim.Echohl(v, "Godef: ", "Identifier", fmt.Sprintf(kind+re.ReplaceAllString(info, "")))
				default:
					nvim.Echohl(v, "Godef: ", "Type", fmt.Sprintf(re.ReplaceAllString(info, "")))
				}

			case args[0] == "jump":
				out := types.FileSet.Position(types.DeclPos(obj))
				log.WithFields(log.Fields{"cmd": "Godef jump"}).Debugln("out.String():", out.String())
				log.WithFields(log.Fields{"cmd": "Godef jump"}).Debugln("out.Filename:", out.Filename)
				log.WithFields(log.Fields{"cmd": "Godef jump"}).Debugln("out.Line:", out.Line)
				log.WithFields(log.Fields{"cmd": "Godef jump"}).Debugln("out.Column:", out.Column)
				log.WithFields(log.Fields{"cmd": "Godef jump"}).Debugln("out.Offset:", out.Offset)
				log.WithFields(log.Fields{"cmd": "Godef jump"}).Debugln("out.IsValid():", out.IsValid())

				v.Command("silent lexpr '" + fmt.Sprintf("%v", out) + "'")
				// v.Command("silent lgetexpr '" + fmt.Sprintf("%v", out) + "'")
				// v.Command("sil ll 1")
				w, err := v.CurrentWindow()
				if err != nil {
					log.Debugln(err)
				}
				v.SetWindowCursor(w, [2]int{out.Line, out.Column - 1})
				v.Feedkeys("zz", "normal", false)
			default:
				nvim.Echomsg(v, "Godef: Invalid arguments")
			}
		}
	default:
		nvim.Echomsg(v, "Godef: no declaration found for %v", pretty{e})
	}
	return nil
}

func typeStrMap(obj *ast.Object, typ types.Type) map[string]string {
	switch obj.Kind {
	case ast.Fun, ast.Var:
		dict := map[string]string{
			"Object.Kind":   obj.Kind.String(),
			"Object.Name":   obj.Name,
			"Type.Kind":     typ.Kind.String(),
			"Type.Pkg":      typ.Pkg,
			"Type.String()": typ.String(),
			// "Object.Decl": obj.Decl,
			// "Object.Data":   obj.Data,
			// "Object.Type":   obj.Type,
			// "Object.Pos()":  obj.Pos(),
			// "Type.Node":     typ.Node,
		}
		return dict
		// 	return fmt.Sprintf("%s %v", typ.obj.Name, prettyType{typ})
		// case ast.Pkg:
		// 	return fmt.Sprintf("import (%s %s)", obj.Name, typ.Node.(*ast.ImportSpec).Path.Value)
		// case ast.Con:
		// 	if decl, ok := obj.Decl.(*ast.ValueSpec); ok {
		// 		return fmt.Sprintf("const %s %v = %s", obj.Name, prettyType{typ}, pretty{decl.Values[0]})
		// 	}
		// 	return fmt.Sprintf("const %s %v", obj.Name, prettyType{typ})
		// case ast.Lbl:
		// 	return fmt.Sprintf("label %s", obj.Name)
		// case ast.Typ:
		// 	typ = typ.Underlying(false, types.DefaultImporter)
		// 	return fmt.Sprintf("type %s %v", obj.Name, prettyType{typ})
		// }
		// return fmt.Sprintf("unknown %s %v", obj.Name, typ.Kind)
	}
	return map[string]string{}
}

func typeStr(obj *ast.Object, typ types.Type) string {
	switch obj.Kind {
	case ast.Fun, ast.Var:
		return fmt.Sprintf("%s %v", obj.Name, prettyType{typ})
	case ast.Pkg:
		return fmt.Sprintf("import (%s %s)", obj.Name, typ.Node.(*ast.ImportSpec).Path.Value)
	case ast.Con:
		if decl, ok := obj.Decl.(*ast.ValueSpec); ok {
			return fmt.Sprintf("const %s %v = %s", obj.Name, prettyType{typ}, pretty{decl.Values[0]})
		}
		return fmt.Sprintf("const %s %v", obj.Name, prettyType{typ})
	case ast.Lbl:
		return fmt.Sprintf("label %s", obj.Name)
	case ast.Typ:
		typ = typ.Underlying(false, types.DefaultImporter)
		return fmt.Sprintf("type %s %v", obj.Name, prettyType{typ})
	}
	return fmt.Sprintf("unknown %s %v", obj.Name, typ.Kind)
}

type orderedObjects []*ast.Object

func (o orderedObjects) Less(i, j int) bool { return o[i].Name < o[j].Name }
func (o orderedObjects) Len() int           { return len(o) }
func (o orderedObjects) Swap(i, j int)      { o[i], o[j] = o[j], o[i] }

func importPath(v *vim.Vim, n *ast.ImportSpec) string {
	p, err := strconv.Unquote(n.Path.Value)
	if err != nil {
		nvim.Echomsg(v, "Godef: invalid string literal %q in ast.ImportSpec", n.Path.Value)
	}
	return p
}

// findIdentifier looks for an identifier at byte-offset searchpos
// inside the parsed source represented by node.
// If it is part of a selector expression, it returns
// that expression rather than the identifier itself.
//
// As a special case, if it finds an import spec, it returns ImportSpec.
func findIdentifier(v *vim.Vim, f *ast.File, searchpos int) ast.Node {
	ec := make(chan ast.Node)
	found := func(startPos, endPos token.Pos) bool {
		start := types.FileSet.Position(startPos).Offset
		end := start + int(endPos-startPos)
		return start <= searchpos && searchpos <= end
	}
	go func() {
		var visit func(ast.Node) bool
		visit = func(n ast.Node) bool {
			var startPos token.Pos
			switch n := n.(type) {
			default:
				return true
			case *ast.Ident:
				startPos = n.NamePos
			case *ast.SelectorExpr:
				startPos = n.Sel.NamePos
			case *ast.ImportSpec:
				startPos = n.Pos()
			case *ast.StructType:
				// If we find an anonymous bare field in a
				// struct type, its definition points to itself,
				// but we actually want to go elsewhere,
				// so assume (dubiously) that the expression
				// works globally and return a new node for it.
				for _, field := range n.Fields.List {
					if field.Names != nil {
						continue
					}
					t := field.Type
					if pt, ok := field.Type.(*ast.StarExpr); ok {
						t = pt.X
					}
					if id, ok := t.(*ast.Ident); ok {
						if found(id.NamePos, id.End()) {
							ec <- parseExpr(v, f.Scope, id.Name)
							runtime.Goexit()
						}
					}
				}
				return true
			}
			if found(startPos, n.End()) {
				ec <- n
				runtime.Goexit()
			}
			return true
		}
		ast.Walk(FVisitor(visit), f)
		ec <- nil
	}()
	ev := <-ec
	if ev == nil {
		nvim.Echomsg(v, "Godef: no identifier found")
	}
	return ev
}

func parseExpr(v *vim.Vim, s *ast.Scope, expr string) ast.Expr {
	n, err := parser.ParseExpr(types.FileSet, "<arg>", expr, s)
	if err != nil {
		nvim.Echomsg(v, "Godef: cannot parse expression: %v", err)
	}
	switch n := n.(type) {
	case *ast.Ident, *ast.SelectorExpr:
		return n
	}
	nvim.Echomsg(v, "Godef: no identifier found in expression")
	return nil
}

type FVisitor func(n ast.Node) bool

func (f FVisitor) Visit(n ast.Node) ast.Visitor {
	if f(n) {
		return f
	}
	return nil
}

// pkgName returns the package name implemented by the go source filename
func pkgName(filename string) string {
	prog, _ := parser.ParseFile(types.FileSet, filename, nil, parser.PackageClauseOnly, nil)
	if prog != nil {
		return prog.Name.Name
	}
	return ""
}

func hasSuffix(s, suff string) bool {
	return len(s) >= len(suff) && s[len(s)-len(suff):] == suff
}

type pretty struct {
	n interface{}
}

func (p pretty) String() string {
	var b bytes.Buffer
	printer.Fprint(&b, types.FileSet, p.n)
	return b.String()
}

type prettyType struct {
	n types.Type
}

func (p prettyType) String() string {
	// TODO print path package when appropriate.
	// Current issues with using p.n.Pkg:
	//	- we should actually print the local package identifier
	//	rather than the package path when possible.
	//	- p.n.Pkg is non-empty even when
	//	the type is not relative to the package.
	return pretty{p.n.Node}.String()
}
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems                */
/*                                                                            */
/* 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 goca

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	"github.com/kolo/xmlrpc"
)

var (
	client *oneClient
)

// OneConfig contains the information to communicate with OpenNebula
type OneConfig struct {
	// Token is the authentication string. In the format of <user>:<password>
	Token string

	// XmlrpcURL contains OpenNebula's XML-RPC API endpoint. Defaults to
	// http://localhost:2633/RPC2
	XmlrpcURL string
}

type oneClient struct {
	url               string
	token             string
	httpClient        *http.Client
}

type response struct {
	status  bool
	body    string
	bodyInt int
}

// Initializes the client variable, used as a singleton
func init() {
	SetClient(NewConfig("", "", ""))
}

// NewConfig returns a new OneConfig object with the specified user, password,
// and xmlrpcURL
func NewConfig(user string, password string, xmlrpcURL string) OneConfig {
	var authToken string
	var oneAuthPath string

	oneXmlrpc := xmlrpcURL

	if user == "" && password == "" {
		oneAuthPath = os.Getenv("ONE_AUTH")
		if oneAuthPath == "" {
			oneAuthPath = os.Getenv("HOME") + "/.one/one_auth"
		}

		token, err := ioutil.ReadFile(oneAuthPath)
		if err == nil {
			authToken = strings.TrimSpace(string(token))
		} else {
			authToken = ""
		}
	} else {
		authToken = user + ":" + password
	}

	if oneXmlrpc == "" {
		oneXmlrpc = os.Getenv("ONE_XMLRPC")
		if oneXmlrpc == "" {
			oneXmlrpc = "http://localhost:2633/RPC2"
		}
	}

	config := OneConfig{
		Token:     authToken,
		XmlrpcURL: oneXmlrpc,
	}

	return config
}

// SetClient assigns a value to the client variable
func SetClient(conf OneConfig) {

	client = &oneClient{
		url:               conf.XmlrpcURL,
		token:             conf.Token,
		httpClient:        &http.Client{},
	}
}

// SystemVersion returns the current OpenNebula Version
func SystemVersion() (string, error) {
	response, err := client.Call("one.system.version")
	if err != nil {
		return "", err
	}

	return response.Body(), nil
}

// SystemConfig returns the current OpenNebula config
func SystemConfig() (string, error) {
	response, err := client.Call("one.system.config")
	if err != nil {
		return "", err
	}

	return response.Body(), nil
}

// Call is an XML-RPC wrapper. It returns a pointer to response and an error.
func (c *oneClient) Call(method string, args ...interface{}) (*response, error) {
	return c.endpointCall(c.url, method, args...)
}

func (c *oneClient) endpointCall(url string, method string, args ...interface{}) (*response, error) {
	var (
		ok bool

		status  bool
		body    string
		bodyInt int64
		errCode int64
	)

	xmlArgs := make([]interface{}, len(args)+1)

	xmlArgs[0] = c.token
	copy(xmlArgs[1:], args[:])

	buf, err := xmlrpc.EncodeMethodCall(method, xmlArgs...)
	if err != nil {
		return nil,
			&ClientError{Code: ClientReqBuild, msg: "xmlrpc request encoding", err: err}
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(buf))
	if err != nil {
		return nil,
			&ClientError{Code: ClientReqBuild, msg: "http request build", err: err}
	}

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil,
			&ClientError{Code: ClientReqHTTP, msg: "http make request", err: err}
	}

	if resp.StatusCode/100 != 2 {
		return nil, &ClientError{
			Code:     ClientRespHTTP,
			msg:      fmt.Sprintf("http status code: %d", resp.StatusCode),
			httpResp: resp,
		}
	}

	respData, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil,
			&ClientError{ClientRespHTTP, "read http response body", resp, err}
	}

	// Server side XML-RPC library: xmlrpc-c
	xmlrpcResp := xmlrpc.NewResponse(respData)

	// Handle the <fault> tag in the xml server response
	if xmlrpcResp.Failed() {
		err = xmlrpcResp.Err()
		return nil,
			&ClientError{ClientRespXMLRPCFault, "server response", resp, err}
	}

	result := []interface{}{}

	// Unmarshall the XML-RPC response
	if err := xmlrpcResp.Unmarshal(&result); err != nil {
		return nil,
			&ClientError{ClientRespXMLRPCParse, "unmarshal xmlrpc", resp, err}
	}

	// Parse according the XML-RPC OpenNebula API documentation
	status, ok = result[0].(bool)
	if ok == false {
		return nil,
			&ClientError{ClientRespONeParse, "index 0: boolean expected", resp, nil}
	}

	body, ok = result[1].(string)
	if ok == false {
		bodyInt, ok = result[1].(int64)
		if ok == false {
			bodyBool, ok = result[1].(bool)
			if ok == false {
				return nil,
					&ClientError{ClientRespONeParse, "index 1: boolean expected", resp, nil}
			}
		}
	}

	errCode, ok = result[2].(int64)
	if ok == false {
		return nil,
			&ClientError{ClientRespONeParse, "index 2: boolean expected", resp, nil}
	}

	if status == false {
		return nil, &ResponseError{
			Code: OneErrCode(errCode),
			msg:  body,
		}
	}

	r := &response{status, body, int(bodyInt)}

	return r, nil
}

// Body accesses the body of the response
func (r *response) Body() string {
	return r.body
}

// BodyInt accesses the body of the response, if it's an int.
func (r *response) BodyInt() int {
	return r.bodyInt
}
<commit_msg>F #2830: Fix merge of PR #3113<commit_after>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems                */
/*                                                                            */
/* 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 goca

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"strings"

	"github.com/kolo/xmlrpc"
)

var (
	client *oneClient
)

// OneConfig contains the information to communicate with OpenNebula
type OneConfig struct {
	// Token is the authentication string. In the format of <user>:<password>
	Token string

	// XmlrpcURL contains OpenNebula's XML-RPC API endpoint. Defaults to
	// http://localhost:2633/RPC2
	XmlrpcURL string
}

type oneClient struct {
	url               string
	token             string
	httpClient        *http.Client
}

type response struct {
	status  bool
	body    string
	bodyInt int
}

// Initializes the client variable, used as a singleton
func init() {
	SetClient(NewConfig("", "", ""))
}

// NewConfig returns a new OneConfig object with the specified user, password,
// and xmlrpcURL
func NewConfig(user string, password string, xmlrpcURL string) OneConfig {
	var authToken string
	var oneAuthPath string

	oneXmlrpc := xmlrpcURL

	if user == "" && password == "" {
		oneAuthPath = os.Getenv("ONE_AUTH")
		if oneAuthPath == "" {
			oneAuthPath = os.Getenv("HOME") + "/.one/one_auth"
		}

		token, err := ioutil.ReadFile(oneAuthPath)
		if err == nil {
			authToken = strings.TrimSpace(string(token))
		} else {
			authToken = ""
		}
	} else {
		authToken = user + ":" + password
	}

	if oneXmlrpc == "" {
		oneXmlrpc = os.Getenv("ONE_XMLRPC")
		if oneXmlrpc == "" {
			oneXmlrpc = "http://localhost:2633/RPC2"
		}
	}

	config := OneConfig{
		Token:     authToken,
		XmlrpcURL: oneXmlrpc,
	}

	return config
}

// SetClient assigns a value to the client variable
func SetClient(conf OneConfig) {

	client = &oneClient{
		url:               conf.XmlrpcURL,
		token:             conf.Token,
		httpClient:        &http.Client{},
	}
}

// SystemVersion returns the current OpenNebula Version
func SystemVersion() (string, error) {
	response, err := client.Call("one.system.version")
	if err != nil {
		return "", err
	}

	return response.Body(), nil
}

// SystemConfig returns the current OpenNebula config
func SystemConfig() (string, error) {
	response, err := client.Call("one.system.config")
	if err != nil {
		return "", err
	}

	return response.Body(), nil
}

// Call is an XML-RPC wrapper. It returns a pointer to response and an error.
func (c *oneClient) Call(method string, args ...interface{}) (*response, error) {
	return c.endpointCall(c.url, method, args...)
}

func (c *oneClient) endpointCall(url string, method string, args ...interface{}) (*response, error) {
	var (
		ok bool

		status  bool
		body    string
		bodyInt int64
		errCode int64
	)

	xmlArgs := make([]interface{}, len(args)+1)

	xmlArgs[0] = c.token
	copy(xmlArgs[1:], args[:])

	buf, err := xmlrpc.EncodeMethodCall(method, xmlArgs...)
	if err != nil {
		return nil,
			&ClientError{Code: ClientReqBuild, msg: "xmlrpc request encoding", err: err}
	}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(buf))
	if err != nil {
		return nil,
			&ClientError{Code: ClientReqBuild, msg: "http request build", err: err}
	}

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return nil,
			&ClientError{Code: ClientReqHTTP, msg: "http make request", err: err}
	}

	if resp.StatusCode/100 != 2 {
		return nil, &ClientError{
			Code:     ClientRespHTTP,
			msg:      fmt.Sprintf("http status code: %d", resp.StatusCode),
			httpResp: resp,
		}
	}

	respData, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	if err != nil {
		return nil,
			&ClientError{ClientRespHTTP, "read http response body", resp, err}
	}

	// Server side XML-RPC library: xmlrpc-c
	xmlrpcResp := xmlrpc.NewResponse(respData)

	// Handle the <fault> tag in the xml server response
	if xmlrpcResp.Failed() {
		err = xmlrpcResp.Err()
		return nil,
			&ClientError{ClientRespXMLRPCFault, "server response", resp, err}
	}

	result := []interface{}{}

	// Unmarshall the XML-RPC response
	if err := xmlrpcResp.Unmarshal(&result); err != nil {
		return nil,
			&ClientError{ClientRespXMLRPCParse, "unmarshal xmlrpc", resp, err}
	}

	// Parse according the XML-RPC OpenNebula API documentation
	status, ok = result[0].(bool)
	if ok == false {
		return nil,
			&ClientError{ClientRespONeParse, "index 0: boolean expected", resp, nil}
	}

	body, ok = result[1].(string)
	if ok == false {
		bodyInt, ok = result[1].(int64)
		if ok == false {
            return nil,
                &ClientError{ClientRespONeParse, "index 1: int or string expected", resp, nil}
		}
	}

	errCode, ok = result[2].(int64)
	if ok == false {
		return nil,
			&ClientError{ClientRespONeParse, "index 2: boolean expected", resp, nil}
	}

	if status == false {
		return nil, &ResponseError{
			Code: OneErrCode(errCode),
			msg:  body,
		}
	}

	r := &response{status, body, int(bodyInt)}

	return r, nil
}

// Body accesses the body of the response
func (r *response) Body() string {
	return r.body
}

// BodyInt accesses the body of the response, if it's an int.
func (r *response) BodyInt() int {
	return r.bodyInt
}
<|endoftext|>


<commit_before>package balagent

import (
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"testing"
	"text/template"
	"time"

	"github.com/squaremo/ambergreen/common/daemon"
	"github.com/squaremo/ambergreen/common/data"
	"github.com/squaremo/ambergreen/common/store/inmem"

	"github.com/stretchr/testify/require"
)

func requireFileContents(t *testing.T, filename string, contents string) {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		t.Fatal(err)
	}
	require.Equal(t, contents, string(bytes))
}

func requireNoError(t *testing.T, a *BalancerAgent) {
	select {
	case err := <-a.errorSink:
		t.Fatal(err)
	default:
	}
}

func requireError(t *testing.T, a *BalancerAgent) {
	select {
	case <-a.errorSink:
		return
	default:
		t.Fatal(fmt.Errorf("expected error, but executed cleanly"))
	}
}

type testcase func(*testing.T, *BalancerAgent, <-chan struct{})

func testCase(t *testing.T, tc testcase) {
	rng := rand.New(rand.NewSource(time.Now().UnixNano()))

	a := &BalancerAgent{
		errorSink: daemon.NewErrorSink(),
		store:     inmem.NewInMemStore(),
		filename: fmt.Sprintf("%s/balagent-%d", os.TempDir(),
			rng.Intn(1000000)),
	}

	tick := make(chan struct{})
	a.start(tick)

	tc(t, a, tick)
	a.Stop()
}

func trivialFixture(a *BalancerAgent, tmpl string) {
	a.template = template.Must(template.New("test").Parse(tmpl))
	a.service = "test-svc"
	a.store.AddService("test-svc", data.Service{
		Address:  "10.5.7.34",
		Port:     8000,
		Protocol: "http",
	})
	a.store.AddInstance("test-svc", "test-instance", data.Instance{})
}

func TestTrivialSuccess(t *testing.T) {
	testCase(t, func(t *testing.T, a *BalancerAgent, tick <-chan struct{}) {
		trivialFixture(a, "{{.Name}}")
		<-tick
		requireFileContents(t, a.filename, "test-svc")
		requireNoError(t, a)
	})
}

func TestBadTemplate(t *testing.T) {
	testCase(t, func(t *testing.T, a *BalancerAgent, tick <-chan struct{}) {
		trivialFixture(a, "{{.wut}}")
		<-tick
		requireError(t, a)
	})
}
<commit_msg>Test iterating over instances in template<commit_after>package balagent

import (
	"fmt"
	"io/ioutil"
	"math/rand"
	"os"
	"testing"
	"text/template"
	"time"

	"github.com/squaremo/ambergreen/common/daemon"
	"github.com/squaremo/ambergreen/common/data"
	"github.com/squaremo/ambergreen/common/store/inmem"

	"github.com/stretchr/testify/require"
)

func fileContentsEqual(t *testing.T, filename, contents string) bool {
	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		t.Fatal(err)
	}
	return contents == string(bytes)
}

func requireFileContents(t *testing.T, filename, contents string) {
	require.True(t, fileContentsEqual(t, filename, contents))
}

func requireNoError(t *testing.T, a *BalancerAgent) {
	select {
	case err := <-a.errorSink:
		t.Fatal(err)
	default:
	}
}

func requireError(t *testing.T, a *BalancerAgent) {
	select {
	case <-a.errorSink:
		return
	default:
		t.Fatal(fmt.Errorf("expected error, but executed cleanly"))
	}
}

type testcase func(*BalancerAgent, <-chan struct{})

func testCase(t *testing.T, tc testcase) {
	rng := rand.New(rand.NewSource(time.Now().UnixNano()))

	a := &BalancerAgent{
		errorSink: daemon.NewErrorSink(),
		store:     inmem.NewInMemStore(),
		filename: fmt.Sprintf("%s/balagent-%d", os.TempDir(),
			rng.Intn(1000000)),
	}

	tick := make(chan struct{})
	a.start(tick)

	tc(a, tick)
	a.Stop()
}

func trivialFixture(a *BalancerAgent, tmpl string) {
	a.template = template.Must(template.New("test").Parse(tmpl))
	a.service = "test-svc"
	a.store.AddService("test-svc", data.Service{
		Address:  "10.5.7.34",
		Port:     8000,
		Protocol: "http",
	})
	a.store.AddInstance("test-svc", "test-instance", data.Instance{
		Address: "192.168.66.77",
		Port:    7000,
	})
}

func TestTrivialSuccess(t *testing.T) {
	testCase(t, func(a *BalancerAgent, tick <-chan struct{}) {
		trivialFixture(a, "{{.Name}}")
		<-tick
		requireFileContents(t, a.filename, "test-svc")
		requireNoError(t, a)
	})
}

func TestBadTemplate(t *testing.T) {
	testCase(t, func(a *BalancerAgent, tick <-chan struct{}) {
		trivialFixture(a, "{{.wut}}")
		<-tick
		requireError(t, a)
	})
}

func TestInstanceUpdate(t *testing.T) {
	testCase(t, func(a *BalancerAgent, tick <-chan struct{}) {
		trivialFixture(a, "{{range .Service.Instances}}|{{.Name}}{{end}}")
		<-tick
		requireFileContents(t, a.filename, "|test-instance")
		a.store.AddInstance("test-svc", "test-instance2", data.Instance{
			Address: "192.168.99.100",
			Port:    9000,
		})
		<-tick
		require.True(t, fileContentsEqual(t, a.filename, "|test-instance|test-instance2") ||
			fileContentsEqual(t, a.filename, "|test-instance2|test-instance"))
		requireNoError(t, a)
	})
}
<|endoftext|>


<commit_before>package swarm

import "time"

// Swarm represents a swarm.
type Swarm struct {
	ID string
	Meta
	Spec Spec
}

// Spec represents the spec of a swarm.
type Spec struct {
	Annotations

	AcceptancePolicy AcceptancePolicy    `json:",omitempty"`
	Orchestration    OrchestrationConfig `json:",omitempty"`
	Raft             RaftConfig          `json:",omitempty"`
	Dispatcher       DispatcherConfig    `json:",omitempty"`
	CAConfig         CAConfig            `json:",omitempty"`
}

// AcceptancePolicy represents the list of policies.
type AcceptancePolicy struct {
	Policies []Policy `json:",omitempty"`
}

// Policy represents a role, autoaccept and secret.
type Policy struct {
	Role       NodeRole
	Autoaccept bool
	Secret     *string `json:",omitempty"`
}

// OrchestrationConfig represents orchestration configuration.
type OrchestrationConfig struct {
	TaskHistoryRetentionLimit int64 `json:",omitempty"`
}

// RaftConfig represents raft configuration.
type RaftConfig struct {
	SnapshotInterval           uint64 `json:",omitempty"`
	KeepOldSnapshots           uint64 `json:",omitempty"`
	LogEntriesForSlowFollowers uint64 `json:",omitempty"`
	HeartbeatTick              uint32 `json:",omitempty"`
	ElectionTick               uint32 `json:",omitempty"`
}

// DispatcherConfig represents dispatcher configuration.
type DispatcherConfig struct {
	HeartbeatPeriod uint64 `json:",omitempty"`
}

// CAConfig represents CA configuration.
type CAConfig struct {
	NodeCertExpiry time.Duration `json:",omitempty"`
}

// InitRequest is the request used to init a swarm.
type InitRequest struct {
	ListenAddr      string
	ForceNewCluster bool
	Spec            Spec
}

// JoinRequest is the request used to join a swarm.
type JoinRequest struct {
	ListenAddr  string
	RemoteAddrs []string
	Secret      string // accept by secret
	CACertHash  string
	Manager     bool
}

// LocalNodeState represents the state of the local node.
type LocalNodeState string

const (
	// LocalNodeStateInactive INACTIVE
	LocalNodeStateInactive LocalNodeState = "inactive"
	// LocalNodeStatePending PENDING
	LocalNodeStatePending LocalNodeState = "pending"
	// LocalNodeStateActive ACTIVE
	LocalNodeStateActive LocalNodeState = "active"
	// LocalNodeStateError ERROR
	LocalNodeStateError LocalNodeState = "error"
)

// Info represents generic information about swarm.
type Info struct {
	NodeID string

	LocalNodeState   LocalNodeState
	ControlAvailable bool
	Error            string

	RemoteManagers []Peer
	Nodes          int
	Managers       int
	CACertHash     string
}

// Peer represents a peer.
type Peer struct {
	NodeID string
	Addr   string
}
<commit_msg>Add ExternalCAs to swarm spec<commit_after>package swarm

import "time"

// Swarm represents a swarm.
type Swarm struct {
	ID string
	Meta
	Spec Spec
}

// Spec represents the spec of a swarm.
type Spec struct {
	Annotations

	AcceptancePolicy AcceptancePolicy    `json:",omitempty"`
	Orchestration    OrchestrationConfig `json:",omitempty"`
	Raft             RaftConfig          `json:",omitempty"`
	Dispatcher       DispatcherConfig    `json:",omitempty"`
	CAConfig         CAConfig            `json:",omitempty"`
}

// AcceptancePolicy represents the list of policies.
type AcceptancePolicy struct {
	Policies []Policy `json:",omitempty"`
}

// Policy represents a role, autoaccept and secret.
type Policy struct {
	Role       NodeRole
	Autoaccept bool
	Secret     *string `json:",omitempty"`
}

// OrchestrationConfig represents orchestration configuration.
type OrchestrationConfig struct {
	TaskHistoryRetentionLimit int64 `json:",omitempty"`
}

// RaftConfig represents raft configuration.
type RaftConfig struct {
	SnapshotInterval           uint64 `json:",omitempty"`
	KeepOldSnapshots           uint64 `json:",omitempty"`
	LogEntriesForSlowFollowers uint64 `json:",omitempty"`
	HeartbeatTick              uint32 `json:",omitempty"`
	ElectionTick               uint32 `json:",omitempty"`
}

// DispatcherConfig represents dispatcher configuration.
type DispatcherConfig struct {
	HeartbeatPeriod uint64 `json:",omitempty"`
}

// CAConfig represents CA configuration.
type CAConfig struct {
	NodeCertExpiry time.Duration `json:",omitempty"`
	ExternalCAs    []*ExternalCA `json:",omitempty"`
}

// ExternalCAProtocol represents type of external CA.
type ExternalCAProtocol string

// ExternalCAProtocolCFSSL CFSSL
const ExternalCAProtocolCFSSL ExternalCAProtocol = "cfssl"

// ExternalCA defines external CA to be used by the cluster.
type ExternalCA struct {
	Protocol ExternalCAProtocol
	URL      string
	Options  map[string]string `json:",omitempty"`
}

// InitRequest is the request used to init a swarm.
type InitRequest struct {
	ListenAddr      string
	ForceNewCluster bool
	Spec            Spec
}

// JoinRequest is the request used to join a swarm.
type JoinRequest struct {
	ListenAddr  string
	RemoteAddrs []string
	Secret      string // accept by secret
	CACertHash  string
	Manager     bool
}

// LocalNodeState represents the state of the local node.
type LocalNodeState string

const (
	// LocalNodeStateInactive INACTIVE
	LocalNodeStateInactive LocalNodeState = "inactive"
	// LocalNodeStatePending PENDING
	LocalNodeStatePending LocalNodeState = "pending"
	// LocalNodeStateActive ACTIVE
	LocalNodeStateActive LocalNodeState = "active"
	// LocalNodeStateError ERROR
	LocalNodeStateError LocalNodeState = "error"
)

// Info represents generic information about swarm.
type Info struct {
	NodeID string

	LocalNodeState   LocalNodeState
	ControlAvailable bool
	Error            string

	RemoteManagers []Peer
	Nodes          int
	Managers       int
	CACertHash     string
}

// Peer represents a peer.
type Peer struct {
	NodeID string
	Addr   string
}
<|endoftext|>


<commit_before>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 index

import (
	"errors"

	"strings"

	"github.com/admpub/nging/application/handler"
	"github.com/admpub/nging/application/library/config"
	"github.com/admpub/nging/application/middleware"
	"github.com/admpub/nging/application/model"
	"github.com/webx-top/com"
	"github.com/webx-top/echo"
	"github.com/webx-top/echo/middleware/tplfunc"
)

func init() {
	handler.Register(func(e *echo.Echo) {
		e.Route("GET", `/`, Index)
		e.Route("GET,POST", `/login`, Login)
		e.Route("GET,POST", `/register`, Register)
		e.Route("GET", `/logout`, Logout)
		e.Route("GET", `/donation`, Donation)
	})
}

func Index(ctx echo.Context) error {
	return ctx.Redirect(`/manage`)
}

func Login(ctx echo.Context) error {
	user := handler.User(ctx)
	if user != nil {
		returnTo := ctx.Query(`return_to`)
		if len(returnTo) == 0 {
			returnTo = `/manage`
		}
		return ctx.Redirect(returnTo)
	}
	var err error
	if ctx.IsPost() {
		if !tplfunc.CaptchaVerify(ctx.Form(`code`), ctx.Form) {
			err = errors.New(ctx.T(`验证码不正确`))
		} else {
			err = middleware.Auth(ctx, true)
			if err == nil {
				returnTo := ctx.Form(`return_to`)
				if len(returnTo) == 0 {
					returnTo = `/manage`
				}
				return ctx.Redirect(returnTo)
			}
		}
	}

	//检查是否已安装
	if !config.IsInstalled() {
		return ctx.Redirect(`/setup`)
	}

	return ctx.Render(`login`, handler.Err(ctx, err))
}

func Register(ctx echo.Context) error {
	var err error
	if ctx.IsPost() {
		c := model.NewCode(ctx)
		m := model.NewUser(ctx)
		code := ctx.Form(`invitationCode`)
		user := ctx.Form(`username`)
		email := ctx.Form(`email`)
		passwd := ctx.Form(`password`)
		repwd := ctx.Form(`confirmationPassword`)
		if len(code) == 0 {
			err = errors.New(ctx.T(`邀请码不能为空`))
		} else if len(user) == 0 {
			err = errors.New(ctx.T(`用户名不能为空`))
		} else if len(email) == 0 {
			err = errors.New(ctx.T(`Email不能为空`))
		} else if len(passwd) < 8 {
			err = errors.New(ctx.T(`密码不能少于8个字符`))
		} else if repwd != passwd {
			err = errors.New(ctx.T(`密码与确认密码不一致`))
		} else if !com.IsUsername(user) {
			err = errors.New(ctx.T(`用户名不能包含特殊字符(只能由字母、数字、下划线和汉字组成)`))
		} else {
			var exists bool
			exists, err = m.Exists(user)
			if exists {
				err = errors.New(ctx.T(`用户名已经存在`))
			}
			if err == nil {
				err = c.VerfyInvitationCode(code)
			}
			if err == nil && !ctx.ValidateField(`email`, email, `email`) {
				err = errors.New(ctx.T(`Email地址格式不正确`))
			}
		}
		if err == nil {
			err = m.Register(user, passwd, email)
			if err == nil {
				c.UseInvitationCode(c.Invitation, m.User.Id)
			}
		}
		if err == nil {
			ctx.Session().Set(`user`, m.User)
			returnTo := ctx.Query(`return_to`)
			if len(returnTo) == 0 {
				returnTo = `/manage`
			}
			return ctx.Redirect(returnTo)
		}
	}
	return ctx.Render(`register`, handler.Err(ctx, err))
}

func Logout(ctx echo.Context) error {
	ctx.Session().Delete(`user`)
	return ctx.Redirect(`/login`)
}

func Donation(ctx echo.Context) error {
	var langSuffix string
	lang := strings.ToLower(ctx.Lang())
	if strings.HasPrefix(lang, `zh`) {
		langSuffix = `_zh-CN`
	}
	return ctx.Redirect(`/public/donation` + langSuffix + `.html`)
}
<commit_msg>update<commit_after>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   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 index

import (
	"errors"

	"strings"

	"github.com/admpub/nging/application/handler"
	"github.com/admpub/nging/application/library/config"
	"github.com/admpub/nging/application/middleware"
	"github.com/admpub/nging/application/model"
	"github.com/webx-top/com"
	"github.com/webx-top/echo"
	"github.com/webx-top/echo/middleware/tplfunc"
)

func init() {
	handler.Register(func(e *echo.Echo) {
		e.Route("GET", `/`, Index)
		e.Route("GET,POST", `/login`, Login)
		e.Route("GET,POST", `/register`, Register)
		e.Route("GET", `/logout`, Logout)
		e.Route("GET", `/donation`, Donation)
	})
}

func Index(ctx echo.Context) error {
	return ctx.Redirect(`/manage`)
}

func Login(ctx echo.Context) error {
	//检查是否已安装
	if !config.IsInstalled() {
		return ctx.Redirect(`/setup`)
	}

	returnTo := ctx.Form(`return_to`)
	if len(returnTo) == 0 {
		returnTo = `/manage`
	}

	user := handler.User(ctx)
	if user != nil {
		return ctx.Redirect(returnTo)
	}
	var err error
	if ctx.IsPost() {
		if !tplfunc.CaptchaVerify(ctx.Form(`code`), ctx.Form) {
			err = errors.New(ctx.T(`验证码不正确`))
		} else {
			err = middleware.Auth(ctx, true)
			if err == nil {
				return ctx.Redirect(returnTo)
			}
		}
	}

	return ctx.Render(`login`, handler.Err(ctx, err))
}

func Register(ctx echo.Context) error {
	var err error
	if ctx.IsPost() {
		c := model.NewCode(ctx)
		m := model.NewUser(ctx)
		code := ctx.Form(`invitationCode`)
		user := ctx.Form(`username`)
		email := ctx.Form(`email`)
		passwd := ctx.Form(`password`)
		repwd := ctx.Form(`confirmationPassword`)
		if len(code) == 0 {
			err = errors.New(ctx.T(`邀请码不能为空`))
		} else if len(user) == 0 {
			err = errors.New(ctx.T(`用户名不能为空`))
		} else if len(email) == 0 {
			err = errors.New(ctx.T(`Email不能为空`))
		} else if len(passwd) < 8 {
			err = errors.New(ctx.T(`密码不能少于8个字符`))
		} else if repwd != passwd {
			err = errors.New(ctx.T(`密码与确认密码不一致`))
		} else if !com.IsUsername(user) {
			err = errors.New(ctx.T(`用户名不能包含特殊字符(只能由字母、数字、下划线和汉字组成)`))
		} else {
			var exists bool
			exists, err = m.Exists(user)
			if exists {
				err = errors.New(ctx.T(`用户名已经存在`))
			}
			if err == nil {
				err = c.VerfyInvitationCode(code)
			}
			if err == nil && !ctx.ValidateField(`email`, email, `email`) {
				err = errors.New(ctx.T(`Email地址格式不正确`))
			}
		}
		if err == nil {
			err = m.Register(user, passwd, email)
			if err == nil {
				c.UseInvitationCode(c.Invitation, m.User.Id)
			}
		}
		if err == nil {
			ctx.Session().Set(`user`, m.User)
			returnTo := ctx.Query(`return_to`)
			if len(returnTo) == 0 {
				returnTo = `/manage`
			}
			return ctx.Redirect(returnTo)
		}
	}
	return ctx.Render(`register`, handler.Err(ctx, err))
}

func Logout(ctx echo.Context) error {
	ctx.Session().Delete(`user`)
	return ctx.Redirect(`/login`)
}

func Donation(ctx echo.Context) error {
	var langSuffix string
	lang := strings.ToLower(ctx.Lang())
	if strings.HasPrefix(lang, `zh`) {
		langSuffix = `_zh-CN`
	}
	return ctx.Redirect(`/public/donation` + langSuffix + `.html`)
}
<|endoftext|>


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

package retrieval

import (
	"reflect"
	"testing"

	"golang.org/x/net/context"
	"gopkg.in/yaml.v2"

	"github.com/prometheus/common/model"
	"github.com/prometheus/prometheus/config"
	"github.com/prometheus/prometheus/storage/local"
)

func TestTargetSetRecreatesTargetGroupsEveryRun(t *testing.T) {

	verifyPresence := func(tgroups map[string][]*Target, name string, present bool) {
		if _, ok := tgroups[name]; ok != present {
			msg := ""
			if !present {
				msg = "not "
			}
			t.Fatalf("'%s' should %sbe present in TargetSet.tgroups: %s", name, msg, tgroups)
		}

	}

	scrapeConfig := &config.ScrapeConfig{}

	sOne := `
job_name: "foo"
dns_sd_configs:
- names:
  - "srv.name.one.example.org"
`
	if err := yaml.Unmarshal([]byte(sOne), scrapeConfig); err != nil {
		t.Fatalf("Unable to load YAML config sOne: %s", err)
	}

	// Not properly setting it up, but that seems okay
	mss := &local.MemorySeriesStorage{}

	ts := newTargetSet(scrapeConfig, mss)

	ts.runProviders(context.Background(), providersFromConfig(scrapeConfig))

	verifyPresence(ts.tgroups, "dns/0/srv.name.one.example.org", true)

	sTwo := `
job_name: "foo"
dns_sd_configs:
- names:
  - "srv.name.two.example.org"
`
	if err := yaml.Unmarshal([]byte(sTwo), scrapeConfig); err != nil {
		t.Fatalf("Unable to load YAML config sTwo: %s", err)
	}

	ts.runProviders(context.Background(), providersFromConfig(scrapeConfig))

	verifyPresence(ts.tgroups, "dns/0/srv.name.one.example.org", false)
	verifyPresence(ts.tgroups, "dns/0/srv.name.two.example.org", true)
}

func mustNewRegexp(s string) config.Regexp {
	re, err := config.NewRegexp(s)
	if err != nil {
		panic(err)
	}
	return re
}

func TestPopulateLabels(t *testing.T) {
	cases := []struct {
		in      model.LabelSet
		cfg     *config.ScrapeConfig
		res     model.LabelSet
		resOrig model.LabelSet
	}{
		// Regular population of scrape config options.
		{
			in: model.LabelSet{
				model.AddressLabel: "1.2.3.4:1000",
				"custom":           "value",
			},
			cfg: &config.ScrapeConfig{
				Scheme:      "https",
				MetricsPath: "/metrics",
				JobName:     "job",
			},
			res: model.LabelSet{
				model.AddressLabel:     "1.2.3.4:1000",
				model.InstanceLabel:    "1.2.3.4:1000",
				model.SchemeLabel:      "https",
				model.MetricsPathLabel: "/metrics",
				model.JobLabel:         "job",
				"custom":               "value",
			},
			resOrig: model.LabelSet{
				model.AddressLabel:     "1.2.3.4:1000",
				model.SchemeLabel:      "https",
				model.MetricsPathLabel: "/metrics",
				model.JobLabel:         "job",
				"custom":               "value",
			},
		},
		// Pre-define/overwrite scrape config labels.
		// Leave out port and expect it to be defaulted to scheme.
		{
			in: model.LabelSet{
				model.AddressLabel:     "1.2.3.4",
				model.SchemeLabel:      "http",
				model.MetricsPathLabel: "/custom",
				model.JobLabel:         "custom-job",
			},
			cfg: &config.ScrapeConfig{
				Scheme:      "https",
				MetricsPath: "/metrics",
				JobName:     "job",
			},
			res: model.LabelSet{
				model.AddressLabel:     "1.2.3.4:80",
				model.InstanceLabel:    "1.2.3.4:80",
				model.SchemeLabel:      "http",
				model.MetricsPathLabel: "/custom",
				model.JobLabel:         "custom-job",
			},
			resOrig: model.LabelSet{
				model.AddressLabel:     "1.2.3.4",
				model.SchemeLabel:      "http",
				model.MetricsPathLabel: "/custom",
				model.JobLabel:         "custom-job",
			},
		},
		// Provide instance label. HTTPS port default for IPv6.
		{
			in: model.LabelSet{
				model.AddressLabel:  "[::1]",
				model.InstanceLabel: "custom-instance",
			},
			cfg: &config.ScrapeConfig{
				Scheme:      "https",
				MetricsPath: "/metrics",
				JobName:     "job",
			},
			res: model.LabelSet{
				model.AddressLabel:     "[::1]:443",
				model.InstanceLabel:    "custom-instance",
				model.SchemeLabel:      "https",
				model.MetricsPathLabel: "/metrics",
				model.JobLabel:         "job",
			},
			resOrig: model.LabelSet{
				model.AddressLabel:     "[::1]",
				model.InstanceLabel:    "custom-instance",
				model.SchemeLabel:      "https",
				model.MetricsPathLabel: "/metrics",
				model.JobLabel:         "job",
			},
		},
		// Apply relabeling.
		{
			in: model.LabelSet{
				model.AddressLabel: "1.2.3.4:1000",
				"custom":           "value",
			},
			cfg: &config.ScrapeConfig{
				Scheme:      "https",
				MetricsPath: "/metrics",
				JobName:     "job",
				RelabelConfigs: []*config.RelabelConfig{
					{
						Action:       config.RelabelDrop,
						Regex:        mustNewRegexp(".*"),
						SourceLabels: model.LabelNames{"job"},
					},
				},
			},
			res:     nil,
			resOrig: nil,
		},
	}
	for i, c := range cases {
		res, orig, err := populateLabels(c.in, c.cfg)
		if err != nil {
			t.Fatalf("case %d: %s", i, err)
		}
		if !reflect.DeepEqual(res, c.res) {
			t.Errorf("case %d: expected res\n\t%+v\n got\n\t%+v", i, c.res, res)
		}
		if !reflect.DeepEqual(orig, c.resOrig) {
			t.Errorf("case %d: expected resOrig\n\t%+v\n got\n\t%+v", i, c.resOrig, orig)
		}
	}
}
<commit_msg>Fix broken test which relied on DNS resolution #1962<commit_after>// Copyright 2013 The Prometheus Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package retrieval

import (
	"reflect"
	"testing"

	"golang.org/x/net/context"
	"gopkg.in/yaml.v2"

	"github.com/prometheus/common/model"
	"github.com/prometheus/prometheus/config"
	"github.com/prometheus/prometheus/storage/local"
)

func TestTargetSetRecreatesTargetGroupsEveryRun(t *testing.T) {

	verifyPresence := func(tgroups map[string][]*Target, name string, present bool) {
		if _, ok := tgroups[name]; ok != present {
			msg := ""
			if !present {
				msg = "not "
			}
			t.Fatalf("'%s' should %sbe present in TargetSet.tgroups: %s", name, msg, tgroups)
		}

	}

	scrapeConfig := &config.ScrapeConfig{}

	sOne := `
job_name: "foo"
static_configs:
- targets: ["foo:9090"]
- targets: ["bar:9090"]
`
	if err := yaml.Unmarshal([]byte(sOne), scrapeConfig); err != nil {
		t.Fatalf("Unable to load YAML config sOne: %s", err)
	}

	// Not properly setting it up, but that seems okay
	mss := &local.MemorySeriesStorage{}

	ts := newTargetSet(scrapeConfig, mss)

	ts.runProviders(context.Background(), providersFromConfig(scrapeConfig))

	verifyPresence(ts.tgroups, "static/0/0", true)
	verifyPresence(ts.tgroups, "static/0/1", true)

	sTwo := `
job_name: "foo"
static_configs:
- targets: ["foo:9090"]
`
	if err := yaml.Unmarshal([]byte(sTwo), scrapeConfig); err != nil {
		t.Fatalf("Unable to load YAML config sTwo: %s", err)
	}

	ts.runProviders(context.Background(), providersFromConfig(scrapeConfig))

	verifyPresence(ts.tgroups, "static/0/0", true)
	verifyPresence(ts.tgroups, "static/0/1", false)
}

func mustNewRegexp(s string) config.Regexp {
	re, err := config.NewRegexp(s)
	if err != nil {
		panic(err)
	}
	return re
}

func TestPopulateLabels(t *testing.T) {
	cases := []struct {
		in      model.LabelSet
		cfg     *config.ScrapeConfig
		res     model.LabelSet
		resOrig model.LabelSet
	}{
		// Regular population of scrape config options.
		{
			in: model.LabelSet{
				model.AddressLabel: "1.2.3.4:1000",
				"custom":           "value",
			},
			cfg: &config.ScrapeConfig{
				Scheme:      "https",
				MetricsPath: "/metrics",
				JobName:     "job",
			},
			res: model.LabelSet{
				model.AddressLabel:     "1.2.3.4:1000",
				model.InstanceLabel:    "1.2.3.4:1000",
				model.SchemeLabel:      "https",
				model.MetricsPathLabel: "/metrics",
				model.JobLabel:         "job",
				"custom":               "value",
			},
			resOrig: model.LabelSet{
				model.AddressLabel:     "1.2.3.4:1000",
				model.SchemeLabel:      "https",
				model.MetricsPathLabel: "/metrics",
				model.JobLabel:         "job",
				"custom":               "value",
			},
		},
		// Pre-define/overwrite scrape config labels.
		// Leave out port and expect it to be defaulted to scheme.
		{
			in: model.LabelSet{
				model.AddressLabel:     "1.2.3.4",
				model.SchemeLabel:      "http",
				model.MetricsPathLabel: "/custom",
				model.JobLabel:         "custom-job",
			},
			cfg: &config.ScrapeConfig{
				Scheme:      "https",
				MetricsPath: "/metrics",
				JobName:     "job",
			},
			res: model.LabelSet{
				model.AddressLabel:     "1.2.3.4:80",
				model.InstanceLabel:    "1.2.3.4:80",
				model.SchemeLabel:      "http",
				model.MetricsPathLabel: "/custom",
				model.JobLabel:         "custom-job",
			},
			resOrig: model.LabelSet{
				model.AddressLabel:     "1.2.3.4",
				model.SchemeLabel:      "http",
				model.MetricsPathLabel: "/custom",
				model.JobLabel:         "custom-job",
			},
		},
		// Provide instance label. HTTPS port default for IPv6.
		{
			in: model.LabelSet{
				model.AddressLabel:  "[::1]",
				model.InstanceLabel: "custom-instance",
			},
			cfg: &config.ScrapeConfig{
				Scheme:      "https",
				MetricsPath: "/metrics",
				JobName:     "job",
			},
			res: model.LabelSet{
				model.AddressLabel:     "[::1]:443",
				model.InstanceLabel:    "custom-instance",
				model.SchemeLabel:      "https",
				model.MetricsPathLabel: "/metrics",
				model.JobLabel:         "job",
			},
			resOrig: model.LabelSet{
				model.AddressLabel:     "[::1]",
				model.InstanceLabel:    "custom-instance",
				model.SchemeLabel:      "https",
				model.MetricsPathLabel: "/metrics",
				model.JobLabel:         "job",
			},
		},
		// Apply relabeling.
		{
			in: model.LabelSet{
				model.AddressLabel: "1.2.3.4:1000",
				"custom":           "value",
			},
			cfg: &config.ScrapeConfig{
				Scheme:      "https",
				MetricsPath: "/metrics",
				JobName:     "job",
				RelabelConfigs: []*config.RelabelConfig{
					{
						Action:       config.RelabelDrop,
						Regex:        mustNewRegexp(".*"),
						SourceLabels: model.LabelNames{"job"},
					},
				},
			},
			res:     nil,
			resOrig: nil,
		},
	}
	for i, c := range cases {
		res, orig, err := populateLabels(c.in, c.cfg)
		if err != nil {
			t.Fatalf("case %d: %s", i, err)
		}
		if !reflect.DeepEqual(res, c.res) {
			t.Errorf("case %d: expected res\n\t%+v\n got\n\t%+v", i, c.res, res)
		}
		if !reflect.DeepEqual(orig, c.resOrig) {
			t.Errorf("case %d: expected resOrig\n\t%+v\n got\n\t%+v", i, c.resOrig, orig)
		}
	}
}
<|endoftext|>