<commit_before>package commands_test

import (
	"fmt"

	"github.com/cloudfoundry/bosh-bootloader/commands"

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

var _ = Describe("Commands Usage", func() {
	Describe("Up", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				upCmd := commands.Up{}
				usageText := upCmd.Usage()
				Expect(usageText).To(Equal(`Deploys BOSH director on an IAAS

  --iaas                     IAAS to deploy your BOSH director onto: "aws", "azure", "gcp", "vsphere"   env: $BBL_IAAS
  --name                     Name to assign to your BOSH director (optional)                            env: $BBL_ENV_NAME

  --aws-access-key-id                AWS Access Key ID                env: $BBL_AWS_ACCESS_KEY_ID
  --aws-secret-access-key            AWS Secret Access Key            env: $BBL_AWS_SECRET_ACCESS_KEY
  --aws-region                       AWS Region                       env: $BBL_AWS_REGION

  --gcp-service-account-key          GCP Service Access Key to use    env: $BBL_GCP_SERVICE_ACCOUNT_KEY
  --gcp-region                       GCP Region to use                env: $BBL_GCP_REGION

  --azure-subscription-id            Azure Subscription ID            env: $BBL_AZURE_SUBSCRIPTION_ID
  --azure-tenant-id                  Azure Tenant ID                  env: $BBL_AZURE_TENANT_ID
  --azure-client-id                  Azure Client ID                  env: $BBL_AZURE_CLIENT_ID
  --azure-client-secret              Azure Client Secret              env: $BBL_AZURE_CLIENT_SECRET
  --azure-region                     Azure Region                     env: $BBL_AZURE_REGION

  --vsphere-vcenter-user             vSphere vCenter User             env: $BBL_VSPHERE_VCENTER_USER
  --vsphere-vcenter-password         vSphere vCenter Password         env: $BBL_VSPHERE_VCENTER_PASSWORD
  --vsphere-vcenter-ip               vSphere vCenter IP               env: $BBL_VSPHERE_VCENTER_IP
  --vsphere-vcenter-dc               vSphere vCenter Datacenter       env: $BBL_VSPHERE_VCENTER_DC
  --vsphere-vcenter-cluster          vSphere vCenter Cluster          env: $BBL_VSPHERE_VCENTER_CLUSTER
  --vsphere-vcenter-rp               vSphere vCenter Resource Pool    env: $BBL_VSPHERE_VCENTER_RP
  --vsphere-network                  vSphere Network                  env: $BBL_VSPHERE_NETWORK
  --vsphere-vcenter-ds               vSphere vCenter Datastore        env: $BBL_VSPHERE_VCENTER_DS
  --vsphere-subnet-cidr              vSphere Subnet CIDR              env: $BBL_VSPHERE_SUBNET_CIDR
  --vsphere-vcenter-disks            vSphere vCenter Disks            env: $BBL_VSPHERE_VCENTER_DISKS
  --vsphere-vcenter-templates        vSphere vCenter Templates        env: $BBL_VSPHERE_VCENTER_TEMPLATES
  --vsphere-vcenter-vms              vSphere vCenter VMs              env: $BBL_VSPHERE_VCENTER_VMS

  --openstack-auth-url               OpenStack Auth URL               env: $BBL_OPENSTACK_AUTH_URL
  --openstack-az                     OpenStack Availability Zone      env: $BBL_OPENSTACK_AZ
  --openstack-network-id             OpenStack Network ID             env: $BBL_OPENSTACK_NETWORK_ID
  --openstack-network-name           OpenStack Network Name           env: $BBL_OPENSTACK_NETWORK_NAME
  --openstack-password               OpenStack Password               env: $BBL_OPENSTACK_PASSWORD
  --openstack-username               OpenStack Username               env: $BBL_OPENSTACK_USERNAME
  --openstack-project                OpenStack Project                env: $BBL_OPENSTACK_PROJECT
  --openstack-domain                 OpenStack Domain                 env: $BBL_OPENSTACK_DOMAIN
  --openstack-region                 OpenStack Region                 env: $BBL_OPENSTACK_REGION
  --openstack-cacert-file            OpenStack CA Cert File           env: $BBL_OPENSTACK_CACERT_FILE
  --openstack-insecure               OpenStack Insecure               env: $BBL_OPENSTACK_INSECURE
  --openstack-dns-name-server        OpenStack DNS Name Servers       env: $BBL_OPENSTACK_DNS_NAME_SERVERS

  Load Balancer options:
  --lb-type                  Load balancer(s) type: "concourse" or "cf"
  --lb-cert                  Path to SSL certificate (supported when type="cf")
  --lb-key                   Path to SSL certificate key (supported when type="cf")
  --lb-chain                 Path to SSL certificate chain (supported when iaas="aws")
  --lb-domain                Creates a DNS zone and records for the given domain (supported when type="cf")`))
			})
		})
	})

	Describe("Plan", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				planCmd := commands.Plan{}
				usageText := planCmd.Usage()
				Expect(usageText).To(Equal(fmt.Sprintf(`Populates a state directory with the latest config without applying it

  --iaas                     IAAS to deploy your BOSH director onto: "aws", "azure", "gcp", "vsphere"   env: $BBL_IAAS
  --name                     Name to assign to your BOSH director (optional)                            env: $BBL_ENV_NAME
%s%s`, commands.Credentials, commands.LBUsage)))
			})
		})
	})

	Describe("Destroy", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				command := commands.Destroy{}
				usageText := command.Usage()
				Expect(usageText).To(Equal(fmt.Sprintf(`Tears down BOSH director infrastructure

  [--no-confirm]       Do not ask for confirmation (optional)

  Credentials for your IaaS are required:%s`, commands.Credentials)))
			})
		})
	})

	Describe("CleanupLeftovers", func() {
		It("returns string describing usage", func() {
			command := commands.CleanupLeftovers{}
			usageText := command.Usage()
			Expect(usageText).To(Equal(fmt.Sprintf(`Cleans up orphaned IAAS resources

  --filter            Only delete resources with this string in their name

  Credentials for your IaaS are required:%s`, commands.Credentials)))
		})
	})

	Describe("Rotate", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				command := commands.Rotate{}
				usageText := command.Usage()
				Expect(usageText).To(Equal(fmt.Sprintf(`Rotates SSH key for the jumpbox user.

  Credentials for your IaaS are required:%s`, commands.Credentials)))
			})
		})
	})

	Describe("SSH", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				command := commands.SSH{}
				usageText := command.Usage()
				Expect(usageText).To(Equal(`Opens an SSH connection to the director or the jumpbox.

  --jumpbox                Open a connection to the jumpbox
  --director               Open a connection to the director
  --cmd                    Execute a command on the director (jumpbox not supported)
`))
			})
		})
	})

	Describe("PrintEnv", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				command := commands.PrintEnv{}
				usageText := command.Usage()
				Expect(usageText).To(Equal(`Prints required BOSH environment variables.

  --shell-type             Prints for the given shell (posix|powershell|yaml)
  --metadata-file          Read from Toolsmiths metadata file instead of bbl state
`))
			})
		})
	})
	Describe("Usage", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				command := commands.Usage{}
				usageText := command.Usage()
				Expect(usageText).To(Equal(`Prints helpful message for the given command`))
			})
		})
	})

	DescribeTable("command description", func(command commands.Command, expectedDescription string) {
		usageText := command.Usage()
		Expect(usageText).To(Equal(expectedDescription))
	},
		Entry("LBs", commands.LBs{}, "Prints attached load balancer(s)"),
		Entry("outputs", commands.Outputs{}, "Prints the outputs from terraform."),
		Entry("jumpbox-address", newStateQuery("jumpbox address"), "Prints BOSH jumpbox address"),
		Entry("director-address", newStateQuery("director address"), "Prints BOSH director address"),
		Entry("director-password", newStateQuery("director password"), "Prints BOSH director password"),
		Entry("director-username", newStateQuery("director username"), "Prints BOSH director username"),
		Entry("director-ca-cert", newStateQuery("director ca cert"), "Prints BOSH director CA certificate"),
		Entry("env-id", newStateQuery("environment id"), "Prints environment ID"),
		Entry("ssh-key", commands.SSHKey{}, "Prints SSH private key for the jumpbox."),
		Entry("director-ssh-key", commands.SSHKey{Director: true}, "Prints SSH private key for the director."),
		Entry("latest-error", commands.LatestError{}, "Prints the output from the latest call to terraform"),
		Entry("version", commands.Version{}, "Prints version"),
	)
})

func newStateQuery(propertyName string) commands.StateQuery {
	return commands.NewStateQuery(nil, nil, nil, propertyName)
}
<commit_msg>Update commands_usage_test.go<commit_after>package commands_test

import (
	"fmt"

	"github.com/cloudfoundry/bosh-bootloader/commands"

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

var _ = Describe("Commands Usage", func() {
	Describe("Up", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				upCmd := commands.Up{}
				usageText := upCmd.Usage()
				Expect(usageText).To(Equal(`Deploys BOSH director on an IAAS

  --iaas                     IAAS to deploy your BOSH director onto: "aws", "azure", "gcp", "vsphere"   env: $BBL_IAAS
  --name                     Name to assign to your BOSH director (optional)                            env: $BBL_ENV_NAME

  --aws-access-key-id                AWS Access Key ID                env: $BBL_AWS_ACCESS_KEY_ID
  --aws-secret-access-key            AWS Secret Access Key            env: $BBL_AWS_SECRET_ACCESS_KEY
  --aws-region                       AWS Region                       env: $BBL_AWS_REGION

  --gcp-service-account-key          GCP Service Access Key to use    env: $BBL_GCP_SERVICE_ACCOUNT_KEY
  --gcp-region                       GCP Region to use                env: $BBL_GCP_REGION

  --azure-subscription-id            Azure Subscription ID            env: $BBL_AZURE_SUBSCRIPTION_ID
  --azure-tenant-id                  Azure Tenant ID                  env: $BBL_AZURE_TENANT_ID
  --azure-client-id                  Azure Client ID                  env: $BBL_AZURE_CLIENT_ID
  --azure-client-secret              Azure Client Secret              env: $BBL_AZURE_CLIENT_SECRET
  --azure-region                     Azure Region                     env: $BBL_AZURE_REGION

  --vsphere-vcenter-user             vSphere vCenter User             env: $BBL_VSPHERE_VCENTER_USER
  --vsphere-vcenter-password         vSphere vCenter Password         env: $BBL_VSPHERE_VCENTER_PASSWORD
  --vsphere-vcenter-ip               vSphere vCenter IP               env: $BBL_VSPHERE_VCENTER_IP
  --vsphere-vcenter-dc               vSphere vCenter Datacenter       env: $BBL_VSPHERE_VCENTER_DC
  --vsphere-vcenter-cluster          vSphere vCenter Cluster          env: $BBL_VSPHERE_VCENTER_CLUSTER
  --vsphere-vcenter-rp               vSphere vCenter Resource Pool    env: $BBL_VSPHERE_VCENTER_RP
  --vsphere-network                  vSphere Network                  env: $BBL_VSPHERE_NETWORK
  --vsphere-vcenter-ds               vSphere vCenter Datastore        env: $BBL_VSPHERE_VCENTER_DS
  --vsphere-subnet-cidr              vSphere Subnet CIDR              env: $BBL_VSPHERE_SUBNET_CIDR
  --vsphere-vcenter-disks            vSphere vCenter Disks            env: $BBL_VSPHERE_VCENTER_DISKS
  --vsphere-vcenter-templates        vSphere vCenter Templates        env: $BBL_VSPHERE_VCENTER_TEMPLATES
  --vsphere-vcenter-vms              vSphere vCenter VMs              env: $BBL_VSPHERE_VCENTER_VMS

  --openstack-auth-url               OpenStack Auth URL               env: $BBL_OPENSTACK_AUTH_URL
  --openstack-az                     OpenStack Availability Zone      env: $BBL_OPENSTACK_AZ
  --openstack-network-id             OpenStack Network ID             env: $BBL_OPENSTACK_NETWORK_ID
  --openstack-network-name           OpenStack Network Name           env: $BBL_OPENSTACK_NETWORK_NAME
  --openstack-password               OpenStack Password               env: $BBL_OPENSTACK_PASSWORD
  --openstack-username               OpenStack Username               env: $BBL_OPENSTACK_USERNAME
  --openstack-project                OpenStack Project                env: $BBL_OPENSTACK_PROJECT
  --openstack-domain                 OpenStack Domain                 env: $BBL_OPENSTACK_DOMAIN
  --openstack-region                 OpenStack Region                 env: $BBL_OPENSTACK_REGION
  --openstack-cacert-file            OpenStack CA Cert File           env: $BBL_OPENSTACK_CACERT_FILE
  --openstack-insecure               OpenStack Insecure               env: $BBL_OPENSTACK_INSECURE
  --openstack-dns-name-server        OpenStack DNS Name Servers       env: $BBL_OPENSTACK_DNS_NAME_SERVERS

  Load Balancer options:
  --lb-type                  Load balancer(s) type: "concourse" or "cf"
  --lb-cert                  Path to SSL certificate (supported when type="cf")
  --lb-key                   Path to SSL certificate key (supported when type="cf")
  --lb-chain                 Path to SSL certificate chain (supported when iaas="aws")
  --lb-domain                Creates a DNS zone and records for the given domain (supported when type="cf")`))
			})
		})
	})

	Describe("Plan", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				planCmd := commands.Plan{}
				usageText := planCmd.Usage()
				Expect(usageText).To(Equal(fmt.Sprintf(`Populates a state directory with the latest config without applying it

  --iaas                     IAAS to deploy your BOSH director onto: "aws", "azure", "gcp", "vsphere"   env: $BBL_IAAS
  --name                     Name to assign to your BOSH director (optional)                            env: $BBL_ENV_NAME
%s%s`, commands.Credentials, commands.LBUsage)))
			})
		})
	})

	Describe("Destroy", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				command := commands.Destroy{}
				usageText := command.Usage()
				Expect(usageText).To(Equal(fmt.Sprintf(`Tears down BOSH director infrastructure

  [--no-confirm]       Do not ask for confirmation (optional)

  Credentials for your IaaS are required:%s`, commands.Credentials)))
			})
		})
	})

	Describe("CleanupLeftovers", func() {
		It("returns string describing usage", func() {
			command := commands.CleanupLeftovers{}
			usageText := command.Usage()
			Expect(usageText).To(Equal(fmt.Sprintf(`Cleans up orphaned IAAS resources

  --filter            Only delete resources with this string in their name
  --dry-run           List all resources without deleting any

  Credentials for your IaaS are required:%s`, commands.Credentials)))
		})
	})

	Describe("Rotate", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				command := commands.Rotate{}
				usageText := command.Usage()
				Expect(usageText).To(Equal(fmt.Sprintf(`Rotates SSH key for the jumpbox user.

  Credentials for your IaaS are required:%s`, commands.Credentials)))
			})
		})
	})

	Describe("SSH", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				command := commands.SSH{}
				usageText := command.Usage()
				Expect(usageText).To(Equal(`Opens an SSH connection to the director or the jumpbox.

  --jumpbox                Open a connection to the jumpbox
  --director               Open a connection to the director
  --cmd                    Execute a command on the director (jumpbox not supported)
`))
			})
		})
	})

	Describe("PrintEnv", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				command := commands.PrintEnv{}
				usageText := command.Usage()
				Expect(usageText).To(Equal(`Prints required BOSH environment variables.

  --shell-type             Prints for the given shell (posix|powershell|yaml)
  --metadata-file          Read from Toolsmiths metadata file instead of bbl state
`))
			})
		})
	})
	Describe("Usage", func() {
		Describe("Usage", func() {
			It("returns string describing usage", func() {
				command := commands.Usage{}
				usageText := command.Usage()
				Expect(usageText).To(Equal(`Prints helpful message for the given command`))
			})
		})
	})

	DescribeTable("command description", func(command commands.Command, expectedDescription string) {
		usageText := command.Usage()
		Expect(usageText).To(Equal(expectedDescription))
	},
		Entry("LBs", commands.LBs{}, "Prints attached load balancer(s)"),
		Entry("outputs", commands.Outputs{}, "Prints the outputs from terraform."),
		Entry("jumpbox-address", newStateQuery("jumpbox address"), "Prints BOSH jumpbox address"),
		Entry("director-address", newStateQuery("director address"), "Prints BOSH director address"),
		Entry("director-password", newStateQuery("director password"), "Prints BOSH director password"),
		Entry("director-username", newStateQuery("director username"), "Prints BOSH director username"),
		Entry("director-ca-cert", newStateQuery("director ca cert"), "Prints BOSH director CA certificate"),
		Entry("env-id", newStateQuery("environment id"), "Prints environment ID"),
		Entry("ssh-key", commands.SSHKey{}, "Prints SSH private key for the jumpbox."),
		Entry("director-ssh-key", commands.SSHKey{Director: true}, "Prints SSH private key for the director."),
		Entry("latest-error", commands.LatestError{}, "Prints the output from the latest call to terraform"),
		Entry("version", commands.Version{}, "Prints version"),
	)
})

func newStateQuery(propertyName string) commands.StateQuery {
	return commands.NewStateQuery(nil, nil, nil, propertyName)
}
<|endoftext|>


<commit_before>package provider

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/jcelliott/lumber"

	"github.com/nanobox-io/nanobox/models"
	"github.com/nanobox-io/nanobox/util/config"
	"github.com/nanobox-io/nanobox/util/display"
)

// Native ...
type Native struct{}

// init ...
func init() {
	Register("native", Native{})
}

// Valid ensures docker-machine is installed and available
func (native Native) Valid() (bool, []string) {
	cmd := exec.Command("docker", "ps")

	//
	if _, err := cmd.CombinedOutput(); err != nil {
		return false, []string{"docker"}
	}

	return true, nil
}

func (native Native) Status() string {
	return "Running"
}

func (native Native) BridgeRequired() bool {
	return runtime.GOOS != "linux"
}

// Create does nothing for native
func (native Native) Create() error {
	// TODO: maybe some setup stuff???
	return nil
}

// Reboot does nothing for native
func (native Native) Reboot() error {
	// TODO: nothing??
	return nil
}

// Stop does nothing on native
func (native Native) Stop() error {
	// TODO: stop what??
	return nil
}

// implode loops through the docker containers we created
// and removes each one
func (native Native) Implode() error {
	// remove any crufty containers
	cmd := exec.Command("docker", "ps", "-a")
	bytes, err := cmd.CombinedOutput()
	if err != nil {
		return err
	}

	s := string(bytes)
	parts := strings.Split(s, "\n")
	containers := []string{}

	for _, part := range parts {
		if strings.Contains(part, "nanobox_") {
			containers = append(containers, strings.Fields(part)[0])
		}
	}

	if len(containers) == 0 {
		return nil
	}
	cmdParts := append([]string{"rm", "-f"}, containers...)
	cmd = exec.Command("docker", cmdParts...)
	cmd.Stdout = display.NewStreamer("  ")
	cmd.Stderr = display.NewStreamer("  ")

	return cmd.Run()
}

// Destroy does nothing on native
func (native Native) Destroy() error {
	// TODO: remove nanobox images

	if native.hasNetwork() {
		display.StartTask("Removing custom docker network...")

		cmd := exec.Command("docker", "network", "rm", "nanobox")

		cmd.Stdout = display.NewStreamer("  ")
		cmd.Stderr = display.NewStreamer("  ")

		if err := cmd.Run(); err != nil {
			display.ErrorTask()
			return err
		}
		display.StopTask()
	}

	return nil
}

// Start does nothing on native
func (native Native) Start() error {

	// TODO: some networking maybe???
	if !native.hasNetwork() {
		display.StartTask("Setting up custom docker network...")

		config, _ := models.LoadConfig()
		ip, ipNet, err := net.ParseCIDR(config.NativeNetworkSpace)
		if err != nil {
			return err
		}

		cmd := exec.Command("docker", "network", "create", "--driver=bridge", fmt.Sprintf("--subnet=%s", ipNet.String()), "--opt=\"com.docker.network.driver.mtu=1450\"", "--opt=\"com.docker.network.bridge.name=redd0\"", fmt.Sprintf("--gateway=%s", ip.String()), "nanobox")

		cmd.Stdout = display.NewStreamer("  ")
		cmd.Stderr = display.NewStreamer("  ")

		if err := cmd.Run(); err != nil {
			display.ErrorTask()
			display.NetworkCreateError("native-network-space", config.NativeNetworkSpace)
			return err
		}
		display.StopTask()
	}

	return nil
}

func (native Native) IsReady() bool {
	return native.hasNetwork()
}

// HostShareDir ...
func (native Native) HostShareDir() string {
	dir := filepath.ToSlash(filepath.Join(config.GlobalDir(), "share"))
	os.MkdirAll(dir, 0755)

	return dir + "/"
}

// HostMntDir ...
func (native Native) HostMntDir() string {
	dir := filepath.ToSlash(filepath.Join(config.GlobalDir(), "mnt"))
	os.MkdirAll(dir, 0755)

	return dir + "/"
}

// HostIP returns the loopback ip
func (native Native) HostIP() (string, error) {
	return "127.0.0.1", nil
}

func (native Native) ReservedIPs() (rtn []string) {
	return []string{}
}

// DockerEnv docker env should already be configured if docker is installed
func (native Native) DockerEnv() error {
	// ensure setup??
	return nil
}

// AddIP adds an IP into the host for host access
func (native Native) AddIP(ip string) error {
	// TODO: ???
	return nil
}

// RemoveIP removes an IP from the docker-machine vm
func (native Native) RemoveIP(ip string) error {
	// TODO: ???
	return nil
}

func (native Native) SetDefaultIP(ip string) error {
	// nothing is necessary here
	return nil
}

// AddNat adds a nat to make an container accessible to the host network stack
func (native Native) AddNat(ip, containerIP string) error {
	// TODO: ???
	return nil
}

// RemoveNat removes nat from making a container inaccessible to the host network stack
func (native Native) RemoveNat(ip, containerIP string) error {
	// TODO: ???
	return nil
}

func (native Native) RequiresMount() bool {
	return false
}

// HasMount will return true if the mount already exists
func (native Native) HasMount(path string) bool {
	//
	fi, err := os.Lstat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		}
		lumber.Debug("Error checking mount: %s", err)
	}

	//
	if (fi.Mode() & os.ModeSymlink) > 0 {
		return true
	}

	return false
}

// AddMount adds a mount into the docker-machine vm
func (native Native) AddMount(local, host string) error {

	// TODO: ???
	if !native.HasMount(host) {
		if err := os.MkdirAll(filepath.Dir(host), 0755); err != nil {
			return err
		}

		return os.Symlink(local, host)
	}

	return nil
}

// RemoveMount ...
func (native Native) RemoveMount(_, host string) error {

	// TODO: ???
	if native.HasMount(host) {
		return os.Remove(host)
	}

	return nil
}

// Run will run a command on the local machine (pass-through)
func (native Native) Run(command []string) ([]byte, error) {
	// when we actually run the command, we need to pop off the first item
	cmd := exec.Command(command[0], command[1:]...)

	// run the command and return the output
	return cmd.CombinedOutput()
}

//
func (native Native) RemoveEnvDir(id string) error {
	if id == "" {
		return nil
	}

	return os.RemoveAll(native.HostMntDir() + id)
}

// hasNetwork ...
func (native Native) hasNetwork() bool {

	// docker-machine ssh nanobox docker network inspect nanobox
	cmd := exec.Command("docker", "network", "inspect", "nanobox")
	b, err := cmd.CombinedOutput()

	//
	if err != nil {
		lumber.Debug("hasNetwork output: %s", b)
		return false
	}

	return true
}
<commit_msg>allow us to check additional networks on native when the default is used<commit_after>package provider

import (
	"fmt"
	"net"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"

	"github.com/jcelliott/lumber"

	"github.com/nanobox-io/nanobox/models"
	"github.com/nanobox-io/nanobox/util/config"
	"github.com/nanobox-io/nanobox/util/display"
)

// Native ...
type Native struct{}

// init ...
func init() {
	Register("native", Native{})
}

// Valid ensures docker-machine is installed and available
func (native Native) Valid() (bool, []string) {
	cmd := exec.Command("docker", "ps")

	//
	if _, err := cmd.CombinedOutput(); err != nil {
		return false, []string{"docker"}
	}

	return true, nil
}

func (native Native) Status() string {
	return "Running"
}

func (native Native) BridgeRequired() bool {
	return runtime.GOOS != "linux"
}

// Create does nothing for native
func (native Native) Create() error {
	// TODO: maybe some setup stuff???
	return nil
}

// Reboot does nothing for native
func (native Native) Reboot() error {
	// TODO: nothing??
	return nil
}

// Stop does nothing on native
func (native Native) Stop() error {
	// TODO: stop what??
	return nil
}

// implode loops through the docker containers we created
// and removes each one
func (native Native) Implode() error {
	// remove any crufty containers
	cmd := exec.Command("docker", "ps", "-a")
	bytes, err := cmd.CombinedOutput()
	if err != nil {
		return err
	}

	s := string(bytes)
	parts := strings.Split(s, "\n")
	containers := []string{}

	for _, part := range parts {
		if strings.Contains(part, "nanobox_") {
			containers = append(containers, strings.Fields(part)[0])
		}
	}

	if len(containers) == 0 {
		return nil
	}
	cmdParts := append([]string{"rm", "-f"}, containers...)
	cmd = exec.Command("docker", cmdParts...)
	cmd.Stdout = display.NewStreamer("  ")
	cmd.Stderr = display.NewStreamer("  ")

	return cmd.Run()
}

// Destroy does nothing on native
func (native Native) Destroy() error {
	// TODO: remove nanobox images

	if native.hasNetwork() {
		display.StartTask("Removing custom docker network...")

		cmd := exec.Command("docker", "network", "rm", "nanobox")

		cmd.Stdout = display.NewStreamer("  ")
		cmd.Stderr = display.NewStreamer("  ")

		if err := cmd.Run(); err != nil {
			display.ErrorTask()
			return err
		}
		display.StopTask()
	}

	return nil
}

// Start does nothing on native
func (native Native) Start() error {

	// TODO: some networking maybe???
	if !native.hasNetwork() {
		display.StartTask("Setting up custom docker network...")

		config, err := models.LoadConfig()
		if err != nil {
			return err
		}

		// if we are using the default network configuration
		// then we are free to try getting one that works without confirming with the user any changes
		if config.NativeNetworkSpace == "172.20.0.1/16" {
			// create the values we will need outside the loop
			var oct int
			var newNetSpace string

			for i := 0; i < 10; i++ {
				// get the value of the 2nd octet and use I to increment it
				// to allow different networks to be used
				fmt.Sscanf(config.NativeNetworkSpace, "172.%d.0.1/16", &oct)
				newNetSpace = fmt.Sprintf("172.%d.0.1/16", oct + i)

				ip, ipNet, err := net.ParseCIDR(newNetSpace)
				if err != nil {
					return err
				}

				cmd := exec.Command("docker", "network", "create", "--driver=bridge", fmt.Sprintf("--subnet=%s", ipNet.String()), "--opt=\"com.docker.network.driver.mtu=1450\"", "--opt=\"com.docker.network.bridge.name=redd0\"", fmt.Sprintf("--gateway=%s", ip.String()), "nanobox")

				cmd.Stdout = display.NewStreamer("  ")
				cmd.Stderr = display.NewStreamer("  ")

				err = cmd.Run()

				if err == nil {
					break
				}
			}

			// if we did all the loops and still have an error. we need to report it
			if err != nil {
				display.ErrorTask()
				display.NetworkCreateError("native-network-space", config.NativeNetworkSpace)
				return err
			}

			// with no errors we will return here
			if newNetSpace != config.NativeNetworkSpace {
				config.NativeNetworkSpace = newNetSpace
				config.Save()
			}

			display.StopTask()
			return nil

		}

		ip, ipNet, err := net.ParseCIDR(config.NativeNetworkSpace)
		if err != nil {
			return err
		}

		cmd := exec.Command("docker", "network", "create", "--driver=bridge", fmt.Sprintf("--subnet=%s", ipNet.String()), "--opt=\"com.docker.network.driver.mtu=1450\"", "--opt=\"com.docker.network.bridge.name=redd0\"", fmt.Sprintf("--gateway=%s", ip.String()), "nanobox")

		cmd.Stdout = display.NewStreamer("  ")
		cmd.Stderr = display.NewStreamer("  ")

		if err := cmd.Run(); err != nil {
			display.ErrorTask()
			display.NetworkCreateError("native-network-space", config.NativeNetworkSpace)
			return err
		}
		display.StopTask()
	}

	return nil
}

func (native Native) IsReady() bool {
	return native.hasNetwork()
}

// HostShareDir ...
func (native Native) HostShareDir() string {
	dir := filepath.ToSlash(filepath.Join(config.GlobalDir(), "share"))
	os.MkdirAll(dir, 0755)

	return dir + "/"
}

// HostMntDir ...
func (native Native) HostMntDir() string {
	dir := filepath.ToSlash(filepath.Join(config.GlobalDir(), "mnt"))
	os.MkdirAll(dir, 0755)

	return dir + "/"
}

// HostIP returns the loopback ip
func (native Native) HostIP() (string, error) {
	return "127.0.0.1", nil
}

func (native Native) ReservedIPs() (rtn []string) {
	return []string{}
}

// DockerEnv docker env should already be configured if docker is installed
func (native Native) DockerEnv() error {
	// ensure setup??
	return nil
}

// AddIP adds an IP into the host for host access
func (native Native) AddIP(ip string) error {
	// TODO: ???
	return nil
}

// RemoveIP removes an IP from the docker-machine vm
func (native Native) RemoveIP(ip string) error {
	// TODO: ???
	return nil
}

func (native Native) SetDefaultIP(ip string) error {
	// nothing is necessary here
	return nil
}

// AddNat adds a nat to make an container accessible to the host network stack
func (native Native) AddNat(ip, containerIP string) error {
	// TODO: ???
	return nil
}

// RemoveNat removes nat from making a container inaccessible to the host network stack
func (native Native) RemoveNat(ip, containerIP string) error {
	// TODO: ???
	return nil
}

func (native Native) RequiresMount() bool {
	return false
}

// HasMount will return true if the mount already exists
func (native Native) HasMount(path string) bool {
	//
	fi, err := os.Lstat(path)
	if err != nil {
		if os.IsNotExist(err) {
			return false
		}
		lumber.Debug("Error checking mount: %s", err)
	}

	//
	if (fi.Mode() & os.ModeSymlink) > 0 {
		return true
	}

	return false
}

// AddMount adds a mount into the docker-machine vm
func (native Native) AddMount(local, host string) error {

	// TODO: ???
	if !native.HasMount(host) {
		if err := os.MkdirAll(filepath.Dir(host), 0755); err != nil {
			return err
		}

		return os.Symlink(local, host)
	}

	return nil
}

// RemoveMount ...
func (native Native) RemoveMount(_, host string) error {

	// TODO: ???
	if native.HasMount(host) {
		return os.Remove(host)
	}

	return nil
}

// Run will run a command on the local machine (pass-through)
func (native Native) Run(command []string) ([]byte, error) {
	// when we actually run the command, we need to pop off the first item
	cmd := exec.Command(command[0], command[1:]...)

	// run the command and return the output
	return cmd.CombinedOutput()
}

//
func (native Native) RemoveEnvDir(id string) error {
	if id == "" {
		return nil
	}

	return os.RemoveAll(native.HostMntDir() + id)
}

// hasNetwork ...
func (native Native) hasNetwork() bool {

	// docker-machine ssh nanobox docker network inspect nanobox
	cmd := exec.Command("docker", "network", "inspect", "nanobox")
	b, err := cmd.CombinedOutput()

	//
	if err != nil {
		lumber.Debug("hasNetwork output: %s", b)
		return false
	}

	return true
}
<|endoftext|>


<commit_before>package main

import (
	"cc/cpp"
	"flag"
	"fmt"
	"io"
	"os"
)

func printVersion() {
	fmt.Println("cc version 0.01")
}

func printUsage() {
	printVersion()
	fmt.Println()
	fmt.Println("This software is a portable C compiler.")
	fmt.Println("It was created with the goals of being the small and hackable.")
	fmt.Println("It is hopefully one of the easiest C compilers to port and understand.")
	fmt.Println()
	fmt.Println("Software by Andrew Chambers 2014 - andrewchamberss@gmail.com")
	fmt.Println()
	flag.PrintDefaults()
}

func preprocessFile(sourceFile string, out io.Writer) {
	_, err := os.Open(sourceFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to open source file %s for preprocessing: %s\n", sourceFile, err)
		os.Exit(1)
	}
	_ = cpp.New(nil)
}

func tokenizeFile(sourceFile string, out io.Writer) {
	f, err := os.Open(sourceFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to open source file %s for preprocessing: %s\n", sourceFile, err)
		os.Exit(1)
	}
	tokChan, errChan := cpp.Lex(sourceFile, f)
	for {
		select {
		case tok := <-tokChan:
			if tok == nil {
				return
			}
			fmt.Println(*tok)
		case err = <-errChan:
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}

}

func main() {
	flag.Usage = printUsage
	preprocessOnly := flag.Bool("E", false, "Preprocess only")
	tokenizeOnly := flag.Bool("T", false, "Tokenize only (For debugging).")
	version := flag.Bool("version", false, "Print version info and exit.")
	outputPath := flag.String("o", "-", "File to write output to, - for stdout.")
	flag.Parse()

	if *version {
		printVersion()
		return
	}

	if flag.NArg() == 0 {
		printUsage()
		os.Exit(1)
	}

	if flag.NArg() != 1 {
		fmt.Fprintf(os.Stderr, "Bad number of args, please specify a single source file.\n")
		os.Exit(1)
	}

	input := flag.Args()[0]
	var output io.Writer
	var err error

	if *outputPath == "-" {
		output = os.Stdout
	} else {
		output, err = os.Create(*outputPath)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to open output file %s\n", err)
			os.Exit(1)
		}
	}

	if *preprocessOnly {
		preprocessFile(input, output)
	} else if *tokenizeOnly {
		tokenizeFile(input, output)
	} else {
		CompileFile(input, nil, output)
	}
}
<commit_msg>send tokens to correct place<commit_after>package main

import (
	"cc/cpp"
	"flag"
	"fmt"
	"io"
	"os"
)

func printVersion() {
	fmt.Println("cc version 0.01")
}

func printUsage() {
	printVersion()
	fmt.Println()
	fmt.Println("This software is a portable C compiler.")
	fmt.Println("It was created with the goals of being the small and hackable.")
	fmt.Println("It is hopefully one of the easiest C compilers to port and understand.")
	fmt.Println()
	fmt.Println("Software by Andrew Chambers 2014 - andrewchamberss@gmail.com")
	fmt.Println()
	flag.PrintDefaults()
}

func preprocessFile(sourceFile string, out io.Writer) {
	_, err := os.Open(sourceFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to open source file %s for preprocessing: %s\n", sourceFile, err)
		os.Exit(1)
	}
	_ = cpp.New(nil)
}

func tokenizeFile(sourceFile string, out io.WriteCloser) {
	f, err := os.Open(sourceFile)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to open source file %s for preprocessing: %s\n", sourceFile, err)
		os.Exit(1)
	}
	tokChan, errChan := cpp.Lex(sourceFile, f)
	for {
		select {
		case tok := <-tokChan:
			if tok == nil {
				out.Close()
				return
			}
			fmt.Fprintln(out, *tok)

		case err = <-errChan:
			fmt.Fprintln(os.Stderr, err)
			os.Exit(1)
		}
	}

}

func main() {
	flag.Usage = printUsage
	preprocessOnly := flag.Bool("E", false, "Preprocess only")
	tokenizeOnly := flag.Bool("T", false, "Tokenize only (For debugging).")
	version := flag.Bool("version", false, "Print version info and exit.")
	outputPath := flag.String("o", "-", "File to write output to, - for stdout.")
	flag.Parse()

	if *version {
		printVersion()
		return
	}

	if flag.NArg() == 0 {
		printUsage()
		os.Exit(1)
	}

	if flag.NArg() != 1 {
		fmt.Fprintf(os.Stderr, "Bad number of args, please specify a single source file.\n")
		os.Exit(1)
	}

	input := flag.Args()[0]
	var output io.WriteCloser
	var err error

	if *outputPath == "-" {
		output = os.Stdout
	} else {
		output, err = os.Create(*outputPath)
		if err != nil {
			fmt.Fprintf(os.Stderr, "Failed to open output file %s\n", err)
			os.Exit(1)
		}
	}

	if *preprocessOnly {
		preprocessFile(input, output)
	} else if *tokenizeOnly {
		tokenizeFile(input, output)
	} else {
		CompileFile(input, nil, output)
	}
}
<|endoftext|>


<commit_before>package bundle

import (
	"errors"
	"github.com/eknkc/amber"
	helpers "github.com/spf13/hugo/template"
	"html/template"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
)

func Gt(a interface{}, b interface{}) bool {
	var left, right int64
	av := reflect.ValueOf(a)

	switch av.Kind() {
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
		left = int64(av.Len())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		left = av.Int()
	case reflect.String:
		left, _ = strconv.ParseInt(av.String(), 10, 64)
	}

	bv := reflect.ValueOf(b)

	switch bv.Kind() {
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
		right = int64(bv.Len())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		right = bv.Int()
	case reflect.String:
		right, _ = strconv.ParseInt(bv.String(), 10, 64)
	}

	return left > right
}

// First is exposed to templates, to iterate over the first N items in a
// rangeable list.
func First(limit int, seq interface{}) (interface{}, error) {
	if limit < 1 {
		return nil, errors.New("can't return negative/empty count of items from sequence")
	}

	seqv := reflect.ValueOf(seq)
	// this is better than my first pass; ripped from text/template/exec.go indirect():
	for ; seqv.Kind() == reflect.Ptr || seqv.Kind() == reflect.Interface; seqv = seqv.Elem() {
		if seqv.IsNil() {
			return nil, errors.New("can't iterate over a nil value")
		}
		if seqv.Kind() == reflect.Interface && seqv.NumMethod() > 0 {
			break
		}
	}

	switch seqv.Kind() {
	case reflect.Array, reflect.Slice, reflect.String:
		// okay
	default:
		return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
	}
	if limit > seqv.Len() {
		limit = seqv.Len()
	}
	return seqv.Slice(0, limit).Interface(), nil
}

func IsSet(a interface{}, key interface{}) bool {
	av := reflect.ValueOf(a)
	kv := reflect.ValueOf(key)

	switch av.Kind() {
	case reflect.Array, reflect.Chan, reflect.Slice:
		if int64(av.Len()) > kv.Int() {
			return true
		}
	case reflect.Map:
		if kv.Type() == av.Type().Key() {
			return av.MapIndex(kv).IsValid()
		}
	}

	return false
}

func ReturnWhenSet(a interface{}, index int) interface{} {
	av := reflect.ValueOf(a)

	switch av.Kind() {
	case reflect.Array, reflect.Slice:
		if av.Len() > index {

			avv := av.Index(index)
			switch avv.Kind() {
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				return avv.Int()
			case reflect.String:
				return avv.String()
			}
		}
	}

	return ""
}

func SafeHtml(text string) template.HTML {
	return template.HTML(text)
}

type Template interface {
	ExecuteTemplate(wr io.Writer, name string, data interface{}) error
	Lookup(name string) *template.Template
	Templates() []*template.Template
	New(name string) *template.Template
	LoadTemplates(absPath string)
	AddTemplate(name, tpl string) error
}

type templateErr struct {
	name string
	err  error
}

type GoHtmlTemplate struct {
	template.Template
	errors []*templateErr
}

func NewTemplate() Template {
	var templates = &GoHtmlTemplate{
		Template: *template.New(""),
		errors:   make([]*templateErr, 0),
	}

	funcMap := template.FuncMap{
		"urlize":    helpers.Urlize,
		"gt":        Gt,
		"isset":     IsSet,
		"echoParam": ReturnWhenSet,
		"safeHtml":  SafeHtml,
		"First":     First,
	}

	templates.Funcs(funcMap)
	return templates
}

func (t *GoHtmlTemplate) AddTemplate(name, tpl string) error {
	_, err := t.New(name).Parse(tpl)
	if err != nil {
		t.errors = append(t.errors, &templateErr{name: name, err: err})
	}
	return err
}

func (t *GoHtmlTemplate) AddTemplateFile(name, path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	s := string(b)
	_, err = t.New(name).Parse(s)
	if err != nil {
		t.errors = append(t.errors, &templateErr{name: name, err: err})
	}
	return err
}

func (t *GoHtmlTemplate) generateTemplateNameFrom(base, path string) string {
	return filepath.ToSlash(path[len(base)+1:])
}

func ignoreDotFile(path string) bool {
	return filepath.Base(path)[0] == '.'
}

func (t *GoHtmlTemplate) LoadTemplates(absPath string) {
	walker := func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			return nil
		}

		if !fi.IsDir() {
			if ignoreDotFile(path) {
				return nil
			}

			tplName := t.generateTemplateNameFrom(absPath, path)

			if strings.HasSuffix(path, ".amber") {
				compiler := amber.New()
				// Parse the input file
				if err := compiler.ParseFile(path); err != nil {
					return nil
				}

				// note t.New(tplName)
				if _, err := compiler.CompileWithTemplate(t.New(tplName)); err != nil {
					return err
				}

			} else {
				t.AddTemplateFile(tplName, path)
			}
		}
		return nil
	}

	filepath.Walk(absPath, walker)
}
<commit_msg>lowercase template function first to be consistent with all other template functions<commit_after>package bundle

import (
	"errors"
	"github.com/eknkc/amber"
	helpers "github.com/spf13/hugo/template"
	"html/template"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"reflect"
	"strconv"
	"strings"
)

func Gt(a interface{}, b interface{}) bool {
	var left, right int64
	av := reflect.ValueOf(a)

	switch av.Kind() {
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
		left = int64(av.Len())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		left = av.Int()
	case reflect.String:
		left, _ = strconv.ParseInt(av.String(), 10, 64)
	}

	bv := reflect.ValueOf(b)

	switch bv.Kind() {
	case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
		right = int64(bv.Len())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		right = bv.Int()
	case reflect.String:
		right, _ = strconv.ParseInt(bv.String(), 10, 64)
	}

	return left > right
}

// First is exposed to templates, to iterate over the first N items in a
// rangeable list.
func First(limit int, seq interface{}) (interface{}, error) {
	if limit < 1 {
		return nil, errors.New("can't return negative/empty count of items from sequence")
	}

	seqv := reflect.ValueOf(seq)
	// this is better than my first pass; ripped from text/template/exec.go indirect():
	for ; seqv.Kind() == reflect.Ptr || seqv.Kind() == reflect.Interface; seqv = seqv.Elem() {
		if seqv.IsNil() {
			return nil, errors.New("can't iterate over a nil value")
		}
		if seqv.Kind() == reflect.Interface && seqv.NumMethod() > 0 {
			break
		}
	}

	switch seqv.Kind() {
	case reflect.Array, reflect.Slice, reflect.String:
		// okay
	default:
		return nil, errors.New("can't iterate over " + reflect.ValueOf(seq).Type().String())
	}
	if limit > seqv.Len() {
		limit = seqv.Len()
	}
	return seqv.Slice(0, limit).Interface(), nil
}

func IsSet(a interface{}, key interface{}) bool {
	av := reflect.ValueOf(a)
	kv := reflect.ValueOf(key)

	switch av.Kind() {
	case reflect.Array, reflect.Chan, reflect.Slice:
		if int64(av.Len()) > kv.Int() {
			return true
		}
	case reflect.Map:
		if kv.Type() == av.Type().Key() {
			return av.MapIndex(kv).IsValid()
		}
	}

	return false
}

func ReturnWhenSet(a interface{}, index int) interface{} {
	av := reflect.ValueOf(a)

	switch av.Kind() {
	case reflect.Array, reflect.Slice:
		if av.Len() > index {

			avv := av.Index(index)
			switch avv.Kind() {
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				return avv.Int()
			case reflect.String:
				return avv.String()
			}
		}
	}

	return ""
}

func SafeHtml(text string) template.HTML {
	return template.HTML(text)
}

type Template interface {
	ExecuteTemplate(wr io.Writer, name string, data interface{}) error
	Lookup(name string) *template.Template
	Templates() []*template.Template
	New(name string) *template.Template
	LoadTemplates(absPath string)
	AddTemplate(name, tpl string) error
}

type templateErr struct {
	name string
	err  error
}

type GoHtmlTemplate struct {
	template.Template
	errors []*templateErr
}

func NewTemplate() Template {
	var templates = &GoHtmlTemplate{
		Template: *template.New(""),
		errors:   make([]*templateErr, 0),
	}

	funcMap := template.FuncMap{
		"urlize":    helpers.Urlize,
		"gt":        Gt,
		"isset":     IsSet,
		"echoParam": ReturnWhenSet,
		"safeHtml":  SafeHtml,
		"first":     First,
	}

	templates.Funcs(funcMap)
	return templates
}

func (t *GoHtmlTemplate) AddTemplate(name, tpl string) error {
	_, err := t.New(name).Parse(tpl)
	if err != nil {
		t.errors = append(t.errors, &templateErr{name: name, err: err})
	}
	return err
}

func (t *GoHtmlTemplate) AddTemplateFile(name, path string) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return err
	}
	s := string(b)
	_, err = t.New(name).Parse(s)
	if err != nil {
		t.errors = append(t.errors, &templateErr{name: name, err: err})
	}
	return err
}

func (t *GoHtmlTemplate) generateTemplateNameFrom(base, path string) string {
	return filepath.ToSlash(path[len(base)+1:])
}

func ignoreDotFile(path string) bool {
	return filepath.Base(path)[0] == '.'
}

func (t *GoHtmlTemplate) LoadTemplates(absPath string) {
	walker := func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			return nil
		}

		if !fi.IsDir() {
			if ignoreDotFile(path) {
				return nil
			}

			tplName := t.generateTemplateNameFrom(absPath, path)

			if strings.HasSuffix(path, ".amber") {
				compiler := amber.New()
				// Parse the input file
				if err := compiler.ParseFile(path); err != nil {
					return nil
				}

				// note t.New(tplName)
				if _, err := compiler.CompileWithTemplate(t.New(tplName)); err != nil {
					return err
				}

			} else {
				t.AddTemplateFile(tplName, path)
			}
		}
		return nil
	}

	filepath.Walk(absPath, walker)
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"fmt"
	"math"
	"os"
	"path"
	"strconv"
	"strings"

	tetra "github.com/phil-mansfield/gotetra"
	"github.com/phil-mansfield/gotetra/catalog"
)

func main() {
	// Parse input information

	if len(os.Args) < 4 {
		fmt.Printf("%s requires three arguments, a regex indicating the " +
			"target\ncatalogs, the output directory, the width of the" +
			"generated catalog\ngrid.", os.Args[0])
		os.Exit(1)
	}

	matches := os.Args[1:len(os.Args) - 2]

	outPath := os.Args[len(os.Args) - 2]
	gridWidth, err := strconv.Atoi(os.Args[len(os.Args) - 1])

	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else if gridWidth <= 0 {
		fmt.Println("Grid width must be positive.")
		os.Exit(1)
	}

	snapDir := path.Base(path.Dir(matches[0]))
	paramDir := path.Base(path.Dir(path.Dir(path.Dir(matches[0]))))

	l, n, str, err := parseDir(paramDir)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	// Create requisite directories.

	outParamDir := fmt.Sprintf("Box_L%04d_N%04d_G%04d_%s", l, n, gridWidth, str)
	outParamPath := path.Join(outPath, outParamDir)
	outSnapPath := path.Join(outParamPath, snapDir)
	if err = os.MkdirAll(path.Join(outParamPath, snapDir), 0777); err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	// Rebin catalogs.

	if err = createHeaders(outSnapPath, matches[0], gridWidth, n); err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	width := float64(l) / float64(gridWidth)

	for _, match := range matches {
		_, ps := catalog.ReadGadget(match, binary.LittleEndian)
		bins := rebinParticles(width, int64(gridWidth), ps)
		for i, ps := range bins {
			if len(ps) > 0 {
				name := path.Join(
					outSnapPath, fmt.Sprintf("gridcell_%04d.dat", i),
				)
				catalog.Append(name, ps)
			}
		}
	}
}

// pasreDir reads one of Benedikt's sim directory names and returns the relevent
// physical information.
func parseDir(dir string) (int, int, string, error) {
	parts := strings.Split(dir, "_")

	if len(parts) != 4 {
		return dirErr(dir)
	} else if len(parts[1]) != 5 {
		return dirErr(dir)
	} else if len(parts[2]) != 5 {
		return dirErr(dir)
	}

	l, err := strconv.Atoi(parts[1][1:5])
	if err != nil { return 0, 0, "", err }
	n, err := strconv.Atoi(parts[2][1:5])
	if err != nil { return 0, 0, "", err }

	return l, n, parts[3], nil
}

func dirErr(dir string) (int, int, string, error) {
	return 0, 0, "", fmt.Errorf("Invalid source directory '%s'.", dir)
}

func createHeaders(outPath string, exampleInput string, gridWidth int, countWidth int) error {
	h := catalog.ReadGadgetHeader(exampleInput, binary.LittleEndian)
	h.Width = h.TotalWidth / float64(gridWidth)
	h.CountWidth = int64(countWidth)
	h.GridWidth = int64(gridWidth)

	ps := make([]tetra.Particle, 0)

	maxIdx := gridWidth * gridWidth * gridWidth
	for i := 0; i < maxIdx; i++ {
		name := path.Join(outPath, fmt.Sprintf("gridcell_%04d.dat", i))
		h.Idx = int64(i)
		catalog.Write(name, h, ps)
	}

	return nil
}

func rebinParticles(width float64, gridWidth int64, ps []tetra.Particle) ([][]tetra.Particle) {
	totalCells := gridWidth * gridWidth * gridWidth
	bins := make([][]tetra.Particle, totalCells)

	for i := 0; i < len(bins); i++ {
		bins[i] = make([]tetra.Particle, 0)
	}

	for _, p := range ps {
		xIdx := int64(math.Floor(p.Xs[0] / width))
		yIdx := int64(math.Floor(p.Xs[1] / width))
		zIdx := int64(math.Floor(p.Xs[2] / width))
		idx :=  xIdx + yIdx * gridWidth + zIdx * gridWidth * gridWidth
		bins[idx] = append(bins[idx], p)
	}

	return bins
}
<commit_msg>Updated generate_catalogs script to use append buffers.<commit_after>package main

import (
	"encoding/binary"
	"flag"
	"fmt"
	"math"
	"os"
	"path"
	"strconv"
	"strings"

	tetra "github.com/phil-mansfield/gotetra"
	"github.com/phil-mansfield/gotetra/catalog"
)

var (
	defaultBufSize   = 1 << 12
	gadgetEndianness = binary.LittleEndian
)

func main() {
	// Parse input information
	flag.Parse()
	args := flag.Args()

	if len(args) < 4 {
		fmt.Printf("%s requires three arguments, a regex indicating the "+
			"target\ncatalogs, the output directory, the width of the "+
			"generated catalog\ngrid.", args[0])
		os.Exit(1)
	}

	matches := args[1 : len(args)-2]

	outPath := args[len(args)-2]
	gridWidth, err := strconv.Atoi(args[len(args)-1])

	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else if gridWidth <= 0 {
		fmt.Println("Grid width must be positive.")
		os.Exit(1)
	}

	snapDir := path.Base(path.Dir(matches[0]))
	paramDir := path.Base(path.Dir(path.Dir(path.Dir(matches[0]))))

	l, n, str, err := parseDir(paramDir)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	// Create files and rebin.

	outParamDir := fmt.Sprintf("Box_L%04d_N%04d_G%04d_%s", l, n, gridWidth, str)
	outParamPath := path.Join(outPath, outParamDir)
	outSnapPath := path.Join(outParamPath, snapDir)

	if err = os.MkdirAll(path.Join(outParamPath, snapDir), 0777); err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	catalogNames := createCatalogs(outSnapPath, matches[0], gridWidth, n)

	rebinParticles(matches, catalogNames, int64(gridWidth))
}

// pasreDir reads one of Benedikt's sim directory names and returns the relevent
// physical information.
func parseDir(dir string) (int, int, string, error) {
	parts := strings.Split(dir, "_")

	if len(parts) != 4 {
		return dirErr(dir)
	} else if len(parts[1]) != 5 {
		return dirErr(dir)
	} else if len(parts[2]) != 5 {
		return dirErr(dir)
	}

	l, err := strconv.Atoi(parts[1][1:5])
	if err != nil {
		return 0, 0, "", err
	}
	n, err := strconv.Atoi(parts[2][1:5])
	if err != nil {
		return 0, 0, "", err
	}

	return l, n, parts[3], nil
}

func dirErr(dir string) (int, int, string, error) {
	return 0, 0, "", fmt.Errorf("Invalid source directory '%s'.", dir)
}

// createCatalogs creates new instances of the needed gridcell files in the
// given directory.
func createCatalogs(outPath, exampleInput string, gridWidth, countWidth int) []string {
	h := catalog.ReadGadgetHeader(exampleInput, gadgetEndianness)
	h.Width = h.TotalWidth / float64(gridWidth)
	h.CountWidth = int64(countWidth)
	h.GridWidth = int64(gridWidth)

	ps := []tetra.Particle{}

	maxIdx := gridWidth * gridWidth * gridWidth
	catalogNames := []string{}
	for i := 0; i < maxIdx; i++ {
		name := path.Join(outPath, fmt.Sprintf("gridcell_%04d.dat", i))
		catalogNames = append(catalogNames, name)
		h.Idx = int64(i)
		catalog.Write(name, h, ps)
	}

	return catalogNames
}

// rebinParticles transfers particles from a slice of Gadget catalogs to a
// slice of tetra catalogs.
func rebinParticles(inFiles, outFiles []string, gridWidth int64) {
	hs := make([]tetra.Header, len(inFiles))
	for i := range hs {
		hs[i] = *catalog.ReadGadgetHeader(inFiles[i], gadgetEndianness)
	}

	width := hs[0].TotalWidth / float64(gridWidth)

	maxLen := int64(0)
	for _, h := range hs {
		if h.Count > maxLen {
			maxLen = h.Count
		}
	}

	floatBufMax := make([]float32, maxLen * 3)
	intBufMax := make([]int64, maxLen)
	psBufMax := make([]tetra.Particle, maxLen)

	bufs := createBuffers(outFiles, defaultBufSize)

	for i, inFile := range inFiles {
		fmt.Println(inFile)

		floatBuf := floatBufMax[0:hs[i].Count*3]
		intBuf := intBufMax[0:hs[i].Count]
		psBuf := psBufMax[0:hs[i].Count]

		catalog.ReadGadgetParticlesAt(
			inFile, gadgetEndianness, floatBuf, intBuf, psBuf,
		)

		rebinSlice(width, gridWidth, bufs, psBuf)
	}

	for _, buf := range bufs {
		buf.Flush()
	}
}

// createBuffers creates buffers for all the catalog files that will be
// witten to.
func createBuffers(paths []string, bufSize int) []*catalog.ParticleBuffer {
	bufs := make([]*catalog.ParticleBuffer, len(paths))

	for i, path := range paths {
		bufs[i] = catalog.NewParticleBuffer(path, bufSize)
	}

	return bufs
}

// rebinSlice rebins the given particles into the grid of files represented
// by bufs.
func rebinSlice(
	width float64,
	gridWidth int64,
	bufs []*catalog.ParticleBuffer,
	ps []tetra.Particle,
) {
	for _, p := range ps {
		xIdx := int64(math.Floor(p.Xs[0] / width))
		yIdx := int64(math.Floor(p.Xs[1] / width))
		zIdx := int64(math.Floor(p.Xs[2] / width))
		idx := xIdx + yIdx*gridWidth + zIdx*gridWidth*gridWidth
		bufs[idx].Append(p)
	}
}
<|endoftext|>


<commit_before>package web

import (
	"fmt"
	"net/http"
	"runtime"
	"time"

	"bytes"
	"github.com/livesense-inc/fanlin/lib/content"
	"github.com/livesense-inc/fanlin/lib/error"
	"io"
)

var ua = fmt.Sprintf("Mozilla/5.0 (fanlin; arch: %s; OS: %s; Go version: %s) Go language Client/1.1 (KHTML, like Gecko) Version/1.0 fanlin", runtime.GOARCH, runtime.GOOS, runtime.Version())

var client = http.Client{
	Transport: &http.Transport{MaxIdleConnsPerHost: 64},
	Timeout:   time.Duration(10) * time.Second,
}

var httpClient = Client{
	Http: new(RealWebClient),
}

type RealWebClient struct {
}

type WebClient interface {
	Get(string) (io.Reader, error)
}

type Client struct {
	Http WebClient
}

func (r *RealWebClient) Get(url string) (io.Reader, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, imgproxyerr.New(imgproxyerr.ERROR, err)
	}
	req.Header.Set("User-Agent", ua)

	resp, err := client.Do(req)
	defer resp.Body.Close()
	if err != nil {
		return nil, imgproxyerr.New(imgproxyerr.ERROR, err)
	}
	buffer := new(bytes.Buffer)
	if _, err := io.Copy(buffer, resp.Body); err != nil {
		return nil, err
	}

	return buffer, nil
}

func isErrorCode(status int) bool {
	switch status / 100 {
	case 4, 5:
		return true
	default:
		return false
	}
}

func GetImageBinary(c *content.Content) (io.Reader, error) {
	return httpClient.Http.Get(c.SourcePlace)
}

func setHttpClient(c Client) {
	httpClient = c
}

func init() {
	content.RegisterContentType("web", GetImageBinary)
}
<commit_msg>fix nil access bug due to defer close timing<commit_after>package web

import (
	"fmt"
	"net/http"
	"runtime"
	"time"

	"bytes"
	"io"

	"github.com/livesense-inc/fanlin/lib/content"
	"github.com/livesense-inc/fanlin/lib/error"
)

var ua = fmt.Sprintf("Mozilla/5.0 (fanlin; arch: %s; OS: %s; Go version: %s) Go language Client/1.1 (KHTML, like Gecko) Version/1.0 fanlin", runtime.GOARCH, runtime.GOOS, runtime.Version())

var client = http.Client{
	Transport: &http.Transport{MaxIdleConnsPerHost: 64},
	Timeout:   time.Duration(10) * time.Second,
}

var httpClient = Client{
	Http: new(RealWebClient),
}

type RealWebClient struct {
}

type WebClient interface {
	Get(string) (io.Reader, error)
}

type Client struct {
	Http WebClient
}

func (r *RealWebClient) Get(url string) (io.Reader, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return nil, imgproxyerr.New(imgproxyerr.ERROR, err)
	}
	req.Header.Set("User-Agent", ua)

	resp, err := client.Do(req)
	if err != nil {
		return nil, imgproxyerr.New(imgproxyerr.ERROR, err)
	}
	defer resp.Body.Close()

	buffer := new(bytes.Buffer)
	if _, err := io.Copy(buffer, resp.Body); err != nil {
		return nil, err
	}

	return buffer, nil
}

func isErrorCode(status int) bool {
	switch status / 100 {
	case 4, 5:
		return true
	default:
		return false
	}
}

func GetImageBinary(c *content.Content) (io.Reader, error) {
	return httpClient.Http.Get(c.SourcePlace)
}

func setHttpClient(c Client) {
	httpClient = c
}

func init() {
	content.RegisterContentType("web", GetImageBinary)
}
<|endoftext|>


<commit_before>package fetcher

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"net/url"
	"unicode/utf8"

	"github.com/PuerkitoBio/goquery"
	goose "github.com/syou6162/GoOse"
)

type Article struct {
	Url           string
	Title         string
	Description   string
	OgDescription string
	OgType        string
	OgImage       string
	Body          string
	StatusCode    int
	Favicon       string
	PublishDate   *time.Time
}

var articleFetcher = http.Client{
	Transport: &http.Transport{
		MaxIdleConns:        0,
		MaxIdleConnsPerHost: 100,
	},
	Timeout: time.Duration(5 * time.Second),
}

func updateMetaDescriptionIfArxiv(article *goose.Article, origUrl string, finalUrl string, html []byte) error {
	arxivUrl := "https://arxiv.org/abs/"
	if strings.Contains(origUrl, arxivUrl) || strings.Contains(finalUrl, arxivUrl) {
		// article.Docでもいけそうだが、gooseが中で書き換えていてダメ。Documentを作りなおす
		doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(html)))
		if err != nil {
			return err
		}
		article.MetaDescription = doc.Find(".abstract").Text()
	}
	return nil
}

func removeUtmParams(origUrl string) (string, error) {
	u, err := url.Parse(origUrl)
	if err != nil {
		return origUrl, err
	}

	q, err := url.ParseQuery(u.RawQuery)
	if err != nil {
		return origUrl, err
	}

	q.Del("utm_source")
	q.Del("utm_medium")
	q.Del("utm_campaign")
	q.Del("utm_term")
	q.Del("utm_content")

	u.RawQuery = q.Encode()

	return u.String(), nil
}

func GetArticle(origUrl string) (*Article, error) {
	g := goose.New()
	resp, err := articleFetcher.Get(origUrl)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode == http.StatusFound ||
		resp.StatusCode == http.StatusUnauthorized ||
		resp.StatusCode == http.StatusForbidden ||
		resp.StatusCode == http.StatusNotFound ||
		resp.StatusCode == http.StatusGone ||
		resp.StatusCode == http.StatusBadGateway ||
		resp.StatusCode == http.StatusServiceUnavailable {
		return nil, errors.New(fmt.Sprintf("%s: Cannot fetch %s", resp.Status, origUrl))
	}
	defer resp.Body.Close()

	html, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if !utf8.Valid(html) {
		return nil, errors.New(fmt.Sprintf("Invalid utf8 document: %s", origUrl))
	}

	article, err := g.ExtractFromRawHTML(resp.Request.URL.String(), string(html))
	if err != nil {
		return nil, err
	}

	finalUrl := article.CanonicalLink
	if finalUrl == "" {
		finalUrl = resp.Request.URL.String()
	}

	finalUrl, err = removeUtmParams(finalUrl)
	if err != nil {
		return nil, err
	}

	updateMetaDescriptionIfArxiv(article, origUrl, finalUrl, html)

	favicon := ""
	if u, err := url.Parse(article.MetaFavicon); err == nil {
		if u.IsAbs() {
			favicon = article.MetaFavicon
		}
	}

	return &Article{
		Url:           finalUrl,
		Title:         article.Title,
		Description:   article.MetaDescription,
		OgDescription: article.MetaOgDescription,
		OgType:        article.MetaOgType,
		OgImage:       article.MetaOgImage,
		Body:          article.CleanedText,
		StatusCode:    resp.StatusCode,
		Favicon:       favicon,
		PublishDate:   article.PublishDate,
	}, nil
}
<commit_msg>mediumのURLにgiパラメータが付与されているので、削除<commit_after>package fetcher

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
	"time"

	"net/url"
	"unicode/utf8"

	"github.com/PuerkitoBio/goquery"
	goose "github.com/syou6162/GoOse"
)

type Article struct {
	Url           string
	Title         string
	Description   string
	OgDescription string
	OgType        string
	OgImage       string
	Body          string
	StatusCode    int
	Favicon       string
	PublishDate   *time.Time
}

var articleFetcher = http.Client{
	Transport: &http.Transport{
		MaxIdleConns:        0,
		MaxIdleConnsPerHost: 100,
	},
	Timeout: time.Duration(5 * time.Second),
}

func updateMetaDescriptionIfArxiv(article *goose.Article, origUrl string, finalUrl string, html []byte) error {
	arxivUrl := "https://arxiv.org/abs/"
	if strings.Contains(origUrl, arxivUrl) || strings.Contains(finalUrl, arxivUrl) {
		// article.Docでもいけそうだが、gooseが中で書き換えていてダメ。Documentを作りなおす
		doc, err := goquery.NewDocumentFromReader(strings.NewReader(string(html)))
		if err != nil {
			return err
		}
		article.MetaDescription = doc.Find(".abstract").Text()
	}
	return nil
}

func removeUtmParams(origUrl string) (string, error) {
	u, err := url.Parse(origUrl)
	if err != nil {
		return origUrl, err
	}

	q, err := url.ParseQuery(u.RawQuery)
	if err != nil {
		return origUrl, err
	}

	q.Del("utm_source")
	q.Del("utm_medium")
	q.Del("utm_campaign")
	q.Del("utm_term")
	q.Del("utm_content")

	q.Del("gi")

	u.RawQuery = q.Encode()

	return u.String(), nil
}

func GetArticle(origUrl string) (*Article, error) {
	g := goose.New()
	resp, err := articleFetcher.Get(origUrl)
	if err != nil {
		return nil, err
	}
	if resp.StatusCode == http.StatusFound ||
		resp.StatusCode == http.StatusUnauthorized ||
		resp.StatusCode == http.StatusForbidden ||
		resp.StatusCode == http.StatusNotFound ||
		resp.StatusCode == http.StatusGone ||
		resp.StatusCode == http.StatusBadGateway ||
		resp.StatusCode == http.StatusServiceUnavailable {
		return nil, errors.New(fmt.Sprintf("%s: Cannot fetch %s", resp.Status, origUrl))
	}
	defer resp.Body.Close()

	html, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if !utf8.Valid(html) {
		return nil, errors.New(fmt.Sprintf("Invalid utf8 document: %s", origUrl))
	}

	article, err := g.ExtractFromRawHTML(resp.Request.URL.String(), string(html))
	if err != nil {
		return nil, err
	}

	finalUrl := article.CanonicalLink
	if finalUrl == "" {
		finalUrl = resp.Request.URL.String()
	}

	finalUrl, err = removeUtmParams(finalUrl)
	if err != nil {
		return nil, err
	}

	updateMetaDescriptionIfArxiv(article, origUrl, finalUrl, html)

	favicon := ""
	if u, err := url.Parse(article.MetaFavicon); err == nil {
		if u.IsAbs() {
			favicon = article.MetaFavicon
		}
	}

	return &Article{
		Url:           finalUrl,
		Title:         article.Title,
		Description:   article.MetaDescription,
		OgDescription: article.MetaOgDescription,
		OgType:        article.MetaOgType,
		OgImage:       article.MetaOgImage,
		Body:          article.CleanedText,
		StatusCode:    resp.StatusCode,
		Favicon:       favicon,
		PublishDate:   article.PublishDate,
	}, nil
}
<|endoftext|>


<commit_before>//
// templates.go
// template model interfaces
//
package srnd

import (
  "fmt"
  "github.com/hoisie/mustache"
  "io"
  "io/ioutil"
  "log"
  "path/filepath"
  "sort"
  "strings"
)

type templateEngine struct {
  // posthash -> url
  links map[string]string
  // shorthash -> posthash
  links_short map[string]string
  // every newsgroup
  groups map[string]GroupModel
  // loaded templates
  templates map[string]string
  // root directory for templates
  template_dir string
}

func (self *templateEngine) templateCached(name string) (ok bool) {
  _, ok = self.templates[name]
  return
}

// explicitly reload a template
func (self *templateEngine) reloadTemplate(name string) {
  self.templates[name] = self.loadTemplate(name)
}

// check if we have this template
func (self *templateEngine) hasTemplate(name string) bool {
  return CheckFile(self.templateFilepath(name))
}

// explicitly reload all loaded templates
func (self *templateEngine) reloadAllTemplates() {
  loadThese := []string{}
  // get all the names of the templates we have loaded
  for tname, _ := range self.templates {
    loadThese = append(loadThese, tname)
  }
  // for each template we have loaded, reload the contents from file
  for _, tname := range loadThese {
    self.reloadTemplate(tname)
  }
}

// update the link -> url cache given our current model
func updateLinkCache() {
  // clear existing cache
  template.links = make(map[string]string)

  // for each group
  for _, group := range template.groups {
    // for each page in group
    for _, page := range group {
      // for each thread in page
      updateLinkCacheForBoard(page)
    }
  }
}

// update the link -> url cache given a board page
func updateLinkCacheForBoard(page BoardModel) {
  // for each thread in page
  for _, thread := range page.Threads() {
    updateLinkCacheForThread(thread)
  }
}

// update link -> url cache given a thread
func updateLinkCacheForThread(thread ThreadModel) {
  m := thread.OP().MessageID()
  u := thread.OP().PostURL()
  s := ShorterHashMessageID(m)
  h := ShortHashMessageID(m)
  template.links_short[s] = u
  template.links[h] = u
  // for each reply
  for _, p := range thread.Replies() {
    // put reply entry
    m = p.MessageID()
    u = p.PostURL()
    s = ShorterHashMessageID(m)
    h = ShortHashMessageID(m)
    template.links_short[s] = u
    template.links[h] = u
  }
}

// get the url for a backlink
func (self *templateEngine) findLink(hash string) (url string) {
  if len(hash) == 10 {
    // short version of hash
    url, _ = self.links_short[hash]
  } else {
    url, _ = self.links[hash]
  }
  return
}

// get the filepath to a template
func (self *templateEngine) templateFilepath(name string) string {
  if strings.Count(name, "..") > 0 {
    return ""
  }
  return filepath.Join(self.template_dir, name)
}

// load a template from file, return as string
func (self *templateEngine) loadTemplate(name string) (t string) {
  b, err := ioutil.ReadFile(self.templateFilepath(name))
  if err == nil {
    t = string(b)
  } else {
    log.Println("error loading template", err)
    t = err.Error()
  }
  return
}

// get a template, if it's not cached load from file and cache it
func (self *templateEngine) getTemplate(name string) (t string) {
  if ! self.templateCached(name) {
    self.templates[name] = self.loadTemplate(name)
  }
  t, _ = self.templates[name]
  return
}

// render a template, self explanitory
func (self *templateEngine) renderTemplate(name string, obj interface{}) string {
  t := self.getTemplate(name)
  return mustache.Render(t, obj)
}

// get a board model given a newsgroup
// load un updated board model if we don't have it
func (self *templateEngine) obtainBoard(prefix, frontend, group string, db Database) (model GroupModel) {
  model, ok := self.groups[group]
  // if we don't already have the board loaded load it
  if ! ok  {
    p := db.GetGroupPageCount(group)
    pages := int(p)
    // ignore error
    perpage, _ := db.GetThreadsPerPage(group)
    for page := 0 ; page < pages ; page ++ {
      model = append(model, db.GetGroupForPage(prefix, frontend, group, page, int(perpage)))
    }
    self.groups[group] = model
  }
  return

}
// generate a board page
func (self *templateEngine) genBoardPage(prefix, frontend, newsgroup string, page int, outfile string, db Database) {
  // get the board model
  board := self.obtainBoard(prefix, frontend, newsgroup, db)
  // update the board page
  board = board.Update(page, db)
  if page >= len(board) {
    log.Println("board page should not exist", newsgroup, "page", page)
    return
  }
  // render it
  wr, err := OpenFileWriter(outfile)
  if err == nil {
    updateLinkCacheForBoard(board[page])
    board[page].RenderTo(wr)
    wr.Close()
    log.Println("wrote file", outfile)
  } else {
    log.Println("error generating board page", page, "for", newsgroup, err)
  }
  // save it
  self.groups[newsgroup] = board
}

// generate every page for a board
func (self *templateEngine) genBoard(prefix, frontend, newsgroup, outdir string, db Database) {
  // get the board model
  board := self.obtainBoard(prefix, frontend, newsgroup, db)
  // update the entire board model
  board = board.UpdateAll(db)
  // save the model
  self.groups[newsgroup] = board
  updateLinkCache()

  pages := len(board)
  for page := 0 ; page < pages ; page ++ {
    outfile := filepath.Join(outdir, fmt.Sprintf("%s-%d.html", newsgroup, page))
    wr, err := OpenFileWriter(outfile)
    if err == nil {
      board[page].RenderTo(wr)
      wr.Close()
      log.Println("wrote file", outfile)
    } else {
      log.Println("error generating board page", page, "for", newsgroup, err)
    }
  }
}

func (self *templateEngine) genUkko(prefix, frontend, outfile string, database Database) {
  var threads []ThreadModel
  // get the last 15 bumped threads globally, for each...
  for _, article := range database.GetLastBumpedThreads("", 15) {
    // get the newsgroup and root post id
    newsgroup, msgid := article[1], article[0]
    // obtain board model
    board := self.obtainBoard(prefix, frontend, newsgroup, database)
    // update first page
    board = board.Update(0, database)
    // grab the root post in question
    th := board[0].GetThread(msgid)
    if th != nil {
        threads = append(threads, th.Update(database))
    }
    // save board model
    self.groups[newsgroup] = board
  }
  wr, err := OpenFileWriter(outfile)
  if err == nil {
    updateLinkCache()
    io.WriteString(wr, template.renderTemplate("ukko.mustache", map[string]interface{} { "prefix" : prefix, "threads" : threads }))
    wr.Close()
  } else {
    log.Println("error generating ukko", err)
  }
}

func (self *templateEngine) genThread(root ArticleEntry, prefix, frontend, outfile string, db Database) {
  newsgroup := root.Newsgroup()
  msgid := root.MessageID()
  var th ThreadModel
  // get the board model
  board := self.obtainBoard(prefix, frontend, newsgroup, db)
  // find the thread model in question
  for _, pagemodel := range board {
    t := pagemodel.GetThread(msgid)
    if t != nil {
      th = t
      break
    }
  }

  if th == nil {
    // a new thread?
    board[0] = board[0].Update(db)
    t := board[0].GetThread(msgid)
    if t != nil {
      th = t
    }
  }

  if th == nil {
    log.Println("we didn't find thread for", msgid, "did not regenerate")
  } else {
    // update thread model and write it out
    th = th.Update(db)
    wr, err := OpenFileWriter(outfile)
    if err == nil {
      updateLinkCacheForThread(th)
      th.RenderTo(wr)
      wr.Close()
      log.Println("wrote file", outfile)
    } else {
      log.Println("did not write", outfile, err)
    }
  }
  // save it
  self.groups[newsgroup] = board
}

// change the directory we are using for templates
func (self *templateEngine) changeTemplateDir(dirname string) {
  log.Println("change template directory to", dirname)
  self.template_dir = dirname
  self.reloadAllTemplates()
}

func newTemplateEngine(dir string) *templateEngine {
  return &templateEngine{
    groups: make(map[string]GroupModel),
    templates: make(map[string]string),
    template_dir: dir,
    links: make(map[string]string),
    links_short: make(map[string]string),
  }
}

var template = newTemplateEngine(defaultTemplateDir())

func renderPostForm(prefix, board, op_msg_id string) string {
  url := prefix + "post/" + board
  button := "New Thread"
  if op_msg_id != "" {
    button = "Reply"
  }
  return template.renderTemplate("postform.mustache", map[string]string { "post_url" : url, "reference" : op_msg_id , "button" : button } )
}

// generate misc graphs
func (self *templateEngine) genGraphs(prefix, outdir string, db Database) {

  //
  // begin gen history.html
  //

  var all_posts postsGraph
  // this may take a bit
  posts := db.GetMonthlyPostHistory()

  if posts == nil {
    // wtf?
  } else {
    for _, entry := range posts {
      all_posts = append(all_posts, postsGraphRow{
        day: entry.Time(),
        Num: entry.Count(),
      })
    }
  }
  sort.Sort(all_posts)

  wr, err := OpenFileWriter(filepath.Join(outdir, "history.html"))
  if err != nil {
    log.Println("cannot render history graph", err)
    return
  }

  _, err = io.WriteString(wr, self.renderTemplate("graph_history.mustache", map[string]interface{} {"history" : all_posts}))
  if err != nil {
    log.Println("error writing history graph", err)
  }
  wr.Close()

  //
  // end gen history.html
  //

}

// generate front page and board list
func (self *templateEngine) genFrontPage(top_count int, prefix, frontend_name, outdir string, db Database) {
  // the graph for the front page
  var frontpage_graph boardPageRows

  // for each group
  groups := db.GetAllNewsgroups()
  for _, group := range groups {
    // posts this hour
    hour := db.CountPostsInGroup(group, 3600)
    // posts today
    day := db.CountPostsInGroup(group, 86400)
    // posts total
    all := db.CountPostsInGroup(group, 0)
    frontpage_graph = append(frontpage_graph, boardPageRow{
      All: all,
      Day: day,
      Hour: hour,
      Board: group,
    })
  }

  var posts_graph postsGraph

  posts := db.GetLastDaysPosts(10)
  if posts == nil {
    // wtf?
  } else {
    for _, entry := range posts {
      posts_graph = append(posts_graph, postsGraphRow{
        day: entry.Time(),
        Num: entry.Count(),
      })
    }
  }

  models := db.GetLastPostedPostModels(prefix, 20)

  wr, err := OpenFileWriter(filepath.Join(outdir, "index.html"))
  if err != nil {
    log.Println("cannot render front page", err)
    return
  }

  param := make(map[string]interface{})

  param["overview"] = overviewModel(models)

  sort.Sort(posts_graph)
  param["postsgraph"] = posts_graph
  sort.Sort(frontpage_graph)
  if len(frontpage_graph) < top_count {
    param["boardgraph"] = frontpage_graph
  } else {
    param["boardgraph"] = frontpage_graph[:top_count]
  }
  param["frontend"] = frontend_name
  param["totalposts"] = db.ArticleCount()
  _, err = io.WriteString(wr, self.renderTemplate("frontpage.mustache", param))
  if err != nil {
    log.Println("error writing front page", err)
  }
  wr.Close()

  wr, err = OpenFileWriter(filepath.Join(outdir, "boards.html"))
  if err != nil {
    log.Println("cannot render board list page", err)
    return
  }

  param["graph"] = frontpage_graph
  _, err = io.WriteString(wr, self.renderTemplate("boardlist.mustache", param))
  if err != nil {
    log.Println("error writing board list page", err)
  }
  wr.Close()
}
<commit_msg>attempt fixing iob<commit_after>//
// templates.go
// template model interfaces
//
package srnd

import (
  "fmt"
  "github.com/hoisie/mustache"
  "io"
  "io/ioutil"
  "log"
  "path/filepath"
  "sort"
  "strings"
)

type templateEngine struct {
  // posthash -> url
  links map[string]string
  // shorthash -> posthash
  links_short map[string]string
  // every newsgroup
  groups map[string]GroupModel
  // loaded templates
  templates map[string]string
  // root directory for templates
  template_dir string
}

func (self *templateEngine) templateCached(name string) (ok bool) {
  _, ok = self.templates[name]
  return
}

// explicitly reload a template
func (self *templateEngine) reloadTemplate(name string) {
  self.templates[name] = self.loadTemplate(name)
}

// check if we have this template
func (self *templateEngine) hasTemplate(name string) bool {
  return CheckFile(self.templateFilepath(name))
}

// explicitly reload all loaded templates
func (self *templateEngine) reloadAllTemplates() {
  loadThese := []string{}
  // get all the names of the templates we have loaded
  for tname, _ := range self.templates {
    loadThese = append(loadThese, tname)
  }
  // for each template we have loaded, reload the contents from file
  for _, tname := range loadThese {
    self.reloadTemplate(tname)
  }
}

// update the link -> url cache given our current model
func updateLinkCache() {
  // clear existing cache
  template.links = make(map[string]string)

  // for each group
  for _, group := range template.groups {
    // for each page in group
    for _, page := range group {
      // for each thread in page
      updateLinkCacheForBoard(page)
    }
  }
}

// update the link -> url cache given a board page
func updateLinkCacheForBoard(page BoardModel) {
  // for each thread in page
  for _, thread := range page.Threads() {
    updateLinkCacheForThread(thread)
  }
}

// update link -> url cache given a thread
func updateLinkCacheForThread(thread ThreadModel) {
  m := thread.OP().MessageID()
  u := thread.OP().PostURL()
  s := ShorterHashMessageID(m)
  h := ShortHashMessageID(m)
  template.links_short[s] = u
  template.links[h] = u
  // for each reply
  for _, p := range thread.Replies() {
    // put reply entry
    m = p.MessageID()
    u = p.PostURL()
    s = ShorterHashMessageID(m)
    h = ShortHashMessageID(m)
    template.links_short[s] = u
    template.links[h] = u
  }
}

// get the url for a backlink
func (self *templateEngine) findLink(hash string) (url string) {
  if len(hash) == 10 {
    // short version of hash
    url, _ = self.links_short[hash]
  } else {
    url, _ = self.links[hash]
  }
  return
}

// get the filepath to a template
func (self *templateEngine) templateFilepath(name string) string {
  if strings.Count(name, "..") > 0 {
    return ""
  }
  return filepath.Join(self.template_dir, name)
}

// load a template from file, return as string
func (self *templateEngine) loadTemplate(name string) (t string) {
  b, err := ioutil.ReadFile(self.templateFilepath(name))
  if err == nil {
    t = string(b)
  } else {
    log.Println("error loading template", err)
    t = err.Error()
  }
  return
}

// get a template, if it's not cached load from file and cache it
func (self *templateEngine) getTemplate(name string) (t string) {
  if ! self.templateCached(name) {
    self.templates[name] = self.loadTemplate(name)
  }
  t, _ = self.templates[name]
  return
}

// render a template, self explanitory
func (self *templateEngine) renderTemplate(name string, obj interface{}) string {
  t := self.getTemplate(name)
  return mustache.Render(t, obj)
}

// get a board model given a newsgroup
// load un updated board model if we don't have it
func (self *templateEngine) obtainBoard(prefix, frontend, group string, db Database) (model GroupModel) {
  model, ok := self.groups[group]
  // if we don't already have the board loaded load it
  if ! ok  {
    p := db.GetGroupPageCount(group)
    pages := int(p)
    // ignore error
    perpage, _ := db.GetThreadsPerPage(group)
    for page := 0 ; page < pages ; page ++ {
      model = append(model, db.GetGroupForPage(prefix, frontend, group, page, int(perpage)))
    }
    self.groups[group] = model
  }
  return

}
// generate a board page
func (self *templateEngine) genBoardPage(prefix, frontend, newsgroup string, page int, outfile string, db Database) {
  // get the board model
  board := self.obtainBoard(prefix, frontend, newsgroup, db)
  // update the board page
  board = board.Update(page, db)
  if page >= len(board) {
    log.Println("board page should not exist", newsgroup, "page", page)
    return
  }
  // render it
  wr, err := OpenFileWriter(outfile)
  if err == nil {
    updateLinkCacheForBoard(board[page])
    board[page].RenderTo(wr)
    wr.Close()
    log.Println("wrote file", outfile)
  } else {
    log.Println("error generating board page", page, "for", newsgroup, err)
  }
  // save it
  self.groups[newsgroup] = board
}

// generate every page for a board
func (self *templateEngine) genBoard(prefix, frontend, newsgroup, outdir string, db Database) {
  // get the board model
  board := self.obtainBoard(prefix, frontend, newsgroup, db)
  // update the entire board model
  board = board.UpdateAll(db)
  // save the model
  self.groups[newsgroup] = board
  updateLinkCache()

  pages := len(board)
  for page := 0 ; page < pages ; page ++ {
    outfile := filepath.Join(outdir, fmt.Sprintf("%s-%d.html", newsgroup, page))
    wr, err := OpenFileWriter(outfile)
    if err == nil {
      board[page].RenderTo(wr)
      wr.Close()
      log.Println("wrote file", outfile)
    } else {
      log.Println("error generating board page", page, "for", newsgroup, err)
    }
  }
}

func (self *templateEngine) genUkko(prefix, frontend, outfile string, database Database) {
  var threads []ThreadModel
  // get the last 15 bumped threads globally, for each...
  for _, article := range database.GetLastBumpedThreads("", 15) {
    // get the newsgroup and root post id
    newsgroup, msgid := article[1], article[0]
    // obtain board model
    board := self.obtainBoard(prefix, frontend, newsgroup, database)
    // update first page
    board = board.Update(0, database)
    // grab the root post in question
    th := board[0].GetThread(msgid)
    if th != nil {
        threads = append(threads, th.Update(database))
    }
    // save board model
    self.groups[newsgroup] = board
  }
  wr, err := OpenFileWriter(outfile)
  if err == nil {
    updateLinkCache()
    io.WriteString(wr, template.renderTemplate("ukko.mustache", map[string]interface{} { "prefix" : prefix, "threads" : threads }))
    wr.Close()
  } else {
    log.Println("error generating ukko", err)
  }
}

func (self *templateEngine) genThread(root ArticleEntry, prefix, frontend, outfile string, db Database) {
  newsgroup := root.Newsgroup()
  msgid := root.MessageID()
  var th ThreadModel
  // get the board model
  board := self.obtainBoard(prefix, frontend, newsgroup, db)
  // find the thread model in question
  for _, pagemodel := range board {
    t := pagemodel.GetThread(msgid)
    if t != nil {
      th = t
      break
    }
  }

  if th == nil {
    // a new thread?
    if len(board) > 0 {
      board[0] = board[0].Update(db)
      t := board[0].GetThread(msgid)
      if t != nil {
        th = t
      }
    }
  }

  if th == nil {
    log.Println("we didn't find thread for", msgid, "did not regenerate")
  } else {
    // update thread model and write it out
    th = th.Update(db)
    wr, err := OpenFileWriter(outfile)
    if err == nil {
      updateLinkCacheForThread(th)
      th.RenderTo(wr)
      wr.Close()
      log.Println("wrote file", outfile)
    } else {
      log.Println("did not write", outfile, err)
    }
  }
  // save it
  self.groups[newsgroup] = board
}

// change the directory we are using for templates
func (self *templateEngine) changeTemplateDir(dirname string) {
  log.Println("change template directory to", dirname)
  self.template_dir = dirname
  self.reloadAllTemplates()
}

func newTemplateEngine(dir string) *templateEngine {
  return &templateEngine{
    groups: make(map[string]GroupModel),
    templates: make(map[string]string),
    template_dir: dir,
    links: make(map[string]string),
    links_short: make(map[string]string),
  }
}

var template = newTemplateEngine(defaultTemplateDir())

func renderPostForm(prefix, board, op_msg_id string) string {
  url := prefix + "post/" + board
  button := "New Thread"
  if op_msg_id != "" {
    button = "Reply"
  }
  return template.renderTemplate("postform.mustache", map[string]string { "post_url" : url, "reference" : op_msg_id , "button" : button } )
}

// generate misc graphs
func (self *templateEngine) genGraphs(prefix, outdir string, db Database) {

  //
  // begin gen history.html
  //

  var all_posts postsGraph
  // this may take a bit
  posts := db.GetMonthlyPostHistory()

  if posts == nil {
    // wtf?
  } else {
    for _, entry := range posts {
      all_posts = append(all_posts, postsGraphRow{
        day: entry.Time(),
        Num: entry.Count(),
      })
    }
  }
  sort.Sort(all_posts)

  wr, err := OpenFileWriter(filepath.Join(outdir, "history.html"))
  if err != nil {
    log.Println("cannot render history graph", err)
    return
  }

  _, err = io.WriteString(wr, self.renderTemplate("graph_history.mustache", map[string]interface{} {"history" : all_posts}))
  if err != nil {
    log.Println("error writing history graph", err)
  }
  wr.Close()

  //
  // end gen history.html
  //

}

// generate front page and board list
func (self *templateEngine) genFrontPage(top_count int, prefix, frontend_name, outdir string, db Database) {
  // the graph for the front page
  var frontpage_graph boardPageRows

  // for each group
  groups := db.GetAllNewsgroups()
  for _, group := range groups {
    // posts this hour
    hour := db.CountPostsInGroup(group, 3600)
    // posts today
    day := db.CountPostsInGroup(group, 86400)
    // posts total
    all := db.CountPostsInGroup(group, 0)
    frontpage_graph = append(frontpage_graph, boardPageRow{
      All: all,
      Day: day,
      Hour: hour,
      Board: group,
    })
  }

  var posts_graph postsGraph

  posts := db.GetLastDaysPosts(10)
  if posts == nil {
    // wtf?
  } else {
    for _, entry := range posts {
      posts_graph = append(posts_graph, postsGraphRow{
        day: entry.Time(),
        Num: entry.Count(),
      })
    }
  }

  models := db.GetLastPostedPostModels(prefix, 20)

  wr, err := OpenFileWriter(filepath.Join(outdir, "index.html"))
  if err != nil {
    log.Println("cannot render front page", err)
    return
  }

  param := make(map[string]interface{})

  param["overview"] = overviewModel(models)

  sort.Sort(posts_graph)
  param["postsgraph"] = posts_graph
  sort.Sort(frontpage_graph)
  if len(frontpage_graph) < top_count {
    param["boardgraph"] = frontpage_graph
  } else {
    param["boardgraph"] = frontpage_graph[:top_count]
  }
  param["frontend"] = frontend_name
  param["totalposts"] = db.ArticleCount()
  _, err = io.WriteString(wr, self.renderTemplate("frontpage.mustache", param))
  if err != nil {
    log.Println("error writing front page", err)
  }
  wr.Close()

  wr, err = OpenFileWriter(filepath.Join(outdir, "boards.html"))
  if err != nil {
    log.Println("cannot render board list page", err)
    return
  }

  param["graph"] = frontpage_graph
  _, err = io.WriteString(wr, self.renderTemplate("boardlist.mustache", param))
  if err != nil {
    log.Println("error writing board list page", err)
  }
  wr.Close()
}
<|endoftext|>


<commit_before>package policy

import (
	"github.com/hashicorp/hcl"
	"github.com/hashicorp/hcl/hcl/ast"
)

type ResponseCachePolicy struct {
	XMLName                     string `xml:"ResponseCache" hcl:"-"`
	Policy                      `hcl:",squash"`
	Type                        string          `xml:"type,attr,omitempty" hcl:"type"`
	DisplayName                 string          `xml:",omitempty" hcl:"display_name"`
	CacheKey                    *cacheKey       `xml:"CacheKey" hcl:"cache_key"`
	Scope                       string          `xml:",omitempty" hcl:"scope"`
	ExpirySettings              *expirySettings `xml:"ExpirySettings" hcl:"expiry_settings"`
	CacheResource               string          `xml:",omitempty" hcl:"cache_resource"`
	CacheLookupTimeoutInSeconds int             `xml:",omitempty" hcl:"lookup_timeout"`
	ExcludeErrorResponse        bool            `xml:",omitempty" hcl:"exclude_error_response"`
	SkipCacheLookup             string          `xml:",omitempty" hcl:"skip_cache_lookup"`
	SkipCachePopulation         string          `xml:",omitempty" hcl:"skip_cache_population"`
	UseAcceptHeader             bool            `xml:",omitempty" hcl:"use_accept_header"`
	UseResponseCacheHeaders     bool            `xml:",omitempty" hcl:"use_response_cache_headers"`
}

type cacheKey struct {
	XMLName     string              `xml:"CacheKey" hcl:"-"`
	Prefix      string              `xml:",omitempty" hcl:"prefix"`
	KeyFragment []*cacheKeyFragment `xml:",omitempty" hcl:"key_fragment"`
}

type cacheKeyFragment struct {
	XMLName string `xml:"KeyFragment" hcl:"-"`
	Ref     string `xml:"ref,attr,omitempty" hcl:"ref"`
	Value   string `xml:",chardata" hcl:"value"`
}

type expirySettings struct {
	XMLName      string              `xml:"ExpirySettings" hcl:"-"`
	TimeOfDay    *expiryTimeOfDay    `xml:",omitempty" hcl:"time_of_day"`
	TimeoutInSec *expiryTimeoutInSec `xml:",omitempty" hcl:"timeout_in_sec"`
	ExpiryDate   *expiryDate         `xml:"" hcl:"expiry_date"`
}

type expiryTimeOfDay struct {
	XMLName string `xml:"TimeOfDay" hcl:"-"`
	Ref     string `xml:"ref,attr,omitempty" hcl:"ref"`
	Value   string `xml:",chardata" hcl:"value"`
}

type expiryTimeoutInSec struct {
	XMLName string `xml:"TimeoutInSec" hcl:"-"`
	Ref     string `xml:"ref,attr,omitempty" hcl:"ref"`
	Value   string `xml:",chardata" hcl:"value"`
}

type expiryDate struct {
	XMLName string `xml:"ExpiryDate" hcl:"-"`
	Ref     string `xml:"ref,attr,omitempty" hcl:"ref"`
	Value   string `xml:",chardata" hcl:"value"`
}

func LoadResponseCacheHCL(item *ast.ObjectItem) (interface{}, error) {
	var p ResponseCachePolicy

	if err := LoadCommonPolicyHCL(item, &p.Policy); err != nil {
		return nil, err
	}

	if err := hcl.DecodeObject(&p, item.Val.(*ast.ObjectType)); err != nil {
		return nil, err
	}

	return p, nil
}
<commit_msg>Adding a missing ,omitempty to ExpirtyDate on ResponseCachePolicy.<commit_after>package policy

import (
	"github.com/hashicorp/hcl"
	"github.com/hashicorp/hcl/hcl/ast"
)

type ResponseCachePolicy struct {
	XMLName                     string `xml:"ResponseCache" hcl:"-"`
	Policy                      `hcl:",squash"`
	Type                        string          `xml:"type,attr,omitempty" hcl:"type"`
	DisplayName                 string          `xml:",omitempty" hcl:"display_name"`
	CacheKey                    *cacheKey       `xml:"CacheKey" hcl:"cache_key"`
	Scope                       string          `xml:",omitempty" hcl:"scope"`
	ExpirySettings              *expirySettings `xml:"ExpirySettings" hcl:"expiry_settings"`
	CacheResource               string          `xml:",omitempty" hcl:"cache_resource"`
	CacheLookupTimeoutInSeconds int             `xml:",omitempty" hcl:"lookup_timeout"`
	ExcludeErrorResponse        bool            `xml:",omitempty" hcl:"exclude_error_response"`
	SkipCacheLookup             string          `xml:",omitempty" hcl:"skip_cache_lookup"`
	SkipCachePopulation         string          `xml:",omitempty" hcl:"skip_cache_population"`
	UseAcceptHeader             bool            `xml:",omitempty" hcl:"use_accept_header"`
	UseResponseCacheHeaders     bool            `xml:",omitempty" hcl:"use_response_cache_headers"`
}

type cacheKey struct {
	XMLName     string              `xml:"CacheKey" hcl:"-"`
	Prefix      string              `xml:",omitempty" hcl:"prefix"`
	KeyFragment []*cacheKeyFragment `xml:",omitempty" hcl:"key_fragment"`
}

type cacheKeyFragment struct {
	XMLName string `xml:"KeyFragment" hcl:"-"`
	Ref     string `xml:"ref,attr,omitempty" hcl:"ref"`
	Value   string `xml:",chardata" hcl:"value"`
}

type expirySettings struct {
	XMLName      string              `xml:"ExpirySettings" hcl:"-"`
	TimeOfDay    *expiryTimeOfDay    `xml:",omitempty" hcl:"time_of_day"`
	TimeoutInSec *expiryTimeoutInSec `xml:",omitempty" hcl:"timeout_in_sec"`
	ExpiryDate   *expiryDate         `xml:",omitempty" hcl:"expiry_date"`
}

type expiryTimeOfDay struct {
	XMLName string `xml:"TimeOfDay" hcl:"-"`
	Ref     string `xml:"ref,attr,omitempty" hcl:"ref"`
	Value   string `xml:",chardata" hcl:"value"`
}

type expiryTimeoutInSec struct {
	XMLName string `xml:"TimeoutInSec" hcl:"-"`
	Ref     string `xml:"ref,attr,omitempty" hcl:"ref"`
	Value   string `xml:",chardata" hcl:"value"`
}

type expiryDate struct {
	XMLName string `xml:"ExpiryDate" hcl:"-"`
	Ref     string `xml:"ref,attr,omitempty" hcl:"ref"`
	Value   string `xml:",chardata" hcl:"value"`
}

func LoadResponseCacheHCL(item *ast.ObjectItem) (interface{}, error) {
	var p ResponseCachePolicy

	if err := LoadCommonPolicyHCL(item, &p.Policy); err != nil {
		return nil, err
	}

	if err := hcl.DecodeObject(&p, item.Val.(*ast.ObjectType)); err != nil {
		return nil, err
	}

	return p, nil
}
<|endoftext|>


<commit_before>package main

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

	"gopkg.in/mgo.v2/bson"
	"github.com/freehaha/token-auth"
	"github.com/gorilla/mux"
)

// GetUserController will answer a JSON of the user
// linked to the given id in the URL
func GetUserController(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	userID := vars["id"]
	var res = GetUser(bson.ObjectIdHex(userID))
	json.NewEncoder(w).Encode(res)
}

func GetAllUserController(w http.ResponseWriter, r *http.Request) {
	var res = GetAllUser()
	json.NewEncoder(w).Encode(res)
}

// AddUserController will answer a JSON of the
// brand new created user (from the JSON Body)
func AddUserController(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var user User
	decoder.Decode(&user)
	res := AddUser(user)
	json.NewEncoder(w).Encode(res)
}

// UpdateUserController will answer the JSON of the
// modified user (from the JSON Body)
func UpdateUserController(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var user User
	decoder.Decode(&user)
	vars := mux.Vars(r)
	userID := vars["id"]
	isValid := VerifyUserRequest(r, bson.ObjectIdHex(userID))
	if !isValid {
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(bson.M{"error": "Contenu Protégé"})
		return
	}
	res := UpdateUser(bson.ObjectIdHex(userID), user)
	json.NewEncoder(w).Encode(res)
}

// DeleteUserController will answer a JSON of an
// empty user if the deletation has succeed
func DeleteUserController(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	userID := vars["id"]
	isValid := VerifyUserRequest(r, bson.ObjectIdHex(userID))
	if !isValid {
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(bson.M{"error": "Contenu Protégé"})
		return
	}
	user := GetUser(bson.ObjectIdHex(userID))
	res := DeleteUser(user)
	json.NewEncoder(w).Encode(res)
}

func SearchUserController(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	users := SearchUser(vars["username"])
	json.NewEncoder(w).Encode(bson.M{"users": users})
}

func ReportUserController(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	userID := vars["id"]
	token := tauth.Get(r)
	reporterID := token.Claims("id").(string)
	ReportUser(bson.ObjectIdHex(userID), bson.ObjectIdHex(reporterID))
	json.NewEncoder(w).Encode(bson.M{})
}

func VerifyUserRequest(r *http.Request, userId bson.ObjectId) bool {
	token := tauth.Get(r)
	id := token.Claims("id").(string)
	return bson.ObjectIdHex(id) == userId
}
<commit_msg>master association can delete user<commit_after>package main

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

	"gopkg.in/mgo.v2/bson"
	"github.com/freehaha/token-auth"
	"github.com/gorilla/mux"
)

// GetUserController will answer a JSON of the user
// linked to the given id in the URL
func GetUserController(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	userID := vars["id"]
	var res = GetUser(bson.ObjectIdHex(userID))
	json.NewEncoder(w).Encode(res)
}

func GetAllUserController(w http.ResponseWriter, r *http.Request) {
	var res = GetAllUser()
	json.NewEncoder(w).Encode(res)
}

// AddUserController will answer a JSON of the
// brand new created user (from the JSON Body)
func AddUserController(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var user User
	decoder.Decode(&user)
	res := AddUser(user)
	json.NewEncoder(w).Encode(res)
}

// UpdateUserController will answer the JSON of the
// modified user (from the JSON Body)
func UpdateUserController(w http.ResponseWriter, r *http.Request) {
	decoder := json.NewDecoder(r.Body)
	var user User
	decoder.Decode(&user)
	vars := mux.Vars(r)
	userID := vars["id"]
	isValidUser := VerifyUserRequest(r, bson.ObjectIdHex(userID))
	isValidAssociation := VerifyAssociationRequest(r, bson.ObjectIdHex(userID))
	if !isValidUser && !isValidAssociation {
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(bson.M{"error": "Contenu Protégé"})
		return
	}
	res := UpdateUser(bson.ObjectIdHex(userID), user)
	json.NewEncoder(w).Encode(res)
}

// DeleteUserController will answer a JSON of an
// empty user if the deletation has succeed
func DeleteUserController(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	userID := vars["id"]
	isValid := VerifyUserRequest(r, bson.ObjectIdHex(userID))
	if !isValid {
		w.WriteHeader(http.StatusUnauthorized)
		json.NewEncoder(w).Encode(bson.M{"error": "Contenu Protégé"})
		return
	}
	user := GetUser(bson.ObjectIdHex(userID))
	res := DeleteUser(user)
	json.NewEncoder(w).Encode(res)
}

func SearchUserController(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	users := SearchUser(vars["username"])
	json.NewEncoder(w).Encode(bson.M{"users": users})
}

func ReportUserController(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	userID := vars["id"]
	token := tauth.Get(r)
	reporterID := token.Claims("id").(string)
	ReportUser(bson.ObjectIdHex(userID), bson.ObjectIdHex(reporterID))
	json.NewEncoder(w).Encode(bson.M{})
}

func VerifyUserRequest(r *http.Request, userId bson.ObjectId) bool {
	token := tauth.Get(r)
	id := token.Claims("id").(string)
	return bson.ObjectIdHex(id) == userId
}
<|endoftext|>