<commit_before>package vcs

import (
	"fmt"
	"os"
	"path/filepath"
	"text/template"

	"github.com/hashicorp/errwrap"
)

var PostCheckoutTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
sourceclock start
`))

var PrepCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
printf "$(cat $1)[$(sourceclock split)]" > "$1"
`))

var PostCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
sourceclock lap
`))

type Git struct {
	dir string
}

func NewGit(dir string) *Git {
	return &Git{
		dir: filepath.Join(dir, ".git"),
	}
}

func (g *Git) Name() string { return "git" }
func (g *Git) Supported() bool {
	fi, err := os.Stat(g.dir)
	if err != nil || !fi.IsDir() {
		return false
	}

	return true
}

func (g *Git) Hook() error {
	hpath := filepath.Join(g.dir, "hooks")

	//post checkout: start()
	postchf, err := os.Create(filepath.Join(hpath, "post-checkout"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-checkout '%s': {{err}}", postchf.Name()), err)
	}

	err = postchf.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-checkout file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCheckoutTmpl.Execute(postchf, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-checkout template: {{err}}", err)
	}

	//prepare commit msg: split()
	prepcof, err := os.Create(filepath.Join(hpath, "prepare-commit-msg"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create prepare-commit-msg  '%s': {{err}}", postchf.Name()), err)
	}

	err = prepcof.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make prepare-commit-msg file '%s' executable: {{err}}", hpath), err)
	}

	err = PrepCommitTmpl.Execute(prepcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	//post commit: lap()
	postcof, err := os.Create(filepath.Join(hpath, "post-commit"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-commit  '%s': {{err}}", postchf.Name()), err)
	}

	err = postcof.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-commit file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCommitTmpl.Execute(postcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	return nil
}
<commit_msg>added todos [1m30s]<commit_after>package vcs

import (
	"fmt"
	"os"
	"path/filepath"
	"text/template"

	"github.com/hashicorp/errwrap"
)

var PostCheckoutTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
# @todo handle checkout files endge case

sourceclock start
`))

var PrepCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
# @todo handle merge/rebase kind of commits

printf "$(cat $1) [$(sourceclock split)]" > "$1"
`))

var PostCommitTmpl = template.Must(template.New("name").Parse(`#!/bin/sh
# @todo handle merge/rebase kind of commits

sourceclock lap
`))

type Git struct {
	dir string
}

func NewGit(dir string) *Git {
	return &Git{
		dir: filepath.Join(dir, ".git"),
	}
}

func (g *Git) Name() string { return "git" }
func (g *Git) Supported() bool {
	fi, err := os.Stat(g.dir)
	if err != nil || !fi.IsDir() {
		return false
	}

	return true
}

func (g *Git) Hook() error {
	hpath := filepath.Join(g.dir, "hooks")

	//post checkout: start()
	postchf, err := os.Create(filepath.Join(hpath, "post-checkout"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-checkout '%s': {{err}}", postchf.Name()), err)
	}

	err = postchf.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-checkout file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCheckoutTmpl.Execute(postchf, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-checkout template: {{err}}", err)
	}

	//prepare commit msg: split()
	prepcof, err := os.Create(filepath.Join(hpath, "prepare-commit-msg"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create prepare-commit-msg  '%s': {{err}}", postchf.Name()), err)
	}

	err = prepcof.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make prepare-commit-msg file '%s' executable: {{err}}", hpath), err)
	}

	err = PrepCommitTmpl.Execute(prepcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	//post commit: lap()
	postcof, err := os.Create(filepath.Join(hpath, "post-commit"))
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to create post-commit  '%s': {{err}}", postchf.Name()), err)
	}

	err = postcof.Chmod(0766)
	if err != nil {
		return errwrap.Wrapf(fmt.Sprintf("Failed to make post-commit file '%s' executable: {{err}}", hpath), err)
	}

	err = PostCommitTmpl.Execute(postcof, struct{}{})
	if err != nil {
		return errwrap.Wrapf("Failed to run post-commit template: {{err}}", err)
	}

	return nil
}
<|endoftext|>


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

package docker

import (
	"archive/tar"
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"net/url"
	"strings"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/tsuru/tsuru/app/image"
	"github.com/tsuru/tsuru/builder"
	tsuruErrors "github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/log"
	"github.com/tsuru/tsuru/net"
	"github.com/tsuru/tsuru/provision"
	"github.com/tsuru/tsuru/provision/dockercommon"
	"github.com/tsuru/tsuru/safe"
)

var _ builder.Builder = &dockerBuilder{}

func (b *dockerBuilder) PlatformAdd(opts builder.PlatformOptions) error {
	return b.buildPlatform(opts.Name, opts.Args, opts.Output, opts.Input)
}

func (b *dockerBuilder) PlatformUpdate(opts builder.PlatformOptions) error {
	return b.buildPlatform(opts.Name, opts.Args, opts.Output, opts.Input)
}

func (b *dockerBuilder) buildPlatform(name string, args map[string]string, w io.Writer, r io.Reader) error {
	var inputStream io.Reader
	var dockerfileURL string
	if r != nil {
		data, err := ioutil.ReadAll(r)
		if err != nil {
			return err
		}
		var buf bytes.Buffer
		writer := tar.NewWriter(&buf)
		writer.WriteHeader(&tar.Header{
			Name: "Dockerfile",
			Mode: 0644,
			Size: int64(len(data)),
		})
		writer.Write(data)
		writer.Close()
		inputStream = &buf
	} else {
		dockerfileURL = args["dockerfile"]
		if dockerfileURL == "" {
			return errors.New("Dockerfile is required")
		}
		if _, err := url.ParseRequestURI(dockerfileURL); err != nil {
			return errors.New("Dockerfile parameter must be a URL")
		}
	}
	imageName := image.PlatformImageName(name)
	client, err := getDockerClient()
	if err != nil {
		return err
	}
	client.HTTPClient = net.Dial5FullUnlimitedClient
	buildOptions := docker.BuildImageOptions{
		Name:              imageName,
		Pull:              true,
		NoCache:           true,
		RmTmpContainer:    true,
		Remote:            dockerfileURL,
		InputStream:       inputStream,
		OutputStream:      w,
		InactivityTimeout: net.StreamInactivityTimeout,
		RawJSONStream:     true,
	}
	err = client.BuildImage(buildOptions)
	if err != nil {
		return err
	}
	parts := strings.Split(imageName, ":")
	var tag string
	if len(parts) > 2 {
		imageName = strings.Join(parts[:len(parts)-1], ":")
		tag = parts[len(parts)-1]
	} else if len(parts) > 1 {
		imageName = parts[0]
		tag = parts[1]
	} else {
		imageName = parts[0]
		tag = "latest"
	}
	var buf safe.Buffer
	pushOpts := docker.PushImageOptions{
		Name:              imageName,
		Tag:               tag,
		OutputStream:      &buf,
		InactivityTimeout: net.StreamInactivityTimeout,
		RawJSONStream:     true,
	}
	err = client.PushImage(pushOpts, dockercommon.RegistryAuthConfig())
	if err != nil {
		log.Errorf("[docker] Failed to push image %q (%s): %s", name, err, buf.String())
		return err
	}
	return nil
}

func getDockerClient() (*docker.Client, error) {
	provisioners, err := provision.Registry()
	if err != nil {
		return nil, err
	}
	var client *docker.Client
	multiErr := tsuruErrors.NewMultiError()
	for _, p := range provisioners {
		if provisioner, ok := p.(provision.BuilderDeploy); ok {
			client, err = provisioner.GetDockerClient(nil)
			if err != nil {
				multiErr.Add(err)
			} else if client != nil {
				return client, nil
			}
		}
	}
	if multiErr.Len() > 0 {
		return nil, multiErr
	}
	return nil, errors.New("No Docker nodes available")
}

func (b *dockerBuilder) PlatformRemove(name string) error {
	client, err := getDockerClient()
	if err != nil {
		return err
	}
	img, err := client.InspectImage(image.PlatformImageName(name))
	if err != nil {
		return err
	}
	err = client.RemoveImage(img.ID)
	if err != nil && err == docker.ErrNoSuchImage {
		log.Errorf("error removing image %s from Docker: no such image", name)
		return nil
	}
	return err
}
<commit_msg>builder/docker: change only timeout in httpclient<commit_after>// Copyright 2017 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package docker

import (
	"archive/tar"
	"bytes"
	"errors"
	"io"
	"io/ioutil"
	"net/url"
	"strings"

	docker "github.com/fsouza/go-dockerclient"
	"github.com/tsuru/tsuru/app/image"
	"github.com/tsuru/tsuru/builder"
	tsuruErrors "github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/log"
	"github.com/tsuru/tsuru/net"
	"github.com/tsuru/tsuru/provision"
	"github.com/tsuru/tsuru/provision/dockercommon"
	"github.com/tsuru/tsuru/safe"
)

var _ builder.Builder = &dockerBuilder{}

func (b *dockerBuilder) PlatformAdd(opts builder.PlatformOptions) error {
	return b.buildPlatform(opts.Name, opts.Args, opts.Output, opts.Input)
}

func (b *dockerBuilder) PlatformUpdate(opts builder.PlatformOptions) error {
	return b.buildPlatform(opts.Name, opts.Args, opts.Output, opts.Input)
}

func (b *dockerBuilder) buildPlatform(name string, args map[string]string, w io.Writer, r io.Reader) error {
	var inputStream io.Reader
	var dockerfileURL string
	if r != nil {
		data, err := ioutil.ReadAll(r)
		if err != nil {
			return err
		}
		var buf bytes.Buffer
		writer := tar.NewWriter(&buf)
		writer.WriteHeader(&tar.Header{
			Name: "Dockerfile",
			Mode: 0644,
			Size: int64(len(data)),
		})
		writer.Write(data)
		writer.Close()
		inputStream = &buf
	} else {
		dockerfileURL = args["dockerfile"]
		if dockerfileURL == "" {
			return errors.New("Dockerfile is required")
		}
		if _, err := url.ParseRequestURI(dockerfileURL); err != nil {
			return errors.New("Dockerfile parameter must be a URL")
		}
	}
	imageName := image.PlatformImageName(name)
	client, err := getDockerClient()
	if err != nil {
		return err
	}
	client.HTTPClient.Timeout = 0
	buildOptions := docker.BuildImageOptions{
		Name:              imageName,
		Pull:              true,
		NoCache:           true,
		RmTmpContainer:    true,
		Remote:            dockerfileURL,
		InputStream:       inputStream,
		OutputStream:      w,
		InactivityTimeout: net.StreamInactivityTimeout,
		RawJSONStream:     true,
	}
	err = client.BuildImage(buildOptions)
	if err != nil {
		return err
	}
	parts := strings.Split(imageName, ":")
	var tag string
	if len(parts) > 2 {
		imageName = strings.Join(parts[:len(parts)-1], ":")
		tag = parts[len(parts)-1]
	} else if len(parts) > 1 {
		imageName = parts[0]
		tag = parts[1]
	} else {
		imageName = parts[0]
		tag = "latest"
	}
	var buf safe.Buffer
	pushOpts := docker.PushImageOptions{
		Name:              imageName,
		Tag:               tag,
		OutputStream:      &buf,
		InactivityTimeout: net.StreamInactivityTimeout,
		RawJSONStream:     true,
	}
	err = client.PushImage(pushOpts, dockercommon.RegistryAuthConfig())
	if err != nil {
		log.Errorf("[docker] Failed to push image %q (%s): %s", name, err, buf.String())
		return err
	}
	return nil
}

func getDockerClient() (*docker.Client, error) {
	provisioners, err := provision.Registry()
	if err != nil {
		return nil, err
	}
	var client *docker.Client
	multiErr := tsuruErrors.NewMultiError()
	for _, p := range provisioners {
		if provisioner, ok := p.(provision.BuilderDeploy); ok {
			client, err = provisioner.GetDockerClient(nil)
			if err != nil {
				multiErr.Add(err)
			} else if client != nil {
				return client, nil
			}
		}
	}
	if multiErr.Len() > 0 {
		return nil, multiErr
	}
	return nil, errors.New("No Docker nodes available")
}

func (b *dockerBuilder) PlatformRemove(name string) error {
	client, err := getDockerClient()
	if err != nil {
		return err
	}
	img, err := client.InspectImage(image.PlatformImageName(name))
	if err != nil {
		return err
	}
	err = client.RemoveImage(img.ID)
	if err != nil && err == docker.ErrNoSuchImage {
		log.Errorf("error removing image %s from Docker: no such image", name)
		return nil
	}
	return err
}
<|endoftext|>


<commit_before>// The amazonebs package contains a packer.Builder implementation that
// builds OMIs for Outscale OAPI.
//
// In general, there are two types of OMIs that can be created: ebs-backed or
// instance-store. This builder _only_ builds ebs-backed images.
package bsu

import (
	"crypto/tls"
	"log"
	"net/http"

	osccommon "github.com/hashicorp/packer/builder/osc/common"
	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/helper/multistep"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
	"github.com/outscale/osc-go/oapi"
)

// The unique ID for this builder
const BuilderId = "oapi.outscale.bsu"

type Config struct {
	common.PackerConfig    `mapstructure:",squash"`
	osccommon.AccessConfig `mapstructure:",squash"`
	osccommon.OMIConfig    `mapstructure:",squash"`
	osccommon.BlockDevices `mapstructure:",squash"`
	osccommon.RunConfig    `mapstructure:",squash"`
	VolumeRunTags          osccommon.TagMap `mapstructure:"run_volume_tags"`

	ctx interpolate.Context
}

type Builder struct {
	config Config
	runner multistep.Runner
}

func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
	b.config.ctx.Funcs = osccommon.TemplateFuncs
	err := config.Decode(&b.config, &config.DecodeOpts{
		Interpolate:        true,
		InterpolateContext: &b.config.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"omi_description",
				"run_tags",
				"run_volume_tags",
				"spot_tags",
				"snapshot_tags",
				"tags",
			},
		},
	}, raws...)
	if err != nil {
		return nil, err
	}

	if b.config.PackerConfig.PackerForce {
		b.config.OMIForceDeregister = true
	}

	// Accumulate any errors
	var errs *packer.MultiError
	errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs,
		b.config.OMIConfig.Prepare(&b.config.AccessConfig, &b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)

	if errs != nil && len(errs.Errors) > 0 {
		return nil, errs
	}

	packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token)
	return nil, nil
}

func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
	clientConfig, err := b.config.Config()
	if err != nil {
		return nil, err
	}

	skipClient := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	}

	oapiconn := oapi.NewClient(clientConfig, skipClient)

	// Setup the state bag and initial state for the steps
	state := new(multistep.BasicStateBag)
	state.Put("config", &b.config)
	state.Put("oapi", oapiconn)
	state.Put("clientConfig", clientConfig)
	state.Put("hook", hook)
	state.Put("ui", ui)

	steps := []multistep.Step{
		&osccommon.StepPreValidate{
			DestOmiName:     b.config.OMIName,
			ForceDeregister: b.config.OMIForceDeregister,
		},
	}

	b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
	b.runner.Run(state)

	// If there was an error, return that
	if rawErr, ok := state.GetOk("error"); ok {
		return nil, rawErr.(error)
	}

	return nil, nil
}

func (b *Builder) Cancel() {
	if b.runner != nil {
		log.Println("Cancelling the step runner...")
		b.runner.Cancel()
	}
}
<commit_msg>feature: bsu, run implementation add steps before createOMI step<commit_after>// The amazonebs package contains a packer.Builder implementation that
// builds OMIs for Outscale OAPI.
//
// In general, there are two types of OMIs that can be created: ebs-backed or
// instance-store. This builder _only_ builds ebs-backed images.
package bsu

import (
	"crypto/tls"
	"fmt"
	"log"
	"net/http"

	osccommon "github.com/hashicorp/packer/builder/osc/common"
	"github.com/hashicorp/packer/common"
	"github.com/hashicorp/packer/helper/communicator"
	"github.com/hashicorp/packer/helper/config"
	"github.com/hashicorp/packer/helper/multistep"
	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template/interpolate"
	"github.com/outscale/osc-go/oapi"
)

// The unique ID for this builder
const BuilderId = "oapi.outscale.bsu"

type Config struct {
	common.PackerConfig    `mapstructure:",squash"`
	osccommon.AccessConfig `mapstructure:",squash"`
	osccommon.OMIConfig    `mapstructure:",squash"`
	osccommon.BlockDevices `mapstructure:",squash"`
	osccommon.RunConfig    `mapstructure:",squash"`
	VolumeRunTags          osccommon.TagMap `mapstructure:"run_volume_tags"`

	ctx interpolate.Context
}

type Builder struct {
	config Config
	runner multistep.Runner
}

func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
	b.config.ctx.Funcs = osccommon.TemplateFuncs
	err := config.Decode(&b.config, &config.DecodeOpts{
		Interpolate:        true,
		InterpolateContext: &b.config.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"omi_description",
				"run_tags",
				"run_volume_tags",
				"spot_tags",
				"snapshot_tags",
				"tags",
			},
		},
	}, raws...)
	if err != nil {
		return nil, err
	}

	if b.config.PackerConfig.PackerForce {
		b.config.OMIForceDeregister = true
	}

	// Accumulate any errors
	var errs *packer.MultiError
	errs = packer.MultiErrorAppend(errs, b.config.AccessConfig.Prepare(&b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs,
		b.config.OMIConfig.Prepare(&b.config.AccessConfig, &b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs, b.config.BlockDevices.Prepare(&b.config.ctx)...)
	errs = packer.MultiErrorAppend(errs, b.config.RunConfig.Prepare(&b.config.ctx)...)

	if errs != nil && len(errs.Errors) > 0 {
		return nil, errs
	}

	packer.LogSecretFilter.Set(b.config.AccessKey, b.config.SecretKey, b.config.Token)
	return nil, nil
}

func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
	clientConfig, err := b.config.Config()
	if err != nil {
		return nil, err
	}

	skipClient := &http.Client{
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	}

	oapiconn := oapi.NewClient(clientConfig, skipClient)

	// Setup the state bag and initial state for the steps
	state := new(multistep.BasicStateBag)
	state.Put("config", &b.config)
	state.Put("oapi", oapiconn)
	state.Put("clientConfig", clientConfig)
	state.Put("hook", hook)
	state.Put("ui", ui)

	steps := []multistep.Step{
		&osccommon.StepPreValidate{
			DestOmiName:     b.config.OMIName,
			ForceDeregister: b.config.OMIForceDeregister,
		},
		&osccommon.StepSourceOMIInfo{
			SourceOmi:                b.config.SourceOmi,
			EnableOMISriovNetSupport: b.config.OMISriovNetSupport,
			EnableOMIENASupport:      b.config.OMIENASupport,
			OmiFilters:               b.config.SourceOmiFilter,
			OMIVirtType:              b.config.OMIVirtType, //TODO: Remove if it is not used
		},
		&osccommon.StepNetworkInfo{
			NetId:               b.config.NetId,
			NetFilter:           b.config.NetFilter,
			SecurityGroupIds:    b.config.SecurityGroupIds,
			SecurityGroupFilter: b.config.SecurityGroupFilter,
			SubnetId:            b.config.SubnetId,
			SubnetFilter:        b.config.SubnetFilter,
			SubregionName:       b.config.Subregion,
		},
		&osccommon.StepKeyPair{
			Debug:        b.config.PackerDebug,
			Comm:         &b.config.RunConfig.Comm,
			DebugKeyPath: fmt.Sprintf("oapi_%s", b.config.PackerBuildName),
		},
		&osccommon.StepSecurityGroup{
			SecurityGroupFilter:   b.config.SecurityGroupFilter,
			SecurityGroupIds:      b.config.SecurityGroupIds,
			CommConfig:            &b.config.RunConfig.Comm,
			TemporarySGSourceCidr: b.config.TemporarySGSourceCidr,
		},
		&osccommon.StepCleanupVolumes{
			BlockDevices: b.config.BlockDevices,
		},
		&osccommon.StepRunSourceVm{
			AssociatePublicIpAddress:    b.config.AssociatePublicIpAddress,
			BlockDevices:                b.config.BlockDevices,
			Comm:                        &b.config.RunConfig.Comm,
			Ctx:                         b.config.ctx,
			Debug:                       b.config.PackerDebug,
			BsuOptimized:                b.config.BsuOptimized,
			EnableT2Unlimited:           b.config.EnableT2Unlimited,
			ExpectedRootDevice:          "ebs", // should it be bsu
			IamVmProfile:                b.config.IamVmProfile,
			VmInitiatedShutdownBehavior: b.config.VmInitiatedShutdownBehavior,
			VmType:                      b.config.VmType,
			IsRestricted:                false,
			SourceOMI:                   b.config.SourceOmi,
			Tags:                        b.config.RunTags,
			UserData:                    b.config.UserData,
			UserDataFile:                b.config.UserDataFile,
			VolumeTags:                  b.config.VolumeRunTags,
		},
		&osccommon.StepGetPassword{
			Debug:     b.config.PackerDebug,
			Comm:      &b.config.RunConfig.Comm,
			Timeout:   b.config.WindowsPasswordTimeout,
			BuildName: b.config.PackerBuildName,
		},
		&communicator.StepConnect{
			Config: &b.config.RunConfig.Comm,
			Host: osccommon.SSHHost(
				oapiconn,
				b.config.Comm.SSHInterface),
			SSHConfig: b.config.RunConfig.Comm.SSHConfigFunc(),
		},
		&common.StepProvision{},
		&common.StepCleanupTempKeys{
			Comm: &b.config.RunConfig.Comm,
		},
		&osccommon.StepStopBSUBackedVm{
			Skip:          false,
			DisableStopVm: b.config.DisableStopVm,
		},
		&osccommon.StepUpdateBSUBackedVm{
			EnableAMISriovNetSupport: b.config.OMISriovNetSupport,
			EnableAMIENASupport:      b.config.OMIENASupport,
		},
		&osccommon.StepDeregisterOMI{
			AccessConfig:        &b.config.AccessConfig,
			ForceDeregister:     b.config.OMIForceDeregister,
			ForceDeleteSnapshot: b.config.OMIForceDeleteSnapshot,
			OMIName:             b.config.OMIName,
			Regions:             b.config.OMIRegions,
		},
	}

	b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
	b.runner.Run(state)

	// If there was an error, return that
	if rawErr, ok := state.GetOk("error"); ok {
		return nil, rawErr.(error)
	}

	return nil, nil
}

func (b *Builder) Cancel() {
	if b.runner != nil {
		log.Println("Cancelling the step runner...")
		b.runner.Cancel()
	}
}
<|endoftext|>


<commit_before>package main

const Version = "0.1.2"
<commit_msg>feat(version): bumo<commit_after>package main

const Version = "0.1.3"
<|endoftext|>


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

package libsacloud

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

package libsacloud

// Version バージョン
const Version = "2.1.6"
<|endoftext|>


<commit_before>package main

import "github.com/tsaikd/KDGoLib/version"

func init() {
	version.VERSION = "1.0.1"
}
<commit_msg>1.0.2<commit_after>package main

import "github.com/tsaikd/KDGoLib/version"

func init() {
	version.VERSION = "1.0.2"
}
<|endoftext|>


<commit_before>package superast

import (
	"go/ast"
	"go/token"
	"log"
	"strconv"
	"strings"
)

const (
	Default = iota
	IfBody
	IfElse
	FuncBody
)

type AST struct {
	curID      int
	RootBlock  *block
	nodeStack  []ast.Node
	stmtsStack []*[]stmt
	fset       *token.FileSet
	pos        token.Pos
}

func NewAST(fset *token.FileSet) *AST {
	a := &AST{
		fset: fset,
	}
	a.RootBlock = &block{
		id:    a.newID(),
		Stmts: make([]stmt, 0),
	}
	a.pushStmts(&a.RootBlock.Stmts)
	return a
}

func (a *AST) newID() id {
	i := a.curID
	a.curID++
	return id{ID: i}
}

func (a *AST) newPos(p token.Pos) pos {
	position := a.fset.Position(p)
	return pos{Line: position.Line, Col: position.Column}
}

func (a *AST) nodePos(n ast.Node) pos {
	return a.newPos(n.Pos())
}

func (a *AST) curPos() pos {
	return a.newPos(a.pos)
}

func (a *AST) pushNode(node ast.Node) {
	a.nodeStack = append(a.nodeStack, node)
}

func (a *AST) curNode() ast.Node {
	return a.nodeStack[len(a.nodeStack)-1]
}

func (a *AST) popNode() {
	a.nodeStack = a.nodeStack[:len(a.nodeStack)-1]
}

func (a *AST) pushStmts(stmts *[]stmt) {
	a.stmtsStack = append(a.stmtsStack, stmts)
}

func (a *AST) curStmts() *[]stmt {
	return a.stmtsStack[len(a.stmtsStack)-1]
}

func (a *AST) addStmt(s stmt) {
	curStmts := a.curStmts()
	*curStmts = append(*curStmts, s)
}

func (a *AST) popStmts() {
	a.stmtsStack = a.stmtsStack[:len(a.stmtsStack)-1]
}

func exprString(x ast.Expr) string {
	switch t := x.(type) {
	case *ast.Ident:
		return t.Name
	case *ast.BasicLit:
		return t.Value
	case *ast.SelectorExpr:
		return exprString(t.X) + "." + t.Sel.Name
	case *ast.StarExpr:
		return exprString(t.X)
	}
	return ""
}

func exprValue(x ast.Expr) value {
	switch t := x.(type) {
	case *ast.BasicLit:
		switch t.Kind {
		case token.INT:
			i, _ := strconv.ParseInt(t.Value, 10, 0)
			return i
		case token.FLOAT:
			f, _ := strconv.ParseFloat(t.Value, 64)
			return f
		case token.CHAR:
			r, _, _, _ := strconv.UnquoteChar(t.Value, '\'')
			return r
		case token.STRING:
			s, _ := strconv.Unquote(t.Value)
			return s
		}
		return t.Value
	}
	return nil
}

func exprType(x ast.Expr) *dataType {
	if s := exprString(x); s != "" {
		return &dataType{
			Name: s,
		}
	}
	switch t := x.(type) {
	case *ast.ArrayType:
		return &dataType{
			Name:    "vector",
			SubType: exprType(t.Elt),
		}
	}
	return nil
}

type namedType struct {
	vName string
	dType *dataType
	node  ast.Node
}

func flattenNames(baseType ast.Expr, names []*ast.Ident) []namedType {
	t := exprType(baseType)
	if len(names) == 0 {
		return []namedType{
			{vName: "", dType: t},
		}
	}
	var types []namedType
	for _, n := range names {
		types = append(types, namedType{
			vName: n.Name,
			dType: t,
			node:  n,
		})
	}
	return types
}

func flattenFieldList(fieldList *ast.FieldList) []namedType {
	if fieldList == nil {
		return nil
	}
	var types []namedType
	for _, f := range fieldList.List {
		for _, t := range flattenNames(f.Type, f.Names) {
			types = append(types, t)
		}
	}
	return types
}

var basicLitName = map[token.Token]string{
	token.INT:    "int",
	token.FLOAT:  "double",
	token.CHAR:   "char",
	token.STRING: "string",
}

var zeroValues = map[string]value{
	"int":    new(int),
	"double": new(float64),
	"char":   new(rune),
	"string": new(string),
}

func (a *AST) parseExpr(expr ast.Expr) expr {
	switch x := expr.(type) {
	case *ast.Ident:
		return &identifier{
			id:    a.newID(),
			pos:   a.nodePos(x),
			Type:  "identifier",
			Value: x.Name,
		}
	case *ast.BasicLit:
		lType, _ := basicLitName[x.Kind]
		return &identifier{
			id:    a.newID(),
			pos:   a.nodePos(x),
			Type:  lType,
			Value: exprValue(x),
		}
	case *ast.UnaryExpr:
		return &unary{
			id:   a.newID(),
			pos:  a.nodePos(x),
			Type: x.Op.String(),
			Expr: a.parseExpr(x.X),
		}
	case *ast.CallExpr:
		call := &funcCall{
			id:   a.newID(),
			pos:  a.nodePos(x),
			Type: "function-call",
			Name: exprString(x.Fun),
		}
		for _, e := range x.Args {
			call.Args = append(call.Args, a.parseExpr(e))
		}
		return call
	case *ast.BinaryExpr:
		return &binary{
			id:    a.newID(),
			pos:   a.nodePos(x),
			Type:  x.Op.String(),
			Left:  a.parseExpr(x.X),
			Right: a.parseExpr(x.Y),
		}
	case *ast.ParenExpr:
		return a.parseExpr(x.X)
	default:
		log.Printf("Unknown expression: %#v", x)
	}
	return nil
}

func (a *AST) assignIdToDataType(dType *dataType) *dataType {
	if dType == nil {
		return nil
	}
	dTypeCopy := *dType
	dTypeCopy.id = a.newID()
	if dTypeCopy.SubType != nil {
		dTypeCopy.SubType = a.assignIdToDataType(dTypeCopy.SubType)
	}
	return &dTypeCopy
}

func (a *AST) Visit(node ast.Node) ast.Visitor {
	if node == nil {
		switch a.curNode().(type) {
		case *ast.BlockStmt:
			a.popStmts()
		}
		a.popNode()
		return nil
	}
	a.pos = node.Pos()
	log.Printf("%s%#v", strings.Repeat("  ", len(a.nodeStack)), node)
	switch x := node.(type) {
	case *ast.TypeSpec:
		n := ""
		if x.Name != nil {
			n = exprString(x.Name)
		}
		switch t := x.Type.(type) {
		case *ast.StructType:
			decl := &structDecl{
				id:   a.newID(),
				pos:  a.curPos(),
				Type: "struct-declaration",
				Name: n,
			}
			for _, f := range flattenFieldList(t.Fields) {
				attr := varDecl{
					id:       a.newID(),
					pos:      a.curPos(),
					Type:     "variable-declaration",
					Name:     f.vName,
					DataType: a.assignIdToDataType(f.dType),
				}
				decl.Attrs = append(decl.Attrs, attr)
			}
			a.addStmt(decl)
		}
		return nil
	case *ast.BasicLit:
		lit := a.parseExpr(x)
		a.addStmt(lit)
		return nil
	case *ast.UnaryExpr:
		unary := a.parseExpr(x)
		a.addStmt(unary)
		return nil
	case *ast.CallExpr:
		call := a.parseExpr(x)
		a.addStmt(call)
		return nil
	case *ast.FuncDecl:
		name := x.Name.Name
		var retType *dataType
		results := flattenFieldList(x.Type.Results)
		switch len(results) {
		case 1:
			retType = results[0].dType
		}
		fn := &funcDecl{
			id:      a.newID(),
			pos:     a.nodePos(x),
			Type:    "function-declaration",
			Name:    name,
			RetType: a.assignIdToDataType(retType),
			Block: &block{
				id:    a.newID(),
				Stmts: make([]stmt, 0),
			},
		}
		for _, f := range flattenFieldList(x.Type.Params) {
			param := varDecl{
				id:       a.newID(),
				pos:      a.nodePos(f.node),
				Type:     "variable-declaration",
				Name:     f.vName,
				DataType: a.assignIdToDataType(f.dType),
			}
			fn.Params = append(fn.Params, param)
		}
		a.addStmt(fn)
		a.pushStmts(&fn.Block.Stmts)
	case *ast.DeclStmt:
		gd, _ := x.Decl.(*ast.GenDecl)
		for _, spec := range gd.Specs {
			s, ok := spec.(*ast.ValueSpec)
			if !ok {
				continue
			}
			for i, t := range flattenNames(s.Type, s.Names) {
				vType := t.dType.Name
				v, _ := zeroValues[vType]
				if s.Values != nil {
					v = exprValue(s.Values[i])
				}
				decl := &varDecl{
					id:       a.newID(),
					pos:      a.curPos(),
					Type:     "variable-declaration",
					Name:     t.vName,
					DataType: a.assignIdToDataType(t.dType),
					Init: &identifier{
						id:    a.newID(),
						pos:   a.curPos(),
						Type:  vType,
						Value: v,
					},
				}
				a.addStmt(decl)
			}
		}
		return nil
	case *ast.AssignStmt:
		for i, l := range x.Lhs {
			r := x.Rhs[i]
			var t string
			switch rx := r.(type) {
			case *ast.BasicLit:
				t, _ = basicLitName[rx.Kind]
			case *ast.CompositeLit:
				t = exprString(rx.Type)
			}
			var s stmt
			if x.Tok == token.DEFINE {
				s = &varDecl{
					id:   a.newID(),
					pos:  a.curPos(),
					Type: "variable-declaration",
					Name: exprString(l),
					DataType: &dataType{
						id:   a.newID(),
						Name: t,
					},
					Init: a.parseExpr(r),
				}
			} else {
				s = &binary{
					id:    a.newID(),
					pos:   a.curPos(),
					Type:  x.Tok.String(),
					Left:  a.parseExpr(l),
					Right: a.parseExpr(r),
				}
			}
			a.addStmt(s)
		}
		return nil
	case *ast.ReturnStmt:
		ret := &retStmt{
			id:   a.newID(),
			pos:  a.nodePos(x),
			Type: "return",
		}
		if len(x.Results) > 0 {
			ret.Expr = a.parseExpr(x.Results[0])
		}
		a.addStmt(ret)
		return nil
	case *ast.IfStmt:
		cond := &conditional{
			id:   a.newID(),
			pos:  a.nodePos(x),
			Type: "conditional",
			Cond: a.parseExpr(x.Cond),
			Then: &block{
				id:    a.newID(),
				Stmts: make([]stmt, 0),
			},
		}
		a.addStmt(cond)
		if x.Else != nil {
			cond.Else = &block{
				id:    a.newID(),
				Stmts: make([]stmt, 0),
			}
			a.pushStmts(&cond.Else.Stmts)
			a.pushNode(node)
		}
		a.pushStmts(&cond.Then.Stmts)
	case *ast.File:
	case *ast.BlockStmt:
	case *ast.ExprStmt:
	case *ast.GenDecl:
	default:
		return nil
	}
	a.pushNode(node)
	return a
}
<commit_msg>Simplify var naming<commit_after>package superast

import (
	"go/ast"
	"go/token"
	"log"
	"strconv"
	"strings"
)

const (
	Default = iota
	IfBody
	IfElse
	FuncBody
)

type AST struct {
	curID      int
	RootBlock  *block
	nodeStack  []ast.Node
	stmtsStack []*[]stmt
	fset       *token.FileSet
	pos        token.Pos
}

func NewAST(fset *token.FileSet) *AST {
	a := &AST{
		fset: fset,
	}
	a.RootBlock = &block{
		id:    a.newID(),
		Stmts: make([]stmt, 0),
	}
	a.pushStmts(&a.RootBlock.Stmts)
	return a
}

func (a *AST) newID() id {
	i := a.curID
	a.curID++
	return id{ID: i}
}

func (a *AST) newPos(p token.Pos) pos {
	position := a.fset.Position(p)
	return pos{Line: position.Line, Col: position.Column}
}

func (a *AST) nodePos(n ast.Node) pos {
	return a.newPos(n.Pos())
}

func (a *AST) curPos() pos {
	return a.newPos(a.pos)
}

func (a *AST) pushNode(node ast.Node) {
	a.nodeStack = append(a.nodeStack, node)
}

func (a *AST) curNode() ast.Node {
	return a.nodeStack[len(a.nodeStack)-1]
}

func (a *AST) popNode() {
	a.nodeStack = a.nodeStack[:len(a.nodeStack)-1]
}

func (a *AST) pushStmts(stmts *[]stmt) {
	a.stmtsStack = append(a.stmtsStack, stmts)
}

func (a *AST) curStmts() *[]stmt {
	return a.stmtsStack[len(a.stmtsStack)-1]
}

func (a *AST) addStmt(s stmt) {
	curStmts := a.curStmts()
	*curStmts = append(*curStmts, s)
}

func (a *AST) popStmts() {
	a.stmtsStack = a.stmtsStack[:len(a.stmtsStack)-1]
}

func exprString(x ast.Expr) string {
	switch t := x.(type) {
	case *ast.Ident:
		return t.Name
	case *ast.BasicLit:
		return t.Value
	case *ast.SelectorExpr:
		return exprString(t.X) + "." + t.Sel.Name
	case *ast.StarExpr:
		return exprString(t.X)
	}
	return ""
}

func exprValue(x ast.Expr) value {
	switch t := x.(type) {
	case *ast.BasicLit:
		switch t.Kind {
		case token.INT:
			i, _ := strconv.ParseInt(t.Value, 10, 0)
			return i
		case token.FLOAT:
			f, _ := strconv.ParseFloat(t.Value, 64)
			return f
		case token.CHAR:
			r, _, _, _ := strconv.UnquoteChar(t.Value, '\'')
			return r
		case token.STRING:
			s, _ := strconv.Unquote(t.Value)
			return s
		}
		return t.Value
	}
	return nil
}

func exprType(x ast.Expr) *dataType {
	if s := exprString(x); s != "" {
		return &dataType{
			Name: s,
		}
	}
	switch t := x.(type) {
	case *ast.ArrayType:
		return &dataType{
			Name:    "vector",
			SubType: exprType(t.Elt),
		}
	}
	return nil
}

type namedType struct {
	vName string
	dType *dataType
	node  ast.Node
}

func flattenNames(baseType ast.Expr, names []*ast.Ident) []namedType {
	t := exprType(baseType)
	if len(names) == 0 {
		return []namedType{
			{vName: "", dType: t},
		}
	}
	var types []namedType
	for _, n := range names {
		types = append(types, namedType{
			vName: n.Name,
			dType: t,
			node:  n,
		})
	}
	return types
}

func flattenFieldList(fieldList *ast.FieldList) []namedType {
	if fieldList == nil {
		return nil
	}
	var types []namedType
	for _, f := range fieldList.List {
		for _, t := range flattenNames(f.Type, f.Names) {
			types = append(types, t)
		}
	}
	return types
}

var basicLitName = map[token.Token]string{
	token.INT:    "int",
	token.FLOAT:  "double",
	token.CHAR:   "char",
	token.STRING: "string",
}

var zeroValues = map[string]value{
	"int":    new(int),
	"double": new(float64),
	"char":   new(rune),
	"string": new(string),
}

func (a *AST) parseExpr(expr ast.Expr) expr {
	switch x := expr.(type) {
	case *ast.Ident:
		return &identifier{
			id:    a.newID(),
			pos:   a.nodePos(x),
			Type:  "identifier",
			Value: x.Name,
		}
	case *ast.BasicLit:
		lType, _ := basicLitName[x.Kind]
		return &identifier{
			id:    a.newID(),
			pos:   a.nodePos(x),
			Type:  lType,
			Value: exprValue(x),
		}
	case *ast.UnaryExpr:
		return &unary{
			id:   a.newID(),
			pos:  a.nodePos(x),
			Type: x.Op.String(),
			Expr: a.parseExpr(x.X),
		}
	case *ast.CallExpr:
		call := &funcCall{
			id:   a.newID(),
			pos:  a.nodePos(x),
			Type: "function-call",
			Name: exprString(x.Fun),
		}
		for _, e := range x.Args {
			call.Args = append(call.Args, a.parseExpr(e))
		}
		return call
	case *ast.BinaryExpr:
		return &binary{
			id:    a.newID(),
			pos:   a.nodePos(x),
			Type:  x.Op.String(),
			Left:  a.parseExpr(x.X),
			Right: a.parseExpr(x.Y),
		}
	case *ast.ParenExpr:
		return a.parseExpr(x.X)
	default:
		log.Printf("Unknown expression: %#v", x)
	}
	return nil
}

func (a *AST) assignIdToDataType(dType *dataType) *dataType {
	if dType == nil {
		return nil
	}
	dTypeCopy := *dType
	dTypeCopy.id = a.newID()
	if dTypeCopy.SubType != nil {
		dTypeCopy.SubType = a.assignIdToDataType(dTypeCopy.SubType)
	}
	return &dTypeCopy
}

func (a *AST) Visit(node ast.Node) ast.Visitor {
	if node == nil {
		switch a.curNode().(type) {
		case *ast.BlockStmt:
			a.popStmts()
		}
		a.popNode()
		return nil
	}
	a.pos = node.Pos()
	log.Printf("%s%#v", strings.Repeat("  ", len(a.nodeStack)), node)
	switch x := node.(type) {
	case *ast.TypeSpec:
		n := ""
		if x.Name != nil {
			n = exprString(x.Name)
		}
		switch t := x.Type.(type) {
		case *ast.StructType:
			d := &structDecl{
				id:   a.newID(),
				pos:  a.curPos(),
				Type: "struct-declaration",
				Name: n,
			}
			for _, f := range flattenFieldList(t.Fields) {
				attr := varDecl{
					id:       a.newID(),
					pos:      a.curPos(),
					Type:     "variable-declaration",
					Name:     f.vName,
					DataType: a.assignIdToDataType(f.dType),
				}
				d.Attrs = append(d.Attrs, attr)
			}
			a.addStmt(d)
		}
		return nil
	case *ast.BasicLit:
		l := a.parseExpr(x)
		a.addStmt(l)
		return nil
	case *ast.UnaryExpr:
		u := a.parseExpr(x)
		a.addStmt(u)
		return nil
	case *ast.CallExpr:
		c := a.parseExpr(x)
		a.addStmt(c)
		return nil
	case *ast.FuncDecl:
		name := x.Name.Name
		var retType *dataType
		results := flattenFieldList(x.Type.Results)
		switch len(results) {
		case 1:
			retType = results[0].dType
		}
		d := &funcDecl{
			id:      a.newID(),
			pos:     a.nodePos(x),
			Type:    "function-declaration",
			Name:    name,
			RetType: a.assignIdToDataType(retType),
			Block: &block{
				id:    a.newID(),
				Stmts: make([]stmt, 0),
			},
		}
		for _, f := range flattenFieldList(x.Type.Params) {
			param := varDecl{
				id:       a.newID(),
				pos:      a.nodePos(f.node),
				Type:     "variable-declaration",
				Name:     f.vName,
				DataType: a.assignIdToDataType(f.dType),
			}
			d.Params = append(d.Params, param)
		}
		a.addStmt(d)
		a.pushStmts(&d.Block.Stmts)
	case *ast.DeclStmt:
		gd, _ := x.Decl.(*ast.GenDecl)
		for _, spec := range gd.Specs {
			s, ok := spec.(*ast.ValueSpec)
			if !ok {
				continue
			}
			for i, t := range flattenNames(s.Type, s.Names) {
				vType := t.dType.Name
				v, _ := zeroValues[vType]
				if s.Values != nil {
					v = exprValue(s.Values[i])
				}
				d := &varDecl{
					id:       a.newID(),
					pos:      a.curPos(),
					Type:     "variable-declaration",
					Name:     t.vName,
					DataType: a.assignIdToDataType(t.dType),
					Init: &identifier{
						id:    a.newID(),
						pos:   a.curPos(),
						Type:  vType,
						Value: v,
					},
				}
				a.addStmt(d)
			}
		}
		return nil
	case *ast.AssignStmt:
		for i, l := range x.Lhs {
			r := x.Rhs[i]
			var t string
			switch rx := r.(type) {
			case *ast.BasicLit:
				t, _ = basicLitName[rx.Kind]
			case *ast.CompositeLit:
				t = exprString(rx.Type)
			}
			var s stmt
			if x.Tok == token.DEFINE {
				s = &varDecl{
					id:   a.newID(),
					pos:  a.curPos(),
					Type: "variable-declaration",
					Name: exprString(l),
					DataType: &dataType{
						id:   a.newID(),
						Name: t,
					},
					Init: a.parseExpr(r),
				}
			} else {
				s = &binary{
					id:    a.newID(),
					pos:   a.curPos(),
					Type:  x.Tok.String(),
					Left:  a.parseExpr(l),
					Right: a.parseExpr(r),
				}
			}
			a.addStmt(s)
		}
		return nil
	case *ast.ReturnStmt:
		r := &retStmt{
			id:   a.newID(),
			pos:  a.nodePos(x),
			Type: "return",
		}
		if len(x.Results) > 0 {
			r.Expr = a.parseExpr(x.Results[0])
		}
		a.addStmt(r)
		return nil
	case *ast.IfStmt:
		c := &conditional{
			id:   a.newID(),
			pos:  a.nodePos(x),
			Type: "conditional",
			Cond: a.parseExpr(x.Cond),
			Then: &block{
				id:    a.newID(),
				Stmts: make([]stmt, 0),
			},
		}
		a.addStmt(c)
		if x.Else != nil {
			c.Else = &block{
				id:    a.newID(),
				Stmts: make([]stmt, 0),
			}
			a.pushStmts(&c.Else.Stmts)
			a.pushNode(node)
		}
		a.pushStmts(&c.Then.Stmts)
	case *ast.File:
	case *ast.BlockStmt:
	case *ast.ExprStmt:
	case *ast.GenDecl:
	default:
		return nil
	}
	a.pushNode(node)
	return a
}
<|endoftext|>


<commit_before>// Package youtube provides loading audio from video files for given youtube channels
package youtube

import (
	"context"
	"encoding/xml"
	"os"
	"path"
	"time"

	log "github.com/go-pkgz/lgr"
	"github.com/google/uuid"
	"github.com/pkg/errors"

	"github.com/umputun/feed-master/app/feed"
	"github.com/umputun/feed-master/app/youtube/channel"
)

//go:generate moq -out mocks/downloader.go -pkg mocks -skip-ensure -fmt goimports . DownloaderService
//go:generate moq -out mocks/channel.go -pkg mocks -skip-ensure -fmt goimports . ChannelService
//go:generate moq -out mocks/store.go -pkg mocks -skip-ensure -fmt goimports . StoreService

// Service loads audio from youtube channels
type Service struct {
	Channels       []ChannelInfo
	Downloader     DownloaderService
	ChannelService ChannelService
	Store          StoreService
	CheckDuration  time.Duration
	RSSFileStore   RSSFileStore
	KeepPerChannel int
	RootURL        string
}

// ChannelInfo is a pait of channel ID and name
type ChannelInfo struct {
	Name string
	ID   string
}

// DownloaderService is an interface for downloading audio from youtube
type DownloaderService interface {
	Get(ctx context.Context, id string, fname string) (file string, err error)
}

// ChannelService is an interface for getting channel entries, i.e. the list of videos
type ChannelService interface {
	Get(ctx context.Context, chanID string) ([]channel.Entry, error)
}

// StoreService is an interface for storing and loading metadata about downloaded audio
type StoreService interface {
	Save(entry channel.Entry) (bool, error)
	Load(channelID string, max int) ([]channel.Entry, error)
	Exist(entry channel.Entry) (bool, error)
	RemoveOld(channelID string, keep int) ([]string, error)
}

// Do is a blocking function that downloads audio from youtube channels and updates metadata
func (s *Service) Do(ctx context.Context) error {
	log.Printf("[INFO] Starting youtube service")
	tick := time.NewTicker(s.CheckDuration)
	defer tick.Stop()

	if err := s.procChannels(ctx); err != nil {
		return errors.Wrap(err, "failed to process channels")
	}

	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-tick.C:
			if err := s.procChannels(ctx); err != nil {
				return errors.Wrap(err, "failed to process channels")
			}
		}
	}
}

// RSSFeed generates RSS feed for given channel
func (s *Service) RSSFeed(cinfo ChannelInfo) (string, error) {
	entries, err := s.Store.Load(cinfo.ID, s.KeepPerChannel)
	if err != nil {
		return "", errors.Wrap(err, "failed to get channel entries")
	}

	if len(entries) == 0 {
		return "", nil
	}

	items := []feed.Item{}
	for _, entry := range entries {

		fileURL := s.RootURL + "/" + path.Base(entry.File)

		var fileSize int
		if fileInfo, fiErr := os.Stat(entry.File); fiErr != nil {
			log.Printf("[WARN] failed to get file size for %s: %v", entry.File, fiErr)
		} else {
			fileSize = int(fileInfo.Size())
		}

		items = append(items, feed.Item{
			Title:       entry.Title,
			Description: entry.Media.Description,
			Link:        entry.Link.Href,
			PubDate:     entry.Published.Format(time.RFC822Z),
			GUID:        entry.ChannelID + "::" + entry.VideoID,
			Author:      entry.Author.Name,
			Enclosure: feed.Enclosure{
				URL:    fileURL,
				Type:   "audio/mpeg",
				Length: fileSize,
			},
			DT: time.Now(),
		})
	}

	rss := feed.Rss2{
		Version:       "2.0",
		ItemList:      items,
		Title:         entries[0].Author.Name,
		Description:   "generated by feed-master",
		Link:          entries[0].Author.URI,
		PubDate:       items[0].PubDate,
		LastBuildDate: time.Now().Format(time.RFC822Z),
	}

	b, err := xml.MarshalIndent(&rss, "", "  ")
	if err != nil {
		return "", errors.Wrap(err, "failed to marshal rss")
	}

	return string(b), nil
}

func (s *Service) procChannels(ctx context.Context) error {
	for _, chanInfo := range s.Channels {
		entries, err := s.ChannelService.Get(ctx, chanInfo.ID)
		if err != nil {
			log.Printf("[WARN] failed to get channel entries for %s: %s", chanInfo.ID, err)
			continue
		}
		log.Printf("[INFO] got %d entries for %s, limit to %d", len(entries), chanInfo.Name, s.KeepPerChannel)
		changed := false
		for i, entry := range entries {
			if i >= s.KeepPerChannel {
				break
			}
			exists, exErr := s.Store.Exist(entry)
			if err != nil {
				return errors.Wrapf(exErr, "failed to check if entry %s exists", entry.VideoID)
			}
			if exists {
				continue
			}
			log.Printf("[INFO] new entry %s, %s, %s", entry.VideoID, entry.Title, chanInfo.Name)
			file, downErr := s.Downloader.Get(ctx, entry.VideoID, uuid.New().String())
			if downErr != nil {
				log.Printf("[WARN] failed to download %s: %s", entry.VideoID, downErr)
				continue
			}
			log.Printf("[DEBUG] downloaded %s (%s) to %s, channel: %+v", entry.VideoID, entry.Title, file, chanInfo)
			entry.File = file
			ok, saveErr := s.Store.Save(entry)
			if saveErr != nil {
				return errors.Wrapf(saveErr, "failed to save entry %+v", entry)
			}
			if !ok {
				log.Printf("[WARN] attempt to save dup entry %+v", entry)
			}
			changed = true
			log.Printf("[INFO] saved %s (%s) to %s, channel: %+v", entry.VideoID, entry.Title, file, chanInfo)
		}

		if changed { // save rss feed to fs if there are new entries
			rss, rssErr := s.RSSFeed(chanInfo)
			if rssErr != nil {
				log.Printf("[WARN] failed to generate rss for %s: %s", chanInfo.Name, rssErr)
			} else {
				if err := s.RSSFileStore.Save(chanInfo.ID, rss); err != nil {
					log.Printf("[WARN] failed to save rss for %s: %s", chanInfo.Name, err)
				}
			}
		}

		// remove old entries and files
		files, rmErr := s.Store.RemoveOld(chanInfo.ID, s.KeepPerChannel)
		if rmErr != nil {
			return errors.Wrapf(rmErr, "failed to remove old meta data for %s", chanInfo.ID)
		}
		for _, f := range files {
			if e := os.Remove(f); e != nil {
				log.Printf("[WARN] failed to remove file %s: %s", f, e)
				continue
			}
			log.Printf("[INFO] removed %s for %s (%s)", f, chanInfo.ID, chanInfo.Name)
		}
	}
	log.Printf("[DEBUG] processed channels completed, total %d", len(s.Channels))
	return nil
}
<commit_msg>keep extra episode<commit_after>// Package youtube provides loading audio from video files for given youtube channels
package youtube

import (
	"context"
	"encoding/xml"
	"os"
	"path"
	"time"

	log "github.com/go-pkgz/lgr"
	"github.com/google/uuid"
	"github.com/pkg/errors"

	"github.com/umputun/feed-master/app/feed"
	"github.com/umputun/feed-master/app/youtube/channel"
)

//go:generate moq -out mocks/downloader.go -pkg mocks -skip-ensure -fmt goimports . DownloaderService
//go:generate moq -out mocks/channel.go -pkg mocks -skip-ensure -fmt goimports . ChannelService
//go:generate moq -out mocks/store.go -pkg mocks -skip-ensure -fmt goimports . StoreService

// Service loads audio from youtube channels
type Service struct {
	Channels       []ChannelInfo
	Downloader     DownloaderService
	ChannelService ChannelService
	Store          StoreService
	CheckDuration  time.Duration
	RSSFileStore   RSSFileStore
	KeepPerChannel int
	RootURL        string
}

// ChannelInfo is a pait of channel ID and name
type ChannelInfo struct {
	Name string
	ID   string
}

// DownloaderService is an interface for downloading audio from youtube
type DownloaderService interface {
	Get(ctx context.Context, id string, fname string) (file string, err error)
}

// ChannelService is an interface for getting channel entries, i.e. the list of videos
type ChannelService interface {
	Get(ctx context.Context, chanID string) ([]channel.Entry, error)
}

// StoreService is an interface for storing and loading metadata about downloaded audio
type StoreService interface {
	Save(entry channel.Entry) (bool, error)
	Load(channelID string, max int) ([]channel.Entry, error)
	Exist(entry channel.Entry) (bool, error)
	RemoveOld(channelID string, keep int) ([]string, error)
}

// Do is a blocking function that downloads audio from youtube channels and updates metadata
func (s *Service) Do(ctx context.Context) error {
	log.Printf("[INFO] Starting youtube service")
	tick := time.NewTicker(s.CheckDuration)
	defer tick.Stop()

	if err := s.procChannels(ctx); err != nil {
		return errors.Wrap(err, "failed to process channels")
	}

	for {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-tick.C:
			if err := s.procChannels(ctx); err != nil {
				return errors.Wrap(err, "failed to process channels")
			}
		}
	}
}

// RSSFeed generates RSS feed for given channel
func (s *Service) RSSFeed(cinfo ChannelInfo) (string, error) {
	entries, err := s.Store.Load(cinfo.ID, s.KeepPerChannel)
	if err != nil {
		return "", errors.Wrap(err, "failed to get channel entries")
	}

	if len(entries) == 0 {
		return "", nil
	}

	items := []feed.Item{}
	for _, entry := range entries {

		fileURL := s.RootURL + "/" + path.Base(entry.File)

		var fileSize int
		if fileInfo, fiErr := os.Stat(entry.File); fiErr != nil {
			log.Printf("[WARN] failed to get file size for %s: %v", entry.File, fiErr)
		} else {
			fileSize = int(fileInfo.Size())
		}

		items = append(items, feed.Item{
			Title:       entry.Title,
			Description: entry.Media.Description,
			Link:        entry.Link.Href,
			PubDate:     entry.Published.Format(time.RFC822Z),
			GUID:        entry.ChannelID + "::" + entry.VideoID,
			Author:      entry.Author.Name,
			Enclosure: feed.Enclosure{
				URL:    fileURL,
				Type:   "audio/mpeg",
				Length: fileSize,
			},
			DT: time.Now(),
		})
	}

	rss := feed.Rss2{
		Version:       "2.0",
		ItemList:      items,
		Title:         entries[0].Author.Name,
		Description:   "generated by feed-master",
		Link:          entries[0].Author.URI,
		PubDate:       items[0].PubDate,
		LastBuildDate: time.Now().Format(time.RFC822Z),
	}

	b, err := xml.MarshalIndent(&rss, "", "  ")
	if err != nil {
		return "", errors.Wrap(err, "failed to marshal rss")
	}

	return string(b), nil
}

func (s *Service) procChannels(ctx context.Context) error {
	for _, chanInfo := range s.Channels {
		entries, err := s.ChannelService.Get(ctx, chanInfo.ID)
		if err != nil {
			log.Printf("[WARN] failed to get channel entries for %s: %s", chanInfo.ID, err)
			continue
		}
		log.Printf("[INFO] got %d entries for %s, limit to %d", len(entries), chanInfo.Name, s.KeepPerChannel)
		changed := false
		for i, entry := range entries {
			if i >= s.KeepPerChannel {
				break
			}
			exists, exErr := s.Store.Exist(entry)
			if err != nil {
				return errors.Wrapf(exErr, "failed to check if entry %s exists", entry.VideoID)
			}
			if exists {
				continue
			}
			log.Printf("[INFO] new entry %s, %s, %s", entry.VideoID, entry.Title, chanInfo.Name)
			file, downErr := s.Downloader.Get(ctx, entry.VideoID, uuid.New().String())
			if downErr != nil {
				log.Printf("[WARN] failed to download %s: %s", entry.VideoID, downErr)
				continue
			}
			log.Printf("[DEBUG] downloaded %s (%s) to %s, channel: %+v", entry.VideoID, entry.Title, file, chanInfo)
			entry.File = file
			ok, saveErr := s.Store.Save(entry)
			if saveErr != nil {
				return errors.Wrapf(saveErr, "failed to save entry %+v", entry)
			}
			if !ok {
				log.Printf("[WARN] attempt to save dup entry %+v", entry)
			}
			changed = true
			log.Printf("[INFO] saved %s (%s) to %s, channel: %+v", entry.VideoID, entry.Title, file, chanInfo)
		}

		if changed { // save rss feed to fs if there are new entries
			rss, rssErr := s.RSSFeed(chanInfo)
			if rssErr != nil {
				log.Printf("[WARN] failed to generate rss for %s: %s", chanInfo.Name, rssErr)
			} else {
				if err := s.RSSFileStore.Save(chanInfo.ID, rss); err != nil {
					log.Printf("[WARN] failed to save rss for %s: %s", chanInfo.Name, err)
				}
			}
		}

		// remove old entries and files
		files, rmErr := s.Store.RemoveOld(chanInfo.ID, s.KeepPerChannel+1)
		if rmErr != nil {
			return errors.Wrapf(rmErr, "failed to remove old meta data for %s", chanInfo.ID)
		}
		for _, f := range files {
			if e := os.Remove(f); e != nil {
				log.Printf("[WARN] failed to remove file %s: %s", f, e)
				continue
			}
			log.Printf("[INFO] removed %s for %s (%s)", f, chanInfo.ID, chanInfo.Name)
		}
	}
	log.Printf("[DEBUG] processed channels completed, total %d", len(s.Channels))
	return nil
}
<|endoftext|>


<commit_before><commit_msg>added some simple rest server<commit_after><|endoftext|>


<commit_before>package db

import (
	"fmt"

	"github.com/jinzhu/gorm"
	"github.com/chaosxu/nerv/lib/model"
)

// Define callbacks for deleting,support cascade deleting
func init() {
	gorm.DefaultCallback.Delete().Replace("gorm:begin_transaction", beginTransactionCallback)
	gorm.DefaultCallback.Delete().Replace("gorm:before_delete", beforeDeleteCallback)
	gorm.DefaultCallback.Delete().After("gorm:before_delete").Replace("chaosxu:before_delete_associations", beforeDeleteAssociationsCallback)
	gorm.DefaultCallback.Delete().Replace("gorm:delete", deleteCallback)
	//gorm.DefaultCallback.Delete().After("gorm:delete").Replace("chaosxu:after_delete_associations", afterDeleteAssociationsCallback)
	gorm.DefaultCallback.Delete().Replace("gorm:after_delete", afterDeleteCallback)
	gorm.DefaultCallback.Delete().Replace("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback)
}

func beginTransactionCallback(scope *gorm.Scope) {
	scope.Begin()
}

// beforeDeleteCallback will invoke `BeforeDelete` method before deleting
func beforeDeleteCallback(scope *gorm.Scope) {
	if !scope.HasError() {
		scope.CallMethod("BeforeDelete")
	}
}

// deleteCallback used to delete data from database or set deleted_at to current time (when using with soft delete)
func deleteCallback(scope *gorm.Scope) {
	logCodeLine()

	if !scope.HasError() {
		var extraOption string
		if str, ok := scope.Get("gorm:delete_option"); ok {
			extraOption = fmt.Sprint(str)
		}

		if !scope.Search.Unscoped && scope.HasColumn("DeletedAt") {
			scope.Raw(fmt.Sprintf(
				"UPDATE %v SET deleted_at=%v%v%v",
				scope.QuotedTableName(),
				scope.AddToVars(gorm.NowFunc()),
				addExtraSpaceIfExist(scope.CombinedConditionSql()),
				addExtraSpaceIfExist(extraOption),
			)).Exec()
		} else {
			scope.Raw(fmt.Sprintf(
				"DELETE FROM %v%v%v",
				scope.QuotedTableName(),
				addExtraSpaceIfExist(scope.CombinedConditionSql()),
				addExtraSpaceIfExist(extraOption),
			)).Exec()
		}
	}
}

// afterDeleteCallback will invoke `AfterDelete` method after deleting
func afterDeleteCallback(scope *gorm.Scope) {
	if !scope.HasError() {
		scope.CallMethod("AfterDelete")
	}
}

func commitOrRollbackTransactionCallback(scope *gorm.Scope) {
	scope.CommitOrRollback()
}

//cascade deleting
func beforeDeleteAssociationsCallback(scope *gorm.Scope) {
	logCodeLine()
	//TBD config  gorm:delete_associations
	//if !scope.shouldDeleteAssociations() {
	//	return
	//}
	for _, field := range scope.Fields() {

		if relationship := field.Relationship; relationship != nil && relationship.Kind == "has_many" {
			//TBD:Now only support one foreign field and unit type
			foreignValue := scope.IndirectValue().FieldByName(relationship.AssociationForeignFieldNames[0]).Uint()
			//fmt.Println(foreignValue)
			sql := fmt.Sprintf("%s = ?", relationship.ForeignDBNames[0])
			//fmt.Println(sql)
			class := field.Field.Type().Elem()
			fmt.Println(class.Name())
			if err := DB.Unscoped().Delete(model.Models[class.Name()].Type, sql, foreignValue).Error; err != nil {
				scope.Err(err)
			}
		}
	}
}

func afterDeleteAssociationsCallback(scope *gorm.Scope) {
	logCodeLine()
	//if !scope.shouldSaveAssociations() {
	//	return
	//}
	//for _, field := range scope.Fields() {
	//	if scope.changeableField(field) && !field.IsBlank && !field.IsIgnored {
	//		if relationship := field.Relationship; relationship != nil &&
	//				(relationship.Kind == "has_one" || relationship.Kind == "has_many" || relationship.Kind == "many_to_many") {
	//			value := field.Field
	//
	//			switch value.Kind() {
	//			case reflect.Slice:
	//				for i := 0; i < value.Len(); i++ {
	//					newDB := scope.NewDB()
	//					elem := value.Index(i).Addr().Interface()
	//					newScope := newDB.NewScope(elem)
	//
	//					if relationship.JoinTableHandler == nil && len(relationship.ForeignFieldNames) != 0 {
	//						for idx, fieldName := range relationship.ForeignFieldNames {
	//							associationForeignName := relationship.AssociationForeignDBNames[idx]
	//							if f, ok := scope.FieldByName(associationForeignName); ok {
	//								scope.Err(newScope.SetColumn(fieldName, f.Field.Interface()))
	//							}
	//						}
	//					}
	//
	//					if relationship.PolymorphicType != "" {
	//						scope.Err(newScope.SetColumn(relationship.PolymorphicType, scope.TableName()))
	//					}
	//
	//					scope.Err(newDB.Save(elem).Error)
	//
	//					if joinTableHandler := relationship.JoinTableHandler; joinTableHandler != nil {
	//						scope.Err(joinTableHandler.Add(joinTableHandler, newDB, scope.Value, newScope.Value))
	//					}
	//				}
	//			default:
	//				elem := value.Addr().Interface()
	//				newScope := scope.New(elem)
	//				if len(relationship.ForeignFieldNames) != 0 {
	//					for idx, fieldName := range relationship.ForeignFieldNames {
	//						associationForeignName := relationship.AssociationForeignDBNames[idx]
	//						if f, ok := scope.FieldByName(associationForeignName); ok {
	//							scope.Err(newScope.SetColumn(fieldName, f.Field.Interface()))
	//						}
	//					}
	//				}
	//
	//				if relationship.PolymorphicType != "" {
	//					scope.Err(newScope.SetColumn(relationship.PolymorphicType, scope.TableName()))
	//				}
	//				scope.Err(scope.NewDB().Save(elem).Error)
	//			}
	//		}
	//	}
}
<commit_msg>Fix delete<commit_after>package db

import (
	"fmt"

	"github.com/jinzhu/gorm"
	"github.com/chaosxu/nerv/lib/model"
)

// Define callbacks for deleting,support cascade deleting
func init() {
	gorm.DefaultCallback.Delete().Replace("gorm:begin_transaction", beginTransactionCallback)
	gorm.DefaultCallback.Delete().Replace("gorm:before_delete", beforeDeleteCallback)
	gorm.DefaultCallback.Delete().After("gorm:before_delete").Replace("chaosxu:before_delete_associations", beforeDeleteAssociationsCallback)
	gorm.DefaultCallback.Delete().Replace("gorm:delete", deleteCallback)
	gorm.DefaultCallback.Delete().After("gorm:delete").Replace("chaosxu:after_delete_associations", afterDeleteAssociationsCallback)
	gorm.DefaultCallback.Delete().Replace("gorm:after_delete", afterDeleteCallback)
	gorm.DefaultCallback.Delete().Replace("gorm:commit_or_rollback_transaction", commitOrRollbackTransactionCallback)
}

func beginTransactionCallback(scope *gorm.Scope) {
	scope.Begin()
}

// beforeDeleteCallback will invoke `BeforeDelete` method before deleting
func beforeDeleteCallback(scope *gorm.Scope) {
	if !scope.HasError() {
		scope.CallMethod("BeforeDelete")
	}
}

// deleteCallback used to delete data from database or set deleted_at to current time (when using with soft delete)
func deleteCallback(scope *gorm.Scope) {
	logCodeLine()

	if !scope.HasError() {
		var extraOption string
		if str, ok := scope.Get("gorm:delete_option"); ok {
			extraOption = fmt.Sprint(str)
		}

		if !scope.Search.Unscoped && scope.HasColumn("DeletedAt") {
			scope.Raw(fmt.Sprintf(
				"UPDATE %v SET deleted_at=%v%v%v",
				scope.QuotedTableName(),
				scope.AddToVars(gorm.NowFunc()),
				addExtraSpaceIfExist(scope.CombinedConditionSql()),
				addExtraSpaceIfExist(extraOption),
			)).Exec()
		} else {
			scope.Raw(fmt.Sprintf(
				"DELETE FROM %v%v%v",
				scope.QuotedTableName(),
				addExtraSpaceIfExist(scope.CombinedConditionSql()),
				addExtraSpaceIfExist(extraOption),
			)).Exec()
		}
	}
}

// afterDeleteCallback will invoke `AfterDelete` method after deleting
func afterDeleteCallback(scope *gorm.Scope) {
	if !scope.HasError() {
		scope.CallMethod("AfterDelete")
	}
}

func commitOrRollbackTransactionCallback(scope *gorm.Scope) {
	scope.CommitOrRollback()
}

//cascade deleting
func beforeDeleteAssociationsCallback(scope *gorm.Scope) {
	logCodeLine()
	//TBD config  gorm:delete_associations
	//if !scope.shouldDeleteAssociations() {
	//	return
	//}
	for _, field := range scope.Fields() {

		if relationship := field.Relationship; relationship != nil && relationship.Kind == "has_many" {
			//TBD:Now only support one foreign field and unit type
			foreignValue := scope.IndirectValue().FieldByName(relationship.AssociationForeignFieldNames[0]).Uint()
			//fmt.Println(foreignValue)
			sql := fmt.Sprintf("%s = ?", relationship.ForeignDBNames[0])
			//fmt.Println(sql)
			class := field.Field.Type().Elem()
			fmt.Println(class.Name())
			if err := DB.Unscoped().Delete(model.Models[class.Name()].Type, sql, foreignValue).Error; err != nil {
				scope.Err(err)
			}
		}
	}
}

func afterDeleteAssociationsCallback(scope *gorm.Scope) {
	logCodeLine()
	//if !scope.shouldSaveAssociations() {
	//	return
	//}
	//for _, field := range scope.Fields() {
	//	if scope.changeableField(field) && !field.IsBlank && !field.IsIgnored {
	//		if relationship := field.Relationship; relationship != nil &&
	//				(relationship.Kind == "has_one" || relationship.Kind == "has_many" || relationship.Kind == "many_to_many") {
	//			value := field.Field
	//
	//			switch value.Kind() {
	//			case reflect.Slice:
	//				for i := 0; i < value.Len(); i++ {
	//					newDB := scope.NewDB()
	//					elem := value.Index(i).Addr().Interface()
	//					newScope := newDB.NewScope(elem)
	//
	//					if relationship.JoinTableHandler == nil && len(relationship.ForeignFieldNames) != 0 {
	//						for idx, fieldName := range relationship.ForeignFieldNames {
	//							associationForeignName := relationship.AssociationForeignDBNames[idx]
	//							if f, ok := scope.FieldByName(associationForeignName); ok {
	//								scope.Err(newScope.SetColumn(fieldName, f.Field.Interface()))
	//							}
	//						}
	//					}
	//
	//					if relationship.PolymorphicType != "" {
	//						scope.Err(newScope.SetColumn(relationship.PolymorphicType, scope.TableName()))
	//					}
	//
	//					scope.Err(newDB.Save(elem).Error)
	//
	//					if joinTableHandler := relationship.JoinTableHandler; joinTableHandler != nil {
	//						scope.Err(joinTableHandler.Add(joinTableHandler, newDB, scope.Value, newScope.Value))
	//					}
	//				}
	//			default:
	//				elem := value.Addr().Interface()
	//				newScope := scope.New(elem)
	//				if len(relationship.ForeignFieldNames) != 0 {
	//					for idx, fieldName := range relationship.ForeignFieldNames {
	//						associationForeignName := relationship.AssociationForeignDBNames[idx]
	//						if f, ok := scope.FieldByName(associationForeignName); ok {
	//							scope.Err(newScope.SetColumn(fieldName, f.Field.Interface()))
	//						}
	//					}
	//				}
	//
	//				if relationship.PolymorphicType != "" {
	//					scope.Err(newScope.SetColumn(relationship.PolymorphicType, scope.TableName()))
	//				}
	//				scope.Err(scope.NewDB().Save(elem).Error)
	//			}
	//		}
	//	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	//	"crypto/sha256"
	//	"encoding/hex"
	"flag"
	"fmt"
	"os"

	"github.com/FactomProject/cli"
	"github.com/FactomProject/factom"
)

var get = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get head|dblock|height|chain|eblock|entry|firstentry"
	cmd.description = "get Block or Entry data from factomd"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()

		c := cli.New()
		c.Handle("head", getHead)
		c.Handle("height", getHeight)
		c.Handle("dblock", getDBlock)
		c.Handle("chainhead", getChainHead)
		c.Handle("eblock", getEBlock)
		c.Handle("entry", getEntry)
		c.Handle("firstentry", getFirstEntry)
		c.HandleDefaultFunc(func(args []string) {
			fmt.Println(cmd.helpMsg)
		})
		c.Execute(args)
	}
	help.Add("get", cmd)
	return cmd
}()

var getHead = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get head"
	cmd.description = "Get the keymr of the last completed directory block"
	cmd.execFunc = func(args []string) {
		head, err := factom.GetDBlockHead()
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(head.KeyMR)
	}
	help.Add("get head", cmd)
	return cmd
}()

var getHeight = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get height"
	cmd.description = "Get the current directory block height"
	cmd.execFunc = func(args []string) {
		height, err := factom.GetDBlockHeight()
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(height)
	}
	help.Add("get height", cmd)
	return cmd
}()

var getDBlock = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get dblock KEYMR"
	cmd.description = "Get dblock contents by merkle root"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		keymr := args[0]
		dblock, err := factom.GetDBlock(keymr)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(dblock)
	}
	help.Add("get dblock", cmd)
	return cmd
}()

var getChainHead = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get chainhead CHAINID"
	cmd.description = "Get ebhead by chainid"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		chainid := args[0]
		chain, err := factom.GetChainHead(chainid)
		if err != nil {
			errorln(err)
			return
		}

		fmt.Println(chain.ChainHead)
	}
	help.Add("get chainhead", cmd)
	return cmd
}()

var getEBlock = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get eblock KEYMR"
	cmd.description = "Get eblock by merkle root"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		keymr := args[0]
		eblock, err := factom.GetEBlock(keymr)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(eblock)
	}
	help.Add("get eblock", cmd)
	return cmd
}()

var getEntry = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get entry HASH"
	cmd.description = "Get entry by hash"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		hash := args[0]
		entry, err := factom.GetEntry(hash)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(entry)
	}
	help.Add("get entry", cmd)
	return cmd
}()

var getFirstEntry = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get firstentry CHAINID"
	cmd.description = "Get the first entry from a chain"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		chainid := args[0]
		entry, err := factom.GetFirstEntry(chainid)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(entry)
	}
	help.Add("get firstentry", cmd)
	return cmd
}()
<commit_msg>help msg for get<commit_after>// Copyright 2016 Factom Foundation
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.

package main

import (
	//	"crypto/sha256"
	//	"encoding/hex"
	"flag"
	"fmt"
	"os"

	"github.com/FactomProject/cli"
	"github.com/FactomProject/factom"
)

var get = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get head|dblock|height|chainhead|eblock|entry|firstentry"
	cmd.description = "get Block or Entry data from factomd"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()

		c := cli.New()
		c.Handle("head", getHead)
		c.Handle("height", getHeight)
		c.Handle("dblock", getDBlock)
		c.Handle("chainhead", getChainHead)
		c.Handle("eblock", getEBlock)
		c.Handle("entry", getEntry)
		c.Handle("firstentry", getFirstEntry)
		c.HandleDefaultFunc(func(args []string) {
			fmt.Println(cmd.helpMsg)
		})
		c.Execute(args)
	}
	help.Add("get", cmd)
	return cmd
}()

var getHead = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get head"
	cmd.description = "Get the keymr of the last completed directory block"
	cmd.execFunc = func(args []string) {
		head, err := factom.GetDBlockHead()
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(head.KeyMR)
	}
	help.Add("get head", cmd)
	return cmd
}()

var getHeight = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get height"
	cmd.description = "Get the current directory block height"
	cmd.execFunc = func(args []string) {
		height, err := factom.GetDBlockHeight()
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(height)
	}
	help.Add("get height", cmd)
	return cmd
}()

var getDBlock = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get dblock KEYMR"
	cmd.description = "Get dblock contents by merkle root"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		keymr := args[0]
		dblock, err := factom.GetDBlock(keymr)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(dblock)
	}
	help.Add("get dblock", cmd)
	return cmd
}()

var getChainHead = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get chainhead CHAINID"
	cmd.description = "Get ebhead by chainid"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		chainid := args[0]
		chain, err := factom.GetChainHead(chainid)
		if err != nil {
			errorln(err)
			return
		}

		fmt.Println(chain.ChainHead)
	}
	help.Add("get chainhead", cmd)
	return cmd
}()

var getEBlock = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get eblock KEYMR"
	cmd.description = "Get eblock by merkle root"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		keymr := args[0]
		eblock, err := factom.GetEBlock(keymr)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(eblock)
	}
	help.Add("get eblock", cmd)
	return cmd
}()

var getEntry = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get entry HASH"
	cmd.description = "Get entry by hash"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		hash := args[0]
		entry, err := factom.GetEntry(hash)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(entry)
	}
	help.Add("get entry", cmd)
	return cmd
}()

var getFirstEntry = func() *fctCmd {
	cmd := new(fctCmd)
	cmd.helpMsg = "factom-cli get firstentry CHAINID"
	cmd.description = "Get the first entry from a chain"
	cmd.execFunc = func(args []string) {
		os.Args = args
		flag.Parse()
		args = flag.Args()
		if len(args) < 1 {
			fmt.Println(cmd.helpMsg)
			return
		}

		chainid := args[0]
		entry, err := factom.GetFirstEntry(chainid)
		if err != nil {
			errorln(err)
			return
		}
		fmt.Println(entry)
	}
	help.Add("get firstentry", cmd)
	return cmd
}()
<|endoftext|>


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

package v1beta2

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

const (
	BackupStorageTypeS3 BackupStorageType = "S3"

	AWSSecretCredentialsFileName = "credentials"
	AWSSecretConfigFileName      = "config"
)

type BackupStorageType string

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// EtcdBackupList is a list of EtcdBackup.
type EtcdBackupList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`
	Items           []EtcdBackup `json:"items"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// EtcdBackup represents a Kubernetes EtcdBackup Custom Resource.
type EtcdBackup struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata"`
	Spec              BackupSpec     `json:"spec"`
	Status            BackupCRStatus `json:"status,omitempty"`
}

// BackupSpec contains a backup specification for an etcd cluster.
type BackupSpec struct {
	// EtcdEndpoints specifies the endpoints of an etcd cluster.
	// When multiple endpoints are given, the backup operator retrieves
	// the backup from the endpoint that has the most up-to-date state.
	// The given endpoints must belong to the same etcd cluster.
	EtcdEndpoints []string `json:"etcdEndpoints,omitempty"`
	// StorageType is the etcd backup storage type.
	// We need this field because CRD doesn't support validation against invalid fields
	// and we cannot verify invalid backup storage source.
	StorageType BackupStorageType `json:"storageType"`
	// BackupSource is the backup storage source.
	BackupSource `json:",inline"`
	// ClientTLSSecret is the secret containing the etcd TLS client certs and
	// must contain the following data items:
	// data:
	//    "etcd-client.crt": <pem-encoded-cert>
	//    "etcd-client.key": <pem-encoded-key>
	//    "etcd-client-ca.crt": <pem-encoded-ca-cert>
	ClientTLSSecret string `json:"clientTLSSecret,omitempty"`
}

// BackupSource contains the supported backup sources.
type BackupSource struct {
	// S3 defines the S3 backup source spec.
	S3 *S3BackupSource `json:"s3,omitempty"`
}

// BackupCRStatus represents the status of the EtcdBackup Custom Resource.
type BackupCRStatus struct {
	// Succeeded indicates if the backup has Succeeded.
	Succeeded bool `json:"succeeded"`
	// Reason indicates the reason for any backup related failures.
	Reason string `json:"Reason,omitempty"`
}

// S3BackupSource provides the spec how to store backups on S3.
type S3BackupSource struct {
	// Path is the full s3 path where the backup is saved.
	// The format of the path must be: "<s3-bucket-name>/<path-to-backup-file>"
	// e.g: "mybucket/etcd.backup"
	Path string `json:"path"`

	// The name of the secret object that stores the AWS credential and config files.
	// The file name of the credential MUST be 'credentials'.
	// The file name of the config MUST be 'config'.
	// The profile to use in both files will be 'default'.
	//
	// AWSSecret overwrites the default etcd operator wide AWS credential and config.
	AWSSecret string `json:"awsSecret"`
}
<commit_msg>apis: add EtcdVersion and EtcdRevision to BackupCRStatus (#1788)<commit_after>// Copyright 2017 The etcd-operator Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package v1beta2

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

const (
	BackupStorageTypeS3 BackupStorageType = "S3"

	AWSSecretCredentialsFileName = "credentials"
	AWSSecretConfigFileName      = "config"
)

type BackupStorageType string

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// EtcdBackupList is a list of EtcdBackup.
type EtcdBackupList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata"`
	Items           []EtcdBackup `json:"items"`
}

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// EtcdBackup represents a Kubernetes EtcdBackup Custom Resource.
type EtcdBackup struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata"`
	Spec              BackupSpec     `json:"spec"`
	Status            BackupCRStatus `json:"status,omitempty"`
}

// BackupSpec contains a backup specification for an etcd cluster.
type BackupSpec struct {
	// EtcdEndpoints specifies the endpoints of an etcd cluster.
	// When multiple endpoints are given, the backup operator retrieves
	// the backup from the endpoint that has the most up-to-date state.
	// The given endpoints must belong to the same etcd cluster.
	EtcdEndpoints []string `json:"etcdEndpoints,omitempty"`
	// StorageType is the etcd backup storage type.
	// We need this field because CRD doesn't support validation against invalid fields
	// and we cannot verify invalid backup storage source.
	StorageType BackupStorageType `json:"storageType"`
	// BackupSource is the backup storage source.
	BackupSource `json:",inline"`
	// ClientTLSSecret is the secret containing the etcd TLS client certs and
	// must contain the following data items:
	// data:
	//    "etcd-client.crt": <pem-encoded-cert>
	//    "etcd-client.key": <pem-encoded-key>
	//    "etcd-client-ca.crt": <pem-encoded-ca-cert>
	ClientTLSSecret string `json:"clientTLSSecret,omitempty"`
}

// BackupSource contains the supported backup sources.
type BackupSource struct {
	// S3 defines the S3 backup source spec.
	S3 *S3BackupSource `json:"s3,omitempty"`
}

// BackupCRStatus represents the status of the EtcdBackup Custom Resource.
type BackupCRStatus struct {
	// Succeeded indicates if the backup has Succeeded.
	Succeeded bool `json:"succeeded"`
	// Reason indicates the reason for any backup related failures.
	Reason string `json:"Reason,omitempty"`
	// EtcdVersion is the version of the backup etcd server.
	EtcdVersion string `json:"etcdVersion,omitempty"`
	// EtcdRevision is the revision of etcd's KV store where the backup is performed on.
	EtcdRevision string `json:"etcdRevision,omitempty"`
}

// S3BackupSource provides the spec how to store backups on S3.
type S3BackupSource struct {
	// Path is the full s3 path where the backup is saved.
	// The format of the path must be: "<s3-bucket-name>/<path-to-backup-file>"
	// e.g: "mybucket/etcd.backup"
	Path string `json:"path"`

	// The name of the secret object that stores the AWS credential and config files.
	// The file name of the credential MUST be 'credentials'.
	// The file name of the config MUST be 'config'.
	// The profile to use in both files will be 'default'.
	//
	// AWSSecret overwrites the default etcd operator wide AWS credential and config.
	AWSSecret string `json:"awsSecret"`
}
<|endoftext|>


<commit_before>/*
	This is the server package.
	The purpouse of this package is to map a connection to each player(who is online) so we have a comunication chanel.

*/
package server

import (
	"errors"
	"fmt"
	"github.com/fzzy/sockjs-go/sockjs"
	"log"
	"net/http"
	"warcluster/db_manager"
	"warcluster/entities"
)

var HOST string     //Server scope constant that keeps the server host address.
var PORT int        //Server scope constant that keeps the server port number.
var IS_RUNNING bool //Server scope variable that represents the is active flag.

var sessions *sockjs.SessionPool = sockjs.NewSessionPool() //This is the SockJs sessions pull (a list of all the currently active client's sessions).

/*This function goes trough all the procedurs needed for the werver to be initialized.
1.Create an empty connections pool
2.Starts the listening foe messages loop.*/
func Start(host string, port int) error {
	log.Print("Server is starting...")
	if IS_RUNNING {
		return errors.New("Server is already started!")
	} else {
		HOST = host
		PORT = port
		IS_RUNNING = true
	}
	log.Println("Server is up and running!")
	mux := sockjs.NewServeMux(http.DefaultServeMux)
	conf := sockjs.NewConfig()

	http.HandleFunc("/console", staticHandler)
	http.Handle("/static", http.FileServer(http.Dir("./static")))
	mux.Handle("/universe", handler, conf)

	if err := http.ListenAndServe(fmt.Sprintf("%v:%v", HOST, PORT), mux); err != nil {
		log.Println(err)
		return err
	}
	return Stop()
}

//Die biatch and get the fuck out.
func Stop() error {
	log.Println("Server is shutting down...")
	if !IS_RUNNING {
		err := errors.New("Server is already stopped!")
		log.Println(err)
		return err
	}

	IS_RUNNING = false
	log.Println("Server has stopped.")
	return nil
}

//Stop + Start = Restart
func Restart() {
	Stop()
	Start(HOST, PORT)
}

//Returns the HTML page needed to display the debug page (server "chat" window).
func staticHandler(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "./static/index.html")
}

/*This function is called from the message handler to parse the first message for every new connection.
It check for existing user in the DB and logs him if the password is correct.
If the user is new he is initiated and a new home planet nad solar system are generated.*/
func login(session sockjs.Session) (*Client, error) {
	nickname, player := authenticate(session)

	client := &Client{
		Session:  session,
		Nickname: nickname,
		Player:   player,
	}

	home_planet_entity, _ := db_manager.GetEntity(client.Player.HomePlanet)
	home_planet := home_planet_entity.(entities.Planet)
	session.Send([]byte(fmt.Sprintf("{\"Command\": \"login_success\", \"Username\": \"%s\", \"Position\": [%d, %d] }",
		client.Nickname, home_planet.GetCoords()[0], home_planet.GetCoords()[1])))
	return client, nil
}

/*On the first rescived message from each connection the server will call the handler.
So it can complete the following actions:
1.Adding a new session to the session pool.
2.Call the login func to validate the connection
3.If the connection is valid enters "while true" state and uses ParseRequest to parse the requests. Shocking right?!?!*/
func handler(session sockjs.Session) {
	sessions.Add(session)
	defer sessions.Remove(session)

	if client, err := login(session); err == nil {
		for {
			message := session.Receive()
			if message == nil {
				break
			}

			if request, err := UnmarshalRequest(message, client); err == nil {
				if action, err := ParseRequest(request); err == nil {
					if err := action(request); err != nil {
						log.Println(err)
					}
				} else {
					log.Println("Error in server.main.handler:", err.Error())
				}
			} else {
				log.Println("Error in server.main.handler:", err.Error())
			}
		}
	} else {
		session.End()
	}
}
<commit_msg>Make parsing requests a little bit more safe<commit_after>/*
	This is the server package.
	The purpouse of this package is to map a connection to each player(who is online) so we have a comunication chanel.

*/
package server

import (
	"errors"
	"fmt"
	"github.com/fzzy/sockjs-go/sockjs"
	"log"
	"net/http"
	"warcluster/db_manager"
	"warcluster/entities"
)

var HOST string     //Server scope constant that keeps the server host address.
var PORT int        //Server scope constant that keeps the server port number.
var IS_RUNNING bool //Server scope variable that represents the is active flag.

var sessions *sockjs.SessionPool = sockjs.NewSessionPool() //This is the SockJs sessions pull (a list of all the currently active client's sessions).

/*This function goes trough all the procedurs needed for the werver to be initialized.
1.Create an empty connections pool
2.Starts the listening foe messages loop.*/
func Start(host string, port int) error {
	log.Print("Server is starting...")
	if IS_RUNNING {
		return errors.New("Server is already started!")
	} else {
		HOST = host
		PORT = port
		IS_RUNNING = true
	}
	log.Println("Server is up and running!")
	mux := sockjs.NewServeMux(http.DefaultServeMux)
	conf := sockjs.NewConfig()

	http.HandleFunc("/console", staticHandler)
	http.Handle("/static", http.FileServer(http.Dir("./static")))
	mux.Handle("/universe", handler, conf)

	if err := http.ListenAndServe(fmt.Sprintf("%v:%v", HOST, PORT), mux); err != nil {
		log.Println(err)
		return err
	}
	return Stop()
}

//Die biatch and get the fuck out.
func Stop() error {
	log.Println("Server is shutting down...")
	if !IS_RUNNING {
		err := errors.New("Server is already stopped!")
		log.Println(err)
		return err
	}

	IS_RUNNING = false
	log.Println("Server has stopped.")
	return nil
}

//Stop + Start = Restart
func Restart() {
	Stop()
	Start(HOST, PORT)
}

//Returns the HTML page needed to display the debug page (server "chat" window).
func staticHandler(w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, "./static/index.html")
}

/*This function is called from the message handler to parse the first message for every new connection.
It check for existing user in the DB and logs him if the password is correct.
If the user is new he is initiated and a new home planet nad solar system are generated.*/
func login(session sockjs.Session) (*Client, error) {
	nickname, player := authenticate(session)

	client := &Client{
		Session:  session,
		Nickname: nickname,
		Player:   player,
	}

	home_planet_entity, _ := db_manager.GetEntity(client.Player.HomePlanet)
	home_planet := home_planet_entity.(entities.Planet)
	session.Send([]byte(fmt.Sprintf("{\"Command\": \"login_success\", \"Username\": \"%s\", \"Position\": [%d, %d] }",
		client.Nickname, home_planet.GetCoords()[0], home_planet.GetCoords()[1])))
	return client, nil
}

/*On the first rescived message from each connection the server will call the handler.
So it can complete the following actions:
1.Adding a new session to the session pool.
2.Call the login func to validate the connection
3.If the connection is valid enters "while true" state and uses ParseRequest to parse the requests. Shocking right?!?!*/
func handler(session sockjs.Session) {
	sessions.Add(session)
	defer sessions.Remove(session)
	defer func() {
		if panicked := recover(); panicked != nil {
			return
		}
	}()

	if client, err := login(session); err == nil {
		for {
			message := session.Receive()
			if message == nil {
				break
			}

			if request, err := UnmarshalRequest(message, client); err == nil {
				if action, err := ParseRequest(request); err == nil {
					if err := action(request); err != nil {
						log.Println(err)
					}
				} else {
					log.Println("Error in server.main.handler:", err.Error())
				}
			} else {
				log.Println("Error in server.main.handler:", err.Error())
			}
		}
	} else {
		session.End()
	}
}
<|endoftext|>