<commit_before>package main

import (
	"flag"
	"io/ioutil"
	"log"
	"strconv"
	"time"

	"github.com/brotherlogic/goserver"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pbd "github.com/brotherlogic/discovery/proto"
	pb "github.com/brotherlogic/gobuildmaster/proto"
	pbs "github.com/brotherlogic/gobuildslave/proto"
	pbg "github.com/brotherlogic/goserver/proto"
	"github.com/brotherlogic/goserver/utils"
)

const (
	intentWait = time.Second
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	config     *pb.Config
	serving    bool
	lastIntent time.Time
}

type mainChecker struct {
	prev []string
}

func getIP(servertype, servername string) (string, int) {
	conn, err := grpc.Dial(utils.RegistryIP+":"+strconv.Itoa(utils.RegistryPort), grpc.WithInsecure())
	log.Printf("Error? %v", err)
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := registry.ListAllServices(ctx, &pbd.Empty{}, grpc.FailFast(false))
	if err != nil {
		return "", -1
	}
	for _, s := range r.Services {
		if s.Name == servertype && s.Identifier == servername {
			return s.Ip, int(s.Port)
		}
	}

	return "", -1
}

func (t *mainChecker) getprev() []string {
	return t.prev
}
func (t *mainChecker) setprev(v []string) {
	t.prev = v
}

func (t *mainChecker) assess(server string) (*pbs.JobList, *pbs.Config) {
	list := &pbs.JobList{}
	conf := &pbs.Config{}

	ip, port := getIP("gobuildslave", server)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	conn, err := grpc.DialContext(ctx, ip+":"+strconv.Itoa(port), grpc.WithInsecure())
	if err != nil {
		return list, conf
	}
	defer conn.Close()

	slave := pbs.NewGoBuildSlaveClient(conn)
	r, err := slave.List(ctx, &pbs.Empty{}, grpc.FailFast(false))
	if err != nil {
		return list, conf
	}

	r2, err := slave.GetConfig(ctx, &pbs.Empty{}, grpc.FailFast(false))
	if err != nil {
		return list, conf
	}

	return r, r2
}

func (t *mainChecker) master(entry *pbd.RegistryEntry) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	conn, _ := grpc.DialContext(ctx, entry.GetIp()+":"+strconv.Itoa(int(entry.GetPort())), grpc.WithInsecure())
	defer conn.Close()

	server := pbg.NewGoserverServiceClient(conn)
	log.Printf("SETTING MASTER: %v", entry)
	_, err := server.Mote(ctx, &pbg.MoteRequest{Master: entry.GetMaster()}, grpc.FailFast(false))
	if err != nil {
		log.Printf("RESPONSE: %v", err)
	}
}

func runJob(job *pbs.JobSpec, server string) {
	log.Printf("Run %v on %v", job.Name, server)
	if server != "" {
		ip, port := getIP("gobuildslave", server)
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()
		conn, _ := grpc.DialContext(ctx, ip+":"+strconv.Itoa(port), grpc.WithInsecure())
		defer conn.Close()

		slave := pbs.NewGoBuildSlaveClient(conn)
		job.Server = server
		slave.Run(ctx, job, grpc.FailFast(false))
	}
}

func (t *mainChecker) discover() *pbd.ServiceList {
	ret := &pbd.ServiceList{}

	conn, _ := grpc.Dial(utils.RegistryIP+":"+strconv.Itoa(utils.RegistryPort), grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := registry.ListAllServices(ctx, &pbd.Empty{}, grpc.FailFast(false))
	if err == nil {
		for _, s := range r.Services {
			ret.Services = append(ret.Services, s)
		}
	}

	return ret
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	pb.RegisterGoBuildMasterServer(server, &s)
}

// ReportHealth determines if the server is healthy
func (s Server) ReportHealth() bool {
	return true
}

// Mote promotes/demotes this server
func (s Server) Mote(master bool) error {
	return nil
}

//GetState gets the state of the server
func (s Server) GetState() []*pbg.State {
	return []*pbg.State{&pbg.State{Key: "last_intent", TimeValue: s.lastIntent.Unix()}}
}

//Compare compares current state to desired state
func (s Server) Compare(ctx context.Context, in *pb.Empty) (*pb.CompareResponse, error) {
	resp := &pb.CompareResponse{}
	list, _ := getFleetStatus(&mainChecker{})
	cc := &pb.Config{}
	for _, jlist := range list {
		for _, job := range jlist.GetDetails() {
			cc.Intents = append(cc.Intents, &pb.Intent{Spec: job.GetSpec()})
		}
	}
	resp.Current = cc
	resp.Desired = s.config

	return resp, nil
}

func getConfig(c checker) *pb.Config {
	list, _ := getFleetStatus(c)
	config := &pb.Config{}

	for _, jlist := range list {
		for _, job := range jlist.Details {
			found := false
			for _, ij := range config.Intents {
				if job.Spec.Name == ij.Spec.Name {
					ij.Count++
					found = true
				}
			}

			if !found {
				config.Intents = append(config.Intents, &pb.Intent{Spec: &pbs.JobSpec{Name: job.Spec.Name}, Count: 1})
			}
		}
	}

	return config
}

// MatchIntent tries to match the intent with the state of production
func (s *Server) MatchIntent() {
	checker := &mainChecker{}
	for s.serving {
		time.Sleep(intentWait)
		s.lastIntent = time.Now()

		state := getConfig(checker)
		diff := configDiff(s.config, state)
		joblist := runJobs(diff)
		for _, job := range joblist {
			runJob(job, chooseServer(job, checker))
		}
	}
}

// SetMaster sets up the master settings
func (s Server) SetMaster() {
	checker := &mainChecker{}
	for s.serving {
		time.Sleep(intentWait)

		fleet := checker.discover()
		matcher := make(map[string]*pbd.RegistryEntry)
		for _, entry := range fleet.GetServices() {
			if _, ok := matcher[entry.GetName()]; !ok {
				matcher[entry.GetName()] = entry
			} else {
				if entry.GetMaster() {
					matcher[entry.GetName()] = entry
				}
			}
		}

		for _, entry := range matcher {
			if !entry.GetMaster() {
				entry.Master = true
				checker.master(entry)
			}
		}
	}
}

func main() {
	config, err := loadConfig("config.pb")
	if err != nil {
		log.Fatalf("Fatal loading of config: %v", err)
	}

	var sync = flag.Bool("once", false, "One pass intent match")
	s := Server{&goserver.GoServer{}, config, true, time.Now()}

	var quiet = flag.Bool("quiet", true, "Show all output")
	flag.Parse()

	if *quiet {
		log.SetFlags(0)
		log.SetOutput(ioutil.Discard)
	}

	if *sync {
		s.MatchIntent()
	} else {
		s.Register = s
		s.PrepServer()
		s.GoServer.Killme = false
		s.RegisterServer("gobuildmaster", false)
		s.RegisterServingTask(s.MatchIntent)
		s.RegisterServingTask(s.SetMaster)
		s.Serve()
	}
}
<commit_msg>Added some logging<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"strconv"
	"time"

	"github.com/brotherlogic/goserver"
	"golang.org/x/net/context"
	"google.golang.org/grpc"

	pbd "github.com/brotherlogic/discovery/proto"
	pb "github.com/brotherlogic/gobuildmaster/proto"
	pbs "github.com/brotherlogic/gobuildslave/proto"
	pbg "github.com/brotherlogic/goserver/proto"
	"github.com/brotherlogic/goserver/utils"
)

const (
	intentWait = time.Second
)

// Server the main server type
type Server struct {
	*goserver.GoServer
	config     *pb.Config
	serving    bool
	lastIntent time.Time
}

type mainChecker struct {
	prev []string
}

func getIP(servertype, servername string) (string, int) {
	conn, err := grpc.Dial(utils.RegistryIP+":"+strconv.Itoa(utils.RegistryPort), grpc.WithInsecure())
	log.Printf("Error? %v", err)
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := registry.ListAllServices(ctx, &pbd.Empty{}, grpc.FailFast(false))
	if err != nil {
		return "", -1
	}
	for _, s := range r.Services {
		if s.Name == servertype && s.Identifier == servername {
			return s.Ip, int(s.Port)
		}
	}

	return "", -1
}

func (t *mainChecker) getprev() []string {
	return t.prev
}
func (t *mainChecker) setprev(v []string) {
	t.prev = v
}

func (t *mainChecker) assess(server string) (*pbs.JobList, *pbs.Config) {
	list := &pbs.JobList{}
	conf := &pbs.Config{}

	ip, port := getIP("gobuildslave", server)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	conn, err := grpc.DialContext(ctx, ip+":"+strconv.Itoa(port), grpc.WithInsecure())
	if err != nil {
		return list, conf
	}
	defer conn.Close()

	slave := pbs.NewGoBuildSlaveClient(conn)
	r, err := slave.List(ctx, &pbs.Empty{}, grpc.FailFast(false))
	if err != nil {
		return list, conf
	}

	r2, err := slave.GetConfig(ctx, &pbs.Empty{}, grpc.FailFast(false))
	if err != nil {
		return list, conf
	}

	return r, r2
}

func (t *mainChecker) master(entry *pbd.RegistryEntry) {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	conn, _ := grpc.DialContext(ctx, entry.GetIp()+":"+strconv.Itoa(int(entry.GetPort())), grpc.WithInsecure())
	defer conn.Close()

	server := pbg.NewGoserverServiceClient(conn)
	log.Printf("SETTING MASTER: %v", entry)
	_, err := server.Mote(ctx, &pbg.MoteRequest{Master: entry.GetMaster()}, grpc.FailFast(false))
	if err != nil {
		log.Printf("RESPONSE: %v", err)
	}
}

func runJob(job *pbs.JobSpec, server string) {
	log.Printf("Run %v on %v", job.Name, server)
	if server != "" {
		ip, port := getIP("gobuildslave", server)
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		defer cancel()
		conn, _ := grpc.DialContext(ctx, ip+":"+strconv.Itoa(port), grpc.WithInsecure())
		defer conn.Close()

		slave := pbs.NewGoBuildSlaveClient(conn)
		job.Server = server
		slave.Run(ctx, job, grpc.FailFast(false))
	}
}

func (t *mainChecker) discover() *pbd.ServiceList {
	ret := &pbd.ServiceList{}

	conn, _ := grpc.Dial(utils.RegistryIP+":"+strconv.Itoa(utils.RegistryPort), grpc.WithInsecure())
	defer conn.Close()

	registry := pbd.NewDiscoveryServiceClient(conn)
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := registry.ListAllServices(ctx, &pbd.Empty{}, grpc.FailFast(false))
	if err == nil {
		for _, s := range r.Services {
			ret.Services = append(ret.Services, s)
		}
	}

	return ret
}

// DoRegister Registers this server
func (s Server) DoRegister(server *grpc.Server) {
	pb.RegisterGoBuildMasterServer(server, &s)
}

// ReportHealth determines if the server is healthy
func (s Server) ReportHealth() bool {
	return true
}

// Mote promotes/demotes this server
func (s Server) Mote(master bool) error {
	return nil
}

//GetState gets the state of the server
func (s Server) GetState() []*pbg.State {
	return []*pbg.State{&pbg.State{Key: "last_intent", TimeValue: s.lastIntent.Unix()}}
}

//Compare compares current state to desired state
func (s Server) Compare(ctx context.Context, in *pb.Empty) (*pb.CompareResponse, error) {
	resp := &pb.CompareResponse{}
	list, _ := getFleetStatus(&mainChecker{})
	cc := &pb.Config{}
	for _, jlist := range list {
		for _, job := range jlist.GetDetails() {
			cc.Intents = append(cc.Intents, &pb.Intent{Spec: job.GetSpec()})
		}
	}
	resp.Current = cc
	resp.Desired = s.config

	return resp, nil
}

func getConfig(c checker) *pb.Config {
	list, _ := getFleetStatus(c)
	config := &pb.Config{}

	for _, jlist := range list {
		for _, job := range jlist.Details {
			found := false
			for _, ij := range config.Intents {
				if job.Spec.Name == ij.Spec.Name {
					ij.Count++
					found = true
				}
			}

			if !found {
				config.Intents = append(config.Intents, &pb.Intent{Spec: &pbs.JobSpec{Name: job.Spec.Name}, Count: 1})
			}
		}
	}

	return config
}

// MatchIntent tries to match the intent with the state of production
func (s *Server) MatchIntent() {
	checker := &mainChecker{}
	for s.serving {
		s.Log(fmt.Sprintf("MATCHING %v", s.serving))
		time.Sleep(intentWait)
		s.lastIntent = time.Now()

		state := getConfig(checker)
		s.Log(fmt.Sprintf("GOT CONFIG"))
		diff := configDiff(s.config, state)
		s.Log(fmt.Sprintf("GOT DIFF"))
		joblist := runJobs(diff)
		for _, job := range joblist {
			s.Log(fmt.Sprintf("RUNNING %v", job))
			runJob(job, chooseServer(job, checker))
			s.Log(fmt.Sprintf("RAN"))
		}
	}
}

// SetMaster sets up the master settings
func (s Server) SetMaster() {
	checker := &mainChecker{}
	for s.serving {
		time.Sleep(intentWait)

		log.Printf("Running SetMaster")

		fleet := checker.discover()
		matcher := make(map[string]*pbd.RegistryEntry)
		for _, entry := range fleet.GetServices() {
			if _, ok := matcher[entry.GetName()]; !ok {
				matcher[entry.GetName()] = entry
			} else {
				if entry.GetMaster() {
					matcher[entry.GetName()] = entry
				}
			}
		}

		for _, entry := range matcher {
			if !entry.GetMaster() {
				entry.Master = true
				checker.master(entry)
			}
		}
	}
}

func main() {
	config, err := loadConfig("config.pb")
	if err != nil {
		log.Fatalf("Fatal loading of config: %v", err)
	}

	var sync = flag.Bool("once", false, "One pass intent match")
	s := Server{&goserver.GoServer{}, config, true, time.Now()}

	var quiet = flag.Bool("quiet", true, "Show all output")
	flag.Parse()

	if *quiet {
		log.SetFlags(0)
		log.SetOutput(ioutil.Discard)
	}

	if *sync {
		s.MatchIntent()
	} else {
		s.Register = s
		s.PrepServer()
		s.GoServer.Killme = false
		s.RegisterServer("gobuildmaster", false)
		s.RegisterServingTask(s.MatchIntent)
		s.RegisterServingTask(s.SetMaster)
		s.Serve()
	}
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// 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 apiGatewayConfDeploy

import (
	"database/sql"
	"sync"

	"github.com/30x/apid-core"
)

var (
	gwBlobId int64
)

type DataDeployment struct {
	ID             string
	OrgID          string
	EnvID          string
	BlobID         string
	BlobResourceID string
	Type           string
	Name           string
	Revision       string
	Path           string
	Created        string
	CreatedBy      string
	Updated        string
	UpdatedBy      string
}

type SQLExec interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
}

type dbManagerInterface interface {
	setDbVersion(string)
	initDb() error
	getUnreadyBlobs() ([]string, error)
	getReadyDeployments() ([]DataDeployment, error)
	updateLocalFsLocation(string, string) error
	getLocalFSLocation(string) (string, error)
}

type dbManager struct {
	data  apid.DataService
	db    apid.DB
	dbMux sync.RWMutex
}

func (dbc *dbManager) setDbVersion(version string) {
	db, err := dbc.data.DBVersion(version)
	if err != nil {
		log.Panicf("Unable to access database: %v", err)
	}
	dbc.dbMux.Lock()
	dbc.db = db
	dbc.dbMux.Unlock()
}

func (dbc *dbManager) getDb() apid.DB {
	dbc.dbMux.RLock()
	defer dbc.dbMux.RUnlock()
	return dbc.db
}

func (dbc *dbManager) initDb() error {
	_, err := dbc.getDb().Exec(`
	CREATE TABLE IF NOT EXISTS apid_blob_available (
		id text primary key,
   		local_fs_location text NOT NULL
	);
	`)
	if err != nil {
		return err
	}

	log.Debug("Database table apid_blob_available created.")
	return nil
}

// getUnreadyDeployments() returns array of resources that are not yet to be processed
// TODO make it work with new schema
func (dbc *dbManager) getUnreadyBlobs() (ids []string, err error) {

	// get unready blob id
	rows, err := dbc.getDb().Query(`
	SELECT a.bean_blob_id
		FROM metadata_runtime_entity_metadata as a
		LEFT JOIN apid_blob_available as b
		ON a.bean_blob_id = b.id
		WHERE b.id IS NULL;
	`)
	if err != nil {
		log.Errorf("DB Query for project_runtime_blob_metadata failed %v", err)
		return
	}
	defer rows.Close()
	for rows.Next() {
		var id string
		rows.Scan(&id)
		ids = append(ids, id)
	}

	// get unready resource id
	rows, err = dbc.getDb().Query(`
	SELECT a.resource_blob_id
		FROM metadata_runtime_entity_metadata as a
		LEFT JOIN apid_blob_available as b
		ON a.resource_blob_id = b.id
		WHERE (b.id IS NULL AND a.resource_blob_id IS NOT NULL AND a.resource_blob_id != '');
	`)
	if err != nil {
		log.Errorf("DB Query for project_runtime_blob_metadata failed %v", err)
		return
	}
	defer rows.Close()
	for rows.Next() {
		var id string
		rows.Scan(&id)
		ids = append(ids, id)
	}

	log.Debugf("Unready blobId %v", ids)
	return
}

// TODO there's a bug in the db statement
func (dbc *dbManager) getReadyDeployments() ([]DataDeployment, error) {

	rows, err := dbc.getDb().Query(`
		SELECT 	a.id,
			a.organization_id,
			a.environment_id,
			a.bean_blob_id,
			a.resource_blob_id,
			a.type,
			a.name,
			a.revision,
			a.path,
			a.created_at,
			a.created_by,
			a.updated_at,
			a.updated_by,
			b.local_fs_location
		FROM metadata_runtime_entity_metadata as a
		INNER JOIN edgex_blob_available as b
		ON (a.bean_blob_id = b.id)
		WHERE a.id IN (
			SELECT
					a.id
				FROM metadata_runtime_entity_metadata as a
				INNER JOIN edgex_blob_available as b
				ON a.resource_blob_id = b.id
				WHERE a.resource_blob_id != ""
			INTERSECT
				SELECT
					a.id
				FROM metadata_runtime_entity_metadata as a
				INNER JOIN edgex_blob_available as b
				ON a.resource_blob_id = b.id
				WHERE a.resource_blob_id != ""

			UNION
				SELECT
					a.id
				FROM metadata_runtime_entity_metadata as a
				INNER JOIN edgex_blob_available as b
				ON a.bean_blob_id = b.id
				WHERE a.resource_blob_id = ""
		)
	;
	`)

	if err != nil {
		log.Errorf("DB Query for project_runtime_blob_metadata failed %v", err)
		return nil, err
	}
	defer rows.Close()

	deployments, err := dataDeploymentsFromRow(rows)
	if err != nil {
		return nil, err
	}

	log.Debugf("Configurations ready: %v", deployments)

	if len(deployments) == 0 {
		log.Debug("No resources ready to be deployed")
		err = sql.ErrNoRows
	}
	return deployments, err

}

func (dbc *dbManager) updateLocalFsLocation(blobId, localFsLocation string) error {

	stmt, err := dbc.getDb().Prepare(`
		INSERT OR IGNORE INTO apid_blob_available (
		id,
		local_fs_location
		) VALUES (?, ?);`)
	if err != nil {
		log.Errorf("PREPARE updateLocalFsLocation failed: %v", err)
		return err
	}
	defer stmt.Close()

	_, err = stmt.Exec(blobId, localFsLocation)
	if err != nil {
		log.Errorf("UPDATE apid_blob_available id {%s} local_fs_location {%s} failed", localFsLocation, err)
		return err
	}

	log.Debugf("INSERT apid_blob_available {%s} local_fs_location {%s} succeeded", blobId, localFsLocation)
	return nil

}

func (dbc *dbManager) getLocalFSLocation(blobId string) (localFsLocation string, err error) {

	log.Debugf("Getting the blob file for blobId {%s}", blobId)
	rows, err := dbc.getDb().Query("SELECT local_fs_location FROM apid_blob_available WHERE id = '" + blobId + "'")
	if err != nil {
		log.Errorf("SELECT local_fs_location failed %v", err)
		return "", err
	}

	defer rows.Close()
	for rows.Next() {
		err = rows.Scan(&localFsLocation)
		if err != nil {
			log.Errorf("Scan local_fs_location failed %v", err)
			return "", err
		}
		log.Debugf("Got the blob file {%s} for blobId {%s}", localFsLocation, blobId)
	}
	return
}

func dataDeploymentsFromRow(rows *sql.Rows) (deployments []DataDeployment, err error) {
	for rows.Next() {
		dep := DataDeployment{}
		err = rows.Scan(
			&dep.ID,
			&dep.OrgID,
			&dep.EnvID,
			&dep.BlobID,
			&dep.BlobResourceID,
			&dep.Type,
			&dep.Name,
			&dep.Revision,
			&dep.Path,
			&dep.Created,
			&dep.CreatedBy,
			&dep.Updated,
			&dep.UpdatedBy,
		)
		if err != nil {
			return nil, err
		}
		deployments = append(deployments, dep)
	}
	return
}
<commit_msg>fix bug in db statement<commit_after>// Copyright 2017 Google Inc.
//
// 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 apiGatewayConfDeploy

import (
	"database/sql"
	"sync"

	"github.com/30x/apid-core"
)

var (
	gwBlobId int64
)

type DataDeployment struct {
	ID             string
	OrgID          string
	EnvID          string
	BlobID         string
	BlobResourceID string
	Type           string
	Name           string
	Revision       string
	Path           string
	Created        string
	CreatedBy      string
	Updated        string
	UpdatedBy      string
}

type SQLExec interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
}

type dbManagerInterface interface {
	setDbVersion(string)
	initDb() error
	getUnreadyBlobs() ([]string, error)
	getReadyDeployments() ([]DataDeployment, error)
	updateLocalFsLocation(string, string) error
	getLocalFSLocation(string) (string, error)
}

type dbManager struct {
	data  apid.DataService
	db    apid.DB
	dbMux sync.RWMutex
}

func (dbc *dbManager) setDbVersion(version string) {
	db, err := dbc.data.DBVersion(version)
	if err != nil {
		log.Panicf("Unable to access database: %v", err)
	}
	dbc.dbMux.Lock()
	dbc.db = db
	dbc.dbMux.Unlock()
}

func (dbc *dbManager) getDb() apid.DB {
	dbc.dbMux.RLock()
	defer dbc.dbMux.RUnlock()
	return dbc.db
}

func (dbc *dbManager) initDb() error {
	_, err := dbc.getDb().Exec(`
	CREATE TABLE IF NOT EXISTS apid_blob_available (
		id text primary key,
   		local_fs_location text NOT NULL
	);
	`)
	if err != nil {
		return err
	}

	log.Debug("Database table apid_blob_available created.")
	return nil
}

// getUnreadyDeployments() returns array of resources that are not yet to be processed
// TODO make it work with new schema
func (dbc *dbManager) getUnreadyBlobs() (ids []string, err error) {

	// get unready blob id
	rows, err := dbc.getDb().Query(`
	SELECT a.bean_blob_id
		FROM metadata_runtime_entity_metadata as a
		LEFT JOIN apid_blob_available as b
		ON a.bean_blob_id = b.id
		WHERE b.id IS NULL;
	`)
	if err != nil {
		log.Errorf("DB Query for project_runtime_blob_metadata failed %v", err)
		return
	}
	defer rows.Close()
	for rows.Next() {
		var id string
		rows.Scan(&id)
		ids = append(ids, id)
	}

	// get unready resource id
	rows, err = dbc.getDb().Query(`
	SELECT a.resource_blob_id
		FROM metadata_runtime_entity_metadata as a
		LEFT JOIN apid_blob_available as b
		ON a.resource_blob_id = b.id
		WHERE (b.id IS NULL AND a.resource_blob_id IS NOT NULL AND a.resource_blob_id != '');
	`)
	if err != nil {
		log.Errorf("DB Query for project_runtime_blob_metadata failed %v", err)
		return
	}
	defer rows.Close()
	for rows.Next() {
		var id string
		rows.Scan(&id)
		ids = append(ids, id)
	}

	log.Debugf("Unready blobId %v", ids)
	return
}

func (dbc *dbManager) getReadyDeployments() ([]DataDeployment, error) {

	rows, err := dbc.getDb().Query(`
		SELECT 	a.id,
			a.organization_id,
			a.environment_id,
			a.bean_blob_id,
			a.resource_blob_id,
			a.type,
			a.name,
			a.revision,
			a.path,
			a.created_at,
			a.created_by,
			a.updated_at,
			a.updated_by
		FROM metadata_runtime_entity_metadata as a
		WHERE a.id IN (
			SELECT
					a.id
				FROM metadata_runtime_entity_metadata as a
				INNER JOIN apid_blob_available as b
				ON a.resource_blob_id = b.id
				WHERE a.resource_blob_id != ""
			INTERSECT
				SELECT
					a.id
				FROM metadata_runtime_entity_metadata as a
				INNER JOIN apid_blob_available as b
				ON a.bean_blob_id = b.id
				WHERE a.resource_blob_id != ""

			UNION
				SELECT
					a.id
				FROM metadata_runtime_entity_metadata as a
				INNER JOIN apid_blob_available as b
				ON a.bean_blob_id = b.id
				WHERE a.resource_blob_id = ""
		)
	;
	`)

	if err != nil {
		log.Errorf("DB Query for project_runtime_blob_metadata failed %v", err)
		return nil, err
	}
	defer rows.Close()

	deployments, err := dataDeploymentsFromRow(rows)
	if err != nil {
		return nil, err
	}

	log.Debugf("Configurations ready: %v", deployments)

	if len(deployments) == 0 {
		log.Debug("No resources ready to be deployed")
		err = sql.ErrNoRows
	}
	return deployments, err

}

func (dbc *dbManager) updateLocalFsLocation(blobId, localFsLocation string) error {

	stmt, err := dbc.getDb().Prepare(`
		INSERT OR IGNORE INTO apid_blob_available (
		id,
		local_fs_location
		) VALUES (?, ?);`)
	if err != nil {
		log.Errorf("PREPARE updateLocalFsLocation failed: %v", err)
		return err
	}
	defer stmt.Close()

	_, err = stmt.Exec(blobId, localFsLocation)
	if err != nil {
		log.Errorf("UPDATE apid_blob_available id {%s} local_fs_location {%s} failed", localFsLocation, err)
		return err
	}

	log.Debugf("INSERT apid_blob_available {%s} local_fs_location {%s} succeeded", blobId, localFsLocation)
	return nil

}

func (dbc *dbManager) getLocalFSLocation(blobId string) (localFsLocation string, err error) {

	log.Debugf("Getting the blob file for blobId {%s}", blobId)
	rows, err := dbc.getDb().Query("SELECT local_fs_location FROM apid_blob_available WHERE id = '" + blobId + "'")
	if err != nil {
		log.Errorf("SELECT local_fs_location failed %v", err)
		return "", err
	}

	defer rows.Close()
	for rows.Next() {
		err = rows.Scan(&localFsLocation)
		if err != nil {
			log.Errorf("Scan local_fs_location failed %v", err)
			return "", err
		}
		log.Debugf("Got the blob file {%s} for blobId {%s}", localFsLocation, blobId)
	}
	return
}

func dataDeploymentsFromRow(rows *sql.Rows) (deployments []DataDeployment, err error) {
	for rows.Next() {
		dep := DataDeployment{}
		err = rows.Scan(
			&dep.ID,
			&dep.OrgID,
			&dep.EnvID,
			&dep.BlobID,
			&dep.BlobResourceID,
			&dep.Type,
			&dep.Name,
			&dep.Revision,
			&dep.Path,
			&dep.Created,
			&dep.CreatedBy,
			&dep.Updated,
			&dep.UpdatedBy,
		)
		if err != nil {
			return nil, err
		}
		deployments = append(deployments, dep)
	}
	return
}
<|endoftext|>


<commit_before>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

package echo

import (
	"encoding/gob"
	"fmt"
	"net/http"
)

func init() {
	gob.Register(&RawData{})
	gob.Register(H{})
}

//Status 状态值
type Status struct {
	Text string
	Code int
}

var (
	//States 状态码对应的文本
	States = map[State]*Status{
		-2: {`Non-Privileged`, http.StatusOK},  //无权限
		-1: {`Unauthenticated`, http.StatusOK}, //未登录
		0:  {`Failure`, http.StatusOK},         //操作失败
		1:  {`Success`, http.StatusOK},         //操作成功
	}
	//GetStatus 获取状态值
	GetStatus = func(key State) (*Status, bool) {
		v, y := States[key]
		return v, y
	}
)

//State 状态码类型
type State int

func (s State) String() string {
	if v, y := GetStatus(s); y {
		return v.Text
	}
	return `Undefined`
}

//Int 返回int类型的自定义状态码
func (s State) Int() int {
	return int(s)
}

//HTTPCode 返回HTTP状态码
func (s State) HTTPCode() int {
	if v, y := GetStatus(s); y {
		return v.Code
	}
	return http.StatusOK
}

//Data 响应数据
type Data interface {
	Assign(key string, val interface{})
	Assignx(values *map[string]interface{})
	SetTmplFuncs()
	SetContext(ctx Context) Data
	String() string
	Set(code int, args ...interface{}) Data
	Reset() Data
	SetError(err error, args ...int) Data
	SetCode(code int) Data
	SetURL(url string) Data
	SetInfo(info interface{}, args ...int) Data
	SetZone(zone interface{}) Data
	SetData(data interface{}, args ...int) Data
	Gets() (code State, info interface{}, zone interface{}, data interface{})
	GetCode() State
	GetInfo() interface{}
	GetZone() interface{}
	GetData() interface{}
}

type RawData struct {
	context Context
	Code    State
	State   string `json:",omitempty" xml:",omitempty"`
	Info    interface{}
	URL     string      `json:",omitempty" xml:",omitempty"`
	Zone    interface{} `json:",omitempty" xml:",omitempty"`
	Data    interface{} `json:",omitempty" xml:",omitempty"`
}

func (d *RawData) Error() string {
	return fmt.Sprintf(`%v`, d.Info)
}

func (d *RawData) Reset() Data {
	d.Code = State(0)
	d.State = ``
	d.Info = nil
	d.Zone = nil
	d.Data = nil
	return d
}

func (d *RawData) String() string {
	return fmt.Sprintf(`%v`, d.Info)
}

//Gets 获取全部数据
func (d *RawData) Gets() (State, interface{}, interface{}, interface{}) {
	return d.Code, d.Info, d.Zone, d.Data
}

func (d *RawData) GetCode() State {
	return d.Code
}

func (d *RawData) GetInfo() interface{} {
	return d.Info
}

func (d *RawData) GetZone() interface{} {
	return d.Zone
}

//GetData 获取数据
func (d *RawData) GetData() interface{} {
	return d.Data
}

//SetError 设置错误
func (d *RawData) SetError(err error, args ...int) Data {
	if err != nil {
		if len(args) > 0 {
			d.SetCode(args[0])
		} else {
			d.SetCode(0)
		}
		d.Info = err.Error()
	} else {
		d.SetCode(1)
	}
	return d
}

//SetCode 设置状态码
func (d *RawData) SetCode(code int) Data {
	d.Code = State(code)
	d.State = d.Code.String()
	return d
}

//SetURL 设置跳转网址
func (d *RawData) SetURL(url string) Data {
	d.URL = url
	return d
}

//SetInfo 设置提示信息
func (d *RawData) SetInfo(info interface{}, args ...int) Data {
	d.Info = info
	if len(args) > 0 {
		d.SetCode(args[0])
	}
	return d
}

//SetZone 设置提示区域
func (d *RawData) SetZone(zone interface{}) Data {
	d.Zone = zone
	return d
}

//SetData 设置正常数据
func (d *RawData) SetData(data interface{}, args ...int) Data {
	d.Data = data
	if len(args) > 0 {
		d.SetCode(args[0])
	} else {
		d.SetCode(1)
	}
	return d
}

//SetContext 设置Context
func (d *RawData) SetContext(ctx Context) Data {
	d.context = ctx
	return d
}

//Assign 赋值
func (d *RawData) Assign(key string, val interface{}) {
	data, _ := d.Data.(H)
	if data == nil {
		data = H{}
	}
	data[key] = val
	d.Data = data
}

//Assignx 批量赋值
func (d *RawData) Assignx(values *map[string]interface{}) {
	if values == nil {
		return
	}
	data, _ := d.Data.(H)
	if data == nil {
		data = H{}
	}
	for key, val := range *values {
		data[key] = val
	}
	d.Data = data
}

//SetTmplFuncs 设置模板函数
func (d *RawData) SetTmplFuncs() {
	flash, ok := d.context.Flash().(*RawData)
	if ok {
		d.context.Session().Save()
		d.context.SetFunc(`Code`, func() State {
			return flash.Code
		})
		d.context.SetFunc(`Info`, func() interface{} {
			return flash.Info
		})
		d.context.SetFunc(`Zone`, func() interface{} {
			return flash.Zone
		})
	} else {
		d.context.SetFunc(`Code`, func() State {
			return d.Code
		})
		d.context.SetFunc(`Info`, func() interface{} {
			return d.Info
		})
		d.context.SetFunc(`Zone`, func() interface{} {
			return d.Zone
		})
	}
}

// Set 设置输出(code,info,zone,RawData)
func (d *RawData) Set(code int, args ...interface{}) Data {
	d.SetCode(code)
	var hasData bool
	switch len(args) {
	case 3:
		d.Data = args[2]
		hasData = true
		fallthrough
	case 2:
		d.Zone = args[1]
		fallthrough
	case 1:
		d.Info = args[0]
		if !hasData {
			flash := &RawData{
				context: d.context,
				Code:    d.Code,
				State:   d.State,
				Info:    d.Info,
				Zone:    d.Zone,
				Data:    nil,
			}
			d.context.Session().AddFlash(flash).Save()
		}
	}
	return d
}

func NewData(ctx Context) *RawData {
	c := State(1)
	return &RawData{
		context: ctx,
		Code:    c,
		State:   c.String(),
	}
}

//KV 键值对
type KV struct {
	K string
	V string
}

type KVList []*KV

func (list *KVList) Add(k, v string) {
	*list = append(*list, &KV{K: k, V: v})
}

func (list *KVList) Del(i int) {
	n := len(*list)
	if i+1 < n {
		*list = append((*list)[0:i], (*list)[i+1:]...)
	} else if i < n {
		*list = (*list)[0:i]
	}
}

func (list *KVList) Reset() {
	*list = (*list)[0:0]
}

//NewKVData 键值对数据
func NewKVData() *KVData {
	return &KVData{
		slice: []*KV{},
		index: map[string][]int{},
	}
}

//KVData 键值对数据（保持顺序）
type KVData struct {
	slice []*KV
	index map[string][]int
}

//Slice 返回切片
func (a *KVData) Slice() []*KV {
	return a.slice
}

//Index 返回某个key的所有索引值
func (a *KVData) Index(k string) []int {
	v, _ := a.index[k]
	return v
}

//Indexes 返回所有索引值
func (a *KVData) Indexes() map[string][]int {
	return a.index
}

//Reset 重置
func (a *KVData) Reset() *KVData {
	a.index = map[string][]int{}
	a.slice = []*KV{}
	return a
}

//Add 添加键值
func (a *KVData) Add(k, v string) *KVData {
	if _, y := a.index[k]; !y {
		a.index[k] = []int{}
	}
	a.index[k] = append(a.index[k], len(a.slice))
	a.slice = append(a.slice, &KV{K: k, V: v})
	return a
}

//Set 设置首个键值
func (a *KVData) Set(k, v string) *KVData {
	a.index[k] = []int{0}
	a.slice = []*KV{&KV{K: k, V: v}}
	return a
}

func (a *KVData) Get(k string) string {
	if indexes, ok := a.index[k]; ok {
		if len(indexes) > 0 {
			return a.slice[indexes[0]].V
		}
	}
	return ``
}

func (a *KVData) Has(k string) bool {
	if _, ok := a.index[k]; ok {
		return true
	}
	return false
}

//Delete 设置某个键的所有值
func (a *KVData) Delete(ks ...string) *KVData {
	indexes := []int{}
	for _, k := range ks {
		v, y := a.index[k]
		if !y {
			continue
		}
		for _, key := range v {
			indexes = append(indexes, key)
		}
	}
	newSlice := []*KV{}
	a.index = map[string][]int{}
	for i, v := range a.slice {
		var exists bool
		for _, idx := range indexes {
			if i != idx {
				continue
			}
			exists = true
			break
		}
		if exists {
			continue
		}
		if _, y := a.index[v.K]; !y {
			a.index[v.K] = []int{}
		}
		a.index[v.K] = append(a.index[v.K], len(newSlice))
		newSlice = append(newSlice, v)
	}
	a.slice = newSlice
	return a
}
<commit_msg>update<commit_after>/*

   Copyright 2016 Wenhui Shen <www.webx.top>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

*/

package echo

import (
	"encoding/gob"
	"fmt"
	"net/http"
)

func init() {
	gob.Register(&RawData{})
	gob.Register(H{})
}

//Status 状态值
type Status struct {
	Text string
	Code int
}

var (
	//States 状态码对应的文本
	States = map[State]*Status{
		-2: {`Non-Privileged`, http.StatusOK},  //无权限
		-1: {`Unauthenticated`, http.StatusOK}, //未登录
		0:  {`Failure`, http.StatusOK},         //操作失败
		1:  {`Success`, http.StatusOK},         //操作成功
	}
	//GetStatus 获取状态值
	GetStatus = func(key State) (*Status, bool) {
		v, y := States[key]
		return v, y
	}
)

//State 状态码类型
type State int

func (s State) String() string {
	if v, y := GetStatus(s); y {
		return v.Text
	}
	return `Undefined`
}

//Int 返回int类型的自定义状态码
func (s State) Int() int {
	return int(s)
}

//HTTPCode 返回HTTP状态码
func (s State) HTTPCode() int {
	if v, y := GetStatus(s); y {
		return v.Code
	}
	return http.StatusOK
}

//Data 响应数据
type Data interface {
	Assign(key string, val interface{})
	Assignx(values *map[string]interface{})
	SetTmplFuncs()
	SetContext(ctx Context) Data
	String() string
	Set(code int, args ...interface{}) Data
	Reset() Data
	SetError(err error, args ...int) Data
	SetCode(code int) Data
	SetURL(url string, args ...int) Data
	SetInfo(info interface{}, args ...int) Data
	SetZone(zone interface{}) Data
	SetData(data interface{}, args ...int) Data
	Gets() (code State, info interface{}, zone interface{}, data interface{})
	GetCode() State
	GetInfo() interface{}
	GetZone() interface{}
	GetData() interface{}
}

type RawData struct {
	context Context
	Code    State
	State   string `json:",omitempty" xml:",omitempty"`
	Info    interface{}
	URL     string      `json:",omitempty" xml:",omitempty"`
	Zone    interface{} `json:",omitempty" xml:",omitempty"`
	Data    interface{} `json:",omitempty" xml:",omitempty"`
}

func (d *RawData) Error() string {
	return fmt.Sprintf(`%v`, d.Info)
}

func (d *RawData) Reset() Data {
	d.Code = State(0)
	d.State = ``
	d.Info = nil
	d.Zone = nil
	d.Data = nil
	return d
}

func (d *RawData) String() string {
	return fmt.Sprintf(`%v`, d.Info)
}

//Gets 获取全部数据
func (d *RawData) Gets() (State, interface{}, interface{}, interface{}) {
	return d.Code, d.Info, d.Zone, d.Data
}

func (d *RawData) GetCode() State {
	return d.Code
}

func (d *RawData) GetInfo() interface{} {
	return d.Info
}

func (d *RawData) GetZone() interface{} {
	return d.Zone
}

//GetData 获取数据
func (d *RawData) GetData() interface{} {
	return d.Data
}

//SetError 设置错误
func (d *RawData) SetError(err error, args ...int) Data {
	if err != nil {
		if len(args) > 0 {
			d.SetCode(args[0])
		} else {
			d.SetCode(0)
		}
		d.Info = err.Error()
	} else {
		d.SetCode(1)
	}
	return d
}

//SetCode 设置状态码
func (d *RawData) SetCode(code int) Data {
	d.Code = State(code)
	d.State = d.Code.String()
	return d
}

//SetURL 设置跳转网址
func (d *RawData) SetURL(url string, args ...int) Data {
	d.URL = url
	if len(args) > 0 {
		d.SetCode(args[0])
	}
	return d
}

//SetInfo 设置提示信息
func (d *RawData) SetInfo(info interface{}, args ...int) Data {
	d.Info = info
	if len(args) > 0 {
		d.SetCode(args[0])
	}
	return d
}

//SetZone 设置提示区域
func (d *RawData) SetZone(zone interface{}) Data {
	d.Zone = zone
	return d
}

//SetData 设置正常数据
func (d *RawData) SetData(data interface{}, args ...int) Data {
	d.Data = data
	if len(args) > 0 {
		d.SetCode(args[0])
	} else {
		d.SetCode(1)
	}
	return d
}

//SetContext 设置Context
func (d *RawData) SetContext(ctx Context) Data {
	d.context = ctx
	return d
}

//Assign 赋值
func (d *RawData) Assign(key string, val interface{}) {
	data, _ := d.Data.(H)
	if data == nil {
		data = H{}
	}
	data[key] = val
	d.Data = data
}

//Assignx 批量赋值
func (d *RawData) Assignx(values *map[string]interface{}) {
	if values == nil {
		return
	}
	data, _ := d.Data.(H)
	if data == nil {
		data = H{}
	}
	for key, val := range *values {
		data[key] = val
	}
	d.Data = data
}

//SetTmplFuncs 设置模板函数
func (d *RawData) SetTmplFuncs() {
	flash, ok := d.context.Flash().(*RawData)
	if ok {
		d.context.Session().Save()
		d.context.SetFunc(`Code`, func() State {
			return flash.Code
		})
		d.context.SetFunc(`Info`, func() interface{} {
			return flash.Info
		})
		d.context.SetFunc(`Zone`, func() interface{} {
			return flash.Zone
		})
	} else {
		d.context.SetFunc(`Code`, func() State {
			return d.Code
		})
		d.context.SetFunc(`Info`, func() interface{} {
			return d.Info
		})
		d.context.SetFunc(`Zone`, func() interface{} {
			return d.Zone
		})
	}
}

// Set 设置输出(code,info,zone,RawData)
func (d *RawData) Set(code int, args ...interface{}) Data {
	d.SetCode(code)
	var hasData bool
	switch len(args) {
	case 3:
		d.Data = args[2]
		hasData = true
		fallthrough
	case 2:
		d.Zone = args[1]
		fallthrough
	case 1:
		d.Info = args[0]
		if !hasData {
			flash := &RawData{
				context: d.context,
				Code:    d.Code,
				State:   d.State,
				Info:    d.Info,
				Zone:    d.Zone,
				Data:    nil,
			}
			d.context.Session().AddFlash(flash).Save()
		}
	}
	return d
}

func NewData(ctx Context) *RawData {
	c := State(1)
	return &RawData{
		context: ctx,
		Code:    c,
		State:   c.String(),
	}
}

//KV 键值对
type KV struct {
	K string
	V string
}

type KVList []*KV

func (list *KVList) Add(k, v string) {
	*list = append(*list, &KV{K: k, V: v})
}

func (list *KVList) Del(i int) {
	n := len(*list)
	if i+1 < n {
		*list = append((*list)[0:i], (*list)[i+1:]...)
	} else if i < n {
		*list = (*list)[0:i]
	}
}

func (list *KVList) Reset() {
	*list = (*list)[0:0]
}

//NewKVData 键值对数据
func NewKVData() *KVData {
	return &KVData{
		slice: []*KV{},
		index: map[string][]int{},
	}
}

//KVData 键值对数据（保持顺序）
type KVData struct {
	slice []*KV
	index map[string][]int
}

//Slice 返回切片
func (a *KVData) Slice() []*KV {
	return a.slice
}

//Index 返回某个key的所有索引值
func (a *KVData) Index(k string) []int {
	v, _ := a.index[k]
	return v
}

//Indexes 返回所有索引值
func (a *KVData) Indexes() map[string][]int {
	return a.index
}

//Reset 重置
func (a *KVData) Reset() *KVData {
	a.index = map[string][]int{}
	a.slice = []*KV{}
	return a
}

//Add 添加键值
func (a *KVData) Add(k, v string) *KVData {
	if _, y := a.index[k]; !y {
		a.index[k] = []int{}
	}
	a.index[k] = append(a.index[k], len(a.slice))
	a.slice = append(a.slice, &KV{K: k, V: v})
	return a
}

//Set 设置首个键值
func (a *KVData) Set(k, v string) *KVData {
	a.index[k] = []int{0}
	a.slice = []*KV{&KV{K: k, V: v}}
	return a
}

func (a *KVData) Get(k string) string {
	if indexes, ok := a.index[k]; ok {
		if len(indexes) > 0 {
			return a.slice[indexes[0]].V
		}
	}
	return ``
}

func (a *KVData) Has(k string) bool {
	if _, ok := a.index[k]; ok {
		return true
	}
	return false
}

//Delete 设置某个键的所有值
func (a *KVData) Delete(ks ...string) *KVData {
	indexes := []int{}
	for _, k := range ks {
		v, y := a.index[k]
		if !y {
			continue
		}
		for _, key := range v {
			indexes = append(indexes, key)
		}
	}
	newSlice := []*KV{}
	a.index = map[string][]int{}
	for i, v := range a.slice {
		var exists bool
		for _, idx := range indexes {
			if i != idx {
				continue
			}
			exists = true
			break
		}
		if exists {
			continue
		}
		if _, y := a.index[v.K]; !y {
			a.index[v.K] = []int{}
		}
		a.index[v.K] = append(a.index[v.K], len(newSlice))
		newSlice = append(newSlice, v)
	}
	a.slice = newSlice
	return a
}
<|endoftext|>


<commit_before>package gorobokassa

import (
	. "github.com/smartystreets/goconvey/convey"
	"log"
	"net/http"
	"net/url"
	"testing"
)

func TestUrlGeneration(t *testing.T) {
	Convey("Url", t, func() {
		in, err := buildRedirectUrl("lel", "lel", 11, 500, "KEK")
		out := "https://auth.robokassa.ru/Merchant/Index.aspx?Desc=KEK&InvId=11&MrchLogin=lel&OutSum=500&SignatureValue=e8c1c7bcacfa991b8612f2759804abd9"
		So(err, ShouldBeNil)
		So(in, ShouldEqual, out)
		Convey("Less than zero", func() {
			_, err := buildRedirectUrl("d", "s", 11, -200, "test")
			So(err, ShouldNotBeNil)
		})
	})
	Convey("Result", t, func() {
		request := &http.Request{}
		q := url.URL{}
		params := url.Values{}
		params.Add("OutSum", "1200")
		params.Add("InvId", "666")
		params.Add("SignatureValue", "3a3869287aaa475dda04d93280705839")
		q.RawQuery = params.Encode()
		request.URL = &q
		log.Println(q.String())
		So(verifyResult("password", 666, 1200, "3a3869287aaa475dda04d93280705839"), ShouldBeTrue)
		So(verifyResult("password", 666, 1200, "3a3869287aaa475dda04e93280705839"), ShouldBeFalse)
		So(verifyRequest("password", request), ShouldBeTrue)
		So(verifyRequest("test", request), ShouldBeFalse)
	})

	Convey("Client", t, func() {

		c := New("login", "pwd1", "password")
		Convey("Url", func() {
			in, err := c.Url(110, 2000, "description")
			out := "https://auth.robokassa.ru/Merchant/Index.aspx?Desc=description&InvId=110&MrchLogin=login&OutSum=2000&SignatureValue=1364f38f54e76a0affe62974bfdbde85"
			So(err, ShouldBeNil)
			So(in, ShouldEqual, out)
		})
		Convey("Check", func() {
			request := &http.Request{}
			q := url.URL{}
			params := url.Values{}
			params.Add("OutSum", "1200")
			params.Add("InvId", "666")
			params.Add("SignatureValue", "3a3869287aaa475dda04d93280705839")
			q.RawQuery = params.Encode()
			request.URL = &q
			So(c.Check(request), ShouldBeTrue)
		})

	})
}
<commit_msg>removed newline<commit_after>package gorobokassa

import (
	. "github.com/smartystreets/goconvey/convey"
	"log"
	"net/http"
	"net/url"
	"testing"
)

func TestUrlGeneration(t *testing.T) {
	Convey("Url", t, func() {
		in, err := buildRedirectUrl("lel", "lel", 11, 500, "KEK")
		out := "https://auth.robokassa.ru/Merchant/Index.aspx?Desc=KEK&InvId=11&MrchLogin=lel&OutSum=500&SignatureValue=e8c1c7bcacfa991b8612f2759804abd9"
		So(err, ShouldBeNil)
		So(in, ShouldEqual, out)
		Convey("Less than zero", func() {
			_, err := buildRedirectUrl("d", "s", 11, -200, "test")
			So(err, ShouldNotBeNil)
		})
	})
	Convey("Result", t, func() {
		request := &http.Request{}
		q := url.URL{}
		params := url.Values{}
		params.Add("OutSum", "1200")
		params.Add("InvId", "666")
		params.Add("SignatureValue", "3a3869287aaa475dda04d93280705839")
		q.RawQuery = params.Encode()
		request.URL = &q
		log.Println(q.String())
		So(verifyResult("password", 666, 1200, "3a3869287aaa475dda04d93280705839"), ShouldBeTrue)
		So(verifyResult("password", 666, 1200, "3a3869287aaa475dda04e93280705839"), ShouldBeFalse)
		So(verifyRequest("password", request), ShouldBeTrue)
		So(verifyRequest("test", request), ShouldBeFalse)
	})

	Convey("Client", t, func() {
		c := New("login", "pwd1", "password")
		Convey("Url", func() {
			in, err := c.Url(110, 2000, "description")
			out := "https://auth.robokassa.ru/Merchant/Index.aspx?Desc=description&InvId=110&MrchLogin=login&OutSum=2000&SignatureValue=1364f38f54e76a0affe62974bfdbde85"
			So(err, ShouldBeNil)
			So(in, ShouldEqual, out)
		})
		Convey("Check", func() {
			request := &http.Request{}
			q := url.URL{}
			params := url.Values{}
			params.Add("OutSum", "1200")
			params.Add("InvId", "666")
			params.Add("SignatureValue", "3a3869287aaa475dda04d93280705839")
			q.RawQuery = params.Encode()
			request.URL = &q
			So(c.Check(request), ShouldBeTrue)
		})

	})
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2014 VMware, Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package importx

import (
	"encoding/xml"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"net/url"
	"sync"
	"time"

	"github.com/vmware/govmomi"
	"github.com/vmware/govmomi/govc/cli"
	"github.com/vmware/govmomi/govc/flags"
	"github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/soap"
	"github.com/vmware/govmomi/vim25/types"
)

type ovf struct {
	*flags.DatastoreFlag
	*flags.ResourcePoolFlag
	*flags.SearchFlag
	*flags.OutputFlag

	Client       *govmomi.Client
	Datacenter   *govmomi.Datacenter
	Datastore    *govmomi.Datastore
	ResourcePool *govmomi.ResourcePool

	Archive
}

func init() {
	cli.Register("import.ovf", newOvf())
}

func newOvf() *ovf {
	return &ovf{
		SearchFlag: flags.NewSearchFlag(flags.SearchHosts),
	}
}

func (cmd *ovf) Register(f *flag.FlagSet) {
}

func (cmd *ovf) Process() error { return nil }

func (cmd *ovf) Run(f *flag.FlagSet) error {
	file, err := cmd.Prepare(f)

	if err != nil {
		return err
	}

	cmd.Archive = &FileArchive{file}

	return cmd.Import(file)
}

func (cmd *ovf) Prepare(f *flag.FlagSet) (importable, error) {
	var err error

	args := f.Args()
	if len(args) != 1 {
		return "", errors.New("no file to import")
	}

	file := importable(f.Arg(0))

	cmd.Client, err = cmd.DatastoreFlag.Client()
	if err != nil {
		return "", err
	}

	cmd.Datacenter, err = cmd.DatastoreFlag.Datacenter()
	if err != nil {
		return "", err
	}

	cmd.Datastore, err = cmd.DatastoreFlag.Datastore()
	if err != nil {
		return "", err
	}

	cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool()
	if err != nil {
		return "", err
	}

	return file, nil
}

func (cmd *ovf) ReadAll(name string) ([]byte, error) {
	f, _, err := cmd.Open(name)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return ioutil.ReadAll(f)
}

func (cmd *ovf) Import(i importable) error {
	c := cmd.Client

	desc, err := cmd.ReadAll(string(i))
	if err != nil {
		return err
	}

	// extract name from .ovf for use as VM name
	ovf := struct {
		VirtualSystem struct {
			Name string
		}
	}{}

	if err := xml.Unmarshal(desc, &ovf); err != nil {
		return fmt.Errorf("failed to parse ovf: %s", err.Error())
	}

	cisp := types.OvfCreateImportSpecParams{
		EntityName: ovf.VirtualSystem.Name,
		OvfManagerCommonParams: types.OvfManagerCommonParams{
			Locale: "US",
		},
	}

	spec, err := c.OvfManager().CreateImportSpec(string(desc), cmd.ResourcePool, cmd.Datastore, cisp)
	if err != nil {
		return err
	}

	if spec.Error != nil {
		return errors.New(spec.Error[0].LocalizedMessage)
	}

	if spec.Warning != nil {
		for _, w := range spec.Warning {
			fmt.Printf("Warning: %s\n", w.LocalizedMessage)
		}
	}

	// TODO: ImportSpec may have unitNumber==0, but this field is optional in the wsdl
	// and hence omitempty in the struct tag; but unitNumber is required for certain devices.
	s := &spec.ImportSpec.(*types.VirtualMachineImportSpec).ConfigSpec
	for _, d := range s.DeviceChange {
		n := &d.GetVirtualDeviceConfigSpec().Device.GetVirtualDevice().UnitNumber
		if *n == 0 {
			*n = -1
		}
	}

	host, err := cmd.HostSystem()
	if err != nil {
		return err
	}

	// TODO: need a folder option
	folders, err := cmd.Datacenter.Folders(c)
	if err != nil {
		return err
	}
	folder := &folders.VmFolder

	lease, err := cmd.ResourcePool.ImportVApp(c, spec.ImportSpec, folder, host)
	if err != nil {
		return err
	}

	info, err := lease.Wait(c)
	if err != nil {
		return err
	}

	for _, device := range info.DeviceUrl {
		for _, item := range spec.FileItem {
			if device.ImportKey != item.DeviceId {
				continue
			}

			u, err := c.Client.ParseURL(device.Url)
			if err != nil {
				return err
			}

			err = cmd.Upload(lease, &item, u)
			if err != nil {
				return err
			}
		}
	}

	return lease.HttpNfcLeaseComplete(c)
}

// LeaseUpdater consumes an Upload.Progress channel (in) used to update HttpNfcLeaseProgress.
// Progress is forwarded to another channel (out), which can in turn be consumed by the ProgressLogger.
func (cmd *ovf) LeaseUpdater(lease *govmomi.HttpNfcLease, in <-chan vim25.Progress, out chan<- vim25.Progress) *sync.WaitGroup {
	var wg sync.WaitGroup

	go func() {
		var p vim25.Progress
		var ok bool
		var err error
		var percent int

		tick := time.NewTicker(2 * time.Second)
		defer tick.Stop()
		defer wg.Done()

		for ok = true; ok && err == nil; {
			select {
			case p, ok = <-in:
				if !ok {
					break
				}
				percent = int(p.Percentage())
				err = p.Error()
				out <- p // Forward to the ProgressLogger
			case <-tick.C:
				// From the vim api HttpNfcLeaseProgress(percent) doc, percent ==
				// "Completion status represented as an integer in the 0-100 range."
				// Always report the current value of percent,
				// as it will renew the lease even if the value hasn't changed or is 0
				err = lease.HttpNfcLeaseProgress(cmd.Client, percent)
			}
		}
	}()

	wg.Add(1)

	return &wg
}

func (cmd *ovf) Upload(lease *govmomi.HttpNfcLease, item *types.OvfFileItem, u *url.URL) error {
	file := item.Path

	f, size, err := cmd.Open(file)
	if err != nil {
		return err
	}
	defer f.Close()

	in := make(chan vim25.Progress)

	out := make(chan vim25.Progress)

	wg := cmd.LeaseUpdater(lease, in, out)

	pwg := cmd.ProgressLogger(fmt.Sprintf("Uploading %s... ", importable(file).Base()), out)

	// defer queue is LIFO..
	defer pwg.Wait() // .... 3) wait for ProgressLogger to return
	defer close(out) // .... 2) propagate close to chained channel
	defer wg.Wait()  // .... 1) wait for Progress channel to close

	opts := soap.Upload{
		Type:          "application/x-vnd.vmware-streamVmdk",
		Method:        "POST",
		ProgressCh:    in,
		ContentLength: size,
	}

	if item.Create {
		opts.Method = "PUT"
	}

	return cmd.Client.Client.Upload(f, u, &opts)
}
<commit_msg>Use OutputFlag.Log for ovf warnings<commit_after>/*
Copyright (c) 2014 VMware, Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package importx

import (
	"encoding/xml"
	"errors"
	"flag"
	"fmt"
	"io/ioutil"
	"net/url"
	"sync"
	"time"

	"github.com/vmware/govmomi"
	"github.com/vmware/govmomi/govc/cli"
	"github.com/vmware/govmomi/govc/flags"
	"github.com/vmware/govmomi/vim25"
	"github.com/vmware/govmomi/vim25/soap"
	"github.com/vmware/govmomi/vim25/types"
)

type ovf struct {
	*flags.DatastoreFlag
	*flags.ResourcePoolFlag
	*flags.SearchFlag
	*flags.OutputFlag

	Client       *govmomi.Client
	Datacenter   *govmomi.Datacenter
	Datastore    *govmomi.Datastore
	ResourcePool *govmomi.ResourcePool

	Archive
}

func init() {
	cli.Register("import.ovf", newOvf())
}

func newOvf() *ovf {
	return &ovf{
		SearchFlag: flags.NewSearchFlag(flags.SearchHosts),
	}
}

func (cmd *ovf) Register(f *flag.FlagSet) {
}

func (cmd *ovf) Process() error { return nil }

func (cmd *ovf) Run(f *flag.FlagSet) error {
	file, err := cmd.Prepare(f)

	if err != nil {
		return err
	}

	cmd.Archive = &FileArchive{file}

	return cmd.Import(file)
}

func (cmd *ovf) Prepare(f *flag.FlagSet) (importable, error) {
	var err error

	args := f.Args()
	if len(args) != 1 {
		return "", errors.New("no file to import")
	}

	file := importable(f.Arg(0))

	cmd.Client, err = cmd.DatastoreFlag.Client()
	if err != nil {
		return "", err
	}

	cmd.Datacenter, err = cmd.DatastoreFlag.Datacenter()
	if err != nil {
		return "", err
	}

	cmd.Datastore, err = cmd.DatastoreFlag.Datastore()
	if err != nil {
		return "", err
	}

	cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool()
	if err != nil {
		return "", err
	}

	return file, nil
}

func (cmd *ovf) ReadAll(name string) ([]byte, error) {
	f, _, err := cmd.Open(name)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return ioutil.ReadAll(f)
}

func (cmd *ovf) Import(i importable) error {
	c := cmd.Client

	desc, err := cmd.ReadAll(string(i))
	if err != nil {
		return err
	}

	// extract name from .ovf for use as VM name
	ovf := struct {
		VirtualSystem struct {
			Name string
		}
	}{}

	if err := xml.Unmarshal(desc, &ovf); err != nil {
		return fmt.Errorf("failed to parse ovf: %s", err.Error())
	}

	cisp := types.OvfCreateImportSpecParams{
		EntityName: ovf.VirtualSystem.Name,
		OvfManagerCommonParams: types.OvfManagerCommonParams{
			Locale: "US",
		},
	}

	spec, err := c.OvfManager().CreateImportSpec(string(desc), cmd.ResourcePool, cmd.Datastore, cisp)
	if err != nil {
		return err
	}

	if spec.Error != nil {
		return errors.New(spec.Error[0].LocalizedMessage)
	}

	if spec.Warning != nil {
		for _, w := range spec.Warning {
			_, _ = cmd.Log(fmt.Sprintf("Warning: %s\n", w.LocalizedMessage))
		}
	}

	// TODO: ImportSpec may have unitNumber==0, but this field is optional in the wsdl
	// and hence omitempty in the struct tag; but unitNumber is required for certain devices.
	s := &spec.ImportSpec.(*types.VirtualMachineImportSpec).ConfigSpec
	for _, d := range s.DeviceChange {
		n := &d.GetVirtualDeviceConfigSpec().Device.GetVirtualDevice().UnitNumber
		if *n == 0 {
			*n = -1
		}
	}

	host, err := cmd.HostSystem()
	if err != nil {
		return err
	}

	// TODO: need a folder option
	folders, err := cmd.Datacenter.Folders(c)
	if err != nil {
		return err
	}
	folder := &folders.VmFolder

	lease, err := cmd.ResourcePool.ImportVApp(c, spec.ImportSpec, folder, host)
	if err != nil {
		return err
	}

	info, err := lease.Wait(c)
	if err != nil {
		return err
	}

	for _, device := range info.DeviceUrl {
		for _, item := range spec.FileItem {
			if device.ImportKey != item.DeviceId {
				continue
			}

			u, err := c.Client.ParseURL(device.Url)
			if err != nil {
				return err
			}

			err = cmd.Upload(lease, &item, u)
			if err != nil {
				return err
			}
		}
	}

	return lease.HttpNfcLeaseComplete(c)
}

// LeaseUpdater consumes an Upload.Progress channel (in) used to update HttpNfcLeaseProgress.
// Progress is forwarded to another channel (out), which can in turn be consumed by the ProgressLogger.
func (cmd *ovf) LeaseUpdater(lease *govmomi.HttpNfcLease, in <-chan vim25.Progress, out chan<- vim25.Progress) *sync.WaitGroup {
	var wg sync.WaitGroup

	go func() {
		var p vim25.Progress
		var ok bool
		var err error
		var percent int

		tick := time.NewTicker(2 * time.Second)
		defer tick.Stop()
		defer wg.Done()

		for ok = true; ok && err == nil; {
			select {
			case p, ok = <-in:
				if !ok {
					break
				}
				percent = int(p.Percentage())
				err = p.Error()
				out <- p // Forward to the ProgressLogger
			case <-tick.C:
				// From the vim api HttpNfcLeaseProgress(percent) doc, percent ==
				// "Completion status represented as an integer in the 0-100 range."
				// Always report the current value of percent,
				// as it will renew the lease even if the value hasn't changed or is 0
				err = lease.HttpNfcLeaseProgress(cmd.Client, percent)
			}
		}
	}()

	wg.Add(1)

	return &wg
}

func (cmd *ovf) Upload(lease *govmomi.HttpNfcLease, item *types.OvfFileItem, u *url.URL) error {
	file := item.Path

	f, size, err := cmd.Open(file)
	if err != nil {
		return err
	}
	defer f.Close()

	in := make(chan vim25.Progress)

	out := make(chan vim25.Progress)

	wg := cmd.LeaseUpdater(lease, in, out)

	pwg := cmd.ProgressLogger(fmt.Sprintf("Uploading %s... ", importable(file).Base()), out)

	// defer queue is LIFO..
	defer pwg.Wait() // .... 3) wait for ProgressLogger to return
	defer close(out) // .... 2) propagate close to chained channel
	defer wg.Wait()  // .... 1) wait for Progress channel to close

	opts := soap.Upload{
		Type:          "application/x-vnd.vmware-streamVmdk",
		Method:        "POST",
		ProgressCh:    in,
		ContentLength: size,
	}

	if item.Create {
		opts.Method = "PUT"
	}

	return cmd.Client.Client.Upload(f, u, &opts)
}
<|endoftext|>


<commit_before>package asciidocgo

import (
	"errors"
	"os"
	"path/filepath"
)

/*
Handles all operations for resolving, cleaning and joining paths.
This class includes operations for handling both web paths (request URIs) and
system paths.

The main emphasis of the class is on creating clean and secure paths. Clean
paths are void of duplicate parent and current directory references in the
path name. Secure paths are paths which are restricted from accessing
directories outside of a jail root, if specified.

Since joining two paths can result in an insecure path, this class also
handles the task of joining a parent (start) and child (target) path.

This class makes no use of path utilities from the Ruby libraries. Instead,
it handles all aspects of path manipulation. The main benefit of
internalizing these operations is that the class is able to handle both posix
and windows paths independent of the operating system on which it runs. This
makes the class both deterministic and easier to test.

Examples:

    resolver = PathResolver.new

    Web Paths

    resolver.web_path('images')
    => 'images'

    resolver.web_path('./images')
    => './images'

    resolver.web_path('/images')
    => '/images'

    resolver.web_path('./images/../assets/images')
    => './assets/images'

    resolver.web_path('/../images')
    => '/images'

    resolver.web_path('images', 'assets')
    => 'assets/images'

    resolver.web_path('tiger.png', '../assets/images')
    => '../assets/images/tiger.png'

    System Paths

    resolver.working_dir
    => '/path/to/docs'

    resolver.system_path('images')
    => '/path/to/docs/images'

    resolver.system_path('../images')
    => '/path/to/images'

    resolver.system_path('/etc/images')
    => '/etc/images'

    resolver.system_path('images', '/etc')
    => '/etc/images'

    resolver.system_path('', '/etc/images')
    => '/etc/images'

    resolver.system_path(nil, nil, '/path/to/docs')
    => '/path/to/docs'

    resolver.system_path('..', nil, '/path/to/docs')
    => '/path/to/docs'

    resolver.system_path('../../../css', nil, '/path/to/docs')
    => '/path/to/docs/css'

    resolver.system_path('../../../css', '../../..', '/path/to/docs')
    => '/path/to/docs/css'

    resolver.system_path('..', 'C:\\data\\docs\\assets', 'C:\\data\\docs')
    => 'C:/data/docs'

    resolver.system_path('..\\..\\css', 'C:\\data\\docs\\assets', 'C:\\data\\docs')
    => 'C:/data/docs/css'

    begin
      resolver.system_path('../../../css', '../../..', '/path/to/docs', :recover => false)
    rescue SecurityError => e
      puts e.message
    end
    => 'path ../../../../../../css refers to location outside jail: /path/to/docs (disallowed in safe mode)'

    resolver.system_path('/path/to/docs/images', nil, '/path/to/docs')
    => '/path/to/docs/images'

    begin
      resolver.system_path('images', '/etc', '/path/to/docs')
    rescue SecurityError => e
      puts e.message
    end
    => Start path /etc is outside of jail: /path/to/docs'
*/
type PathResolver struct {
	fileSeparator byte
	workingDir    string
}

func (pr *PathResolver) FileSeparator() byte {
	return pr.fileSeparator
}
func (pr *PathResolver) WorkingDir() string {
	return pr.workingDir
}

/* Construct a new instance of PathResolver, optionally specifying
the file separator (to override the system default) and
the working directory (to override the present working directory).
The working directory will be expanded to an absolute path inside the constructor.
file_separator - the String file separator to use for path operations
(optional, default: File::FILE_SEPARATOR)
working_dir    - the String working directory (optional, default: Dir.pwd)
*/
func newPathResolver(fileSeparator byte, workingDir string) *PathResolver {
	if fileSeparator == 0 {
		fileSeparator = os.PathSeparator
	}
	if workingDir == "" || workingDir == "panic on os.Getwd" {
		pwd, err := os.Getwd()
		if err != nil || workingDir == "panic on os.Getwd" {
			if workingDir == "panic on os.Getwd" {
				err = errors.New("test on bad os.Getwd")
			}
			panic(err)
		}
		workingDir = pwd
	} else {
		if isRoot(workingDir) == false {
			wd, err := filepath.Abs(workingDir)
			if err != nil || workingDir == "panic on filepath.Abs" {
				if workingDir == "panic on filepath.Abs" {
					err = errors.New("test on bad filepath.Abs")
				}
				panic(err)
			}
			workingDir = wd
		}
	}
	return &PathResolver{fileSeparator, workingDir}
}

/*Check if the specified path is an absolute root path
his operation correctly handles both posix and windows paths.
returns a Boolean indicating whether the path is an absolute root path
*/
func isRoot(path string) bool {
	return filepath.IsAbs(path)
}
<commit_msg>IsRoot() is public function in PathResolver.<commit_after>package asciidocgo

import (
	"errors"
	"os"
	"path/filepath"
)

/*
Handles all operations for resolving, cleaning and joining paths.
This class includes operations for handling both web paths (request URIs) and
system paths.

The main emphasis of the class is on creating clean and secure paths. Clean
paths are void of duplicate parent and current directory references in the
path name. Secure paths are paths which are restricted from accessing
directories outside of a jail root, if specified.

Since joining two paths can result in an insecure path, this class also
handles the task of joining a parent (start) and child (target) path.

This class makes no use of path utilities from the Ruby libraries. Instead,
it handles all aspects of path manipulation. The main benefit of
internalizing these operations is that the class is able to handle both posix
and windows paths independent of the operating system on which it runs. This
makes the class both deterministic and easier to test.

Examples:

    resolver = PathResolver.new

    Web Paths

    resolver.web_path('images')
    => 'images'

    resolver.web_path('./images')
    => './images'

    resolver.web_path('/images')
    => '/images'

    resolver.web_path('./images/../assets/images')
    => './assets/images'

    resolver.web_path('/../images')
    => '/images'

    resolver.web_path('images', 'assets')
    => 'assets/images'

    resolver.web_path('tiger.png', '../assets/images')
    => '../assets/images/tiger.png'

    System Paths

    resolver.working_dir
    => '/path/to/docs'

    resolver.system_path('images')
    => '/path/to/docs/images'

    resolver.system_path('../images')
    => '/path/to/images'

    resolver.system_path('/etc/images')
    => '/etc/images'

    resolver.system_path('images', '/etc')
    => '/etc/images'

    resolver.system_path('', '/etc/images')
    => '/etc/images'

    resolver.system_path(nil, nil, '/path/to/docs')
    => '/path/to/docs'

    resolver.system_path('..', nil, '/path/to/docs')
    => '/path/to/docs'

    resolver.system_path('../../../css', nil, '/path/to/docs')
    => '/path/to/docs/css'

    resolver.system_path('../../../css', '../../..', '/path/to/docs')
    => '/path/to/docs/css'

    resolver.system_path('..', 'C:\\data\\docs\\assets', 'C:\\data\\docs')
    => 'C:/data/docs'

    resolver.system_path('..\\..\\css', 'C:\\data\\docs\\assets', 'C:\\data\\docs')
    => 'C:/data/docs/css'

    begin
      resolver.system_path('../../../css', '../../..', '/path/to/docs', :recover => false)
    rescue SecurityError => e
      puts e.message
    end
    => 'path ../../../../../../css refers to location outside jail: /path/to/docs (disallowed in safe mode)'

    resolver.system_path('/path/to/docs/images', nil, '/path/to/docs')
    => '/path/to/docs/images'

    begin
      resolver.system_path('images', '/etc', '/path/to/docs')
    rescue SecurityError => e
      puts e.message
    end
    => Start path /etc is outside of jail: /path/to/docs'
*/
type PathResolver struct {
	fileSeparator byte
	workingDir    string
}

func (pr *PathResolver) FileSeparator() byte {
	return pr.fileSeparator
}
func (pr *PathResolver) WorkingDir() string {
	return pr.workingDir
}

/* Construct a new instance of PathResolver, optionally specifying
the file separator (to override the system default) and
the working directory (to override the present working directory).
The working directory will be expanded to an absolute path inside the constructor.
file_separator - the String file separator to use for path operations
(optional, default: File::FILE_SEPARATOR)
working_dir    - the String working directory (optional, default: Dir.pwd)
*/
func newPathResolver(fileSeparator byte, workingDir string) *PathResolver {
	if fileSeparator == 0 {
		fileSeparator = os.PathSeparator
	}
	if workingDir == "" || workingDir == "panic on os.Getwd" {
		pwd, err := os.Getwd()
		if err != nil || workingDir == "panic on os.Getwd" {
			if workingDir == "panic on os.Getwd" {
				err = errors.New("test on bad os.Getwd")
			}
			panic(err)
		}
		workingDir = pwd
	} else {
		if IsRoot(workingDir) == false {
			wd, err := filepath.Abs(workingDir)
			if err != nil || workingDir == "panic on filepath.Abs" {
				if workingDir == "panic on filepath.Abs" {
					err = errors.New("test on bad filepath.Abs")
				}
				panic(err)
			}
			workingDir = wd
		}
	}
	return &PathResolver{fileSeparator, workingDir}
}

/*Check if the specified path is an absolute root path
his operation correctly handles both posix and windows paths.
returns a Boolean indicating whether the path is an absolute root path
*/
func IsRoot(path string) bool {
	return filepath.IsAbs(path)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"regexp"
	"strconv"
	"time"
)

func _newMatchDate(matchDate string, baseDate *time.Time) (*time.Time, error) {
	matchDateRegexp := regexp.MustCompile(`(\d{1,2})/(\d{1,2})\s?\(.\)(.)(\d{1,2}):(\d{1,2}) KO`)

	m := matchDateRegexp.FindAllStringSubmatch(matchDate, -1)

	if len(m) == 0 {
		return nil, fmt.Errorf("match failed: %v", matchDate)
	}
	month, err := strconv.Atoi(m[0][1])
	if err != nil {
		return nil, err
	}
	day, err := strconv.Atoi(m[0][2])
	if err != nil {
		return nil, err
	}

	hour, err := strconv.Atoi(m[0][4])
	if err != nil {
		return nil, err
	}
	s := m[0][3]
	switch s {
	case "前":
	case "後":
		hour += 12
	case "深":
		hour += 24
	default:
		return nil, fmt.Errorf("not support:", s)
	}

	min, err := strconv.Atoi(m[0][5])
	if err != nil {
		return nil, err
	}

	year := baseDate.Year()
	// when current month is december, but match date seems to be january. it is next year case.
	if int(baseDate.Month()) > month {
		year++
	}
	d := time.Date(year, time.Month(month), day, hour, min, 0, 0, baseDate.Location())
	return &d, nil
}

func _newProgramStartDate(date string, live bool, baseDate *time.Time) (*time.Time, error) {
	dateRegexp := regexp.MustCompile(`(.)(\d{1,2}):(\d{1,2})`)

	m := dateRegexp.FindAllStringSubmatch(date, -1)

	if len(m) == 0 {
		return nil, fmt.Errorf("match failed: %v", date)
	}

	hour, err := strconv.Atoi(m[0][2])
	if err != nil {
		return nil, err
	}

	s := m[0][1]
	switch s {
	case "前", "深":
	case "後":
		hour += 12
	default:
		return nil, fmt.Errorf("not support:", s)
	}
	min, err := strconv.Atoi(m[0][3])
	if err != nil {
		return nil, err
	}

	diffDay := 0

	if live {
		// live program may start before kick off.

		// seems to be before day. ( for example 0 hour and 23 hour )
		if baseDate.Hour() < hour {
			diffDay--
		}

	} else {
		// not live program bay start after kick off.

		// seems to be before day. ( for example 23 hour and 0 hour )
		if baseDate.Hour() > hour {
			diffDay++
		}
	}

	d := time.Date(baseDate.Year(), baseDate.Month(), baseDate.Day()+diffDay, hour, min, 0, 0, baseDate.Location())
	return &d, nil
}
<commit_msg>fix regexp<commit_after>package main

import (
	"fmt"
	"regexp"
	"strconv"
	"time"
)

func _newMatchDate(matchDate string, baseDate *time.Time) (*time.Time, error) {
	matchDateRegexp := regexp.MustCompile(`(\d{1,2})/(\d{1,2})\s?\(.\)\s?(.)(\d{1,2}):(\d{1,2}).+KO`)

	m := matchDateRegexp.FindAllStringSubmatch(matchDate, -1)

	if len(m) == 0 {
		return nil, fmt.Errorf("match failed: %v", matchDate)
	}
	month, err := strconv.Atoi(m[0][1])
	if err != nil {
		return nil, err
	}
	day, err := strconv.Atoi(m[0][2])
	if err != nil {
		return nil, err
	}

	hour, err := strconv.Atoi(m[0][4])
	if err != nil {
		return nil, err
	}
	s := m[0][3]
	switch s {
	case "前":
	case "後":
		hour += 12
	case "深":
		hour += 24
	default:
		return nil, fmt.Errorf("not support:", s)
	}

	min, err := strconv.Atoi(m[0][5])
	if err != nil {
		return nil, err
	}

	year := baseDate.Year()
	// when current month is december, but match date seems to be january. it is next year case.
	if int(baseDate.Month()) > month {
		year++
	}
	d := time.Date(year, time.Month(month), day, hour, min, 0, 0, baseDate.Location())
	return &d, nil
}

func _newProgramStartDate(date string, live bool, baseDate *time.Time) (*time.Time, error) {
	dateRegexp := regexp.MustCompile(`(.)(\d{1,2}):(\d{1,2})`)

	m := dateRegexp.FindAllStringSubmatch(date, -1)

	if len(m) == 0 {
		return nil, fmt.Errorf("match failed: %v", date)
	}

	hour, err := strconv.Atoi(m[0][2])
	if err != nil {
		return nil, err
	}

	s := m[0][1]
	switch s {
	case "前", "深":
	case "後":
		hour += 12
	default:
		return nil, fmt.Errorf("not support:", s)
	}
	min, err := strconv.Atoi(m[0][3])
	if err != nil {
		return nil, err
	}

	diffDay := 0

	if live {
		// live program may start before kick off.

		// seems to be before day. ( for example 0 hour and 23 hour )
		if baseDate.Hour() < hour {
			diffDay--
		}

	} else {
		// not live program bay start after kick off.

		// seems to be before day. ( for example 23 hour and 0 hour )
		if baseDate.Hour() > hour {
			diffDay++
		}
	}

	d := time.Date(baseDate.Year(), baseDate.Month(), baseDate.Day()+diffDay, hour, min, 0, 0, baseDate.Location())
	return &d, nil
}
<|endoftext|>


<commit_before>package parser // CQL
import (
	"fmt"
	"testing"

	"github.com/antlr/antlr4/runtime/Go/antlr"
)

type CqlTestListener struct {
	BaseCQLListener
}

func NewCqlTestListener() *CqlTestListener {
	return new(CqlTestListener)
}

/*func (l *CqlTestListener) EnterEveryRule(ctx antlr.ParserRuleContext) {
	fmt.Println(ctx.GetText())
}*/

func (l *CqlTestListener) EnterCql(ctx *CqlContext) {
	fmt.Printf("EnterCql: %v\n", ctx.GetText())
}

func (l *CqlTestListener) ExitCreate(ctx *CreateContext) {
	fmt.Printf("ExitCreate: %v\n", ctx.GetText())
	fmt.Printf("create indexName: %v\n", ctx.IndexName().GetText())
}
func TestCqlListenerCreate(t *testing.T) {
	fmt.Println("================TestCqlListenerCreate================")
	input := antlr.NewInputStream("IDX.CREATE orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64")
	lexer := NewCQLLexer(input)
	stream := antlr.NewCommonTokenStream(lexer, 0)
	parser := NewCQLParser(stream)
	//parser.AddErrorListener(antlr.NewDiagnosticErrorListener(true))
	//parser.BuildParseTrees = true
	tree := parser.Cql()
	listener := NewCqlTestListener()
	antlr.ParseTreeWalkerDefault.Walk(listener, tree)
}

type CqlTestVisitor struct {
	BaseCQLVisitor
}

func (v *CqlTestVisitor) Visit(localctx ICqlContext) interface{} {
	fmt.Println("Visit...")
	ctx := localctx.(*CqlContext)
	return v.VisitChildren(ctx)
}

func (v *CqlTestVisitor) VisitChildren(node antlr.RuleNode) interface{} {
	fmt.Printf("VisitChildren %v\n", node)
	return nil
}

func (v *CqlTestVisitor) VisitCql(ctx *CqlContext) interface{} {
	fmt.Println("VisitCql...")
	return v.VisitChildren(ctx)
}

func (v *CqlTestVisitor) VisitCreate(ctx *CreateContext) interface{} {
	fmt.Println("VisitCreate...")
	return v.VisitChildren(ctx)
}

func TestCqlVisitorCreate(t *testing.T) {
	fmt.Println("================TestCqlVisitorCreate================")
	input := antlr.NewInputStream("IDX.CREATE orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64")
	lexer := NewCQLLexer(input)
	stream := antlr.NewCommonTokenStream(lexer, 0)
	parser := NewCQLParser(stream)
	//parser.AddErrorListener(antlr.NewDiagnosticErrorListener(true))
	//parser.BuildParseTrees = true
	tree := parser.Cql()
	visitor := new(CqlTestVisitor)
	visitor.Visit(tree)
	//visitor.VisitCql(tree.(CqlContext))
}
<commit_msg>updated cql_antlr_test.go<commit_after>package parser // CQL
import (
	"fmt"
	"testing"

	"github.com/antlr/antlr4/runtime/Go/antlr"
)

type CqlTestListener struct {
	BaseCQLListener
}

func NewCqlTestListener() *CqlTestListener {
	return new(CqlTestListener)
}

/*func (l *CqlTestListener) EnterEveryRule(ctx antlr.ParserRuleContext) {
	fmt.Println(ctx.GetText())
}*/

func (l *CqlTestListener) EnterCql(ctx *CqlContext) {
	fmt.Printf("EnterCql: %v\n", ctx.GetText())
}

func (l *CqlTestListener) ExitCreate(ctx *CreateContext) {
	fmt.Printf("ExitCreate: %v\n", ctx.GetText())
	fmt.Printf("create indexName: %v\n", ctx.IndexName().GetText())
}
func TestCqlListenerCreate(t *testing.T) {
	fmt.Println("================TestCqlListenerCreate================")
	input := antlr.NewInputStream("IDX.CREATE orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64")
	lexer := NewCQLLexer(input)
	stream := antlr.NewCommonTokenStream(lexer, 0)
	parser := NewCQLParser(stream)
	//parser.AddErrorListener(antlr.NewDiagnosticErrorListener(true))
	//parser.BuildParseTrees = true
	tree := parser.Cql()
	listener := NewCqlTestListener()
	antlr.ParseTreeWalkerDefault.Walk(listener, tree)
}

type CqlTestVisitor struct {
	BaseCQLVisitor
}

func (v *CqlTestVisitor) Visit(tree antlr.ParseTree) interface{} {
	fmt.Println("Visit...")
	ctx := tree.(*CqlContext)
	return v.VisitCql(ctx)
}

func (v *CqlTestVisitor) VisitCql(ctx *CqlContext) interface{} {
	fmt.Println("VisitCql...")
	create := ctx.Create().(*CreateContext)
	return v.VisitCreate(create)
}

func (v *CqlTestVisitor) VisitCreate(ctx *CreateContext) interface{} {
	fmt.Println("VisitCreate...")
	indexName := ctx.IndexName().GetText()
	fmt.Printf("indexName: %s\n", indexName)
	return nil
}

func TestCqlVisitorCreate(t *testing.T) {
	fmt.Println("================TestCqlVisitorCreate================")
	input := antlr.NewInputStream("IDX.CREATE orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64")
	lexer := NewCQLLexer(input)
	stream := antlr.NewCommonTokenStream(lexer, 0)
	parser := NewCQLParser(stream)
	//parser.AddErrorListener(antlr.NewDiagnosticErrorListener(true))
	//parser.BuildParseTrees = true
	tree := parser.Cql()
	visitor := new(CqlTestVisitor)
	tree.Accept(visitor)
}
<|endoftext|>


<commit_before>package parser // CQL
import (
	"fmt"
	"testing"

	"github.com/antlr/antlr4/runtime/Go/antlr"
)

type VerboseErrorListener struct {
	antlr.DefaultErrorListener
	exp antlr.RecognitionException
	msg string
}

func (el *VerboseErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
	parser := recognizer.(antlr.Parser)
	stack := parser.GetRuleInvocationStack(parser.GetParserRuleContext())
	el.msg = fmt.Sprintf("rule stack: %v, line %d:%d at %v: %s\n", stack, line, column, offendingSymbol, msg)
	el.exp = e
}

type ParserCase struct {
	Input       string
	ExpectError bool
}

func TestCqlParserError(t *testing.T) {
	fmt.Println("================TestCqlParserError================")
	tcs := []ParserCase{
		{"IDX.CREATE orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64", false},
		{"IDX orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64", true},
	}
	for i, tc := range tcs {
		input := antlr.NewInputStream(tc.Input)
		lexer := NewCQLLexer(input)
		stream := antlr.NewCommonTokenStream(lexer, 0)
		parser := NewCQLParser(stream)
		el := new(VerboseErrorListener)
		parser.AddErrorListener(el)
		_ = parser.Cql()
		if el.exp != nil {
			fmt.Printf("parser raised exception %s\n", el.msg)
		}
		if (tc.ExpectError && el.exp == nil) || (!tc.ExpectError && el.exp != nil) {
			t.Fatalf("case %d failed. has %v, want %v", i, !tc.ExpectError, tc.ExpectError)
		}
	}
}

type CqlTestListener struct {
	BaseCQLListener
}

func NewCqlTestListener() *CqlTestListener {
	return new(CqlTestListener)
}

/*func (l *CqlTestListener) EnterEveryRule(ctx antlr.ParserRuleContext) {
	fmt.Println(ctx.GetText())
}*/

func (l *CqlTestListener) EnterCql(ctx *CqlContext) {
	fmt.Printf("EnterCql: %v\n", ctx.GetText())
}

func (l *CqlTestListener) ExitCreate(ctx *CreateContext) {
	fmt.Printf("ExitCreate: %v\n", ctx.GetText())
	fmt.Printf("create indexName: %v\n", ctx.IndexName().GetText())
}

//POC of listener
func TestCqlListener(t *testing.T) {
	fmt.Println("================TestCqlListener================")
	input := antlr.NewInputStream("IDX.CREATE orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64")
	lexer := NewCQLLexer(input)
	stream := antlr.NewCommonTokenStream(lexer, 0)
	parser := NewCQLParser(stream)
	//parser.AddErrorListener(antlr.NewDiagnosticErrorListener(true))
	//parser.BuildParseTrees = true
	tree := parser.Cql()
	listener := NewCqlTestListener()
	antlr.ParseTreeWalkerDefault.Walk(listener, tree)
}

type CqlTestVisitor struct {
	BaseCQLVisitor
}

func (v *CqlTestVisitor) Visit(tree antlr.ParseTree) interface{} {
	fmt.Println("Visit...")
	ctx := tree.(*CqlContext)
	return v.VisitCql(ctx)
}

func (v *CqlTestVisitor) VisitCql(ctx *CqlContext) interface{} {
	fmt.Printf("VisitCql %v...\n", ctx)
	//If there are multiple subrules, than check one by one.
	if create := ctx.Create(); create != nil {
		return v.VisitCreate(create.(*CreateContext))
	} else if destroy := ctx.Destroy(); destroy != nil {
		return v.VisitDestroy(destroy.(*DestroyContext))
	}
	return nil
}

func (v *CqlTestVisitor) VisitCreate(ctx *CreateContext) interface{} {
	fmt.Println("VisitCreate...")
	indexName := ctx.IndexName().GetText()
	fmt.Printf("indexName: %s\n", indexName)
	return nil
}

func (v *CqlTestVisitor) VisitDestroy(ctx *DestroyContext) interface{} {
	fmt.Println("VisitDestroy...")
	indexName := ctx.IndexName().GetText()
	fmt.Printf("indexName: %s\n", indexName)
	return nil
}

//POC of visitor
func TestCqlVisitor(t *testing.T) {
	fmt.Println("================TestCqlVisitor================")

	//input := antlr.NewInputStream("IDX.CREATE orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64")
	input := antlr.NewInputStream("IDX.DESTROY orders")
	lexer := NewCQLLexer(input)
	stream := antlr.NewCommonTokenStream(lexer, 0)
	parser := NewCQLParser(stream)
	el := new(VerboseErrorListener)
	parser.AddErrorListener(el)
	//parser.BuildParseTrees = true

	tree := parser.Cql()
	if el.exp != nil {
		fmt.Printf("parser raised exception %+v\n", el.exp)
		t.Fatalf(el.msg)
	}

	visitor := new(CqlTestVisitor)
	tree.Accept(visitor)
}
<commit_msg>revised TestCqlVisitor<commit_after>package parser // CQL
import (
	"fmt"
	"testing"

	"github.com/antlr/antlr4/runtime/Go/antlr"
)

type VerboseErrorListener struct {
	antlr.DefaultErrorListener
	exp antlr.RecognitionException
	msg string
}

func (el *VerboseErrorListener) SyntaxError(recognizer antlr.Recognizer, offendingSymbol interface{}, line, column int, msg string, e antlr.RecognitionException) {
	parser := recognizer.(antlr.Parser)
	stack := parser.GetRuleInvocationStack(parser.GetParserRuleContext())
	el.msg = fmt.Sprintf("rule stack: %v, line %d:%d at %v: %s\n", stack, line, column, offendingSymbol, msg)
	el.exp = e
}

type ParserCase struct {
	Input       string
	ExpectError bool
}

func TestCqlParserError(t *testing.T) {
	fmt.Println("================TestCqlParserError================")
	tcs := []ParserCase{
		{"IDX.CREATE orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64", false},
		{"IDX orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64", true},
	}
	for i, tc := range tcs {
		input := antlr.NewInputStream(tc.Input)
		lexer := NewCQLLexer(input)
		stream := antlr.NewCommonTokenStream(lexer, 0)
		parser := NewCQLParser(stream)
		el := new(VerboseErrorListener)
		parser.AddErrorListener(el)
		_ = parser.Cql()
		if el.exp != nil {
			fmt.Printf("parser raised exception %s\n", el.msg)
		}
		if (tc.ExpectError && el.exp == nil) || (!tc.ExpectError && el.exp != nil) {
			t.Fatalf("case %d failed. has %v, want %v", i, !tc.ExpectError, tc.ExpectError)
		}
	}
}

type CqlTestListener struct {
	BaseCQLListener
}

func NewCqlTestListener() *CqlTestListener {
	return new(CqlTestListener)
}

/*func (l *CqlTestListener) EnterEveryRule(ctx antlr.ParserRuleContext) {
	fmt.Println(ctx.GetText())
}*/

func (l *CqlTestListener) EnterCql(ctx *CqlContext) {
	fmt.Printf("EnterCql: %v\n", ctx.GetText())
}

func (l *CqlTestListener) ExitCreate(ctx *CreateContext) {
	fmt.Printf("ExitCreate: %v\n", ctx.GetText())
	fmt.Printf("create indexName: %v\n", ctx.IndexName().GetText())
}

//POC of listener
func TestCqlListener(t *testing.T) {
	fmt.Println("================TestCqlListener================")
	input := antlr.NewInputStream("IDX.CREATE orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64")
	lexer := NewCQLLexer(input)
	stream := antlr.NewCommonTokenStream(lexer, 0)
	parser := NewCQLParser(stream)
	//parser.AddErrorListener(antlr.NewDiagnosticErrorListener(true))
	//parser.BuildParseTrees = true
	tree := parser.Cql()
	listener := NewCqlTestListener()
	antlr.ParseTreeWalkerDefault.Walk(listener, tree)
}

type CqlTestVisitor struct {
	BaseCQLVisitor
	res interface{}
}

func (v *CqlTestVisitor) VisitCql(ctx *CqlContext) interface{} {
	fmt.Printf("VisitCql %v...\n", ctx)
	//If there are multiple subrules, than check one by one.
	if create := ctx.Create(); create != nil {
		v.res = v.VisitCreate(create.(*CreateContext))
	} else if destroy := ctx.Destroy(); destroy != nil {
		v.res = v.VisitDestroy(destroy.(*DestroyContext))
	}
	return nil
}

func (v *CqlTestVisitor) VisitCreate(ctx *CreateContext) interface{} {
	fmt.Println("VisitCreate...")
	indexName := ctx.IndexName().GetText()
	fmt.Printf("indexName: %s\n", indexName)
	return fmt.Sprintf("Create %s", indexName)
}

func (v *CqlTestVisitor) VisitDestroy(ctx *DestroyContext) interface{} {
	fmt.Println("VisitDestroy...")
	indexName := ctx.IndexName().GetText()
	fmt.Printf("indexName: %s\n", indexName)
	return fmt.Sprintf("Destroy %s", indexName)
}

//POC of visitor
func TestCqlVisitor(t *testing.T) {
	fmt.Println("================TestCqlVisitor================")

	//input := antlr.NewInputStream("IDX.CREATE orders SCHEMA object UINT64 price FLOAT number UINT32 date UINT64")
	input := antlr.NewInputStream("IDX.DESTROY orders")
	lexer := NewCQLLexer(input)
	stream := antlr.NewCommonTokenStream(lexer, 0)
	parser := NewCQLParser(stream)
	el := new(VerboseErrorListener)
	parser.AddErrorListener(el)
	//parser.BuildParseTrees = true

	tree := parser.Cql()
	if el.exp != nil {
		fmt.Printf("parser raised exception %+v\n", el.exp)
		t.Fatalf(el.msg)
	}

	visitor := new(CqlTestVisitor)
	tree.Accept(visitor)
	fmt.Printf("the result of visitor: %v\n", visitor.res)
}
<|endoftext|>


<commit_before>package creational

import (
	"testing"

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

func TestGetInstance_ReturnsSingleton(t *testing.T) {
	singleton := GetInstance()

	assert.NotNil(t, singleton)
}
<commit_msg>Add new singleton test<commit_after>package creational

import (
	"testing"

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

func TestGetInstance_ReturnsSingleton(t *testing.T) {
	singleton := GetInstance()
	assert.NotNil(t, singleton)
}

func TestGetInstance_MultipleCallsToGetInstance_ReturnsSingleton(t *testing.T) {
	singleton := GetInstance()
	newSingleton := GetInstance()

	assert.Equal(t, singleton, newSingleton)
}
<|endoftext|>