<commit_before>// Copyright 2017 Jeff Foley. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package format

import (
	"fmt"
	"io"
	"net"
	"strconv"
	"strings"

	amassnet "github.com/OWASP/Amass/v3/net"
	"github.com/OWASP/Amass/v3/requests"
	"github.com/fatih/color"
)

// Banner is the ASCII art logo used within help output.
const Banner = `
        .+++:.            :                             .+++.
      +W@@@@@@8        &+W@#               o8W8:      +W@@@@@@#.   oW@@@W#+
     &@#+   .o@##.    .@@@o@W.o@@o       :@@#&W8o    .@#:  .:oW+  .@#+++&#&
    +@&        &@&     #@8 +@W@&8@+     :@W.   +@8   +@:          .@8
    8@          @@     8@o  8@8  WW    .@W      W@+  .@W.          o@#:
    WW          &@o    &@:  o@+  o@+   #@.      8@o   +W@#+.        +W@8:
    #@          :@W    &@+  &@+   @8  :@o       o@o     oW@@W+        oW@8
    o@+          @@&   &@+  &@+   #@  &@.      .W@W       .+#@&         o@W.
     WW         +@W@8. &@+  :&    o@+ #@      :@W&@&         &@:  ..     :@o
     :@W:      o@# +Wo &@+        :W: +@W&o++o@W. &@&  8@#o+&@W.  #@:    o@+
      :W@@WWWW@@8       +              :&W@@@@&    &W  .o#@@W&.   :W@WWW@@&
        +o&&&&+.                                                    +oooo.
`

const (
	// Version is used to display the current version of Amass.
	Version = "v3.11.7"

	// Author is used to display the Amass Project Team.
	Author = "OWASP Amass Project - @owaspamass"

	// Description is the slogan for the Amass Project.
	Description = "In-depth Attack Surface Mapping and Asset Discovery"
)

var (
	// Colors used to ease the reading of program output
	g      = color.New(color.FgHiGreen)
	b      = color.New(color.FgHiBlue)
	yellow = color.New(color.FgHiYellow).SprintFunc()
	green  = color.New(color.FgHiGreen).SprintFunc()
	blue   = color.New(color.FgHiBlue).SprintFunc()
)

// ASNSummaryData stores information related to discovered ASs and netblocks.
type ASNSummaryData struct {
	Name      string
	Netblocks map[string]int
}

// UpdateSummaryData updates the summary maps using the provided requests.Output data.
func UpdateSummaryData(output *requests.Output, tags map[string]int, asns map[int]*ASNSummaryData) {
	tags[output.Tag]++

	for _, addr := range output.Addresses {
		if addr.CIDRStr == "" {
			continue
		}

		data, found := asns[addr.ASN]
		if !found {
			asns[addr.ASN] = &ASNSummaryData{
				Name:      addr.Description,
				Netblocks: make(map[string]int),
			}
			data = asns[addr.ASN]
		}
		// Increment how many IPs were in this netblock
		data.Netblocks[addr.CIDRStr]++
	}
}

// PrintEnumerationSummary outputs the summary information utilized by the command-line tools.
func PrintEnumerationSummary(total int, tags map[string]int, asns map[int]*ASNSummaryData, demo bool) {
	FprintEnumerationSummary(color.Error, total, tags, asns, demo)
}

// FprintEnumerationSummary outputs the summary information utilized by the command-line tools.
func FprintEnumerationSummary(out io.Writer, total int, tags map[string]int, asns map[int]*ASNSummaryData, demo bool) {
	pad := func(num int, chr string) {
		for i := 0; i < num; i++ {
			b.Fprint(out, chr)
		}
	}

	fmt.Fprintln(out)
	// Print the header information
	title := "OWASP Amass "
	site := "https://github.com/OWASP/Amass"
	b.Fprint(out, title+Version)
	num := 80 - (len(title) + len(Version) + len(site))
	pad(num, " ")
	b.Fprintf(out, "%s\n", site)
	pad(8, "----------")
	fmt.Fprintf(out, "\n%s%s", yellow(strconv.Itoa(total)), green(" names discovered - "))
	// Print the stats using tag information
	num, length := 1, len(tags)
	for k, v := range tags {
		fmt.Fprintf(out, "%s: %s", green(k), yellow(strconv.Itoa(v)))
		if num < length {
			g.Fprint(out, ", ")
		}
		num++
	}
	fmt.Fprintln(out)

	if len(asns) == 0 {
		return
	}
	// Another line gets printed
	pad(8, "----------")
	fmt.Fprintln(out)
	// Print the ASN and netblock information
	for asn, data := range asns {
		asnstr := strconv.Itoa(asn)
		datastr := data.Name

		if demo && asn > 0 {
			asnstr = censorString(asnstr, 0, len(asnstr))
			datastr = censorString(datastr, 0, len(datastr))
		}
		fmt.Fprintf(out, "%s%s %s %s\n", blue("ASN: "), yellow(asnstr), green("-"), green(datastr))

		for cidr, ips := range data.Netblocks {
			countstr := strconv.Itoa(ips)
			cidrstr := cidr

			if demo {
				cidrstr = censorNetBlock(cidrstr)
			}

			countstr = fmt.Sprintf("\t%-4s", countstr)
			cidrstr = fmt.Sprintf("\t%-18s", cidrstr)
			fmt.Fprintf(out, "%s%s %s\n", yellow(cidrstr), yellow(countstr), blue("Subdomain Name(s)"))
		}
	}
}

// PrintBanner outputs the Amass banner the same for all tools.
func PrintBanner() {
	FprintBanner(color.Error)
}

// FprintBanner outputs the Amass banner the same for all tools.
func FprintBanner(out io.Writer) {
	y := color.New(color.FgHiYellow)
	r := color.New(color.FgHiRed)
	rightmost := 76

	pad := func(num int) {
		for i := 0; i < num; i++ {
			fmt.Fprint(out, " ")
		}
	}
	r.Fprintln(out, Banner)
	pad(rightmost - len(Version))
	y.Fprintln(out, Version)
	pad(rightmost - len(Author))
	y.Fprintln(out, Author)
	pad(rightmost - len(Description))
	y.Fprintf(out, "%s\n\n\n", Description)
}

func censorDomain(input string) string {
	return censorString(input, strings.Index(input, "."), len(input))
}

func censorIP(input string) string {
	return censorString(input, 0, strings.LastIndex(input, "."))
}

func censorNetBlock(input string) string {
	return censorString(input, 0, strings.Index(input, "/"))
}

func censorString(input string, start, end int) string {
	runes := []rune(input)
	for i := start; i < end; i++ {
		if runes[i] == '.' ||
			runes[i] == '/' ||
			runes[i] == '-' ||
			runes[i] == ' ' {
			continue
		}
		runes[i] = 'x'
	}
	return string(runes)
}

// OutputLineParts returns the parts of a line to be printed for a requests.Output.
func OutputLineParts(out *requests.Output, src, addrs, demo bool) (source, name, ips string) {
	if src {
		source = fmt.Sprintf("%-18s", "["+out.Sources[0]+"] ")
	}
	if addrs {
		for i, a := range out.Addresses {
			if i != 0 {
				ips += ","
			}
			if demo {
				ips += censorIP(a.Address.String())
			} else {
				ips += a.Address.String()
			}
		}
		if ips == "" {
			ips = "N/A"
		}
	}
	name = out.Name
	if demo {
		name = censorDomain(name)
	}
	return
}

// DesiredAddrTypes removes undesired address types from the AddressInfo slice.
func DesiredAddrTypes(addrs []requests.AddressInfo, ipv4, ipv6 bool) []requests.AddressInfo {
	if !ipv4 && !ipv6 {
		return addrs
	}

	var keep []requests.AddressInfo
	for _, addr := range addrs {
		if amassnet.IsIPv4(addr.Address) && !ipv4 {
			continue
		} else if amassnet.IsIPv6(addr.Address) && !ipv6 {
			continue
		}
		keep = append(keep, addr)
	}
	return keep
}

// InterfaceInfo returns network interface information specific to the current host.
func InterfaceInfo() string {
	var output string

	if ifaces, err := net.Interfaces(); err == nil {
		for _, i := range ifaces {
			addrs, err := i.Addrs()
			if err != nil {
				continue
			}
			output += fmt.Sprintf("%s%s%s\n", blue(i.Name+": "), green("flags="), yellow("<"+strings.ToUpper(i.Flags.String()+">")))
			if i.HardwareAddr.String() != "" {
				output += fmt.Sprintf("\t%s%s\n", green("ether: "), yellow(i.HardwareAddr.String()))
			}
			for _, addr := range addrs {
				inet := "inet"
				if a, ok := addr.(*net.IPNet); ok && amassnet.IsIPv6(a.IP) {
					inet += "6"
				}
				inet += ": "
				output += fmt.Sprintf("\t%s%s\n", green(inet), yellow(addr.String()))
			}
		}
	}

	return output
}
<commit_msg>v3.11.8 release<commit_after>// Copyright 2017 Jeff Foley. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.

package format

import (
	"fmt"
	"io"
	"net"
	"strconv"
	"strings"

	amassnet "github.com/OWASP/Amass/v3/net"
	"github.com/OWASP/Amass/v3/requests"
	"github.com/fatih/color"
)

// Banner is the ASCII art logo used within help output.
const Banner = `
        .+++:.            :                             .+++.
      +W@@@@@@8        &+W@#               o8W8:      +W@@@@@@#.   oW@@@W#+
     &@#+   .o@##.    .@@@o@W.o@@o       :@@#&W8o    .@#:  .:oW+  .@#+++&#&
    +@&        &@&     #@8 +@W@&8@+     :@W.   +@8   +@:          .@8
    8@          @@     8@o  8@8  WW    .@W      W@+  .@W.          o@#:
    WW          &@o    &@:  o@+  o@+   #@.      8@o   +W@#+.        +W@8:
    #@          :@W    &@+  &@+   @8  :@o       o@o     oW@@W+        oW@8
    o@+          @@&   &@+  &@+   #@  &@.      .W@W       .+#@&         o@W.
     WW         +@W@8. &@+  :&    o@+ #@      :@W&@&         &@:  ..     :@o
     :@W:      o@# +Wo &@+        :W: +@W&o++o@W. &@&  8@#o+&@W.  #@:    o@+
      :W@@WWWW@@8       +              :&W@@@@&    &W  .o#@@W&.   :W@WWW@@&
        +o&&&&+.                                                    +oooo.
`

const (
	// Version is used to display the current version of Amass.
	Version = "v3.11.8"

	// Author is used to display the Amass Project Team.
	Author = "OWASP Amass Project - @owaspamass"

	// Description is the slogan for the Amass Project.
	Description = "In-depth Attack Surface Mapping and Asset Discovery"
)

var (
	// Colors used to ease the reading of program output
	g      = color.New(color.FgHiGreen)
	b      = color.New(color.FgHiBlue)
	yellow = color.New(color.FgHiYellow).SprintFunc()
	green  = color.New(color.FgHiGreen).SprintFunc()
	blue   = color.New(color.FgHiBlue).SprintFunc()
)

// ASNSummaryData stores information related to discovered ASs and netblocks.
type ASNSummaryData struct {
	Name      string
	Netblocks map[string]int
}

// UpdateSummaryData updates the summary maps using the provided requests.Output data.
func UpdateSummaryData(output *requests.Output, tags map[string]int, asns map[int]*ASNSummaryData) {
	tags[output.Tag]++

	for _, addr := range output.Addresses {
		if addr.CIDRStr == "" {
			continue
		}

		data, found := asns[addr.ASN]
		if !found {
			asns[addr.ASN] = &ASNSummaryData{
				Name:      addr.Description,
				Netblocks: make(map[string]int),
			}
			data = asns[addr.ASN]
		}
		// Increment how many IPs were in this netblock
		data.Netblocks[addr.CIDRStr]++
	}
}

// PrintEnumerationSummary outputs the summary information utilized by the command-line tools.
func PrintEnumerationSummary(total int, tags map[string]int, asns map[int]*ASNSummaryData, demo bool) {
	FprintEnumerationSummary(color.Error, total, tags, asns, demo)
}

// FprintEnumerationSummary outputs the summary information utilized by the command-line tools.
func FprintEnumerationSummary(out io.Writer, total int, tags map[string]int, asns map[int]*ASNSummaryData, demo bool) {
	pad := func(num int, chr string) {
		for i := 0; i < num; i++ {
			b.Fprint(out, chr)
		}
	}

	fmt.Fprintln(out)
	// Print the header information
	title := "OWASP Amass "
	site := "https://github.com/OWASP/Amass"
	b.Fprint(out, title+Version)
	num := 80 - (len(title) + len(Version) + len(site))
	pad(num, " ")
	b.Fprintf(out, "%s\n", site)
	pad(8, "----------")
	fmt.Fprintf(out, "\n%s%s", yellow(strconv.Itoa(total)), green(" names discovered - "))
	// Print the stats using tag information
	num, length := 1, len(tags)
	for k, v := range tags {
		fmt.Fprintf(out, "%s: %s", green(k), yellow(strconv.Itoa(v)))
		if num < length {
			g.Fprint(out, ", ")
		}
		num++
	}
	fmt.Fprintln(out)

	if len(asns) == 0 {
		return
	}
	// Another line gets printed
	pad(8, "----------")
	fmt.Fprintln(out)
	// Print the ASN and netblock information
	for asn, data := range asns {
		asnstr := strconv.Itoa(asn)
		datastr := data.Name

		if demo && asn > 0 {
			asnstr = censorString(asnstr, 0, len(asnstr))
			datastr = censorString(datastr, 0, len(datastr))
		}
		fmt.Fprintf(out, "%s%s %s %s\n", blue("ASN: "), yellow(asnstr), green("-"), green(datastr))

		for cidr, ips := range data.Netblocks {
			countstr := strconv.Itoa(ips)
			cidrstr := cidr

			if demo {
				cidrstr = censorNetBlock(cidrstr)
			}

			countstr = fmt.Sprintf("\t%-4s", countstr)
			cidrstr = fmt.Sprintf("\t%-18s", cidrstr)
			fmt.Fprintf(out, "%s%s %s\n", yellow(cidrstr), yellow(countstr), blue("Subdomain Name(s)"))
		}
	}
}

// PrintBanner outputs the Amass banner the same for all tools.
func PrintBanner() {
	FprintBanner(color.Error)
}

// FprintBanner outputs the Amass banner the same for all tools.
func FprintBanner(out io.Writer) {
	y := color.New(color.FgHiYellow)
	r := color.New(color.FgHiRed)
	rightmost := 76

	pad := func(num int) {
		for i := 0; i < num; i++ {
			fmt.Fprint(out, " ")
		}
	}
	r.Fprintln(out, Banner)
	pad(rightmost - len(Version))
	y.Fprintln(out, Version)
	pad(rightmost - len(Author))
	y.Fprintln(out, Author)
	pad(rightmost - len(Description))
	y.Fprintf(out, "%s\n\n\n", Description)
}

func censorDomain(input string) string {
	return censorString(input, strings.Index(input, "."), len(input))
}

func censorIP(input string) string {
	return censorString(input, 0, strings.LastIndex(input, "."))
}

func censorNetBlock(input string) string {
	return censorString(input, 0, strings.Index(input, "/"))
}

func censorString(input string, start, end int) string {
	runes := []rune(input)
	for i := start; i < end; i++ {
		if runes[i] == '.' ||
			runes[i] == '/' ||
			runes[i] == '-' ||
			runes[i] == ' ' {
			continue
		}
		runes[i] = 'x'
	}
	return string(runes)
}

// OutputLineParts returns the parts of a line to be printed for a requests.Output.
func OutputLineParts(out *requests.Output, src, addrs, demo bool) (source, name, ips string) {
	if src {
		source = fmt.Sprintf("%-18s", "["+out.Sources[0]+"] ")
	}
	if addrs {
		for i, a := range out.Addresses {
			if i != 0 {
				ips += ","
			}
			if demo {
				ips += censorIP(a.Address.String())
			} else {
				ips += a.Address.String()
			}
		}
		if ips == "" {
			ips = "N/A"
		}
	}
	name = out.Name
	if demo {
		name = censorDomain(name)
	}
	return
}

// DesiredAddrTypes removes undesired address types from the AddressInfo slice.
func DesiredAddrTypes(addrs []requests.AddressInfo, ipv4, ipv6 bool) []requests.AddressInfo {
	if !ipv4 && !ipv6 {
		return addrs
	}

	var keep []requests.AddressInfo
	for _, addr := range addrs {
		if amassnet.IsIPv4(addr.Address) && !ipv4 {
			continue
		} else if amassnet.IsIPv6(addr.Address) && !ipv6 {
			continue
		}
		keep = append(keep, addr)
	}
	return keep
}

// InterfaceInfo returns network interface information specific to the current host.
func InterfaceInfo() string {
	var output string

	if ifaces, err := net.Interfaces(); err == nil {
		for _, i := range ifaces {
			addrs, err := i.Addrs()
			if err != nil {
				continue
			}
			output += fmt.Sprintf("%s%s%s\n", blue(i.Name+": "), green("flags="), yellow("<"+strings.ToUpper(i.Flags.String()+">")))
			if i.HardwareAddr.String() != "" {
				output += fmt.Sprintf("\t%s%s\n", green("ether: "), yellow(i.HardwareAddr.String()))
			}
			for _, addr := range addrs {
				inet := "inet"
				if a, ok := addr.(*net.IPNet); ok && amassnet.IsIPv6(a.IP) {
					inet += "6"
				}
				inet += ": "
				output += fmt.Sprintf("\t%s%s\n", green(inet), yellow(addr.String()))
			}
		}
	}

	return output
}
<|endoftext|>


<commit_before>// errchk $G $D/$F.go

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

package main

type T struct {
	// legal according to spec
	x int
	y (int)
	int
	*float
	// not legal according to spec
	(complex)  // ERROR "non-declaration|expected|parenthesize"
	(*string)  // ERROR "non-declaration|expected|parenthesize"
	*(bool)    // ERROR "non-declaration|expected|parenthesize"
}

// legal according to spec
func (p T) m() {}

// not legal according to spec
func (p (T)) f() {}   // ERROR "parenthesize"
func (p *(T)) g() {}  // ERROR "parenthesize"
func (p (*T)) h() {}  // ERROR "parenthesize"
<commit_msg>test: Recognize gccgo error messages.<commit_after>// errchk $G $D/$F.go

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

package main

type T struct {
	// legal according to spec
	x int
	y (int)
	int
	*float
	// not legal according to spec
	(complex)  // ERROR "non-declaration|expected|parenthesize"
	(*string)  // ERROR "non-declaration|expected|parenthesize"
	*(bool)    // ERROR "non-declaration|expected|parenthesize"
}

// legal according to spec
func (p T) m() {}

// not legal according to spec
func (p (T)) f() {}   // ERROR "parenthesize|expected"
func (p *(T)) g() {}  // ERROR "parenthesize|expected"
func (p (*T)) h() {}  // ERROR "parenthesize|expected"
<|endoftext|>


<commit_before>package aws

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"

	"github.com/hashicorp/terraform/helper/schema"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/s3"
)

func resourceAwsS3BucketObject() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsS3BucketObjectPut,
		Read:   resourceAwsS3BucketObjectRead,
		Delete: resourceAwsS3BucketObjectDelete,

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

			"cache_control": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"content_disposition": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"content_encoding": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"content_language": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"content_type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},

			"key": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"source": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"content"},
			},

			"content": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"source"},
			},

			"etag": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsS3BucketObjectPut(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)
	var body io.ReadSeeker

	if v, ok := d.GetOk("source"); ok {
		source := v.(string)
		file, err := os.Open(source)
		if err != nil {
			return fmt.Errorf("Error opening S3 bucket object source (%s): %s", source, err)
		}

		body = file
	} else if v, ok := d.GetOk("content"); ok {
		content := v.(string)
		body = bytes.NewReader([]byte(content))
	} else {

		return fmt.Errorf("Must specify \"source\" or \"content\" field")
	}
	putInput := &s3.PutObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
		Body:   body,
	}

	if v, ok := d.GetOk("cache_control"); ok {
		putInput.CacheControl = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_type"); ok {
		putInput.ContentType = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_encoding"); ok {
		putInput.ContentEncoding = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_language"); ok {
		putInput.ContentLanguage = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_disposition"); ok {
		putInput.ContentDisposition = aws.String(v.(string))
	}

	resp, err := s3conn.PutObject(putInput)
	if err != nil {
		return fmt.Errorf("Error putting object in S3 bucket (%s): %s", bucket, err)
	}

	d.Set("etag", resp.ETag)
	d.SetId(key)
	return nil
}

func resourceAwsS3BucketObjectRead(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)
	etag := d.Get("etag").(string)

	resp, err := s3conn.HeadObject(
		&s3.HeadObjectInput{
			Bucket:  aws.String(bucket),
			Key:     aws.String(key),
			IfMatch: aws.String(etag),
		})

	if err != nil {
		// If S3 returns a 404 Request Failure, mark the object as destroyed
		if awsErr, ok := err.(awserr.RequestFailure); ok && awsErr.StatusCode() == 404 {
			d.SetId("")
			log.Printf("[WARN] Error Reading Object (%s), object not found (HTTP status 404)", key)
			return nil
		}
		return err
	}

	d.Set("cache_control", resp.CacheControl)
	d.Set("content_disposition", resp.ContentDisposition)
	d.Set("content_encoding", resp.ContentEncoding)
	d.Set("content_language", resp.ContentLanguage)
	d.Set("content_type", resp.ContentType)

	log.Printf("[DEBUG] Reading S3 Bucket Object meta: %s", resp)
	return nil
}

func resourceAwsS3BucketObjectDelete(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)

	_, err := s3conn.DeleteObject(
		&s3.DeleteObjectInput{
			Bucket: aws.String(bucket),
			Key:    aws.String(key),
		})
	if err != nil {
		return fmt.Errorf("Error deleting S3 bucket object: %s", err)
	}
	return nil
}
<commit_msg>provider/aws: homedir expand in s3 object source<commit_after>package aws

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/mitchellh/go-homedir"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/s3"
)

func resourceAwsS3BucketObject() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsS3BucketObjectPut,
		Read:   resourceAwsS3BucketObjectRead,
		Delete: resourceAwsS3BucketObjectDelete,

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

			"cache_control": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"content_disposition": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"content_encoding": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"content_language": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"content_type": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
				Computed: true,
			},

			"key": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"source": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"content"},
			},

			"content": &schema.Schema{
				Type:          schema.TypeString,
				Optional:      true,
				ForceNew:      true,
				ConflictsWith: []string{"source"},
			},

			"etag": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},
		},
	}
}

func resourceAwsS3BucketObjectPut(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)
	var body io.ReadSeeker

	if v, ok := d.GetOk("source"); ok {
		source := v.(string)
		path, err := homedir.Expand(source)
		if err != nil {
			return fmt.Errorf("Error expanding homedir in source (%s): %s", source, err)
		}
		file, err := os.Open(path)
		if err != nil {
			return fmt.Errorf("Error opening S3 bucket object source (%s): %s", source, err)
		}

		body = file
	} else if v, ok := d.GetOk("content"); ok {
		content := v.(string)
		body = bytes.NewReader([]byte(content))
	} else {

		return fmt.Errorf("Must specify \"source\" or \"content\" field")
	}
	putInput := &s3.PutObjectInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
		Body:   body,
	}

	if v, ok := d.GetOk("cache_control"); ok {
		putInput.CacheControl = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_type"); ok {
		putInput.ContentType = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_encoding"); ok {
		putInput.ContentEncoding = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_language"); ok {
		putInput.ContentLanguage = aws.String(v.(string))
	}

	if v, ok := d.GetOk("content_disposition"); ok {
		putInput.ContentDisposition = aws.String(v.(string))
	}

	resp, err := s3conn.PutObject(putInput)
	if err != nil {
		return fmt.Errorf("Error putting object in S3 bucket (%s): %s", bucket, err)
	}

	d.Set("etag", resp.ETag)
	d.SetId(key)
	return nil
}

func resourceAwsS3BucketObjectRead(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)
	etag := d.Get("etag").(string)

	resp, err := s3conn.HeadObject(
		&s3.HeadObjectInput{
			Bucket:  aws.String(bucket),
			Key:     aws.String(key),
			IfMatch: aws.String(etag),
		})

	if err != nil {
		// If S3 returns a 404 Request Failure, mark the object as destroyed
		if awsErr, ok := err.(awserr.RequestFailure); ok && awsErr.StatusCode() == 404 {
			d.SetId("")
			log.Printf("[WARN] Error Reading Object (%s), object not found (HTTP status 404)", key)
			return nil
		}
		return err
	}

	d.Set("cache_control", resp.CacheControl)
	d.Set("content_disposition", resp.ContentDisposition)
	d.Set("content_encoding", resp.ContentEncoding)
	d.Set("content_language", resp.ContentLanguage)
	d.Set("content_type", resp.ContentType)

	log.Printf("[DEBUG] Reading S3 Bucket Object meta: %s", resp)
	return nil
}

func resourceAwsS3BucketObjectDelete(d *schema.ResourceData, meta interface{}) error {
	s3conn := meta.(*AWSClient).s3conn

	bucket := d.Get("bucket").(string)
	key := d.Get("key").(string)

	_, err := s3conn.DeleteObject(
		&s3.DeleteObjectInput{
			Bucket: aws.String(bucket),
			Key:    aws.String(key),
		})
	if err != nil {
		return fmt.Errorf("Error deleting S3 bucket object: %s", err)
	}
	return nil
}
<|endoftext|>


<commit_before>package network

import (
	"fmt"
	"net"
	"os"
	"strings"

	"github.com/pkg/errors"

	lxd "github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	log "github.com/lxc/lxd/shared/log15"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
	"github.com/lxc/lxd/shared/validate"
)

// common represents a generic LXD network.
type common struct {
	logger      logger.Logger
	state       *state.State
	id          int64
	name        string
	netType     string
	description string
	config      map[string]string
	status      string
}

// init initialise internal variables.
func (n *common) init(state *state.State, id int64, name string, netType string, description string, config map[string]string, status string) {
	n.logger = logging.AddContext(logger.Log, log.Ctx{"driver": netType, "network": name})
	n.id = id
	n.name = name
	n.netType = netType
	n.config = config
	n.state = state
	n.description = description
	n.status = status
}

// fillConfig fills requested config with any default values, by default this is a no-op.
func (n *common) fillConfig(config map[string]string) error {
	return nil
}

// validationRules returns a map of config rules common to all drivers.
func (n *common) validationRules() map[string]func(string) error {
	return map[string]func(string) error{}
}

// validate a network config against common rules and optional driver specific rules.
func (n *common) validate(config map[string]string, driverRules map[string]func(value string) error) error {
	checkedFields := map[string]struct{}{}

	// Get rules common for all drivers.
	rules := n.validationRules()

	// Merge driver specific rules into common rules.
	for field, validator := range driverRules {
		rules[field] = validator
	}

	// Run the validator against each field.
	for k, validator := range rules {
		checkedFields[k] = struct{}{} //Mark field as checked.
		err := validator(config[k])
		if err != nil {
			return errors.Wrapf(err, "Invalid value for network %q option %q", n.name, k)
		}
	}

	// Look for any unchecked fields, as these are unknown fields and validation should fail.
	for k := range config {
		_, checked := checkedFields[k]
		if checked {
			continue
		}

		// User keys are not validated.
		if strings.HasPrefix(k, "user.") {
			continue
		}

		return fmt.Errorf("Invalid option for network %q option %q", n.name, k)
	}

	return nil
}

// ValidateName validates network name.
func (n *common) ValidateName(name string) error {
	return validate.IsURLSegmentSafe(name)
}

// ID returns the network ID.
func (n *common) ID() int64 {
	return n.id
}

// Name returns the network name.
func (n *common) Name() string {
	return n.name
}

// Status returns the network status.
func (n *common) Status() string {
	return n.status
}

// Type returns the network type.
func (n *common) Type() string {
	return n.netType
}

// Config returns the network config.
func (n *common) Config() map[string]string {
	return n.config
}

// IsUsed returns whether the network is used by any instances or profiles.
func (n *common) IsUsed() (bool, error) {
	// Look for instances using the network.
	insts, err := instance.LoadFromAllProjects(n.state)
	if err != nil {
		return false, err
	}

	for _, inst := range insts {
		inUse, err := IsInUseByInstance(n.state, inst, n.name)
		if err != nil {
			return false, err
		}

		if inUse {
			return true, nil
		}
	}

	// Look for profiles using the network.
	var profiles []db.Profile
	err = n.state.Cluster.Transaction(func(tx *db.ClusterTx) error {
		profiles, err = tx.GetProfiles(db.ProfileFilter{})
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return false, err
	}

	for _, profile := range profiles {
		inUse, err := IsInUseByProfile(n.state, *db.ProfileToAPI(&profile), n.name)
		if err != nil {
			return false, err
		}

		if inUse {
			return true, nil
		}
	}

	return false, nil
}

// DHCPv4Subnet returns nil always.
func (n *common) DHCPv4Subnet() *net.IPNet {
	return nil
}

// DHCPv6Subnet returns nil always.
func (n *common) DHCPv6Subnet() *net.IPNet {
	return nil
}

// DHCPv4Ranges returns a parsed set of DHCPv4 ranges for this network.
func (n *common) DHCPv4Ranges() []shared.IPRange {
	dhcpRanges := make([]shared.IPRange, 0)
	if n.config["ipv4.dhcp.ranges"] != "" {
		for _, r := range strings.Split(n.config["ipv4.dhcp.ranges"], ",") {
			parts := strings.SplitN(strings.TrimSpace(r), "-", 2)
			if len(parts) == 2 {
				startIP := net.ParseIP(parts[0])
				endIP := net.ParseIP(parts[1])
				dhcpRanges = append(dhcpRanges, shared.IPRange{
					Start: startIP.To4(),
					End:   endIP.To4(),
				})
			}
		}
	}

	return dhcpRanges
}

// DHCPv6Ranges returns a parsed set of DHCPv6 ranges for this network.
func (n *common) DHCPv6Ranges() []shared.IPRange {
	dhcpRanges := make([]shared.IPRange, 0)
	if n.config["ipv6.dhcp.ranges"] != "" {
		for _, r := range strings.Split(n.config["ipv6.dhcp.ranges"], ",") {
			parts := strings.SplitN(strings.TrimSpace(r), "-", 2)
			if len(parts) == 2 {
				startIP := net.ParseIP(parts[0])
				endIP := net.ParseIP(parts[1])
				dhcpRanges = append(dhcpRanges, shared.IPRange{
					Start: startIP.To16(),
					End:   endIP.To16(),
				})
			}
		}
	}

	return dhcpRanges
}

// update the internal config variables, and if not cluster notification, notifies all nodes and updates database.
func (n *common) update(applyNetwork api.NetworkPut, targetNode string, clusterNotification bool) error {
	// Update internal config before database has been updated (so that if update is a notification we apply
	// the config being supplied and not that in the database).
	n.init(n.state, n.id, n.name, n.netType, applyNetwork.Description, applyNetwork.Config, n.status)

	// If this update isn't coming via a cluster notification itself, then notify all nodes of change and then
	// update the database.
	if !clusterNotification {
		if targetNode == "" {
			// Notify all other nodes to update the network if no target specified.
			notifier, err := cluster.NewNotifier(n.state, n.state.Endpoints.NetworkCert(), cluster.NotifyAll)
			if err != nil {
				return err
			}

			sendNetwork := applyNetwork
			sendNetwork.Config = make(map[string]string)
			for k, v := range applyNetwork.Config {
				// Don't forward node specific keys (these will be merged in on recipient node).
				if shared.StringInSlice(k, db.NodeSpecificNetworkConfig) {
					continue
				}

				sendNetwork.Config[k] = v
			}

			err = notifier(func(client lxd.InstanceServer) error {
				return client.UpdateNetwork(n.name, sendNetwork, "")
			})
			if err != nil {
				return err
			}
		}

		// Update the database.
		err := n.state.Cluster.UpdateNetwork(n.name, applyNetwork.Description, applyNetwork.Config)
		if err != nil {
			return err
		}
	}

	return nil
}

// configChanged compares supplied new config with existing config. Returns a boolean indicating if differences in
// the config or description were found (and the database record needs updating), and a list of non-user config
// keys that have changed, and a copy of the current internal network config that can be used to revert if needed.
func (n *common) configChanged(newNetwork api.NetworkPut) (bool, []string, api.NetworkPut, error) {
	// Backup the current state.
	oldNetwork := api.NetworkPut{
		Description: n.description,
		Config:      map[string]string{},
	}

	err := shared.DeepCopy(&n.config, &oldNetwork.Config)
	if err != nil {
		return false, nil, oldNetwork, err
	}

	// Diff the configurations.
	changedKeys := []string{}
	dbUpdateNeeded := false

	if newNetwork.Description != n.description {
		dbUpdateNeeded = true
	}

	for k, v := range oldNetwork.Config {
		if v != newNetwork.Config[k] {
			dbUpdateNeeded = true

			// Add non-user changed key to list of changed keys.
			if !strings.HasPrefix(k, "user.") && !shared.StringInSlice(k, changedKeys) {
				changedKeys = append(changedKeys, k)
			}
		}
	}

	for k, v := range newNetwork.Config {
		if v != oldNetwork.Config[k] {
			dbUpdateNeeded = true

			// Add non-user changed key to list of changed keys.
			if !strings.HasPrefix(k, "user.") && !shared.StringInSlice(k, changedKeys) {
				changedKeys = append(changedKeys, k)
			}
		}
	}

	return dbUpdateNeeded, changedKeys, oldNetwork, nil
}

// rename the network directory, update database record and update internal variables.
func (n *common) rename(newName string) error {
	// Clear new directory if exists.
	if shared.PathExists(shared.VarPath("networks", newName)) {
		os.RemoveAll(shared.VarPath("networks", newName))
	}

	// Rename directory to new name.
	if shared.PathExists(shared.VarPath("networks", n.name)) {
		err := os.Rename(shared.VarPath("networks", n.name), shared.VarPath("networks", newName))
		if err != nil {
			return err
		}
	}

	// Rename the database entry.
	err := n.state.Cluster.RenameNetwork(n.name, newName)
	if err != nil {
		return err
	}

	// Reinitialise internal name variable and logger context with new name.
	n.init(n.state, n.id, newName, n.netType, n.description, n.config, n.status)

	return nil
}

// delete the network from the database if clusterNotification is false.
func (n *common) delete(clusterNotification bool) error {
	// Only delete database record if not cluster notification.
	if !clusterNotification {
		// Notify all other nodes. If any node is down, an error will be returned.
		notifier, err := cluster.NewNotifier(n.state, n.state.Endpoints.NetworkCert(), cluster.NotifyAll)
		if err != nil {
			return err
		}
		err = notifier(func(client lxd.InstanceServer) error {
			return client.DeleteNetwork(n.name)
		})
		if err != nil {
			return err
		}

		// Remove the network from the database.
		err = n.state.Cluster.DeleteNetwork(n.name)
		if err != nil {
			return err
		}
	}

	// Cleanup storage.
	if shared.PathExists(shared.VarPath("networks", n.name)) {
		os.RemoveAll(shared.VarPath("networks", n.name))
	}

	return nil
}

// Create is a no-op.
func (n *common) Create(clusterNotification bool) error {
	return nil
}

// HandleHeartbeat is a no-op.
func (n *common) HandleHeartbeat(heartbeatData *cluster.APIHeartbeat) error {
	return nil
}
<commit_msg>lxd/network/driver/common: cluster.ClientType usage<commit_after>package network

import (
	"fmt"
	"net"
	"os"
	"strings"

	"github.com/pkg/errors"

	lxd "github.com/lxc/lxd/client"
	"github.com/lxc/lxd/lxd/cluster"
	"github.com/lxc/lxd/lxd/db"
	"github.com/lxc/lxd/lxd/instance"
	"github.com/lxc/lxd/lxd/state"
	"github.com/lxc/lxd/shared"
	"github.com/lxc/lxd/shared/api"
	log "github.com/lxc/lxd/shared/log15"
	"github.com/lxc/lxd/shared/logger"
	"github.com/lxc/lxd/shared/logging"
	"github.com/lxc/lxd/shared/validate"
)

// common represents a generic LXD network.
type common struct {
	logger      logger.Logger
	state       *state.State
	id          int64
	name        string
	netType     string
	description string
	config      map[string]string
	status      string
}

// init initialise internal variables.
func (n *common) init(state *state.State, id int64, name string, netType string, description string, config map[string]string, status string) {
	n.logger = logging.AddContext(logger.Log, log.Ctx{"driver": netType, "network": name})
	n.id = id
	n.name = name
	n.netType = netType
	n.config = config
	n.state = state
	n.description = description
	n.status = status
}

// fillConfig fills requested config with any default values, by default this is a no-op.
func (n *common) fillConfig(config map[string]string) error {
	return nil
}

// validationRules returns a map of config rules common to all drivers.
func (n *common) validationRules() map[string]func(string) error {
	return map[string]func(string) error{}
}

// validate a network config against common rules and optional driver specific rules.
func (n *common) validate(config map[string]string, driverRules map[string]func(value string) error) error {
	checkedFields := map[string]struct{}{}

	// Get rules common for all drivers.
	rules := n.validationRules()

	// Merge driver specific rules into common rules.
	for field, validator := range driverRules {
		rules[field] = validator
	}

	// Run the validator against each field.
	for k, validator := range rules {
		checkedFields[k] = struct{}{} //Mark field as checked.
		err := validator(config[k])
		if err != nil {
			return errors.Wrapf(err, "Invalid value for network %q option %q", n.name, k)
		}
	}

	// Look for any unchecked fields, as these are unknown fields and validation should fail.
	for k := range config {
		_, checked := checkedFields[k]
		if checked {
			continue
		}

		// User keys are not validated.
		if strings.HasPrefix(k, "user.") {
			continue
		}

		return fmt.Errorf("Invalid option for network %q option %q", n.name, k)
	}

	return nil
}

// ValidateName validates network name.
func (n *common) ValidateName(name string) error {
	return validate.IsURLSegmentSafe(name)
}

// ID returns the network ID.
func (n *common) ID() int64 {
	return n.id
}

// Name returns the network name.
func (n *common) Name() string {
	return n.name
}

// Status returns the network status.
func (n *common) Status() string {
	return n.status
}

// Type returns the network type.
func (n *common) Type() string {
	return n.netType
}

// Config returns the network config.
func (n *common) Config() map[string]string {
	return n.config
}

// IsUsed returns whether the network is used by any instances or profiles.
func (n *common) IsUsed() (bool, error) {
	// Look for instances using the network.
	insts, err := instance.LoadFromAllProjects(n.state)
	if err != nil {
		return false, err
	}

	for _, inst := range insts {
		inUse, err := IsInUseByInstance(n.state, inst, n.name)
		if err != nil {
			return false, err
		}

		if inUse {
			return true, nil
		}
	}

	// Look for profiles using the network.
	var profiles []db.Profile
	err = n.state.Cluster.Transaction(func(tx *db.ClusterTx) error {
		profiles, err = tx.GetProfiles(db.ProfileFilter{})
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return false, err
	}

	for _, profile := range profiles {
		inUse, err := IsInUseByProfile(n.state, *db.ProfileToAPI(&profile), n.name)
		if err != nil {
			return false, err
		}

		if inUse {
			return true, nil
		}
	}

	return false, nil
}

// DHCPv4Subnet returns nil always.
func (n *common) DHCPv4Subnet() *net.IPNet {
	return nil
}

// DHCPv6Subnet returns nil always.
func (n *common) DHCPv6Subnet() *net.IPNet {
	return nil
}

// DHCPv4Ranges returns a parsed set of DHCPv4 ranges for this network.
func (n *common) DHCPv4Ranges() []shared.IPRange {
	dhcpRanges := make([]shared.IPRange, 0)
	if n.config["ipv4.dhcp.ranges"] != "" {
		for _, r := range strings.Split(n.config["ipv4.dhcp.ranges"], ",") {
			parts := strings.SplitN(strings.TrimSpace(r), "-", 2)
			if len(parts) == 2 {
				startIP := net.ParseIP(parts[0])
				endIP := net.ParseIP(parts[1])
				dhcpRanges = append(dhcpRanges, shared.IPRange{
					Start: startIP.To4(),
					End:   endIP.To4(),
				})
			}
		}
	}

	return dhcpRanges
}

// DHCPv6Ranges returns a parsed set of DHCPv6 ranges for this network.
func (n *common) DHCPv6Ranges() []shared.IPRange {
	dhcpRanges := make([]shared.IPRange, 0)
	if n.config["ipv6.dhcp.ranges"] != "" {
		for _, r := range strings.Split(n.config["ipv6.dhcp.ranges"], ",") {
			parts := strings.SplitN(strings.TrimSpace(r), "-", 2)
			if len(parts) == 2 {
				startIP := net.ParseIP(parts[0])
				endIP := net.ParseIP(parts[1])
				dhcpRanges = append(dhcpRanges, shared.IPRange{
					Start: startIP.To16(),
					End:   endIP.To16(),
				})
			}
		}
	}

	return dhcpRanges
}

// update the internal config variables, and if not cluster notification, notifies all nodes and updates database.
func (n *common) update(applyNetwork api.NetworkPut, targetNode string, clientType cluster.ClientType) error {
	// Update internal config before database has been updated (so that if update is a notification we apply
	// the config being supplied and not that in the database).
	n.init(n.state, n.id, n.name, n.netType, applyNetwork.Description, applyNetwork.Config, n.status)

	// If this update isn't coming via a cluster notification itself, then notify all nodes of change and then
	// update the database.
	if clientType != cluster.ClientTypeNotifier {
		if targetNode == "" {
			// Notify all other nodes to update the network if no target specified.
			notifier, err := cluster.NewNotifier(n.state, n.state.Endpoints.NetworkCert(), cluster.NotifyAll)
			if err != nil {
				return err
			}

			sendNetwork := applyNetwork
			sendNetwork.Config = make(map[string]string)
			for k, v := range applyNetwork.Config {
				// Don't forward node specific keys (these will be merged in on recipient node).
				if shared.StringInSlice(k, db.NodeSpecificNetworkConfig) {
					continue
				}

				sendNetwork.Config[k] = v
			}

			err = notifier(func(client lxd.InstanceServer) error {
				return client.UpdateNetwork(n.name, sendNetwork, "")
			})
			if err != nil {
				return err
			}
		}

		// Update the database.
		err := n.state.Cluster.UpdateNetwork(n.name, applyNetwork.Description, applyNetwork.Config)
		if err != nil {
			return err
		}
	}

	return nil
}

// configChanged compares supplied new config with existing config. Returns a boolean indicating if differences in
// the config or description were found (and the database record needs updating), and a list of non-user config
// keys that have changed, and a copy of the current internal network config that can be used to revert if needed.
func (n *common) configChanged(newNetwork api.NetworkPut) (bool, []string, api.NetworkPut, error) {
	// Backup the current state.
	oldNetwork := api.NetworkPut{
		Description: n.description,
		Config:      map[string]string{},
	}

	err := shared.DeepCopy(&n.config, &oldNetwork.Config)
	if err != nil {
		return false, nil, oldNetwork, err
	}

	// Diff the configurations.
	changedKeys := []string{}
	dbUpdateNeeded := false

	if newNetwork.Description != n.description {
		dbUpdateNeeded = true
	}

	for k, v := range oldNetwork.Config {
		if v != newNetwork.Config[k] {
			dbUpdateNeeded = true

			// Add non-user changed key to list of changed keys.
			if !strings.HasPrefix(k, "user.") && !shared.StringInSlice(k, changedKeys) {
				changedKeys = append(changedKeys, k)
			}
		}
	}

	for k, v := range newNetwork.Config {
		if v != oldNetwork.Config[k] {
			dbUpdateNeeded = true

			// Add non-user changed key to list of changed keys.
			if !strings.HasPrefix(k, "user.") && !shared.StringInSlice(k, changedKeys) {
				changedKeys = append(changedKeys, k)
			}
		}
	}

	return dbUpdateNeeded, changedKeys, oldNetwork, nil
}

// rename the network directory, update database record and update internal variables.
func (n *common) rename(newName string) error {
	// Clear new directory if exists.
	if shared.PathExists(shared.VarPath("networks", newName)) {
		os.RemoveAll(shared.VarPath("networks", newName))
	}

	// Rename directory to new name.
	if shared.PathExists(shared.VarPath("networks", n.name)) {
		err := os.Rename(shared.VarPath("networks", n.name), shared.VarPath("networks", newName))
		if err != nil {
			return err
		}
	}

	// Rename the database entry.
	err := n.state.Cluster.RenameNetwork(n.name, newName)
	if err != nil {
		return err
	}

	// Reinitialise internal name variable and logger context with new name.
	n.init(n.state, n.id, newName, n.netType, n.description, n.config, n.status)

	return nil
}

// delete the network from the database if clusterNotification is false.
func (n *common) delete(clientType cluster.ClientType) error {
	// Only delete database record if not cluster notification.
	if clientType != cluster.ClientTypeNotifier {
		// Notify all other nodes. If any node is down, an error will be returned.
		notifier, err := cluster.NewNotifier(n.state, n.state.Endpoints.NetworkCert(), cluster.NotifyAll)
		if err != nil {
			return err
		}
		err = notifier(func(client lxd.InstanceServer) error {
			return client.DeleteNetwork(n.name)
		})
		if err != nil {
			return err
		}

		// Remove the network from the database.
		err = n.state.Cluster.DeleteNetwork(n.name)
		if err != nil {
			return err
		}
	}

	// Cleanup storage.
	if shared.PathExists(shared.VarPath("networks", n.name)) {
		os.RemoveAll(shared.VarPath("networks", n.name))
	}

	return nil
}

// Create is a no-op.
func (n *common) Create(clientType cluster.ClientType) error {
	n.logger.Debug("Create", log.Ctx{"clientType": clientType, "config": n.config})

	return nil
}

// HandleHeartbeat is a no-op.
func (n *common) HandleHeartbeat(heartbeatData *cluster.APIHeartbeat) error {
	return nil
}
<|endoftext|>


<commit_before>package manifest

import (
	"errors"
	"fmt"
	"sync"

	"github.com/bpicode/fritzctl/console"
	"github.com/bpicode/fritzctl/fritz"
)

// AhaApiApplier is an Applier that performs changes to the AHA system via the HTTP API.
func AhaApiApplier(f fritz.HomeAutomationApi) Applier {
	return &ahaApiApplier{fritz: f}
}

type ahaApiApplier struct {
	fritz fritz.HomeAutomationApi
}

// Apply does only log the proposed changes.
func (a *ahaApiApplier) Apply(src, target *Plan) error {
	planner := TargetBasedPlanner(reconfigureSwitch, reconfigureThermostat)
	actions, err := planner.Plan(src, target)
	if err != nil {
		return err
	}
	fanOutChan, wg := a.fanOut(actions)
	fanInChan := a.fanIn(fanOutChan)
	wg.Wait()
	close(fanOutChan)
	err = <-fanInChan
	close(fanInChan)
	return err
}

func (a *ahaApiApplier) fanIn(fanOutChan chan error) chan error {
	fanInChan := make(chan error)
	go func() {
		var msg string
		for e := range fanOutChan {
			if e != nil {
				msg += e.Error() + "\n"
			}
		}
		if msg != "" {
			fanInChan <- errors.New(msg)
		} else {
			fanInChan <- nil
		}
	}()
	return fanInChan
}
func (a *ahaApiApplier) fanOut(actions []Action) (chan error, *sync.WaitGroup) {
	var wg sync.WaitGroup
	fanOutChan := make(chan error)
	for _, action := range actions {
		wg.Add(1)
		go func(ac Action) {
			fanOutChan <- ac.Perform(a.fritz)
			wg.Done()
		}(action)
	}
	return fanOutChan, &wg
}

type reconfigureSwitchAction struct {
	before Switch
	after  Switch
}

func reconfigureSwitch(before, after Switch) Action {
	return &reconfigureSwitchAction{before: before, after: after}
}

// Perform applies the target state to a switch by turning it on/off.
func (a *reconfigureSwitchAction) Perform(f fritz.HomeAutomationApi) (err error) {
	if a.before.State != a.after.State {
		if a.after.State {
			_, err = f.SwitchOn(a.before.ain)
		} else {
			_, err = f.SwitchOff(a.before.ain)
		}
		if err == nil {
			fmt.Printf("\tOK\t'%s'\t%s\t⟶\t%s\n", a.before.Name, console.Btoc(a.before.State), console.Btoc(a.after.State))
		}
	}
	return err
}

type reconfigureThermostatAction struct {
	before Thermostat
	after  Thermostat
}

func reconfigureThermostat(before, after Thermostat) Action {
	return &reconfigureThermostatAction{before: before, after: after}
}

// Perform applies the target state to a switch by turning it on/off.
func (a *reconfigureThermostatAction) Perform(f fritz.HomeAutomationApi) (err error) {
	if a.before.Temperature != a.after.Temperature {
		_, err = f.ApplyTemperature(a.after.Temperature, a.before.ain)
		if err == nil {
			fmt.Printf("\tOK\t'%s'\t%.1f°C\t⟶\t%.1f°C\n", a.before.Name, a.before.Temperature, a.after.Temperature)
		}
	}
	return err
}
<commit_msg>fix static analysis (block nesting): extract method<commit_after>package manifest

import (
	"errors"
	"fmt"
	"strings"
	"sync"

	"github.com/bpicode/fritzctl/console"
	"github.com/bpicode/fritzctl/fritz"
)

// AhaApiApplier is an Applier that performs changes to the AHA system via the HTTP API.
func AhaApiApplier(f fritz.HomeAutomationApi) Applier {
	return &ahaApiApplier{fritz: f}
}

type ahaApiApplier struct {
	fritz fritz.HomeAutomationApi
}

// Apply does only log the proposed changes.
func (a *ahaApiApplier) Apply(src, target *Plan) error {
	planner := TargetBasedPlanner(reconfigureSwitch, reconfigureThermostat)
	actions, err := planner.Plan(src, target)
	if err != nil {
		return err
	}
	fanOutChan, wg := a.fanOut(actions)
	fanInChan := a.fanIn(fanOutChan)
	wg.Wait()
	close(fanOutChan)
	err = <-fanInChan
	close(fanInChan)
	return err
}

func (a *ahaApiApplier) fanIn(fanOutChan chan error) chan error {
	fanInChan := make(chan error)
	go func() {
		var errMessages []string
		for err := range fanOutChan {
			errMessages = appendToErrorMessages(errMessages, err)
		}
		if len(errMessages) > 0 {
			fanInChan <- errors.New("the following operations failed:\n" + strings.Join(errMessages, "\n"))
		} else {
			fanInChan <- nil
		}
	}()
	return fanInChan
}

func appendToErrorMessages(errMsgs []string, err error) []string {
	if err != nil {
		return append(errMsgs, err.Error())
	}
	return errMsgs
}

func (a *ahaApiApplier) fanOut(actions []Action) (chan error, *sync.WaitGroup) {
	var wg sync.WaitGroup
	fanOutChan := make(chan error)
	for _, action := range actions {
		wg.Add(1)
		go func(ac Action) {
			fanOutChan <- ac.Perform(a.fritz)
			wg.Done()
		}(action)
	}
	return fanOutChan, &wg
}

type reconfigureSwitchAction struct {
	before Switch
	after  Switch
}

func reconfigureSwitch(before, after Switch) Action {
	return &reconfigureSwitchAction{before: before, after: after}
}

// Perform applies the target state to a switch by turning it on/off.
func (a *reconfigureSwitchAction) Perform(f fritz.HomeAutomationApi) (err error) {
	if a.before.State != a.after.State {
		if a.after.State {
			_, err = f.SwitchOn(a.before.ain)
		} else {
			_, err = f.SwitchOff(a.before.ain)
		}
		if err == nil {
			fmt.Printf("\tOK\t'%s'\t%s\t⟶\t%s\n", a.before.Name, console.Btoc(a.before.State), console.Btoc(a.after.State))
		}
	}
	return err
}

type reconfigureThermostatAction struct {
	before Thermostat
	after  Thermostat
}

func reconfigureThermostat(before, after Thermostat) Action {
	return &reconfigureThermostatAction{before: before, after: after}
}

// Perform applies the target state to a switch by turning it on/off.
func (a *reconfigureThermostatAction) Perform(f fritz.HomeAutomationApi) (err error) {
	if a.before.Temperature != a.after.Temperature {
		_, err = f.ApplyTemperature(a.after.Temperature, a.before.ain)
		if err == nil {
			fmt.Printf("\tOK\t'%s'\t%.1f°C\t⟶\t%.1f°C\n", a.before.Name, a.before.Temperature, a.after.Temperature)
		}
	}
	return err
}
<|endoftext|>


<commit_before>// Copyright 2021 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 internal

import (
	"fmt"
	"sort"

	"golang.org/x/mod/semver"
	"golang.org/x/pkgsite/internal/derrors"
)

// SymbolSection is the documentation section where a symbol appears.
type SymbolSection string

const (
	SymbolSectionConstants SymbolSection = "Constants"
	SymbolSectionVariables SymbolSection = "Variables"
	SymbolSectionFunctions SymbolSection = "Functions"
	SymbolSectionTypes     SymbolSection = "Types"
)

// SymbolKind is the type of a symbol.
type SymbolKind string

const (
	SymbolKindConstant SymbolKind = "Constant"
	SymbolKindVariable SymbolKind = "Variable"
	SymbolKindFunction SymbolKind = "Function"
	SymbolKindType     SymbolKind = "Type"
	SymbolKindField    SymbolKind = "Field"
	SymbolKindMethod   SymbolKind = "Method"
)

// Symbol is an element in the package API. A symbol can be a constant,
// variable, function, or type.
type Symbol struct {
	SymbolMeta

	// Children contain the child symbols for this symbol. This will
	// only be populated when the SymbolType is "Type". For example, the
	// children of net/http.Handler are FileServer, NotFoundHandler,
	// RedirectHandler, StripPrefix, and TimeoutHandler. Each child
	// symbol will have ParentName set to the Name of this type.
	Children []*SymbolMeta

	// GOOS specifies the execution operating system where the symbol appears.
	GOOS string

	// GOARCH specifies the execution architecture where the symbol appears.
	GOARCH string
}

// SymbolMeta is the metadata for an element in the package API. A symbol can
// be a constant, variable, function, or type.
type SymbolMeta struct {
	// Name is the name of the symbol.
	Name string

	// Synopsis is the one line description of the symbol as displayed
	// in the package documentation.
	Synopsis string

	// Section is the section that a symbol appears in.
	Section SymbolSection

	// Kind is the type of a symbol, which is either a constant, variable,
	// function, type, field or method.
	Kind SymbolKind

	// ParentName if name of the parent type if available, otherwise
	// the empty string. For example, the parent type for
	// net/http.FileServer is Handler.
	ParentName string
}

// SymbolHistory represents the history for when a symbol name was first added
// to a package.
type SymbolHistory struct {
	// m is a map of version to name to SymbolMeta to UnitSymbol.
	// SymbolMeta is stored as a distinct key from name, since it is possible
	// for a symbol in the same version for different build contexts to have
	// different SymbolMeta. For example:
	// https://pkg.go.dev/syscall@go1.16.3#CloseOnExec has function signature:
	// func CloseOnExec(fd int)
	//
	// versus
	// https://pkg.go.dev/syscall?GOOS=windows#CloseOnExec has function
	// signature:
	// func CloseOnExec(fd Handle)
	m map[string]map[string]map[SymbolMeta]*SymbolBuildContexts
}

// NewSymbolHistory returns a new *SymbolHistory.
func NewSymbolHistory() *SymbolHistory {
	return &SymbolHistory{
		m: map[string]map[string]map[SymbolMeta]*SymbolBuildContexts{},
	}
}

// SymbolsAtVersion returns a map of name to SymbolMeta to UnitSymbol for a
// given version.
func (sh *SymbolHistory) SymbolsAtVersion(v string) map[string]map[SymbolMeta]*SymbolBuildContexts {
	return sh.m[v]
}

// Versions returns an array of the versions in versionToNameToUnitSymbol, sorted by
// increasing semver.
func (sh *SymbolHistory) Versions() []string {
	var orderdVersions []string
	for v := range sh.m {
		orderdVersions = append(orderdVersions, v)
	}
	sort.Slice(orderdVersions, func(i, j int) bool {
		return semver.Compare(orderdVersions[i], orderdVersions[j]) == -1
	})
	return orderdVersions
}

// GetSymbol returns the unit symbol for a given name, version and build context.
func (sh *SymbolHistory) GetSymbol(name, v string, build BuildContext) (_ *SymbolMeta, err error) {
	defer derrors.Wrap(&err, "GetSymbol(%q, %q, %v)", name, v, build)
	sav, ok := sh.m[v]
	if !ok {
		return nil, fmt.Errorf("version %q could not be found: %q", v, name)
	}
	stu, ok := sav[name]
	if !ok {
		return nil, fmt.Errorf("symbol %q could not be found at version %q", name, v)
	}
	for sm, us := range stu {
		if us.SupportsBuild(build) {
			return &sm, nil
		}
	}
	return nil, fmt.Errorf("symbol %q does not have build %v at version %q", name, build, v)
}

// AddSymbol adds the given symbol to SymbolHistory.
func (sh *SymbolHistory) AddSymbol(sm SymbolMeta, v string, build BuildContext) {
	if v == "v1.10.0" && (sm.Name == "FD" || sm.ParentName == "FD") {
		fmt.Println(build, v, sm.Name, sm.Synopsis)
	}
	sav, ok := sh.m[v]
	if !ok {
		sav = map[string]map[SymbolMeta]*SymbolBuildContexts{}
		sh.m[v] = sav
	}
	stu, ok := sav[sm.Name]
	if !ok {
		stu = map[SymbolMeta]*SymbolBuildContexts{}
		sh.m[v][sm.Name] = stu
	}
	us, ok := stu[sm]
	if !ok {
		us = &SymbolBuildContexts{}
		sh.m[v][sm.Name][sm] = us
	}
	us.AddBuildContext(build)
}

// SymbolBuildContexts represents the build contexts that are associated with a
// SymbolMeta.
type SymbolBuildContexts struct {
	// builds are the build contexts that apply to this symbol.
	builds map[BuildContext]bool
}

// BuildContexts returns the build contexts for this UnitSymbol.
func (us *SymbolBuildContexts) BuildContexts() []BuildContext {
	var builds []BuildContext
	for b := range us.builds {
		builds = append(builds, b)
	}
	sort.Slice(builds, func(i, j int) bool {
		return builds[i].GOOS < builds[j].GOOS
	})
	return builds
}

// AddBuildContext adds a build context supported by this UnitSymbol.
func (us *SymbolBuildContexts) AddBuildContext(build BuildContext) {
	if us.builds == nil {
		us.builds = map[BuildContext]bool{}
	}
	if build != BuildContextAll {
		us.builds[build] = true
		return
	}
	for _, b := range BuildContexts {
		us.builds[b] = true
	}
}

// SupportsBuild reports whether the provided build is supported by this
// UnitSymbol. If the build is BuildContextAll, this is interpreted as this
// unit symbol supports at least one build context.
func (us *SymbolBuildContexts) SupportsBuild(build BuildContext) bool {
	if build == BuildContextAll {
		return len(us.builds) > 0
	}
	return us.builds[build]
}

// InAll reports whether the unit symbol supports all build contexts.
func (us *SymbolBuildContexts) InAll() bool {
	return len(us.builds) == len(BuildContexts)
}

// RemoveBuildContexts removes all of the build contexts associated with this
// unit symbol.
func (us *SymbolBuildContexts) RemoveBuildContexts() {
	us.builds = map[BuildContext]bool{}
}
<commit_msg>internal: delete stray print<commit_after>// Copyright 2021 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 internal

import (
	"fmt"
	"sort"

	"golang.org/x/mod/semver"
	"golang.org/x/pkgsite/internal/derrors"
)

// SymbolSection is the documentation section where a symbol appears.
type SymbolSection string

const (
	SymbolSectionConstants SymbolSection = "Constants"
	SymbolSectionVariables SymbolSection = "Variables"
	SymbolSectionFunctions SymbolSection = "Functions"
	SymbolSectionTypes     SymbolSection = "Types"
)

// SymbolKind is the type of a symbol.
type SymbolKind string

const (
	SymbolKindConstant SymbolKind = "Constant"
	SymbolKindVariable SymbolKind = "Variable"
	SymbolKindFunction SymbolKind = "Function"
	SymbolKindType     SymbolKind = "Type"
	SymbolKindField    SymbolKind = "Field"
	SymbolKindMethod   SymbolKind = "Method"
)

// Symbol is an element in the package API. A symbol can be a constant,
// variable, function, or type.
type Symbol struct {
	SymbolMeta

	// Children contain the child symbols for this symbol. This will
	// only be populated when the SymbolType is "Type". For example, the
	// children of net/http.Handler are FileServer, NotFoundHandler,
	// RedirectHandler, StripPrefix, and TimeoutHandler. Each child
	// symbol will have ParentName set to the Name of this type.
	Children []*SymbolMeta

	// GOOS specifies the execution operating system where the symbol appears.
	GOOS string

	// GOARCH specifies the execution architecture where the symbol appears.
	GOARCH string
}

// SymbolMeta is the metadata for an element in the package API. A symbol can
// be a constant, variable, function, or type.
type SymbolMeta struct {
	// Name is the name of the symbol.
	Name string

	// Synopsis is the one line description of the symbol as displayed
	// in the package documentation.
	Synopsis string

	// Section is the section that a symbol appears in.
	Section SymbolSection

	// Kind is the type of a symbol, which is either a constant, variable,
	// function, type, field or method.
	Kind SymbolKind

	// ParentName if name of the parent type if available, otherwise
	// the empty string. For example, the parent type for
	// net/http.FileServer is Handler.
	ParentName string
}

// SymbolHistory represents the history for when a symbol name was first added
// to a package.
type SymbolHistory struct {
	// m is a map of version to name to SymbolMeta to UnitSymbol.
	// SymbolMeta is stored as a distinct key from name, since it is possible
	// for a symbol in the same version for different build contexts to have
	// different SymbolMeta. For example:
	// https://pkg.go.dev/syscall@go1.16.3#CloseOnExec has function signature:
	// func CloseOnExec(fd int)
	//
	// versus
	// https://pkg.go.dev/syscall?GOOS=windows#CloseOnExec has function
	// signature:
	// func CloseOnExec(fd Handle)
	m map[string]map[string]map[SymbolMeta]*SymbolBuildContexts
}

// NewSymbolHistory returns a new *SymbolHistory.
func NewSymbolHistory() *SymbolHistory {
	return &SymbolHistory{
		m: map[string]map[string]map[SymbolMeta]*SymbolBuildContexts{},
	}
}

// SymbolsAtVersion returns a map of name to SymbolMeta to UnitSymbol for a
// given version.
func (sh *SymbolHistory) SymbolsAtVersion(v string) map[string]map[SymbolMeta]*SymbolBuildContexts {
	return sh.m[v]
}

// Versions returns an array of the versions in versionToNameToUnitSymbol, sorted by
// increasing semver.
func (sh *SymbolHistory) Versions() []string {
	var orderdVersions []string
	for v := range sh.m {
		orderdVersions = append(orderdVersions, v)
	}
	sort.Slice(orderdVersions, func(i, j int) bool {
		return semver.Compare(orderdVersions[i], orderdVersions[j]) == -1
	})
	return orderdVersions
}

// GetSymbol returns the unit symbol for a given name, version and build context.
func (sh *SymbolHistory) GetSymbol(name, v string, build BuildContext) (_ *SymbolMeta, err error) {
	defer derrors.Wrap(&err, "GetSymbol(%q, %q, %v)", name, v, build)
	sav, ok := sh.m[v]
	if !ok {
		return nil, fmt.Errorf("version %q could not be found: %q", v, name)
	}
	stu, ok := sav[name]
	if !ok {
		return nil, fmt.Errorf("symbol %q could not be found at version %q", name, v)
	}
	for sm, us := range stu {
		if us.SupportsBuild(build) {
			return &sm, nil
		}
	}
	return nil, fmt.Errorf("symbol %q does not have build %v at version %q", name, build, v)
}

// AddSymbol adds the given symbol to SymbolHistory.
func (sh *SymbolHistory) AddSymbol(sm SymbolMeta, v string, build BuildContext) {
	sav, ok := sh.m[v]
	if !ok {
		sav = map[string]map[SymbolMeta]*SymbolBuildContexts{}
		sh.m[v] = sav
	}
	stu, ok := sav[sm.Name]
	if !ok {
		stu = map[SymbolMeta]*SymbolBuildContexts{}
		sh.m[v][sm.Name] = stu
	}
	us, ok := stu[sm]
	if !ok {
		us = &SymbolBuildContexts{}
		sh.m[v][sm.Name][sm] = us
	}
	us.AddBuildContext(build)
}

// SymbolBuildContexts represents the build contexts that are associated with a
// SymbolMeta.
type SymbolBuildContexts struct {
	// builds are the build contexts that apply to this symbol.
	builds map[BuildContext]bool
}

// BuildContexts returns the build contexts for this UnitSymbol.
func (us *SymbolBuildContexts) BuildContexts() []BuildContext {
	var builds []BuildContext
	for b := range us.builds {
		builds = append(builds, b)
	}
	sort.Slice(builds, func(i, j int) bool {
		return builds[i].GOOS < builds[j].GOOS
	})
	return builds
}

// AddBuildContext adds a build context supported by this UnitSymbol.
func (us *SymbolBuildContexts) AddBuildContext(build BuildContext) {
	if us.builds == nil {
		us.builds = map[BuildContext]bool{}
	}
	if build != BuildContextAll {
		us.builds[build] = true
		return
	}
	for _, b := range BuildContexts {
		us.builds[b] = true
	}
}

// SupportsBuild reports whether the provided build is supported by this
// UnitSymbol. If the build is BuildContextAll, this is interpreted as this
// unit symbol supports at least one build context.
func (us *SymbolBuildContexts) SupportsBuild(build BuildContext) bool {
	if build == BuildContextAll {
		return len(us.builds) > 0
	}
	return us.builds[build]
}

// InAll reports whether the unit symbol supports all build contexts.
func (us *SymbolBuildContexts) InAll() bool {
	return len(us.builds) == len(BuildContexts)
}

// RemoveBuildContexts removes all of the build contexts associated with this
// unit symbol.
func (us *SymbolBuildContexts) RemoveBuildContexts() {
	us.builds = map[BuildContext]bool{}
}
<|endoftext|>


<commit_before>package util

import (
	"fmt"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/sky-uk/go-pulse-vtm/api"
	"net/http"
)

//SchemaSSLKey : Returns an SSL Key Schema
func SchemaSSLKey() map[string]*schema.Schema {
	return map[string]*schema.Schema{
		"name": {
			Type:         schema.TypeString,
			Required:     true,
			ForceNew:     true,
			ValidateFunc: NoZeroValues,
		},

		"note": {
			Type:     schema.TypeString,
			Optional: true,
		},

		"private": {
			Type:     schema.TypeString,
			Optional: true,
		},

		"public": {
			Type:     schema.TypeString,
			Optional: true,
		},

		"request": {
			Type:     schema.TypeString,
			Optional: true,
		},
	}
}

//SSLKeyCreate : Creates an SSL Key
func SSLKeyCreate(d *schema.ResourceData, meta interface{}, keyType string) error {

	name := d.Get("name").(string)

	sslKeyPropertiesConfig := make(map[string]interface{})
	sslKeyBasicConfig := make(map[string]interface{})
	sslKeyConfig := make(map[string]interface{})

	if v, ok := d.GetOk("note"); ok {
		sslKeyBasicConfig["note"] = v.(string)
	}
	if v, ok := d.GetOk("private"); ok {
		sslKeyBasicConfig["private"] = v.(string)
	}
	if v, ok := d.GetOk("public"); ok {
		sslKeyBasicConfig["public"] = v.(string)
	}
	if v, ok := d.GetOk("request"); ok {
		sslKeyBasicConfig["request"] = v.(string)
	}
	sslKeyPropertiesConfig["basic"] = sslKeyBasicConfig
	sslKeyConfig["properties"] = sslKeyPropertiesConfig

	config := meta.(map[string]interface{})
	client := config["jsonClient"].(*api.Client)
	err := client.Set(keyType, name, sslKeyConfig, nil)
	if err != nil {
		return fmt.Errorf("[ERROR] PulseVTM %s error whilst creating %s: %v", keyType, name, err)
	}
	d.SetId(name)

	return nil
}

//SSLKeyRead : Reads an SSL Key
func SSLKeyRead(d *schema.ResourceData, meta interface{}, keyType string) error {
	config := meta.(map[string]interface{})
	client := config["jsonClient"].(*api.Client)
	client.WorkWithConfigurationResources()
	sslClientKeyConfig := make(map[string]interface{})
	err := client.GetByName(keyType, d.Id(), &sslClientKeyConfig)
	if client.StatusCode == http.StatusNotFound {
		d.SetId("")
		return nil
	}
	if err != nil {
		return fmt.Errorf("[ERROR] PulseVTM %s error whilst retrieving %s: %v", keyType, d.Id(), err)
	}

	sslClientKeyPropertiesConfig := sslClientKeyConfig["properties"].(map[string]interface{})
	sslClientKeyBasicConfig := sslClientKeyPropertiesConfig["basic"].(map[string]interface{})

	for _, attribute := range []string{"note", "public", "request"} {
		err := d.Set(attribute, sslClientKeyBasicConfig[attribute])
		if err != nil {
			return fmt.Errorf("[ERROR] PulseVTM %s error whilst setting attribute %s: %v", keyType, attribute, err)
		}
	}

	return nil
}

//SSLKeyUpdate : Updates an SSL Key
func SSLKeyUpdate(d *schema.ResourceData, meta interface{}, keyType string) error {

	sslKeyPropertiesConfig := make(map[string]interface{})
	sslKeyBasicConfig := make(map[string]interface{})
	sslKeyConfig := make(map[string]interface{})

	if d.HasChange("note") {
		sslKeyBasicConfig["note"] = d.Get("note").(string)
	}
	if d.HasChange("private") {
		sslKeyBasicConfig["private"] = d.Get("private").(string)
	}
	if d.HasChange("public") {
		sslKeyBasicConfig["public"] = d.Get("public").(string)
	}
	if d.HasChange("request") {
		sslKeyBasicConfig["request"] = d.Get("request").(string)
	}

	sslKeyPropertiesConfig["basic"] = sslKeyBasicConfig
	sslKeyConfig["properties"] = sslKeyPropertiesConfig

	config := meta.(map[string]interface{})
	client := config["jsonClient"].(*api.Client)
	err := client.Set(keyType, d.Id(), sslKeyConfig, nil)
	if err != nil {
		return fmt.Errorf("[ERROR] PulseVTM %s error whilst updating %s: %v", keyType, d.Id(), err)
	}
	return nil
}
<commit_msg>Made the 'private' field of SSL keys sensitive (#129)<commit_after>package util

import (
	"fmt"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/sky-uk/go-pulse-vtm/api"
	"net/http"
)

//SchemaSSLKey : Returns an SSL Key Schema
func SchemaSSLKey() map[string]*schema.Schema {
	return map[string]*schema.Schema{
		"name": {
			Type:         schema.TypeString,
			Required:     true,
			ForceNew:     true,
			ValidateFunc: NoZeroValues,
		},

		"note": {
			Type:     schema.TypeString,
			Optional: true,
		},

		"private": {
			Type:      schema.TypeString,
			Optional:  true,
			Sensitive: true,
		},

		"public": {
			Type:     schema.TypeString,
			Optional: true,
		},

		"request": {
			Type:     schema.TypeString,
			Optional: true,
		},
	}
}

//SSLKeyCreate : Creates an SSL Key
func SSLKeyCreate(d *schema.ResourceData, meta interface{}, keyType string) error {

	name := d.Get("name").(string)

	sslKeyPropertiesConfig := make(map[string]interface{})
	sslKeyBasicConfig := make(map[string]interface{})
	sslKeyConfig := make(map[string]interface{})

	if v, ok := d.GetOk("note"); ok {
		sslKeyBasicConfig["note"] = v.(string)
	}
	if v, ok := d.GetOk("private"); ok {
		sslKeyBasicConfig["private"] = v.(string)
	}
	if v, ok := d.GetOk("public"); ok {
		sslKeyBasicConfig["public"] = v.(string)
	}
	if v, ok := d.GetOk("request"); ok {
		sslKeyBasicConfig["request"] = v.(string)
	}
	sslKeyPropertiesConfig["basic"] = sslKeyBasicConfig
	sslKeyConfig["properties"] = sslKeyPropertiesConfig

	config := meta.(map[string]interface{})
	client := config["jsonClient"].(*api.Client)
	err := client.Set(keyType, name, sslKeyConfig, nil)
	if err != nil {
		return fmt.Errorf("[ERROR] PulseVTM %s error whilst creating %s: %v", keyType, name, err)
	}
	d.SetId(name)

	return nil
}

//SSLKeyRead : Reads an SSL Key
func SSLKeyRead(d *schema.ResourceData, meta interface{}, keyType string) error {
	config := meta.(map[string]interface{})
	client := config["jsonClient"].(*api.Client)
	client.WorkWithConfigurationResources()
	sslClientKeyConfig := make(map[string]interface{})
	err := client.GetByName(keyType, d.Id(), &sslClientKeyConfig)
	if client.StatusCode == http.StatusNotFound {
		d.SetId("")
		return nil
	}
	if err != nil {
		return fmt.Errorf("[ERROR] PulseVTM %s error whilst retrieving %s: %v", keyType, d.Id(), err)
	}

	sslClientKeyPropertiesConfig := sslClientKeyConfig["properties"].(map[string]interface{})
	sslClientKeyBasicConfig := sslClientKeyPropertiesConfig["basic"].(map[string]interface{})

	for _, attribute := range []string{"note", "public", "request"} {
		err := d.Set(attribute, sslClientKeyBasicConfig[attribute])
		if err != nil {
			return fmt.Errorf("[ERROR] PulseVTM %s error whilst setting attribute %s: %v", keyType, attribute, err)
		}
	}

	return nil
}

//SSLKeyUpdate : Updates an SSL Key
func SSLKeyUpdate(d *schema.ResourceData, meta interface{}, keyType string) error {

	sslKeyPropertiesConfig := make(map[string]interface{})
	sslKeyBasicConfig := make(map[string]interface{})
	sslKeyConfig := make(map[string]interface{})

	if d.HasChange("note") {
		sslKeyBasicConfig["note"] = d.Get("note").(string)
	}
	if d.HasChange("private") {
		sslKeyBasicConfig["private"] = d.Get("private").(string)
	}
	if d.HasChange("public") {
		sslKeyBasicConfig["public"] = d.Get("public").(string)
	}
	if d.HasChange("request") {
		sslKeyBasicConfig["request"] = d.Get("request").(string)
	}

	sslKeyPropertiesConfig["basic"] = sslKeyBasicConfig
	sslKeyConfig["properties"] = sslKeyPropertiesConfig

	config := meta.(map[string]interface{})
	client := config["jsonClient"].(*api.Client)
	err := client.Set(keyType, d.Id(), sslKeyConfig, nil)
	if err != nil {
		return fmt.Errorf("[ERROR] PulseVTM %s error whilst updating %s: %v", keyType, d.Id(), err)
	}
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2018 The Kubernetes 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 internal

import (
	"fmt"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/structured-merge-diff/fieldpath"
	"sigs.k8s.io/structured-merge-diff/merge"
	"sigs.k8s.io/structured-merge-diff/typed"
)

// versionConverter is an implementation of
// sigs.k8s.io/structured-merge-diff/merge.Converter
type versionConverter struct {
	typeConverter   TypeConverter
	objectConvertor runtime.ObjectConvertor
	hubVersion      schema.GroupVersion
}

var _ merge.Converter = &versionConverter{}

// NewVersionConverter builds a VersionConverter from a TypeConverter and an ObjectConvertor.
func NewVersionConverter(t TypeConverter, o runtime.ObjectConvertor, h schema.GroupVersion) merge.Converter {
	return &versionConverter{
		typeConverter:   t,
		objectConvertor: o,
		hubVersion:      h,
	}
}

// Convert implements sigs.k8s.io/structured-merge-diff/merge.Converter
func (v *versionConverter) Convert(object typed.TypedValue, version fieldpath.APIVersion) (typed.TypedValue, error) {
	// Convert the smd typed value to a kubernetes object.
	objectToConvert, err := v.typeConverter.TypedToObject(object)
	if err != nil {
		return object, err
	}

	// Parse the target groupVersion.
	groupVersion, err := schema.ParseGroupVersion(string(version))
	if err != nil {
		return object, err
	}

	// If attempting to convert to the same version as we already have, just return it.
	if objectToConvert.GetObjectKind().GroupVersionKind().GroupVersion() == groupVersion {
		return object, nil
	}

	// Convert to internal
	internalObject, err := v.objectConvertor.ConvertToVersion(objectToConvert, v.hubVersion)
	if err != nil {
		return object, fmt.Errorf("failed to convert object (%v to %v): %v",
			objectToConvert.GetObjectKind().GroupVersionKind(), v.hubVersion, err)
	}

	// Convert the object into the target version
	convertedObject, err := v.objectConvertor.ConvertToVersion(internalObject, groupVersion)
	if err != nil {
		return object, fmt.Errorf("failed to convert object (%v to %v): %v",
			internalObject.GetObjectKind().GroupVersionKind(), groupVersion, err)
	}

	// Convert the object back to a smd typed value and return it.
	return v.typeConverter.ObjectToTyped(convertedObject)
}
<commit_msg>add IsMissingVersionError<commit_after>/*
Copyright 2018 The Kubernetes 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 internal

import (
	"fmt"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/runtime/schema"
	"sigs.k8s.io/structured-merge-diff/fieldpath"
	"sigs.k8s.io/structured-merge-diff/merge"
	"sigs.k8s.io/structured-merge-diff/typed"
)

// versionConverter is an implementation of
// sigs.k8s.io/structured-merge-diff/merge.Converter
type versionConverter struct {
	typeConverter   TypeConverter
	objectConvertor runtime.ObjectConvertor
	hubVersion      schema.GroupVersion
}

var _ merge.Converter = &versionConverter{}

// NewVersionConverter builds a VersionConverter from a TypeConverter and an ObjectConvertor.
func NewVersionConverter(t TypeConverter, o runtime.ObjectConvertor, h schema.GroupVersion) merge.Converter {
	return &versionConverter{
		typeConverter:   t,
		objectConvertor: o,
		hubVersion:      h,
	}
}

// Convert implements sigs.k8s.io/structured-merge-diff/merge.Converter
func (v *versionConverter) Convert(object typed.TypedValue, version fieldpath.APIVersion) (typed.TypedValue, error) {
	// Convert the smd typed value to a kubernetes object.
	objectToConvert, err := v.typeConverter.TypedToObject(object)
	if err != nil {
		return object, err
	}

	// Parse the target groupVersion.
	groupVersion, err := schema.ParseGroupVersion(string(version))
	if err != nil {
		return object, err
	}

	// If attempting to convert to the same version as we already have, just return it.
	if objectToConvert.GetObjectKind().GroupVersionKind().GroupVersion() == groupVersion {
		return object, nil
	}

	// Convert to internal
	internalObject, err := v.objectConvertor.ConvertToVersion(objectToConvert, v.hubVersion)
	if err != nil {
		return object, fmt.Errorf("failed to convert object (%v to %v): %v",
			objectToConvert.GetObjectKind().GroupVersionKind(), v.hubVersion, err)
	}

	// Convert the object into the target version
	convertedObject, err := v.objectConvertor.ConvertToVersion(internalObject, groupVersion)
	if err != nil {
		return object, fmt.Errorf("failed to convert object (%v to %v): %v",
			internalObject.GetObjectKind().GroupVersionKind(), groupVersion, err)
	}

	// Convert the object back to a smd typed value and return it.
	return v.typeConverter.ObjectToTyped(convertedObject)
}

// IsMissingVersionError
func (v *versionConverter) IsMissingVersionError(err error) bool {
	return runtime.IsNotRegisteredError(err)
}
<|endoftext|>


<commit_before>// +build !windows

package cliedit

import (
	"os"
	"path/filepath"
	"reflect"
	"sort"
	"testing"

	"github.com/elves/elvish/cli/el/layout"
	"github.com/elves/elvish/cli/term"
	"github.com/elves/elvish/edit/ui"
	"github.com/elves/elvish/store/storedefs"
	"github.com/elves/elvish/styled"
	"github.com/elves/elvish/util"
)

func TestLocationAddon(t *testing.T) {
	f := setupWithOpt(setupOpt{StoreOp: func(s storedefs.Store) {
		s.AddDir("/usr/bin", 1)
		s.AddDir("/tmp", 1)
		s.AddDir("/home/elf", 1)
	}})
	f.TTYCtrl.SetSize(24, 30) // Set width to 30
	defer f.Cleanup()

	evals(f.Evaler,
		`edit:location:pinned = [/opt]`,
		`edit:location:hidden = [/tmp]`)
	f.TTYCtrl.Inject(term.K('L', ui.Ctrl))

	wantBuf := bbAddon("LOCATION").
		WriteMarkedLines(
			"  * /opt                      ", styles,
			"##############################",
			" 10 /home/elf",
			" 10 /usr/bin",
		).Buffer()
	f.TTYCtrl.TestBuffer(t, wantBuf)
}

func TestLocationAddon_Workspace(t *testing.T) {
	f := setupWithOpt(setupOpt{StoreOp: func(s storedefs.Store) {
		s.AddDir("/usr/bin", 1)
		s.AddDir("ws/bin", 1)
		s.AddDir("other-ws/bin", 1)
	}})
	defer f.Cleanup()
	util.ApplyDir(
		util.Dir{
			"ws1": util.Dir{
				"bin": util.Dir{},
				"tmp": util.Dir{}}})
	err := os.Chdir("ws1/tmp")
	if err != nil {
		t.Skip("chdir:", err)
	}
	f.TTYCtrl.SetSize(24, 30) // Set width to 30

	evals(f.Evaler,
		`edit:location:workspaces = [&ws=$E:HOME/ws.]`)

	f.TTYCtrl.Inject(term.K('L', ui.Ctrl))
	wantBuf := ui.NewBufferBuilder(30).
		WritePlain("~/ws1/tmp> ").Newline().
		WriteStyled(layout.ModeLine("LOCATION", true)).SetDotHere().Newline().
		WriteMarkedLines(
			" 10 ws/bin                    ", styles,
			"##############################",
			" 10 /usr/bin",
		).Buffer()
	f.TTYCtrl.TestBuffer(t, wantBuf)

	f.TTYCtrl.Inject(term.K(ui.Enter))
	wantBuf = ui.NewBufferBuilder(30).
		WritePlain("~/ws1/bin> ").SetDotHere().Buffer()
	f.TTYCtrl.TestBuffer(t, wantBuf)
}

func TestLocation_AddDir(t *testing.T) {
	f := setup()
	defer f.Cleanup()
	util.ApplyDir(
		util.Dir{
			"bin": util.Dir{},
			"ws1": util.Dir{
				"bin": util.Dir{}}})
	evals(f.Evaler, `edit:location:workspaces = [&ws=$E:HOME/ws.]`)

	chdir := func(path string) {
		err := f.Evaler.Chdir(path)
		if err != nil {
			t.Skip("chdir:", err)
		}
	}
	chdir("bin")
	chdir("../ws1/bin")

	entries, err := f.Store.Dirs(map[string]struct{}{})
	if err != nil {
		t.Error("unable to list dir history:", err)
	}
	dirs := make([]string, len(entries))
	for i, entry := range entries {
		dirs[i] = entry.Path
	}

	wantDirs := []string{
		filepath.Join(f.Home, "bin"),
		filepath.Join(f.Home, "ws1", "bin"),
		filepath.Join("ws", "bin"),
	}

	sort.Strings(dirs)
	sort.Strings(wantDirs)
	if !reflect.DeepEqual(dirs, wantDirs) {
		t.Errorf("got dirs %v, want %v", dirs, wantDirs)
	}
}
<commit_msg>cliedit: Really fix test on non-Windows OSes.<commit_after>// +build !windows

package cliedit

import (
	"os"
	"path/filepath"
	"reflect"
	"sort"
	"testing"

	"github.com/elves/elvish/cli/el/layout"
	"github.com/elves/elvish/cli/term"
	"github.com/elves/elvish/edit/ui"
	"github.com/elves/elvish/store/storedefs"
	"github.com/elves/elvish/util"
)

func TestLocationAddon(t *testing.T) {
	f := setupWithOpt(setupOpt{StoreOp: func(s storedefs.Store) {
		s.AddDir("/usr/bin", 1)
		s.AddDir("/tmp", 1)
		s.AddDir("/home/elf", 1)
	}})
	f.TTYCtrl.SetSize(24, 30) // Set width to 30
	defer f.Cleanup()

	evals(f.Evaler,
		`edit:location:pinned = [/opt]`,
		`edit:location:hidden = [/tmp]`)
	f.TTYCtrl.Inject(term.K('L', ui.Ctrl))

	wantBuf := bbAddon("LOCATION").
		WriteMarkedLines(
			"  * /opt                      ", styles,
			"##############################",
			" 10 /home/elf",
			" 10 /usr/bin",
		).Buffer()
	f.TTYCtrl.TestBuffer(t, wantBuf)
}

func TestLocationAddon_Workspace(t *testing.T) {
	f := setupWithOpt(setupOpt{StoreOp: func(s storedefs.Store) {
		s.AddDir("/usr/bin", 1)
		s.AddDir("ws/bin", 1)
		s.AddDir("other-ws/bin", 1)
	}})
	defer f.Cleanup()
	util.ApplyDir(
		util.Dir{
			"ws1": util.Dir{
				"bin": util.Dir{},
				"tmp": util.Dir{}}})
	err := os.Chdir("ws1/tmp")
	if err != nil {
		t.Skip("chdir:", err)
	}
	f.TTYCtrl.SetSize(24, 30) // Set width to 30

	evals(f.Evaler,
		`edit:location:workspaces = [&ws=$E:HOME/ws.]`)

	f.TTYCtrl.Inject(term.K('L', ui.Ctrl))
	wantBuf := ui.NewBufferBuilder(30).
		WritePlain("~/ws1/tmp> ").Newline().
		WriteStyled(layout.ModeLine("LOCATION", true)).SetDotHere().Newline().
		WriteMarkedLines(
			" 10 ws/bin                    ", styles,
			"##############################",
			" 10 /usr/bin",
		).Buffer()
	f.TTYCtrl.TestBuffer(t, wantBuf)

	f.TTYCtrl.Inject(term.K(ui.Enter))
	wantBuf = ui.NewBufferBuilder(30).
		WritePlain("~/ws1/bin> ").SetDotHere().Buffer()
	f.TTYCtrl.TestBuffer(t, wantBuf)
}

func TestLocation_AddDir(t *testing.T) {
	f := setup()
	defer f.Cleanup()
	util.ApplyDir(
		util.Dir{
			"bin": util.Dir{},
			"ws1": util.Dir{
				"bin": util.Dir{}}})
	evals(f.Evaler, `edit:location:workspaces = [&ws=$E:HOME/ws.]`)

	chdir := func(path string) {
		err := f.Evaler.Chdir(path)
		if err != nil {
			t.Skip("chdir:", err)
		}
	}
	chdir("bin")
	chdir("../ws1/bin")

	entries, err := f.Store.Dirs(map[string]struct{}{})
	if err != nil {
		t.Error("unable to list dir history:", err)
	}
	dirs := make([]string, len(entries))
	for i, entry := range entries {
		dirs[i] = entry.Path
	}

	wantDirs := []string{
		filepath.Join(f.Home, "bin"),
		filepath.Join(f.Home, "ws1", "bin"),
		filepath.Join("ws", "bin"),
	}

	sort.Strings(dirs)
	sort.Strings(wantDirs)
	if !reflect.DeepEqual(dirs, wantDirs) {
		t.Errorf("got dirs %v, want %v", dirs, wantDirs)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path"

	mmap "github.com/edsrzf/mmap-go"

	"github.com/nsf/termbox-go"
)

const PROGRAM_NAME = "hecate"

type FileInfo struct {
	filename string
	bytes    []byte
}

func mainLoop(files []FileInfo, style Style) {
	screens := defaultScreensForFiles(files)
	active_idx := DATA_SCREEN_INDEX

	var screen_key_channels []chan termbox.Event
	var screen_quit_channels []chan bool
	switch_channel := make(chan int)
	main_key_channel := make(chan termbox.Event, 10)

	layoutAndDrawScreen(screens[active_idx], style)

	for _ = range screens {
		key_channel := make(chan termbox.Event, 10)
		screen_key_channels = append(screen_key_channels, key_channel)

		quit_channel := make(chan bool, 10)
		screen_quit_channels = append(screen_quit_channels, quit_channel)
	}

	for i, s := range screens {
		go func(index int, screen Screen) {
			screen.receiveEvents(screen_key_channels[index], switch_channel,
				screen_quit_channels[index])
		}(i, s)
	}

	go func() {
		for {
			event := termbox.PollEvent()
			if event.Type == termbox.EventInterrupt {
				break
			} else {
				main_key_channel <- event
			}
		}
	}()

	for {
		do_quit := false
		select {
		case event := <-main_key_channel:
			if event.Type == termbox.EventKey {
				handleSpecialKeys(event.Key)

				screen_key_channels[active_idx] <- event
			}
			if event.Type == termbox.EventResize {
				layoutAndDrawScreen(screens[active_idx], style)
			}
		case new_screen_index := <-switch_channel:
			if new_screen_index < len(screens) {
				active_idx = new_screen_index
				layoutAndDrawScreen(screens[active_idx], style)
			} else {
				do_quit = true
			}
		}
		if do_quit {
			for _, c := range screen_quit_channels {
				c <- true
			}
			termbox.Interrupt()
			break
		}
	}
}

func main() {
	var err error

	if len(os.Args) < 2 {
		fmt.Printf("Usage: %s <filename> [...]\n", PROGRAM_NAME)
		os.Exit(1)
	}
	var files []FileInfo
	for i := 1; i < len(os.Args); i++ {
		file_path := os.Args[i]

		file, err := os.Open(file_path)
		if err != nil {
			fmt.Printf("Error opening file: %q\n", err.Error())
			os.Exit(1)
		}

		fi, err := file.Stat()
		if err != nil {
			fmt.Printf("Error stat'ing file: %q\n", err.Error())
			os.Exit(1)
		}

		if fi.Size() < 8 {
			fmt.Printf("File %s is too short to be edited\n", file_path)
			os.Exit(1)
		}

		mm, err := mmap.Map(file, mmap.RDONLY, 0)
		if err != nil {
			fmt.Printf("Error mmap'ing file: %q\n", err.Error())
			os.Exit(1)
		}
		files = append(files, FileInfo{filename: path.Base(file_path), bytes: mm})
	}

	err = termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()

	style := defaultStyle()
	termbox.SetOutputMode(outputMode)

	mainLoop(files, style)
}
<commit_msg>refactor file open operation into own function.<commit_after>package main

import (
	"fmt"
	"os"
	"path"
	"errors"

	mmap "github.com/edsrzf/mmap-go"

	"github.com/nsf/termbox-go"
)

const PROGRAM_NAME = "hecate"

type FileInfo struct {
	filename string
	bytes    []byte
}

func mainLoop(files []FileInfo, style Style) {
	screens := defaultScreensForFiles(files)
	active_idx := DATA_SCREEN_INDEX

	var screen_key_channels []chan termbox.Event
	var screen_quit_channels []chan bool
	switch_channel := make(chan int)
	main_key_channel := make(chan termbox.Event, 10)

	layoutAndDrawScreen(screens[active_idx], style)

	for _ = range screens {
		key_channel := make(chan termbox.Event, 10)
		screen_key_channels = append(screen_key_channels, key_channel)

		quit_channel := make(chan bool, 10)
		screen_quit_channels = append(screen_quit_channels, quit_channel)
	}

	for i, s := range screens {
		go func(index int, screen Screen) {
			screen.receiveEvents(screen_key_channels[index], switch_channel,
				screen_quit_channels[index])
		}(i, s)
	}

	go func() {
		for {
			event := termbox.PollEvent()
			if event.Type == termbox.EventInterrupt {
				break
			} else {
				main_key_channel <- event
			}
		}
	}()

	for {
		do_quit := false
		select {
		case event := <-main_key_channel:
			if event.Type == termbox.EventKey {
				handleSpecialKeys(event.Key)

				screen_key_channels[active_idx] <- event
			}
			if event.Type == termbox.EventResize {
				layoutAndDrawScreen(screens[active_idx], style)
			}
		case new_screen_index := <-switch_channel:
			if new_screen_index < len(screens) {
				active_idx = new_screen_index
				layoutAndDrawScreen(screens[active_idx], style)
			} else {
				do_quit = true
			}
		}
		if do_quit {
			for _, c := range screen_quit_channels {
				c <- true
			}
			termbox.Interrupt()
			break
		}
	}
}

func openFile (filename string) (*FileInfo, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error opening file: %q\n", err.Error()))
	}

	fi, err := file.Stat()
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error stat'ing file: %q\n", err.Error()))
	}

	if fi.Size() < 8 {
		return nil, errors.New(fmt.Sprintf("File %s is too short to be edited\n", filename))
	}

	mm, err := mmap.Map(file, mmap.RDONLY, 0)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("Error mmap'ing file: %q\n", err.Error()))
	}

	return &FileInfo{filename: path.Base(filename), bytes: mm}, nil
}

func main() {
	var err error

	if len(os.Args) < 2 {
		fmt.Printf("Usage: %s <filename> [...]\n", PROGRAM_NAME)
		os.Exit(1)
	}
	var files []FileInfo
	for i := 1; i < len(os.Args); i++ {
		file_info, err := openFile(os.Args[i])
		if err != nil {
			fmt.Print(err)
			os.Exit(1)
		}

		files = append(files, *file_info)
	}

	err = termbox.Init()
	if err != nil {
		panic(err)
	}
	defer termbox.Close()

	style := defaultStyle()
	termbox.SetOutputMode(outputMode)

	mainLoop(files, style)
}
<|endoftext|>