<commit_before>// +build integration

/*
Copyright 2019 The Kubernetes Authors 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 integration

import (
	"context"
	"fmt"
	"os"
	"strings"
	"testing"
	"time"

	"net/http"

	"github.com/elazarl/goproxy"
	"github.com/phayes/freeport"
	"github.com/pkg/errors"
)

// setUpProxy runs a local http proxy and sets the env vars for it.
func setUpProxy(t *testing.T) (*http.Server, error) {
	port, err := freeport.GetFreePort()
	if err != nil {
		return nil, errors.Wrap(err, "Failed to get an open port")
	}

	addr := fmt.Sprintf("localhost:%d", port)
	err = os.Setenv("NO_PROXY", "")
	if err != nil {
		return nil, errors.Wrap(err, "Failed to set no proxy env")
	}
	err = os.Setenv("HTTP_PROXY", addr)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to set http proxy env")
	}

	proxy := goproxy.NewProxyHttpServer()
	srv := &http.Server{Addr: addr, Handler: proxy}
	go func(s *http.Server, t *testing.T) {
		if err := s.ListenAndServe(); err != http.ErrServerClosed {
			t.Errorf("Failed to start http server for proxy mock")
		}
	}(srv, t)
	return srv, nil
}

func TestProxy(t *testing.T) {
	origHP := os.Getenv("HTTP_PROXY")
	origNP := os.Getenv("NO_PROXY")
	srv, err := setUpProxy(t)
	if err != nil {
		t.Fatalf("Failed to set up the test proxy: %s", err)
	}

	defer func(t *testing.T) { // Clean up after setting up proxy
		err = os.Setenv("HTTP_PROXY", origHP)
		if err != nil {
			t.Errorf("Error reverting the HTTP_PROXY env")
		}
		err = os.Setenv("NO_PROCY", origNP)
		if err != nil {
			t.Errorf("Error reverting the HTTP_PROXY env")
		}

		err := srv.Shutdown(context.TODO()) // shutting down the http proxy after tests
		if err != nil {
			t.Errorf("Error shutting down the http proxy")
		}
	}(t)

	t.Run("ConsoleWarnning", testProxyWarning)
	t.Run("DashboardProxy", testDashboard)

}

// testProxyWarning checks user is warned correctly about the proxy related env vars
func testProxyWarning(t *testing.T) {
	mk := NewMinikubeRunner(t)
	// Start a timer for all remaining commands, to display failure output before a panic.
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
	defer cancel()
	startCmd := fmt.Sprintf("start %s %s %s", mk.StartArgs, mk.Args, "--alsologtostderr --v=5")
	stdout, stderr, err := mk.RunWithContext(ctx, startCmd)
	if err != nil {
		t.Fatalf("start: %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
	}
	mk.EnsureRunning()

	// Pre-cleanup: this usually fails, because no instance is running.
	// mk.RunWithContext(ctx, "delete")
	msg := "Found network options:"
	if !strings.Contains(stdout, msg) {
		t.Errorf("Proxy wranning (%s) is missing from the output: %s", msg, stderr)
	}

	msg = "You appear to be using a proxy"
	if !strings.Contains(stderr, msg) {
		t.Errorf("Proxy wranning (%s) is missing from the output: %s", msg, stderr)
	}

}
<commit_msg>Fix typo<commit_after>// +build integration

/*
Copyright 2019 The Kubernetes Authors 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 integration

import (
	"context"
	"fmt"
	"os"
	"strings"
	"testing"
	"time"

	"net/http"

	"github.com/elazarl/goproxy"
	"github.com/phayes/freeport"
	"github.com/pkg/errors"
)

// setUpProxy runs a local http proxy and sets the env vars for it.
func setUpProxy(t *testing.T) (*http.Server, error) {
	port, err := freeport.GetFreePort()
	if err != nil {
		return nil, errors.Wrap(err, "Failed to get an open port")
	}

	addr := fmt.Sprintf("localhost:%d", port)
	err = os.Setenv("NO_PROXY", "")
	if err != nil {
		return nil, errors.Wrap(err, "Failed to set no proxy env")
	}
	err = os.Setenv("HTTP_PROXY", addr)
	if err != nil {
		return nil, errors.Wrap(err, "Failed to set http proxy env")
	}

	proxy := goproxy.NewProxyHttpServer()
	srv := &http.Server{Addr: addr, Handler: proxy}
	go func(s *http.Server, t *testing.T) {
		if err := s.ListenAndServe(); err != http.ErrServerClosed {
			t.Errorf("Failed to start http server for proxy mock")
		}
	}(srv, t)
	return srv, nil
}

func TestProxy(t *testing.T) {
	origHP := os.Getenv("HTTP_PROXY")
	origNP := os.Getenv("NO_PROXY")
	srv, err := setUpProxy(t)
	if err != nil {
		t.Fatalf("Failed to set up the test proxy: %s", err)
	}

	defer func(t *testing.T) { // Clean up after setting up proxy
		err = os.Setenv("HTTP_PROXY", origHP)
		if err != nil {
			t.Errorf("Error reverting the HTTP_PROXY env")
		}
		err = os.Setenv("NO_PROXY", origNP)
		if err != nil {
			t.Errorf("Error reverting the NO_PROXY env")
		}

		err := srv.Shutdown(context.TODO()) // shutting down the http proxy after tests
		if err != nil {
			t.Errorf("Error shutting down the http proxy")
		}
	}(t)

	t.Run("ConsoleWarnning", testProxyWarning)
	t.Run("DashboardProxy", testDashboard)

}

// testProxyWarning checks user is warned correctly about the proxy related env vars
func testProxyWarning(t *testing.T) {
	mk := NewMinikubeRunner(t)
	// Start a timer for all remaining commands, to display failure output before a panic.
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
	defer cancel()
	startCmd := fmt.Sprintf("start %s %s %s", mk.StartArgs, mk.Args, "--alsologtostderr --v=5")
	stdout, stderr, err := mk.RunWithContext(ctx, startCmd)
	if err != nil {
		t.Fatalf("start: %v\nstdout: %s\nstderr: %s", err, stdout, stderr)
	}
	mk.EnsureRunning()

	// Pre-cleanup: this usually fails, because no instance is running.
	// mk.RunWithContext(ctx, "delete")
	msg := "Found network options:"
	if !strings.Contains(stdout, msg) {
		t.Errorf("Proxy wranning (%s) is missing from the output: %s", msg, stderr)
	}

	msg = "You appear to be using a proxy"
	if !strings.Contains(stderr, msg) {
		t.Errorf("Proxy wranning (%s) is missing from the output: %s", msg, stderr)
	}

}
<|endoftext|>


<commit_before>package kinesumer

import (
	k "github.com/remind101/kinesumer/interface"
)

type Record struct {
	data               []byte
	partitionKey       string
	sequenceNumber     string
	shardId            string
	millisBehindLatest int64
	checkpointC        chan<- k.Record
}

func (r *Record) Data() []byte {
	return r.data
}

func (r *Record) PartitionKey() string {
	return r.partitionKey
}

func (r *Record) SequenceNumber() string {
	return r.sequenceNumber
}

func (r *Record) ShardId() string {
	return r.shardId
}

func (r *Record) MillisBehindLatest() int64 {
	return r.millisBehindLatest
}

func (r *Record) Done() {
	r.checkpointC <- r
}
<commit_msg>Don't attempt to send to the channel if it is nil<commit_after>package kinesumer

import (
	k "github.com/remind101/kinesumer/interface"
)

type Record struct {
	data               []byte
	partitionKey       string
	sequenceNumber     string
	shardId            string
	millisBehindLatest int64
	checkpointC        chan<- k.Record
}

func (r *Record) Data() []byte {
	return r.data
}

func (r *Record) PartitionKey() string {
	return r.partitionKey
}

func (r *Record) SequenceNumber() string {
	return r.sequenceNumber
}

func (r *Record) ShardId() string {
	return r.shardId
}

func (r *Record) MillisBehindLatest() int64 {
	return r.millisBehindLatest
}

func (r *Record) Done() {
	if r.checkpointC != nil {
		r.checkpointC <- r
	}
}
<|endoftext|>


<commit_before>package httpc

import (
	"encoding/json"
	"fmt"
	"mime"
	"net/http"
	"strings"

	"github.com/pnelson/tmpl"
)

// Viewable represents a view. To provide an expressive API, this
// type is an alias for interface{} that is named for documentation.
type Viewable interface{}

// Render writes the view in the requested format, if available.
func Render(w http.ResponseWriter, req *http.Request, view Viewable, code int) error {
	accept := req.Header.Get("Accept")
	if accept == "" {
		return RenderJSON(w, view, code)
	}
	for _, h := range strings.Split(accept, ",") {
		media, _, err := mime.ParseMediaType(h)
		if err != nil {
			return err
		}
		switch media {
		case "text/html", "text/*":
			if renderer == nil {
				continue
			}
			v, ok := view.(tmpl.Viewable)
			if ok {
				return RenderHTML(w, v, code)
			}
		case "application/json", "application/*", "*/*":
			return RenderJSON(w, view, code)
		case "text/plain":
			return RenderPlain(w, view, code)
		}
	}
	return Abort(w, http.StatusNotAcceptable)
}

// Renderer represents the ability to render a tmpl.Viewable.
type Renderer interface {
	Render(view tmpl.Viewable) ([]byte, error)
}

// renderer is used to render HTML templates.
var renderer Renderer

// SetRenderer sets the Renderer used to render HTML templates.
// This function is not thread safe and is intended to be called
// once during application initialization.
func SetRenderer(r Renderer) {
	mu.Lock()
	renderer = r
	mu.Unlock()
}

// RenderHTML writes the view as templated HTML.
func RenderHTML(w http.ResponseWriter, view tmpl.Viewable, code int) error {
	b, err := renderer.Render(view)
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(code)
	_, err = w.Write(b)
	return err
}

// RenderJSON writes the view as marshalled JSON.
func RenderJSON(w http.ResponseWriter, view Viewable, code int) error {
	b, err := json.Marshal(view)
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(code)
	if view == nil {
		return nil
	}
	_, err = w.Write(b)
	return err
}

// RenderPlain writes the view as a string.
func RenderPlain(w http.ResponseWriter, view Viewable, code int) error {
	s, ok := view.(string)
	if !ok {
		return fmt.Errorf("httpc: view for RenderPlain must be a string")
	}
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.Header().Set("X-Content-Type-Options", "nosniff")
	w.WriteHeader(code)
	_, err := fmt.Fprintln(w, s)
	return err
}
<commit_msg>Remove tmpl package dependency.<commit_after>package httpc

import (
	"encoding/json"
	"errors"
	"fmt"
	"mime"
	"net/http"
	"strings"
)

// Viewable represents a view. To provide an expressive API, this
// type is an alias for interface{} that is named for documentation.
type Viewable interface{}

// Render writes the view in the requested format, if available.
func Render(w http.ResponseWriter, req *http.Request, view Viewable, code int) error {
	accept := req.Header.Get("Accept")
	if accept == "" {
		return RenderJSON(w, view, code)
	}
	for _, h := range strings.Split(accept, ",") {
		media, _, err := mime.ParseMediaType(h)
		if err != nil {
			return err
		}
		switch media {
		case "text/html", "text/*":
			if renderer == nil {
				continue
			}
			return RenderHTML(w, view, code)
		case "application/json", "application/*", "*/*":
			return RenderJSON(w, view, code)
		case "text/plain":
			return RenderPlain(w, view, code)
		}
	}
	return Abort(w, http.StatusNotAcceptable)
}

// Renderer represents the ability to render HTML templates.
type Renderer interface {
	Render(view interface{}) ([]byte, error)
}

// renderer is used to render HTML templates.
var renderer Renderer

// SetRenderer sets the Renderer used to render HTML templates.
// This function is not thread safe and is intended to be called
// once during application initialization.
func SetRenderer(r Renderer) {
	renderer = r
}

// RenderHTML writes the view as templated HTML.
func RenderHTML(w http.ResponseWriter, view Viewable, code int) error {
	if renderer == nil {
		return errors.New("httpc: renderer must be set")
	}
	b, err := renderer.Render(view)
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	w.WriteHeader(code)
	_, err = w.Write(b)
	return err
}

// RenderJSON writes the view as marshalled JSON.
func RenderJSON(w http.ResponseWriter, view Viewable, code int) error {
	b, err := json.Marshal(view)
	if err != nil {
		return err
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(code)
	if view == nil {
		return nil
	}
	_, err = w.Write(b)
	return err
}

// RenderPlain writes the view as a string.
func RenderPlain(w http.ResponseWriter, view Viewable, code int) error {
	s, ok := view.(string)
	if !ok {
		return fmt.Errorf("httpc: view for RenderPlain must be a string")
	}
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	w.Header().Set("X-Content-Type-Options", "nosniff")
	w.WriteHeader(code)
	_, err := fmt.Fprintln(w, s)
	return err
}
<|endoftext|>


<commit_before>// Package render is a middleware for Martini that provides easy JSON serialization and HTML template rendering.
//
//  package main
//
//  import (
//    "github.com/codegangsta/martini"
//    "github.com/codegangsta/martini-contrib/render"
//  )
//
//  func main() {
//    m := martini.Classic()
//    m.Use(render.Renderer("templates"))
//
//    m.Get("/html", func(r render.Render) {
//      r.HTML(200, "mytemplate", nil)
//    })
//
//    m.Get("/json", func(r render.Render) {
//      r.JSON(200, "hello world")
//    })
//
//    m.Run()
//  }
package render

import (
	"bytes"
	"encoding/json"
	"github.com/codegangsta/martini"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
)

const (
	ContentType = "Content-Type"
	ContentJSON = "application/json"
	ContentHTML = "text/html"
)

// Render is a service that can be injected into a Martini handler. Render provides functions for easily writing JSON and
// HTML templates out to a http Response.
type Render interface {
	// JSON writes the given status and JSON serialized version of the given value to the http.ResponseWriter.
	JSON(status int, v interface{})
	// HTML renders a html template specified by the name and writes the result and given status to the http.ResponseWriter.
	HTML(status int, name string, v interface{})
}

// Renderer is a Middleware that maps a render.Render service into the Martini handler chain. Renderer will compile templates
// globbed in the given dir. Templates must have the .tmpl extension to be compiled.
//
// If MARTINI_ENV is set to "" or "development" then templates will be recompiled on every request. For more performance, set the
// MARTINI_ENV environment variable to "production"
func Renderer(dir string) martini.Handler {
	t := compile(dir)
	return func(res http.ResponseWriter, c martini.Context) {
		// recompile for easy development
		if martini.Env == martini.Dev {
			t = compile(dir)
		}
		c.MapTo(&renderer{res, t}, (*Render)(nil))
	}
}

func compile(dir string) *template.Template {
	t := template.New(dir)

	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		r, err := filepath.Rel(dir, path)
		if err != nil {
			return err
		}

		ext := filepath.Ext(r)
		if ext == ".tmpl" {

			buf, err := ioutil.ReadFile(path)
			if err != nil {
				panic(err)
			}

			name := (r[0 : len(r)-len(ext)])
			tmpl := t.New(filepath.ToSlash(name))
			// Bomb out if parse fails. We don't want any silent server starts.
			template.Must(tmpl.Parse(string(buf)))
		}

		return nil
	})

	return t
}

type renderer struct {
	http.ResponseWriter
	t *template.Template
}

func (r *renderer) JSON(status int, v interface{}) {
	result, err := json.Marshal(v)
	if err != nil {
		http.Error(r, err.Error(), 500)
		return
	}

	// json rendered fine, write out the result
	r.Header().Set(ContentType, ContentJSON)
	r.WriteHeader(status)
	r.Write(result)
}

func (r *renderer) HTML(status int, name string, binding interface{}) {
	buf := new(bytes.Buffer)
	err := r.t.ExecuteTemplate(buf, name, binding)
	if err != nil {
		http.Error(r, err.Error(), 500)
		return
	}

	// template rendered fine, write out the result
	r.Header().Set(ContentType, ContentHTML)
	r.WriteHeader(status)
	r.Write(buf.Bytes())
}
<commit_msg>-n [Migrated] JMS #17: Made improvements to template rendering code<commit_after>// Package render is a middleware for Martini that provides easy JSON serialization and HTML template rendering.
//
//  package main
//
//  import (
//    "github.com/codegangsta/martini"
//    "github.com/codegangsta/martini-contrib/render"
//  )
//
//  func main() {
//    m := martini.Classic()
//    m.Use(render.Renderer("templates"))
//
//    m.Get("/html", func(r render.Render) {
//      r.HTML(200, "mytemplate", nil)
//    })
//
//    m.Get("/json", func(r render.Render) {
//      r.JSON(200, "hello world")
//    })
//
//    m.Run()
//  }
package render

import (
	"bytes"
	"encoding/json"
	"github.com/codegangsta/martini"
	"html/template"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
)

const (
	ContentType = "Content-Type"
	ContentJSON = "application/json"
	ContentHTML = "text/html"
)

// Render is a service that can be injected into a Martini handler. Render provides functions for easily writing JSON and
// HTML templates out to a http Response.
type Render interface {
	// JSON writes the given status and JSON serialized version of the given value to the http.ResponseWriter.
	JSON(status int, v interface{})
	// HTML renders a html template specified by the name and writes the result and given status to the http.ResponseWriter.
	HTML(status int, name string, v interface{})
}

// Renderer is a Middleware that maps a render.Render service into the Martini handler chain. Renderer will compile templates
// globbed in the given dir. Templates must have the .tmpl extension to be compiled.
//
// If MARTINI_ENV is set to "" or "development" then templates will be recompiled on every request. For more performance, set the
// MARTINI_ENV environment variable to "production"
func Renderer(dir string) martini.Handler {
	t := compile(dir)
	return func(res http.ResponseWriter, c martini.Context) {
		// recompile for easy development
		if martini.Env == martini.Dev {
			t = compile(dir)
		}
		c.MapTo(&renderer{res, t}, (*Render)(nil))
	}
}

func compile(dir string) *template.Template {
	t := template.New(dir)

	filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		r, err := filepath.Rel(dir, path)
		if err != nil {
			return err
		}

		ext := filepath.Ext(r)
		if ext == ".tmpl" {

			buf, err := ioutil.ReadFile(path)
			if err != nil {
				panic(err)
			}

			name := (r[0 : len(r)-len(ext)])
			tmpl := t.New(filepath.ToSlash(name))
			// Bomb out if parse fails. We don't want any silent server starts.
			template.Must(tmpl.Parse(string(buf)))
		}

		return nil
	})

	return t
}

type renderer struct {
	http.ResponseWriter
	t *template.Template
}

func (r *renderer) JSON(status int, v interface{}) {
	result, err := json.Marshal(v)
	if err != nil {
		http.Error(r, err.Error(), 500)
		return
	}

	// json rendered fine, write out the result
	r.Header().Set(ContentType, ContentJSON)
	r.WriteHeader(status)
	r.Write(result)
}

func (r *renderer) HTML(status int, name string, binding interface{}) {
	var buf bytes.Buffer
	if err := r.t.ExecuteTemplate(&buf, name, binding); err != nil {
		http.Error(r, err.Error(), 500)
		return
	}

	// template rendered fine, write out the result
	r.Header().Set(ContentType, ContentHTML)
	r.WriteHeader(status)
	r.Write(buf.Bytes())
}
<|endoftext|>


<commit_before>package main

import "net"
import "fmt"
import "log"

//import "bytes"
import "strconv"
import "errors"
import "math/rand"
import "io/ioutil"
import "encoding/json"
import "time"
import "sync"

const (
	MAX_BUFF_LEN   = 1024
	SECONDARY_PORT = 7346
	letters        = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	sessLen        = 24  // 24 digits session length
	heartbeat      = 600 // set heartbeat time, default 600
)

// Define the message format
type message struct {
	src  string
	dest string
    state string
	msg string
    timeStamp time.Time
	err  error
}

// Mainloop tfor tcp connection
// Open server thread client --> server
func runServer(addr string, port int) error {
	lstn, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
	if err != nil {
		return err
	}
	defer lstn.Close()

	m := make(chan message)
	go runClient(addr, m)

	for {
		conn, err := lstn.Accept()
		log.Println("Incoming connection from: ", conn.RemoteAddr())
		if err != nil {
			return err
		}
		go comm(conn, m)
		defer conn.Close()
	}

}

// Open client thread server --> client
func runClient(addr string, m chan message) {
    lstn, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, SECONDARY_PORT))

    if err != nil {
        log.Fatal(err)
        return
    }

    defer lstn.Close()

    for {
        conn, err := lstn.Accept()
        log.Println("Incoming connection from:", conn.RemoteAddr())
        if err != nil {
            log.Fatal(err)
            return
        }
        go checkStatus(conn, m)
        defer conn.Close()
    }
}

// Listen the heartbeat of client and communicate
func checkStatus(conn net.Conn, m chan message) {
    // Receive the connection message from the client
    recvbyte, err := ioutil.ReadAll(conn)
	if err != nil {
		log.Fatal(err)
		return
	}

	defer conn.Close()

	var data map[string]interface{}
	err = json.Unmarshal(recvbyte, data)
	if err != nil {
		log.Fatal(err)
		return
	}

    infomap := data["info"].(map[string]string)
    session, hasSession := infomap["session"]
    user, hasUser := infomap["user"]

    if !hasSession {
        log.Fatal("No session id, exit.")
        return
    }

    if !hasUser {
        log.Fatal("No username, exit.")
        return
    }

    if !checkAlive(user, session) {
        log.Fatal("Session not alive, exit.")
        return
    }

    mt := &sync.Mutex{}

    // Openning loop, for the message and heartbeat
	go sendHeartBeat(user, conn, mt)
	var msg message

    for {
        mt.Lock()
		msg = <-m

		if msg.dest != user {
			m <- msg
		} else {
			// shall somehow trigger the exit mechanism
			if (msg.state =="exit") {
				log.Print("message triggered exit")
				mt.Unlock()
				return
			} else {
		        var reply map[string]interface{}
		        reply["status"] = "m"
				var info map[string]string
				reply["info"] = info
				info["msg"] = msg.msg
				replydata, err := json.Marshal(reply)
				_, err = conn.Write(replydata)
				if err != nil {
		            log.Fatal(err)
				    mt.Unlock()
					return
			    }
			}
		}

        mt.Unlock()
    }

}

// Function to send HeartBeat for som time
func sendHeartBeat(user string, conn net.Conn, mt *sync.Mutex){
	//var err error

	for {
		time.Sleep(10 * time.Minute)
		mt.Lock()

		var msg map[string]interface{}
		msg["status"] = "q"
		var info map[string]string
		info["info"] = "heartbeat"
		msg["info"] = info
		query, err := json.Marshal(msg)

		if err != nil {
			log.Fatal(err)
			mt.Unlock()
			return
		}

		_, err = conn.Write(query)
		if err != nil {
			log.Fatal(err)
			mt.Unlock()
			return
		}

		recvbyte, err := ioutil.ReadAll(conn)
		if err != nil {
			log.Fatal(err)
			return
		}

		err = json.Unmarshal(recvbyte, msg)
		if err != nil {
			log.Fatal(err)
			return
		}
		touchUser(user)
		mt.Unlock()
	}
	return
}

// communicate with the client, main logic
func comm(conn net.Conn, msgQueue chan message) {
	// First send connection message
	// init the connection
	for {
		recvbyte, err := ioutil.ReadAll(conn)
		if err != nil {
			log.Fatal(err)
			return
		}

        defer conn.Close()

		var data map[string]interface{}
		err = json.Unmarshal(recvbyte, data)
		if err != nil {
			log.Fatal(err)
			return
		}
		// Process the data according to the protocal
		switch data["status"].(string) {
		case "q":
			// do query hadling, login the client
			msg := data["info"].(map[string]string)

			switch msg["req"] {
			case "login":
				if login(msg, conn) != nil {
					// returning messages
					m := make(map[string]interface{})
					m["status"] = "r"
					m["status_code"] = 20
					mdata := make(map[string]string)
					mdata["error"] = "Invalid username or password"
					m["info"] = mdata
					reply, err := json.Marshal(m)
					_, err = conn.Write(reply)
					if err != nil {
						log.Fatal(err)
					}
					return
				}
			// Query online users, should firstly verify sessions
			// Following all operations should carry a session id
			case "users":
				if checkLogin(msg) {
					ulist := getUsers()
					m := make(map[string]interface{})
					m["status"] = "r"
					m["status_code"] = 30
					mdata := make(map[string]interface{})
					mdata["ulist"] = ulist
					m["info"] = mdata
					reply, err := json.Marshal(m)
					_, err = conn.Write(reply)
					if err != nil {
						log.Fatal(err)
					}
				} else {
					m := make(map[string]interface{})
					m["status"] = "e"
					m["status_code"] = 40
					mdata := make(map[string]string)
					mdata["error"] = "Invalid username or sessionid"
					m["info"] = mdata
					reply, err := json.Marshal(m)
					_, err = conn.Write(reply)
					if err != nil {
						log.Fatal(err)
					}
					return
				}
			case "logout":
				if checkLogin(msg) {
					if err := logout(msg, conn); err != nil {
						log.Fatal(err)
					}
					return

				} else {

				}

			default:
				return

			}

		case "m":
			// sending messages
			// firstly we will check whether arrivable
		default:
			// return error, and exit
			return
		}
	}
}

func cleaner(m chan message) {
	// Periodically check un arrivable message and sweep them out in the queue
	for {

	}
}

//@deprecated, each function should log error itself
//func logger(m chan message) {
// Handle the error during server run
//    log.Println("Init server logger")
//}
// Function for generate session key

func randSeq(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func login(msg map[string]string, conn net.Conn) error {
	user := msg["user"]
	passwd := msg["passwd"]

	// Call the database function to validater user passwd
	if checkLogin(msg) {
		log.Fatal("User is already online")
		return errors.New("User is already online...")
	}

	if validate(user, passwd) {
		// Sending the secondary port of server
		m := make(map[string]interface{})
		m["status"] = "r"
		m["status_code"] = 30
		infomap := make(map[string]string)
		m["info"] = infomap
		//Listen to secondary, for ending informations
		infomap["port"] = strconv.Itoa(SECONDARY_PORT)
		infomap["session"] = randSeq(sessLen)
		// Marshal the map
		reply, err := json.Marshal(m)

		// Register and activate the user session
		if err = activate(user, infomap["session"]); err != nil {
			log.Fatal(err)
			return err
		}
		if err != nil {
			log.Fatal(err)
			return err
		}
		_, err = conn.Write(reply)
		if err != nil {
			log.Fatal(err)
			return err
		}

		return nil
	} else {
		ret := errors.New("Cannot validate user!")
		log.Fatal(ret)
		return ret
	}
}

func logout(msg map[string]string, conn net.Conn) error {
	uname, hasUserName := msg["uname"]
	sessionId, hasSessionId := msg["sessionId"]

	if hasSessionId && hasUserName {
		return killOnline(uname, sessionId)
	} else {
		return errors.New("No such user!")
	}
}

func checkLogin(msg map[string]string) bool {

	uname, hasUserName := msg["uname"]
	sessionId, hasSessionId := msg["sessionId"]

	if hasSessionId && hasUserName {
		return checkAlive(uname, sessionId)
	} else {
		return false
	}
}
<commit_msg>[devel] implement channel message sending<commit_after>package main

import "net"
import "fmt"
import "log"

//import "bytes"
import "strconv"
import "errors"
import "math/rand"
import "io/ioutil"
import "encoding/json"
import "time"
import "sync"

const (
	MAX_BUFF_LEN   = 1024
	SECONDARY_PORT = 7346
	letters        = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
	sessLen        = 24  // 24 digits session length
	heartbeat      = 600 // set heartbeat time, default 600
)

// Define the message format
type message struct {
	src  string
	dest string
    state string
	msg string
    timeStamp time.Time
	err  error
}

// Mainloop tfor tcp connection
// Open server thread client --> server
func runServer(addr string, port int) error {
	lstn, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))
	if err != nil {
		return err
	}
	defer lstn.Close()

	m := make(chan message)
	go runClient(addr, m)

	for {
		conn, err := lstn.Accept()
		log.Println("Incoming connection from: ", conn.RemoteAddr())
		if err != nil {
			return err
		}
		go comm(conn, m)
		defer conn.Close()
	}

}

// Open client thread server --> client
func runClient(addr string, m chan message) {
    lstn, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, SECONDARY_PORT))

    if err != nil {
        log.Fatal(err)
        return
    }

    defer lstn.Close()

    for {
        conn, err := lstn.Accept()
        log.Println("Incoming connection from:", conn.RemoteAddr())
        if err != nil {
            log.Fatal(err)
            return
        }
        go checkStatus(conn, m)
        defer conn.Close()
    }
}

// Listen the heartbeat of client and communicate
func checkStatus(conn net.Conn, m chan message) {
    // Receive the connection message from the client
    recvbyte, err := ioutil.ReadAll(conn)
	if err != nil {
		log.Fatal(err)
		return
	}

	defer conn.Close()

	var data map[string]interface{}
	err = json.Unmarshal(recvbyte, data)
	if err != nil {
		log.Fatal(err)
		return
	}

    infomap := data["info"].(map[string]string)
    session, hasSession := infomap["session"]
    user, hasUser := infomap["user"]

    if !hasSession {
        log.Fatal("No session id, exit.")
        return
    }

    if !hasUser {
        log.Fatal("No username, exit.")
        return
    }

    if !checkAlive(user, session) {
        log.Fatal("Session not alive, exit.")
        return
    }

    mt := &sync.Mutex{}

    // Openning loop, for the message and heartbeat
	go sendHeartBeat(user, conn, mt)
	var msg message

    for {
        mt.Lock()
		msg = <-m

		if msg.dest != user {
			m <- msg
		} else {
			// shall somehow trigger the exit mechanism
			if (msg.state =="exit") {
				log.Print("message triggered exit")
				mt.Unlock()
				return
			} else {
		        var reply map[string]interface{}
		        reply["status"] = "m"
				var info map[string]string
				reply["info"] = info
				info["msg"] = msg.msg
				replydata, err := json.Marshal(reply)
				_, err = conn.Write(replydata)
				if err != nil {
		            log.Fatal(err)
				    mt.Unlock()
					return
			    }
			}
		}

        mt.Unlock()
    }

}

// Function to send HeartBeat for som time
func sendHeartBeat(user string, conn net.Conn, mt *sync.Mutex){
	//var err error

	for {
		time.Sleep(10 * time.Minute)
		mt.Lock()

		var msg map[string]interface{}
		msg["status"] = "q"
		var info map[string]string
		info["info"] = "heartbeat"
		msg["info"] = info
		query, err := json.Marshal(msg)

		if err != nil {
			log.Fatal(err)
			mt.Unlock()
			return
		}

		_, err = conn.Write(query)
		if err != nil {
			log.Fatal(err)
			mt.Unlock()
			return
		}

		recvbyte, err := ioutil.ReadAll(conn)
		if err != nil {
			log.Fatal(err)
			return
		}

		err = json.Unmarshal(recvbyte, msg)
		if err != nil {
			log.Fatal(err)
			return
		}
		touchUser(user)
		mt.Unlock()
	}
	return
}

// communicate with the client, main logic
func comm(conn net.Conn, msgQueue chan message) {
	// First send connection message
	// init the connection
	for {
		recvbyte, err := ioutil.ReadAll(conn)
		if err != nil {
			log.Fatal(err)
			return
		}

        defer conn.Close()

		var data map[string]interface{}
		err = json.Unmarshal(recvbyte, data)
		if err != nil {
			log.Fatal(err)
			return
		}
		// Process the data according to the protocal
		switch data["status"].(string) {
		case "q":
			// do query hadling, login the client
			msg := data["info"].(map[string]string)

			switch msg["req"] {
			case "login":
				if login(msg, conn) != nil {
					// returning messages
					m := make(map[string]interface{})
					m["status"] = "r"
					m["status_code"] = 20
					mdata := make(map[string]string)
					mdata["error"] = "Invalid username or password"
					m["info"] = mdata
					reply, err := json.Marshal(m)
					_, err = conn.Write(reply)
					if err != nil {
						log.Fatal(err)
					}
					return
				}
			// Query online users, should firstly verify sessions
			// Following all operations should carry a session id
			case "users":
				if checkLogin(msg) {
					ulist := getUsers()
					m := make(map[string]interface{})
					m["status"] = "r"
					m["status_code"] = 30
					mdata := make(map[string]interface{})
					mdata["ulist"] = ulist
					m["info"] = mdata
					reply, err := json.Marshal(m)
					_, err = conn.Write(reply)
					if err != nil {
						log.Fatal(err)
					}
				} else {
					m := make(map[string]interface{})
					m["status"] = "e"
					m["status_code"] = 40
					mdata := make(map[string]string)
					mdata["error"] = "Invalid username or sessionid"
					m["info"] = mdata
					reply, err := json.Marshal(m)
					_, err = conn.Write(reply)
					if err != nil {
						log.Fatal(err)
					}
					return
				}
			case "logout":
				if checkLogin(msg) {
					if err := logout(msg, conn); err != nil {
						log.Fatal(err)
					}
					return

				} else {

				}

			default:
				return

			}

		case "m":
			// sending messages
			// firstly we will check whether arrivable
			msg := data["info"].(map[string]string)

			channelMsg := message {
				src: msg["user"],
				dest: msg["dest"],
				state: "send",
				msg: msg["msg"],
				timeStamp: time.Now(),
				err: nil,
			}

			msgQueue <- channelMsg

		default:
			// return error, and exit
			return
		}
	}
}

func cleaner(m chan message) {
	// Periodically check un arrivable message and sweep them out in the queue
	for {

	}
}

//@deprecated, each function should log error itself
//func logger(m chan message) {
// Handle the error during server run
//    log.Println("Init server logger")
//}
// Function for generate session key

func randSeq(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letters[rand.Intn(len(letters))]
	}
	return string(b)
}

func login(msg map[string]string, conn net.Conn) error {
	user := msg["user"]
	passwd := msg["passwd"]

	// Call the database function to validater user passwd
	if checkLogin(msg) {
		log.Fatal("User is already online")
		return errors.New("User is already online...")
	}

	if validate(user, passwd) {
		// Sending the secondary port of server
		m := make(map[string]interface{})
		m["status"] = "r"
		m["status_code"] = 30
		infomap := make(map[string]string)
		m["info"] = infomap
		//Listen to secondary, for ending informations
		infomap["port"] = strconv.Itoa(SECONDARY_PORT)
		infomap["session"] = randSeq(sessLen)
		// Marshal the map
		reply, err := json.Marshal(m)

		// Register and activate the user session
		if err = activate(user, infomap["session"]); err != nil {
			log.Fatal(err)
			return err
		}
		if err != nil {
			log.Fatal(err)
			return err
		}
		_, err = conn.Write(reply)
		if err != nil {
			log.Fatal(err)
			return err
		}

		return nil
	} else {
		ret := errors.New("Cannot validate user!")
		log.Fatal(ret)
		return ret
	}
}

func logout(msg map[string]string, conn net.Conn) error {
	uname, hasUserName := msg["uname"]
	sessionId, hasSessionId := msg["sessionId"]

	if hasSessionId && hasUserName {
		return killOnline(uname, sessionId)
	} else {
		return errors.New("No such user!")
	}
}

func checkLogin(msg map[string]string) bool {

	uname, hasUserName := msg["uname"]
	sessionId, hasSessionId := msg["sessionId"]

	if hasSessionId && hasUserName {
		return checkAlive(uname, sessionId)
	} else {
		return false
	}
}
<|endoftext|>


<commit_before>package gotest

import (
	"fmt"
	"go/ast"
	"go/doc"
	"go/parser"
	"go/token"
	"os"
	"path"
	"strings"
	"text/template"
	"unicode"
	"unicode/utf8"
)

type testDescr struct {
	Package        string
	Main           string
	TestFunctions  []string
	BenchFunctions []string
	Examples       []*doc.Example
	CoverVars      []CoverVar
	Imports        []string
	Coverage       bool
	Benchmark      bool
}

// WriteTestMain templates a test main file from the given sources to the given output file.
// This mimics what 'go test' does, although we do not currently support benchmarks or examples.
func WriteTestMain(pkgDir, importPath string, sources []string, output string, coverage bool, coverVars []CoverVar, benchmark bool) error {
	testDescr, err := parseTestSources(sources)
	if err != nil {
		return err
	}
	testDescr.Coverage = coverage
	testDescr.CoverVars = coverVars
	if len(testDescr.TestFunctions) > 0 || len(testDescr.BenchFunctions) > 0 || len(testDescr.Examples) > 0 {
		// Can't set this if there are no test functions, it'll be an unused import.
		testDescr.Imports = extraImportPaths(testDescr.Package, pkgDir, importPath, coverVars)
	}

	testDescr.Benchmark = benchmark

	f, err := os.Create(output)
	if err != nil {
		return err
	}
	defer f.Close()
	// This might be consumed by other things.
	fmt.Printf("Package: %s\n", testDescr.Package)
	return testMainTmpl.Execute(f, testDescr)
}

// extraImportPaths returns the set of extra import paths that are needed.
func extraImportPaths(pkg, pkgDir, importPath string, coverVars []CoverVar) []string {
	pkgDir = collapseFinalDir(path.Join(pkgDir, pkg), importPath)
	ret := []string{fmt.Sprintf("%s \"%s\"", pkg, path.Join(importPath, pkgDir))}
	for i, v := range coverVars {
		name := fmt.Sprintf("_cover%d", i)
		coverVars[i].ImportName = name
		ret = append(ret, fmt.Sprintf("%s \"%s\"", name, path.Join(importPath, v.ImportPath)))
	}
	return ret
}

// parseTestSources parses the test sources and returns the package and set of test functions in them.
func parseTestSources(sources []string) (testDescr, error) {
	descr := testDescr{}
	for _, source := range sources {
		f, err := parser.ParseFile(token.NewFileSet(), source, nil, parser.ParseComments)
		if err != nil {
			log.Errorf("Error parsing %s: %s", source, err)
			return descr, err
		}
		descr.Package = f.Name.Name
		// If we're testing main, we will get errors from it clashing with func main.
		if descr.Package == "main" {
			descr.Package = "_main"
		}
		for _, d := range f.Decls {
			if fd, ok := d.(*ast.FuncDecl); ok && fd.Recv == nil {
				name := fd.Name.String()
				if isTestMain(fd) {
					descr.Main = name
				} else if isTest(fd, 1, name, "Test") {
					descr.TestFunctions = append(descr.TestFunctions, name)
				} else if isTest(fd, 1, name, "Benchmark") {
					descr.BenchFunctions = append(descr.BenchFunctions, name)
				}
			}
		}
		// Get doc to find the examples for us :)
		descr.Examples = append(descr.Examples, doc.Examples(f)...)
	}
	return descr, nil
}

// isTestMain returns true if fn is a TestMain(m *testing.M) function.
// Copied from Go sources.
func isTestMain(fn *ast.FuncDecl) bool {
	if fn.Name.String() != "TestMain" ||
		fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
		fn.Type.Params == nil ||
		len(fn.Type.Params.List) != 1 ||
		len(fn.Type.Params.List[0].Names) > 1 {
		return false
	}
	ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
	if !ok {
		return false
	}
	// We can't easily check that the type is *testing.M
	// because we don't know how testing has been imported,
	// but at least check that it's *M or *something.M.
	if name, ok := ptr.X.(*ast.Ident); ok && name.Name == "M" {
		return true
	}
	if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "M" {
		return true
	}
	return false
}

// isTest returns true if the given function looks like a test.
// Copied from Go sources.
func isTest(fd *ast.FuncDecl, argLen int, name, prefix string) bool {
	if !strings.HasPrefix(name, prefix) || fd.Recv != nil || len(fd.Type.Params.List) != argLen {
		return false
	} else if len(name) == len(prefix) { // "Test" is ok
		return true
	}

	rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
	return !unicode.IsLower(rune)
}

// testMainTmpl is the template for our test main, copied from Go's builtin one.
// Some bits are excluded because we don't support them and/or do them differently.
var testMainTmpl = template.Must(template.New("main").Parse(`
package main

import (
	"os"
	{{if not .Benchmark}}"strings"{{end}}
	"testing"
    "testing/internal/testdeps"

{{range .Imports}}
	{{.}}
{{end}}
)

var tests = []testing.InternalTest{
{{range .TestFunctions}}
	{"{{.}}", {{$.Package}}.{{.}}},
{{end}}
}
var examples = []testing.InternalExample{
{{range .Examples}}
	{"{{.Name}}", {{$.Package}}.Example{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
{{end}}
}

var benchmarks = []testing.InternalBenchmark{
{{range .BenchFunctions}}
	{"{{.}}", {{$.Package}}.{{.}}},
{{end}}
}

{{if .Coverage}}

// Only updated by init functions, so no need for atomicity.
var (
	coverCounters = make(map[string][]uint32)
	coverBlocks = make(map[string][]testing.CoverBlock)
)

func init() {
	{{range $i, $c := .CoverVars}}
	coverRegisterFile({{printf "%q" $c.File}}, {{$c.ImportName}}.{{$c.Var}}.Count[:], {{$c.ImportName}}.{{$c.Var}}.Pos[:], {{$c.ImportName}}.{{$c.Var}}.NumStmt[:])
	{{end}}
}

func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
	if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
		panic("coverage: mismatched sizes")
	}
	if coverCounters[fileName] != nil {
		// Already registered.
		return
	}
	coverCounters[fileName] = counter
	block := make([]testing.CoverBlock, len(counter))
	for i := range counter {
		block[i] = testing.CoverBlock{
			Line0: pos[3*i+0],
			Col0: uint16(pos[3*i+2]),
			Line1: pos[3*i+1],
			Col1: uint16(pos[3*i+2]>>16),
			Stmts: numStmts[i],
		}
	}
	coverBlocks[fileName] = block
}
{{end}}

var testDeps = testdeps.TestDeps{}

func main() {
{{if .Coverage}}
	testing.RegisterCover(testing.Cover{
		Mode: "set",
		Counters: coverCounters,
		Blocks: coverBlocks,
		CoveredPackages: "",
	})
    coverfile := os.Getenv("COVERAGE_FILE")
    args := []string{os.Args[0], "-test.v", "-test.coverprofile", coverfile}
{{else}}
    args := []string{os.Args[0], "-test.v"}
{{end}}
{{if not .Benchmark}}
    testVar := os.Getenv("TESTS")
    if testVar != "" {
		testVar = strings.Replace(testVar, " ", "|", -1)
		args = append(args, "-test.run", testVar)
    }
    os.Args = append(args, os.Args[1:]...)
	m := testing.MainStart(testDeps, tests, nil, examples)
{{else}}
	args = append(args, "-test.bench", ".*")
	os.Args = append(args, os.Args[1:]...)
	m := testing.MainStart(testDeps, nil, benchmarks, nil)
{{end}}

{{if .Main}}
	{{.Package}}.{{.Main}}(m)
{{else}}
	os.Exit(m.Run())
{{end}}
}
`))
<commit_msg>go_test(): avoid redefined imports in generated test main files (#1066)<commit_after>package gotest

import (
	"fmt"
	"go/ast"
	"go/doc"
	"go/parser"
	"go/token"
	"os"
	"path"
	"strings"
	"text/template"
	"unicode"
	"unicode/utf8"
)

type testDescr struct {
	Package        string
	Main           string
	TestFunctions  []string
	BenchFunctions []string
	Examples       []*doc.Example
	CoverVars      []CoverVar
	Imports        []string
	Coverage       bool
	Benchmark      bool
}

// WriteTestMain templates a test main file from the given sources to the given output file.
// This mimics what 'go test' does, although we do not currently support benchmarks or examples.
func WriteTestMain(pkgDir, importPath string, sources []string, output string, coverage bool, coverVars []CoverVar, benchmark bool) error {
	testDescr, err := parseTestSources(sources)
	if err != nil {
		return err
	}
	testDescr.Coverage = coverage
	testDescr.CoverVars = coverVars
	if len(testDescr.TestFunctions) > 0 || len(testDescr.BenchFunctions) > 0 || len(testDescr.Examples) > 0 {
		// Can't set this if there are no test functions, it'll be an unused import.
		testDescr.Imports = extraImportPaths(testDescr.Package, pkgDir, importPath, coverVars)
	}

	testDescr.Benchmark = benchmark

	f, err := os.Create(output)
	if err != nil {
		return err
	}
	defer f.Close()
	// This might be consumed by other things.
	fmt.Printf("Package: %s\n", testDescr.Package)
	return testMainTmpl.Execute(f, testDescr)
}

// extraImportPaths returns the set of extra import paths that are needed.
func extraImportPaths(pkg, pkgDir, importPath string, coverVars []CoverVar) []string {
	pkgDir = collapseFinalDir(path.Join(pkgDir, pkg), importPath)
	ret := []string{fmt.Sprintf("%s \"%s\"", pkg, path.Join(importPath, pkgDir))}
	for i, v := range coverVars {
		name := fmt.Sprintf("_cover%d", i)
		coverVars[i].ImportName = name
		ret = append(ret, fmt.Sprintf("%s \"%s\"", name, path.Join(importPath, v.ImportPath)))
	}
	return ret
}

// parseTestSources parses the test sources and returns the package and set of test functions in them.
func parseTestSources(sources []string) (testDescr, error) {
	descr := testDescr{}
	for _, source := range sources {
		f, err := parser.ParseFile(token.NewFileSet(), source, nil, parser.ParseComments)
		if err != nil {
			log.Errorf("Error parsing %s: %s", source, err)
			return descr, err
		}
		descr.Package = f.Name.Name
		// If we're testing main, we will get errors from it clashing with func main.
		if descr.Package == "main" {
			descr.Package = "_main"
		}
		for _, d := range f.Decls {
			if fd, ok := d.(*ast.FuncDecl); ok && fd.Recv == nil {
				name := fd.Name.String()
				if isTestMain(fd) {
					descr.Main = name
				} else if isTest(fd, 1, name, "Test") {
					descr.TestFunctions = append(descr.TestFunctions, name)
				} else if isTest(fd, 1, name, "Benchmark") {
					descr.BenchFunctions = append(descr.BenchFunctions, name)
				}
			}
		}
		// Get doc to find the examples for us :)
		descr.Examples = append(descr.Examples, doc.Examples(f)...)
	}
	return descr, nil
}

// isTestMain returns true if fn is a TestMain(m *testing.M) function.
// Copied from Go sources.
func isTestMain(fn *ast.FuncDecl) bool {
	if fn.Name.String() != "TestMain" ||
		fn.Type.Results != nil && len(fn.Type.Results.List) > 0 ||
		fn.Type.Params == nil ||
		len(fn.Type.Params.List) != 1 ||
		len(fn.Type.Params.List[0].Names) > 1 {
		return false
	}
	ptr, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr)
	if !ok {
		return false
	}
	// We can't easily check that the type is *testing.M
	// because we don't know how testing has been imported,
	// but at least check that it's *M or *something.M.
	if name, ok := ptr.X.(*ast.Ident); ok && name.Name == "M" {
		return true
	}
	if sel, ok := ptr.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "M" {
		return true
	}
	return false
}

// isTest returns true if the given function looks like a test.
// Copied from Go sources.
func isTest(fd *ast.FuncDecl, argLen int, name, prefix string) bool {
	if !strings.HasPrefix(name, prefix) || fd.Recv != nil || len(fd.Type.Params.List) != argLen {
		return false
	} else if len(name) == len(prefix) { // "Test" is ok
		return true
	}

	rune, _ := utf8.DecodeRuneInString(name[len(prefix):])
	return !unicode.IsLower(rune)
}

// testMainTmpl is the template for our test main, copied from Go's builtin one.
// Some bits are excluded because we don't support them and/or do them differently.
var testMainTmpl = template.Must(template.New("main").Parse(`
package main

import (
	_gostdlib_os "os"
	{{if not .Benchmark}}_gostdlib_strings "strings"{{end}}
	_gostdlib_testing "testing"
	_gostdlib_testdeps "testing/internal/testdeps"

{{range .Imports}}
	{{.}}
{{end}}
)

var tests = []_gostdlib_testing.InternalTest{
{{range .TestFunctions}}
	{"{{.}}", {{$.Package}}.{{.}}},
{{end}}
}
var examples = []_gostdlib_testing.InternalExample{
{{range .Examples}}
	{"{{.Name}}", {{$.Package}}.Example{{.Name}}, {{.Output | printf "%q"}}, {{.Unordered}}},
{{end}}
}

var benchmarks = []_gostdlib_testing.InternalBenchmark{
{{range .BenchFunctions}}
	{"{{.}}", {{$.Package}}.{{.}}},
{{end}}
}

{{if .Coverage}}

// Only updated by init functions, so no need for atomicity.
var (
	coverCounters = make(map[string][]uint32)
	coverBlocks = make(map[string][]_gostdlib_testing.CoverBlock)
)

func init() {
	{{range $i, $c := .CoverVars}}
	coverRegisterFile({{printf "%q" $c.File}}, {{$c.ImportName}}.{{$c.Var}}.Count[:], {{$c.ImportName}}.{{$c.Var}}.Pos[:], {{$c.ImportName}}.{{$c.Var}}.NumStmt[:])
	{{end}}
}

func coverRegisterFile(fileName string, counter []uint32, pos []uint32, numStmts []uint16) {
	if 3*len(counter) != len(pos) || len(counter) != len(numStmts) {
		panic("coverage: mismatched sizes")
	}
	if coverCounters[fileName] != nil {
		// Already registered.
		return
	}
	coverCounters[fileName] = counter
	block := make([]_gostdlib_testing.CoverBlock, len(counter))
	for i := range counter {
		block[i] = _gostdlib_testing.CoverBlock{
			Line0: pos[3*i+0],
			Col0: uint16(pos[3*i+2]),
			Line1: pos[3*i+1],
			Col1: uint16(pos[3*i+2]>>16),
			Stmts: numStmts[i],
		}
	}
	coverBlocks[fileName] = block
}
{{end}}

var testDeps = _gostdlib_testdeps.TestDeps{}

func main() {
{{if .Coverage}}
	_gostdlib_testing.RegisterCover(_gostdlib_testing.Cover{
		Mode: "set",
		Counters: coverCounters,
		Blocks: coverBlocks,
		CoveredPackages: "",
	})
    coverfile := _gostdlib_os.Getenv("COVERAGE_FILE")
    args := []string{_gostdlib_os.Args[0], "-test.v", "-test.coverprofile", coverfile}
{{else}}
    args := []string{_gostdlib_os.Args[0], "-test.v"}
{{end}}
{{if not .Benchmark}}
    testVar := _gostdlib_os.Getenv("TESTS")
    if testVar != "" {
		testVar = _gostdlib_strings.Replace(testVar, " ", "|", -1)
		args = append(args, "-test.run", testVar)
    }
    _gostdlib_os.Args = append(args, _gostdlib_os.Args[1:]...)
	m := _gostdlib_testing.MainStart(testDeps, tests, nil, examples)
{{else}}
	args = append(args, "-test.bench", ".*")
	_gostdlib_os.Args = append(args, _gostdlib_os.Args[1:]...)
	m := _gostdlib_testing.MainStart(testDeps, nil, benchmarks, nil)
{{end}}

{{if .Main}}
	{{.Package}}.{{.Main}}(m)
{{else}}
	_gostdlib_os.Exit(m.Run())
{{end}}
}
`))
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package azure

import (
	"fmt"
	"io/ioutil"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/schema"
)

var azureConfigChecker = schema.StrictFieldMap(
	schema.Fields{
		"management-subscription-id":     schema.String(),
		"management-certificate-path":    schema.String(),
		"management-certificate":         schema.String(),
		"management-hosted-service-name": schema.String(),
		"storage-account-name":           schema.String(),
		"storage-account-key":            schema.String(),
		"storage-container-name":         schema.String(),
	},
	schema.Defaults{
		"management-hosted-service-name": "",
		"management-certificate":         "",
		"management-certificate-path":    "",
		"storage-container-name":         "",
	},
)

type azureEnvironConfig struct {
	*config.Config
	attrs map[string]interface{}
}

func (cfg *azureEnvironConfig) ManagementSubscriptionId() string {
	return cfg.attrs["management-subscription-id"].(string)
}

func (cfg *azureEnvironConfig) ManagementCertificate() string {
	return cfg.attrs["management-certificate"].(string)
}

func (cfg *azureEnvironConfig) ManagementHostedServiceName() string {
	return cfg.attrs["management-hosted-service-name"].(string)
}

func (cfg *azureEnvironConfig) StorageAccountName() string {
	return cfg.attrs["storage-account-name"].(string)
}

func (cfg *azureEnvironConfig) StorageAccountKey() string {
	return cfg.attrs["storage-account-key"].(string)
}

func (cfg *azureEnvironConfig) StorageContainerName() string {
	return cfg.attrs["storage-container-name"].(string)
}

func (prov azureEnvironProvider) newConfig(cfg *config.Config) (*azureEnvironConfig, error) {
	validCfg, err := prov.Validate(cfg, nil)
	if err != nil {
		return nil, err
	}
	result := new(azureEnvironConfig)
	result.Config = validCfg
	result.attrs = validCfg.UnknownAttrs()
	return result, nil
}

// Validate is specified in the EnvironProvider interface.
func (prov azureEnvironProvider) Validate(cfg, oldCfg *config.Config) (*config.Config, error) {
	// Validate base configuration change before validating Azure specifics.
	err := config.Validate(cfg, oldCfg)
	if err != nil {
		return nil, err
	}

	v, err := azureConfigChecker.Coerce(cfg.UnknownAttrs(), nil)
	if err != nil {
		return nil, err
	}
	envCfg := new(azureEnvironConfig)
	envCfg.Config = cfg
	envCfg.attrs = v.(map[string]interface{})

	cert := envCfg.ManagementCertificate()
	if cert == "" {
		certPath := envCfg.attrs["management-certificate-path"].(string)
		pemData, err := ioutil.ReadFile(certPath)
		if err != nil {
			return nil, fmt.Errorf("invalid management-certificate-path: %s", err)
		}
		envCfg.attrs["management-certificate"] = string(pemData)
	}
	delete(envCfg.attrs, "management-certificate-path")
	if envCfg.ManagementHostedServiceName() == "" {
		return nil, fmt.Errorf("environment has no management-hosted-service-name; auto-creation of hosted services is not yet supported")
	}
	if envCfg.StorageContainerName() == "" {
		return nil, fmt.Errorf("environment has no storage-container-name; auto-creation of storage containers is not yet supported")
	}
	if oldCfg != nil {
		attrs := oldCfg.UnknownAttrs()
		if hostedServiceName, _ := attrs["management-hosted-service-name"].(string); envCfg.ManagementHostedServiceName() != hostedServiceName {
			return nil, fmt.Errorf("cannot change management-hosted-service-name from %q to %q", hostedServiceName, envCfg.ManagementHostedServiceName())
		}
		if storageContainerName, _ := attrs["storage-container-name"].(string); envCfg.StorageContainerName() != storageContainerName {
			return nil, fmt.Errorf("cannot change storage-container-name from %q to %q", storageContainerName, envCfg.StorageContainerName())
		}
	}

	return cfg.Apply(envCfg.attrs)
}

const boilerplateYAML = `azure:
  type: azure
  # http://msdn.microsoft.com/en-us/library/windowsazure
  # Windows Azure Management info.
  management-subscription-id: 886413e1-3b8a-5382-9b90-0c9aee199e5d
  management-certificate-path: /home/me/azure.pem
  management-hosted-service-name: gwaclbize3r9qh67ro6qbgvm
  # Windows Azure Storage info.
  storage-account-name: ghedlkjhw54e
  storage-account-key: fdjh4sfkg
  storage-container-name: sdg50984jmsdf
`

func (prov azureEnvironProvider) BoilerplateConfig() string {
	return boilerplateYAML
}

// SecretAttrs is specified in the EnvironProvider interface.
func (prov azureEnvironProvider) SecretAttrs(cfg *config.Config) (map[string]interface{}, error) {
	secretAttrs := make(map[string]interface{})
	azureCfg, err := prov.newConfig(cfg)
	if err != nil {
		return nil, err
	}
	secretAttrs["management-certificate"] = azureCfg.ManagementCertificate()
	secretAttrs["storage-account-key"] = azureCfg.StorageAccountKey()
	return secretAttrs, nil
}
<commit_msg>Review fixes.<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package azure

import (
	"fmt"
	"io/ioutil"
	"launchpad.net/juju-core/environs/config"
	"launchpad.net/juju-core/schema"
)

var azureConfigChecker = schema.StrictFieldMap(
	schema.Fields{
		"management-subscription-id":     schema.String(),
		"management-certificate-path":    schema.String(),
		"management-certificate":         schema.String(),
		"management-hosted-service-name": schema.String(),
		"storage-account-name":           schema.String(),
		"storage-account-key":            schema.String(),
		"storage-container-name":         schema.String(),
	},
	schema.Defaults{
		"management-hosted-service-name": "",
		"management-certificate":         "",
		"management-certificate-path":    "",
		"storage-container-name":         "",
	},
)

type azureEnvironConfig struct {
	*config.Config
	attrs map[string]interface{}
}

func (cfg *azureEnvironConfig) ManagementSubscriptionId() string {
	return cfg.attrs["management-subscription-id"].(string)
}

func (cfg *azureEnvironConfig) ManagementCertificate() string {
	return cfg.attrs["management-certificate"].(string)
}

func (cfg *azureEnvironConfig) ManagementHostedServiceName() string {
	return cfg.attrs["management-hosted-service-name"].(string)
}

func (cfg *azureEnvironConfig) StorageAccountName() string {
	return cfg.attrs["storage-account-name"].(string)
}

func (cfg *azureEnvironConfig) StorageAccountKey() string {
	return cfg.attrs["storage-account-key"].(string)
}

func (cfg *azureEnvironConfig) StorageContainerName() string {
	return cfg.attrs["storage-container-name"].(string)
}

func (prov azureEnvironProvider) newConfig(cfg *config.Config) (*azureEnvironConfig, error) {
	validCfg, err := prov.Validate(cfg, nil)
	if err != nil {
		return nil, err
	}
	result := new(azureEnvironConfig)
	result.Config = validCfg
	result.attrs = validCfg.UnknownAttrs()
	return result, nil
}

// Validate ensures that config is a valid configuration for this
// provider like specified in the EnvironProvider interface.
func (prov azureEnvironProvider) Validate(cfg, oldCfg *config.Config) (*config.Config, error) {
	// Validate base configuration change before validating Azure specifics.
	err := config.Validate(cfg, oldCfg)
	if err != nil {
		return nil, err
	}

	v, err := azureConfigChecker.Coerce(cfg.UnknownAttrs(), nil)
	if err != nil {
		return nil, err
	}
	envCfg := new(azureEnvironConfig)
	envCfg.Config = cfg
	envCfg.attrs = v.(map[string]interface{})

	cert := envCfg.ManagementCertificate()
	if cert == "" {
		certPath := envCfg.attrs["management-certificate-path"].(string)
		pemData, err := ioutil.ReadFile(certPath)
		if err != nil {
			return nil, fmt.Errorf("invalid management-certificate-path: %s", err)
		}
		envCfg.attrs["management-certificate"] = string(pemData)
	}
	delete(envCfg.attrs, "management-certificate-path")
	if envCfg.ManagementHostedServiceName() == "" {
		return nil, fmt.Errorf("environment has no management-hosted-service-name; auto-creation of hosted services is not yet supported")
	}
	if envCfg.StorageContainerName() == "" {
		return nil, fmt.Errorf("environment has no storage-container-name; auto-creation of storage containers is not yet supported")
	}
	if oldCfg != nil {
		attrs := oldCfg.UnknownAttrs()
		if hostedServiceName, _ := attrs["management-hosted-service-name"].(string); envCfg.ManagementHostedServiceName() != hostedServiceName {
			return nil, fmt.Errorf("cannot change management-hosted-service-name from %q to %q", hostedServiceName, envCfg.ManagementHostedServiceName())
		}
		if storageContainerName, _ := attrs["storage-container-name"].(string); envCfg.StorageContainerName() != storageContainerName {
			return nil, fmt.Errorf("cannot change storage-container-name from %q to %q", storageContainerName, envCfg.StorageContainerName())
		}
	}

	return cfg.Apply(envCfg.attrs)
}

const boilerplateYAML = `azure:
  type: azure
  # http://msdn.microsoft.com/en-us/library/windowsazure
  # Windows Azure Management info.
  management-subscription-id: 886413e1-3b8a-5382-9b90-0c9aee199e5d
  management-certificate-path: /home/me/azure.pem
  management-hosted-service-name: gwaclbize3r9qh67ro6qbgvm
  # Windows Azure Storage info.
  storage-account-name: ghedlkjhw54e
  storage-account-key: fdjh4sfkg
  storage-container-name: sdg50984jmsdf
`

func (prov azureEnvironProvider) BoilerplateConfig() string {
	return boilerplateYAML
}

// SecretAttrs is specified in the EnvironProvider interface.
func (prov azureEnvironProvider) SecretAttrs(cfg *config.Config) (map[string]interface{}, error) {
	secretAttrs := make(map[string]interface{})
	azureCfg, err := prov.newConfig(cfg)
	if err != nil {
		return nil, err
	}
	secretAttrs["management-certificate"] = azureCfg.ManagementCertificate()
	secretAttrs["storage-account-key"] = azureCfg.StorageAccountKey()
	return secretAttrs, nil
}
<|endoftext|>


<commit_before>// Package gcloudtf handles parsing Terraform files to extract structured
// information out of it, to support a few tools to speed up the DeployStack
// authoring process
package gcloudtf

import (
	"fmt"
	"io/ioutil"
	"os"
	"sort"
	"strings"

	"github.com/hashicorp/terraform-config-inspect/tfconfig"
	"gopkg.in/yaml.v2"
)

// Extract points to a path that includes Terraform files and extracts all of
// the information out of it for use with DeployStack Tools
func Extract(path string) (*Blocks, error) {
	mod, dia := tfconfig.LoadModule(path)
	if dia.Err() != nil {
		return nil, fmt.Errorf("terraform config problem %s", dia.Err())
	}

	b, err := NewBlocks(mod)
	if dia.Err() != nil {
		return nil, fmt.Errorf("could not properly parse blocks %s", err)
	}

	return b, nil
}

// Block represents one of several kinds of Terraform constructs: resources,
// variables, module
type Block struct {
	Name  string            `json:"name" yaml:"name"`
	Text  string            `json:"text" yaml:"text"`
	Kind  string            `json:"kind" yaml:"kind"`
	Type  string            `json:"type" yaml:"type"`
	Attr  map[string]string `json:"attr" yaml:"attr"`
	file  string
	start int
}

// NewResourceBlock converts a parsed Terraform Resource to a Block
func NewResourceBlock(t *tfconfig.Resource) (Block, error) {
	b := Block{}
	var err error
	b.Name = t.Name
	b.Type = t.Type
	b.Kind = t.Mode.String()
	b.start = t.Pos.Line
	b.file = t.Pos.Filename
	b.Text, err = getResourceText(t.Pos.Filename, t.Pos.Line)
	if err != nil {
		return b, fmt.Errorf("could not extract text from Resource: %s", err)
	}

	return b, nil
}

// NewVariableBlock converts a parsed Terraform Variable to a Block
func NewVariableBlock(t *tfconfig.Variable) (Block, error) {
	b := Block{}
	var err error
	b.Name = t.Name
	b.Type = t.Type
	b.Kind = "variable"
	b.start = t.Pos.Line
	b.file = t.Pos.Filename
	b.Text, err = getResourceText(t.Pos.Filename, t.Pos.Line)
	if err != nil {
		return b, fmt.Errorf("could not extract text from Variable: %s", err)
	}
	return b, nil
}

// NewModuleBlock converts a parsed Terraform Module to a Block
func NewModuleBlock(t *tfconfig.ModuleCall) (Block, error) {
	b := Block{}
	var err error
	b.Name = t.Name
	b.Type = t.Source
	b.Kind = "module"
	b.start = t.Pos.Line
	b.file = t.Pos.Filename
	b.Text, err = getResourceText(t.Pos.Filename, t.Pos.Line)
	if err != nil {
		return b, fmt.Errorf("could not extract text from Module: %s", err)
	}
	return b, nil
}

// IsResource returns true if block is a Terraform resource
func (b Block) IsResource() bool {
	return b.Kind == "managed"
}

// IsModule returns true if block is a Terraform module
func (b Block) IsModule() bool {
	return b.Kind == "module"
}

// IsVariable returns true if block is a Terraform variable
func (b Block) IsVariable() bool {
	return b.Kind == "variable"
}

// NoDefault returns true if block does not contain a default value
func (b Block) NoDefault() bool {
	return !strings.Contains(b.Text, "default")
}

func getResourceText(file string, start int) (string, error) {
	dat, _ := os.ReadFile(file)
	sl := strings.Split(string(dat), "\n")

	resultSl := []string{}

	startpos := start - 1

	end := len(sl) - 1

	end = findClosingBracket(start, sl) + 1

	if startpos == 0 {
		startpos = 1
	}

	for i := startpos - 1; i < end; i++ {
		resultSl = append(resultSl, sl[i])
	}

	result := strings.Join(resultSl, "\n")

	return result, nil
}

func findClosingBracket(start int, sl []string) int {
	count := 0
	for i := start - 1; i < len(sl); i++ {
		if strings.Contains(sl[i], "{") {
			count++
		}
		if strings.Contains(sl[i], "}") {
			count--
		}
		if count == 0 {
			return i
		}
	}

	return len(sl)
}

// Blocks is a slice of type Block
type Blocks []Block

// NewBlocks converts the results from a Terraform parse operation to Blocks.
func NewBlocks(mod *tfconfig.Module) (*Blocks, error) {
	result := Blocks{}

	for _, v := range mod.ModuleCalls {
		b, err := NewModuleBlock(v)
		if err != nil {
			return nil, fmt.Errorf("could not parse Module Calls: %s", err)
		}
		result = append(result, b)
	}

	for _, v := range mod.ManagedResources {
		b, err := NewResourceBlock(v)
		if err != nil {
			return nil, fmt.Errorf("could not parse ManagedResources: %s", err)
		}
		result = append(result, b)
	}

	for _, v := range mod.DataResources {
		b, err := NewResourceBlock(v)
		if err != nil {
			return nil, fmt.Errorf("could not parse DataResources: %s", err)
		}
		result = append(result, b)
	}

	for _, v := range mod.Variables {
		b, err := NewVariableBlock(v)
		if err != nil {
			return nil, fmt.Errorf("could not parse Variables: %s", err)
		}
		result = append(result, b)
	}

	sort.Slice(result, func(i, j int) bool {
		return result[i].start < result[j].start
	})

	return &result, nil
}

// List is a slice of strings that we add extra functionality to
type List []string

// Matches determines if a given string is an entry in the list.
func (l List) Matches(s string) bool {
	tmp := strings.ToLower(s)
	for _, v := range l {
		if strings.Contains(tmp, strings.ToLower(v)) {
			return true
		}
	}
	return false
}

// GCPResources is a collection of GCPResource
type GCPResources map[string]GCPResource

// GetProduct returns the prouct name assoicated with the terraform resource
func (g GCPResources) GetProduct(key string) string {
	v, ok := g[key]
	if !ok {
		return ""
	}

	return v.Product
}

// GCPResource is a Terraform resource that matches up with a GCP product. This
// is used to automate the generation of tests and documentation
type GCPResource struct {
	Label      string     `json:"label" yaml:"label"`
	Product    string     `json:"product" yaml:"product"`
	APICalls   []string   `json:"api_calls" yaml:"api_calls"`
	TestConfig TestConfig `json:"test_config" yaml:"test_config"`
}

// TestConfig is the information needed to automate test creation.
type TestConfig struct {
	TestType    string `json:"test_type" yaml:"test_type"`
	TestCommand string `json:"test_command" yaml:"test_command"`
	Suffix      string `json:"suffix" yaml:"suffix"`
	Region      bool   `json:"region" yaml:"region"`
	Zone        bool   `json:"zone" yaml:"zone"`
	LabelField  string `json:"label_field" yaml:"label_field"`
	Expected    string `json:"expected" yaml:"expected"`
	Todo        string `json:"todo" yaml:"todo"`
}

// HasTest returns true if test config actually has a test in it.
func (t TestConfig) HasTest() bool {
	return len(t.TestCommand) > 0
}

// HasTodo returns true if test config actually has a todo in it.
func (t TestConfig) HasTodo() bool {
	return len(t.Todo) > 0
}

// NewGCPResources reads in a yaml file as a config
func NewGCPResources(path string) (GCPResources, error) {
	result := GCPResources{}

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return result, fmt.Errorf("unable to find or read config file: %s", err)
	}

	if err := yaml.Unmarshal(content, &result); err != nil {
		return result, fmt.Errorf("unable to convert content to GCPResources: %s", err)
	}

	return result, nil
}

// Repos is a slice of strings containing github urls
type Repos []string

// NewRepos retrieves the list of repos from a ymal file.
func NewRepos(path string) (Repos, error) {
	result := Repos{}

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return result, fmt.Errorf("unable to find or read config file: %s", err)
	}

	if err := yaml.Unmarshal(content, &result); err != nil {
		return result, fmt.Errorf("unable to convert content to a list of repos: %s", err)
	}

	return result, nil
}
<commit_msg>fix: typo in type - oh!<commit_after>// Package gcloudtf handles parsing Terraform files to extract structured
// information out of it, to support a few tools to speed up the DeployStack
// authoring process
package gcloudtf

import (
	"fmt"
	"io/ioutil"
	"os"
	"sort"
	"strings"

	"github.com/hashicorp/terraform-config-inspect/tfconfig"
	"gopkg.in/yaml.v2"
)

// Extract points to a path that includes Terraform files and extracts all of
// the information out of it for use with DeployStack Tools
func Extract(path string) (*Blocks, error) {
	mod, dia := tfconfig.LoadModule(path)
	if dia.Err() != nil {
		return nil, fmt.Errorf("terraform config problem %s", dia.Err())
	}

	b, err := NewBlocks(mod)
	if dia.Err() != nil {
		return nil, fmt.Errorf("could not properly parse blocks %s", err)
	}

	return b, nil
}

// Block represents one of several kinds of Terraform constructs: resources,
// variables, module
type Block struct {
	Name  string            `json:"name" yaml:"name"`
	Text  string            `json:"text" yaml:"text"`
	Kind  string            `json:"kind" yaml:"kind"`
	Type  string            `json:"type" yaml:"type"`
	Attr  map[string]string `json:"attr" yaml:"attr"`
	file  string
	start int
}

// NewResourceBlock converts a parsed Terraform Resource to a Block
func NewResourceBlock(t *tfconfig.Resource) (Block, error) {
	b := Block{}
	var err error
	b.Name = t.Name
	b.Type = t.Type
	b.Kind = t.Mode.String()
	b.start = t.Pos.Line
	b.file = t.Pos.Filename
	b.Text, err = getResourceText(t.Pos.Filename, t.Pos.Line)
	if err != nil {
		return b, fmt.Errorf("could not extract text from Resource: %s", err)
	}

	return b, nil
}

// NewVariableBlock converts a parsed Terraform Variable to a Block
func NewVariableBlock(t *tfconfig.Variable) (Block, error) {
	b := Block{}
	var err error
	b.Name = t.Name
	b.Type = t.Type
	b.Kind = "variable"
	b.start = t.Pos.Line
	b.file = t.Pos.Filename
	b.Text, err = getResourceText(t.Pos.Filename, t.Pos.Line)
	if err != nil {
		return b, fmt.Errorf("could not extract text from Variable: %s", err)
	}
	return b, nil
}

// NewModuleBlock converts a parsed Terraform Module to a Block
func NewModuleBlock(t *tfconfig.ModuleCall) (Block, error) {
	b := Block{}
	var err error
	b.Name = t.Name
	b.Type = t.Source
	b.Kind = "module"
	b.start = t.Pos.Line
	b.file = t.Pos.Filename
	b.Text, err = getResourceText(t.Pos.Filename, t.Pos.Line)
	if err != nil {
		return b, fmt.Errorf("could not extract text from Module: %s", err)
	}
	return b, nil
}

// IsResource returns true if block is a Terraform resource
func (b Block) IsResource() bool {
	return b.Kind == "managed"
}

// IsModule returns true if block is a Terraform module
func (b Block) IsModule() bool {
	return b.Kind == "module"
}

// IsVariable returns true if block is a Terraform variable
func (b Block) IsVariable() bool {
	return b.Kind == "variable"
}

// NoDefault returns true if block does not contain a default value
func (b Block) NoDefault() bool {
	return !strings.Contains(b.Text, "default")
}

func getResourceText(file string, start int) (string, error) {
	dat, _ := os.ReadFile(file)
	sl := strings.Split(string(dat), "\n")

	resultSl := []string{}

	startpos := start - 1

	end := len(sl) - 1

	end = findClosingBracket(start, sl) + 1

	if startpos == 0 {
		startpos = 1
	}

	for i := startpos - 1; i < end; i++ {
		resultSl = append(resultSl, sl[i])
	}

	result := strings.Join(resultSl, "\n")

	return result, nil
}

func findClosingBracket(start int, sl []string) int {
	count := 0
	for i := start - 1; i < len(sl); i++ {
		if strings.Contains(sl[i], "{") {
			count++
		}
		if strings.Contains(sl[i], "}") {
			count--
		}
		if count == 0 {
			return i
		}
	}

	return len(sl)
}

// Blocks is a slice of type Block
type Blocks []Block

// NewBlocks converts the results from a Terraform parse operation to Blocks.
func NewBlocks(mod *tfconfig.Module) (*Blocks, error) {
	result := Blocks{}

	for _, v := range mod.ModuleCalls {
		b, err := NewModuleBlock(v)
		if err != nil {
			return nil, fmt.Errorf("could not parse Module Calls: %s", err)
		}
		result = append(result, b)
	}

	for _, v := range mod.ManagedResources {
		b, err := NewResourceBlock(v)
		if err != nil {
			return nil, fmt.Errorf("could not parse ManagedResources: %s", err)
		}
		result = append(result, b)
	}

	for _, v := range mod.DataResources {
		b, err := NewResourceBlock(v)
		if err != nil {
			return nil, fmt.Errorf("could not parse DataResources: %s", err)
		}
		result = append(result, b)
	}

	for _, v := range mod.Variables {
		b, err := NewVariableBlock(v)
		if err != nil {
			return nil, fmt.Errorf("could not parse Variables: %s", err)
		}
		result = append(result, b)
	}

	sort.Slice(result, func(i, j int) bool {
		return result[i].start < result[j].start
	})

	return &result, nil
}

// List is a slice of strings that we add extra functionality to
type List []string

// Matches determines if a given string is an entry in the list.
func (l List) Matches(s string) bool {
	tmp := strings.ToLower(s)
	for _, v := range l {
		if strings.Contains(tmp, strings.ToLower(v)) {
			return true
		}
	}
	return false
}

// GCPResources is a collection of GCPResource
type GCPResources map[string]GCPResource

// GetProduct returns the prouct name assoicated with the terraform resource
func (g GCPResources) GetProduct(key string) string {
	v, ok := g[key]
	if !ok {
		return ""
	}

	return v.Product
}

// GCPResource is a Terraform resource that matches up with a GCP product. This
// is used to automate the generation of tests and documentation
type GCPResource struct {
	Label      string     `json:"label" yaml:"label"`
	Product    string     `json:"product" yaml:"product"`
	APICalls   []string   `json:"api_calls" yaml:"api_calls"`
	TestConfig TestConfig `json:"test_config" yaml:"test_config"`
	AliasOf    []string   `json:"aliasof" yaml:"aliasof"`
}

// TestConfig is the information needed to automate test creation.
type TestConfig struct {
	TestType    string `json:"test_type" yaml:"test_type"`
	TestCommand string `json:"test_command" yaml:"test_command"`
	Suffix      string `json:"suffix" yaml:"suffix"`
	Region      bool   `json:"region" yaml:"region"`
	Zone        bool   `json:"zone" yaml:"zone"`
	LabelField  string `json:"label_field" yaml:"label_field"`
	Expected    string `json:"expected" yaml:"expected"`
	Todo        string `json:"todo" yaml:"todo"`
}

// HasTest returns true if test config actually has a test in it.
func (t TestConfig) HasTest() bool {
	return len(t.TestCommand) > 0
}

// HasTodo returns true if test config actually has a todo in it.
func (t TestConfig) HasTodo() bool {
	return len(t.Todo) > 0
}

// NewGCPResources reads in a yaml file as a config
func NewGCPResources(path string) (GCPResources, error) {
	result := GCPResources{}

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return result, fmt.Errorf("unable to find or read config file: %s", err)
	}

	if err := yaml.Unmarshal(content, &result); err != nil {
		return result, fmt.Errorf("unable to convert content to GCPResources: %s", err)
	}

	return result, nil
}

// Repos is a slice of strings containing github urls
type Repos []string

// NewRepos retrieves the list of repos from a ymal file.
func NewRepos(path string) (Repos, error) {
	result := Repos{}

	content, err := ioutil.ReadFile(path)
	if err != nil {
		return result, fmt.Errorf("unable to find or read config file: %s", err)
	}

	if err := yaml.Unmarshal(content, &result); err != nil {
		return result, fmt.Errorf("unable to convert content to a list of repos: %s", err)
	}

	return result, nil
}
<|endoftext|>


<commit_before>package generator

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"os"

	"github.com/agonzalezro/polo/templates"
)

var (
	archiveTemplate,
	articleTemplate,
	atomTemplate,
	baseTemplate,
	categoryTemplate,
	indexTemplate,
	pageTemplate,
	tagTemplate *template.Template
)

// parsedFiles is a wrapper similar to template.ParseFiles that is going to
// load the templates from the disk, and if they can not be found from the
// go-bindata file.
func parseFiles(filenames ...string) (*template.Template, error) {
	tpl := template.New(filenames[0])
	for _, filename := range filenames {
		b, err := ioutil.ReadFile(filename)
		if err != nil {
			b, err = templates.Asset(filename)
			if err != nil {
				log.Printf("Template: %s not found. Not in HD neihter in bindata!", filename)
				return nil, err
			}
		}
		tpl.Parse(string(b))
	}
	return tpl, nil
}

// loadTemplates is an ugly function but I need it to run the test without the
// template files. If I don't call .Write() I don't need the template files.
func loadTemplates() {
	archiveTemplate = template.Must(parseFiles("templates/archives.html", "templates/base.html"))
	articleTemplate = template.Must(parseFiles("templates/article.html", "templates/base.html"))
	atomTemplate = template.Must(parseFiles("templates/atom.xml"))
	categoryTemplate = template.Must(parseFiles("templates/category.html", "templates/base.html"))
	indexTemplate = template.Must(parseFiles("templates/index.html", "templates/base.html"))
	pageTemplate = template.Must(parseFiles("templates/page.html", "templates/base.html"))
	tagTemplate = template.Must(parseFiles("templates/tag.html", "templates/base.html"))
}

// Dump all the site content to the disk
func (site Site) Write() {
	loadTemplates()

	site.writeIndexes()
	site.writeFeeds()
	site.writeArticles()
	site.writePages()
	if site.Config.ShowArchive {
		site.writeArchive()
	}
	if site.Config.ShowCategories {
		site.writeCategories()
	}
	if site.Config.ShowTags {
		site.writeTags()
	}
}

func (site Site) getNumberOfPages() int {
	if site.NumberOfPages == 0 {
		site.NumberOfPages = len(site.Articles()) / site.Config.PaginationSize
	}
	// If it continue being 0, we don't have pages
	if site.NumberOfPages == 0 {
		site.NumberOfPages = -1
	}
	return site.NumberOfPages
}

func (site Site) writeIndexes() {
	site.NumberOfPages = site.getNumberOfPages()

	for site.PageNumber = 1; site.PageNumber <= site.NumberOfPages; site.PageNumber++ {
		indexFile := fmt.Sprintf("%s/index%d.html", site.outputPath, site.PageNumber)
		if site.PageNumber == 1 {
			indexFile = fmt.Sprintf("%s/index.html", site.outputPath)
		}

		file, err := os.Create(indexFile)
		if err != nil {
			log.Panicf("Error creating index file for page '%d': %v", site.PageNumber, err)
		}

		if err := indexTemplate.ExecuteTemplate(file, "base", site); err != nil {
			log.Panicf("Error rendering the index file for page '%d': %v", site.PageNumber, err)
		}
	}
}

func (site Site) writeParsedFiles(rootPath string, files []*ParsedFile) {
	if rootPath != "" {
		if _, err := os.Stat(rootPath); os.IsNotExist(err) {
			os.Mkdir(rootPath, 0777)
		}
	}

	for _, parsedFile := range files {
		filePath := fmt.Sprintf("%s/%s.html", rootPath, parsedFile.Slug)

		var template *template.Template
		if files[0].isPage {
			template = pageTemplate
		} else {
			template = articleTemplate
		}

		file, err := os.Create(filePath)
		if err != nil {
			log.Panicf("Error creating the file: %s\n%v", filePath, err)
		}

		if files[0].isPage {
			site.Page = *parsedFile
		} else {
			site.Article = *parsedFile
		}
		if err := template.ExecuteTemplate(file, "base", site); err != nil {
			log.Panicf("Error rendering the template for the file: %s\n%v", filePath, err)
		}
	}
}

func (site Site) writeArticles() {
	site.writeParsedFiles(site.outputPath, site.Articles())
}

func (site Site) writePages() {
	pagesPath := fmt.Sprintf("%s/pages", site.outputPath)
	site.writeParsedFiles(pagesPath, site.Pages())
}

func (site Site) writeArchive() {
	archivesPath := fmt.Sprintf("%s/archives.html", site.outputPath)
	file, err := os.Create(archivesPath)
	if err != nil {
		log.Panicf("Error creating archive file: %v", err)
	}

	if err := archiveTemplate.ExecuteTemplate(file, "base", site); err != nil {
		log.Panicf("Error rendering the template for the archives: %v", err)
	}
}

func (site Site) writeCategories() {
	// First of all create the tags/ folder if it doesn't exist
	categoriesPath := fmt.Sprintf("%s/category", site.outputPath)
	if _, err := os.Stat(categoriesPath); os.IsNotExist(err) {
		os.Mkdir(categoriesPath, 0777)
	}

	for _, category := range site.Categories() {
		categoryFile := fmt.Sprintf("%s/%s.html", categoriesPath, category)

		file, err := os.Create(categoryFile)
		if err != nil {
			log.Panicf("Error creating the category '%s' file: %v", category, err)
		}

		site.Category = category
		if err := categoryTemplate.ExecuteTemplate(file, "base", site); err != nil {
			log.Panicf("Error rendering the template for the category '%s': %v", category, err)
		}
	}
}

func (site Site) writeTags() {
	// First of all create the tags/ folder if it doesn't exist
	tagsPath := fmt.Sprintf("%s/tag", site.outputPath)
	if _, err := os.Stat(tagsPath); os.IsNotExist(err) {
		os.Mkdir(tagsPath, 0777)
	}

	for _, tag := range site.Tags() {
		tagFile := fmt.Sprintf("%s/%s.html", tagsPath, tag)

		file, err := os.Create(tagFile)
		if err != nil {
			log.Panicf("Error creating the tag '%s' file: %v", tag, err)
		}

		site.Tag = tag
		if err := tagTemplate.ExecuteTemplate(file, "base", site); err != nil {
			log.Panicf("Error rendering the template for the tag '%s': %v", tag, err)
		}
	}
}

func (site Site) writeFeeds() {
	feedsPath := fmt.Sprintf("%s/feeds", site.outputPath)
	if _, err := os.Stat(feedsPath); os.IsNotExist(err) {
		os.Mkdir(feedsPath, 0777)
	}

	site.writeAtomFeed(feedsPath)
	site.writeRSSFeed(feedsPath)
}

func (site Site) writeAtomFeed(feedsPath string) {
	path := fmt.Sprintf("%s/all.atom.xml", feedsPath)

	file, err := os.Create(path)
	if err != nil {
		log.Panicf("Error creating the atom file: %v", err)
	}

	articles := site.Articles()
	limit := len(articles)
	if limit > 10 {
		limit = 10
	}
	site.FeedArticles = articles[:limit] // TODO: do it inside the function
	if err := atomTemplate.Execute(file, site); err != nil {
		log.Panicf("Error rendering the template for the atom file: %v", err)
	}
}

func (site Site) writeRSSFeed(feedsPath string) {
	// TODO (agonzalezro): to be implemented if somebody needs it
	return
}
<commit_msg>Fixing up the template code at writers<commit_after>package generator

import (
	"fmt"
	"html/template"
	"io/ioutil"
	"log"
	"os"
	"path"

	// TODO: Perhaps it worth moving the template rendering to the template
	// package
	assets "github.com/agonzalezro/polo/templates"
)

var templates map[string]*template.Template

// parsedFiles is a wrapper similar to template.ParseFiles that is going to
// load the templates from the disk, and if they can not be found from the
// go-bindata file.
func parseFiles(filenames ...string) (*template.Template, error) {
	tpl := template.New(filenames[0])
	for _, filename := range filenames {
		b, err := ioutil.ReadFile(filename)
		if err != nil {
			b, err = assets.Asset(filename)
			if err != nil {
				log.Printf("Template: %s not found. Not in HD neihter in bindata!", filename)
				return nil, err
			}
		}
		tpl.Parse(string(b))
	}
	return tpl, nil
}

// loadTemplates is an ugly function but I need it to run the test without the
// template files. If I don't call .Write() I don't need the template files.
func loadTemplates() {
	templates = make(map[string]*template.Template)
	toRender := make(map[string][]string)

	toRender["archives"] = []string{"templates/archives.html", "templates/base.html"}
	toRender["article"] = []string{"templates/article.html", "templates/base.html"}
	toRender["atom"] = []string{"templates/atom.xml"}
	toRender["category"] = []string{"templates/category.html", "templates/base.html"}
	toRender["index"] = []string{"templates/index.html", "templates/base.html"}
	toRender["page"] = []string{"templates/page.html", "templates/base.html"}
	toRender["tag"] = []string{"templates/tag.html", "templates/base.html"}

	for name, values := range toRender {
		templates[name] = template.Must(parseFiles(values...))
	}
}

func (site Site) getAbsolutePath(elem ...string) string {
	// TODO: I am not pretty sure that this is the best way to do this
	s := make([]string, 1, 1)
	s[0] = site.outputPath
	elem = append(s, elem...)
	return path.Join(elem...)
}

// Dump all the site content to the disk
func (site Site) Write() {
	loadTemplates()

	site.writeIndexes()
	site.writeFeeds()
	site.writeArticles()
	site.writePages()
	if site.Config.ShowArchive {
		site.writeArchive()
	}
	if site.Config.ShowCategories {
		site.writeCategories()
	}
	if site.Config.ShowTags {
		site.writeTags()
	}
}

func (site Site) getNumberOfPages() int {
	if site.NumberOfPages == 0 {
		site.NumberOfPages = len(site.Articles()) / site.Config.PaginationSize
	}
	// If it continue being 0, we don't have pages
	if site.NumberOfPages == 0 {
		site.NumberOfPages = -1
	}
	return site.NumberOfPages
}

func (site Site) writeIndexes() {
	site.NumberOfPages = site.getNumberOfPages()

	for site.PageNumber = 1; site.PageNumber <= site.NumberOfPages; site.PageNumber++ {
		indexFile := site.getAbsolutePath(fmt.Sprintf("index%d.html", site.PageNumber))
		if site.PageNumber == 1 {
			indexFile = site.getAbsolutePath("index.html")
		}

		file, err := os.Create(indexFile)
		if err != nil {
			log.Panicf("Error creating index file for page '%d': %v", site.PageNumber, err)
		}

		if err := templates["index"].ExecuteTemplate(file, "base", site); err != nil {
			log.Panicf("Error rendering the index file for page '%d': %v", site.PageNumber, err)
		}
	}
}

func (site Site) writeParsedFiles(rootPath string, files []*ParsedFile) {
	if rootPath != "" {
		if _, err := os.Stat(rootPath); os.IsNotExist(err) {
			os.Mkdir(rootPath, 0777)
		}
	}

	for _, parsedFile := range files {
		filePath := fmt.Sprintf("%s/%s.html", rootPath, parsedFile.Slug)

		var template *template.Template
		if files[0].isPage {
			template = templates["page"]
		} else {
			template = templates["article"]
		}

		file, err := os.Create(filePath)
		if err != nil {
			log.Panicf("Error creating the file: %s\n%v", filePath, err)
		}

		if files[0].isPage {
			site.Page = *parsedFile
		} else {
			site.Article = *parsedFile
		}
		if err := template.ExecuteTemplate(file, "base", site); err != nil {
			log.Panicf("Error rendering the template for the file: %s\n%v", filePath, err)
		}
	}
}

func (site Site) writeArticles() {
	site.writeParsedFiles(site.outputPath, site.Articles())
}

func (site Site) writePages() {
	pagesPath := site.getAbsolutePath("pages")
	site.writeParsedFiles(pagesPath, site.Pages())
}

func (site Site) writeArchive() {
	archivesPath := site.getAbsolutePath("archives.html")
	file, err := os.Create(archivesPath)
	if err != nil {
		log.Panicf("Error creating archive file: %v", err)
	}

	if err := templates["archives"].ExecuteTemplate(file, "base", site); err != nil {
		log.Panicf("Error rendering the template for the archives: %v", err)
	}
}

func (site Site) writeCategories() {
	// First of all create the tags/ folder if it doesn't exist
	categoriesPath := site.getAbsolutePath("category")
	if _, err := os.Stat(categoriesPath); os.IsNotExist(err) {
		os.Mkdir(categoriesPath, 0777)
	}

	for _, category := range site.Categories() {
		categoryFile := fmt.Sprintf("%s/%s.html", categoriesPath, category)

		file, err := os.Create(categoryFile)
		if err != nil {
			log.Panicf("Error creating the category '%s' file: %v", category, err)
		}

		site.Category = category
		if err := templates["category"].ExecuteTemplate(file, "base", site); err != nil {
			log.Panicf("Error rendering the template for the category '%s': %v", category, err)
		}
	}
}

func (site Site) writeTags() {
	// First of all create the tags/ folder if it doesn't exist
	tagsPath := site.getAbsolutePath("tag")
	if _, err := os.Stat(tagsPath); os.IsNotExist(err) {
		os.Mkdir(tagsPath, 0777)
	}

	for _, tag := range site.Tags() {
		tagFile := fmt.Sprintf("%s/%s.html", tagsPath, tag)

		file, err := os.Create(tagFile)
		if err != nil {
			log.Panicf("Error creating the tag '%s' file: %v", tag, err)
		}

		site.Tag = tag
		if err := templates["tag"].ExecuteTemplate(file, "base", site); err != nil {
			log.Panicf("Error rendering the template for the tag '%s': %v", tag, err)
		}
	}
}

func (site Site) writeFeeds() {
	feedsPath := site.getAbsolutePath("feeds")
	if _, err := os.Stat(feedsPath); os.IsNotExist(err) {
		os.Mkdir(feedsPath, 0777)
	}

	site.writeAtomFeed(feedsPath)
	site.writeRSSFeed(feedsPath)
}

func (site Site) writeAtomFeed(feedsPath string) {
	path := fmt.Sprintf("%s/all.atom.xml", feedsPath)

	file, err := os.Create(path)
	if err != nil {
		log.Panicf("Error creating the atom file: %v", err)
	}

	articles := site.Articles()
	limit := len(articles)
	if limit > 10 {
		limit = 10
	}
	site.FeedArticles = articles[:limit] // TODO: do it inside the function
	if err := templates["atom"].Execute(file, site); err != nil {
		log.Panicf("Error rendering the template for the atom file: %v", err)
	}
}

func (site Site) writeRSSFeed(feedsPath string) {
	// TODO (agonzalezro): to be implemented if somebody needs it
	return
}
<|endoftext|>


<commit_before>package atlas

import (
	"testing"
)

func TestLongestCommonPrefix(t *testing.T) {
	cases := []struct {
		Input  []string
		Output string
	}{
		{
			[]string{"foo", "bar"},
			"",
		},
		{
			[]string{"foo", "foobar"},
			"",
		},
		{
			[]string{"foo/", "foo/bar"},
			"foo/",
		},
		{
			[]string{"/foo/", "/bar"},
			"/",
		},
	}

	for _, tc := range cases {
		actual := longestCommonPrefix(tc.Input)
		if actual != tc.Output {
			t.Fatalf("bad: %#v\n\n%#v", actual, tc.Input)
		}
	}
}
<commit_msg>post-processor/atlas: adjust test for cross-platform filepath separator<commit_after>package atlas

import (
	"path/filepath"
	"testing"
)

func TestLongestCommonPrefix(t *testing.T) {
	sep := string(filepath.Separator)
	cases := []struct {
		Input  []string
		Output string
	}{
		{
			[]string{"foo", "bar"},
			"",
		},
		{
			[]string{"foo", "foobar"},
			"",
		},
		{
			[]string{"foo" + sep, "foo" + sep + "bar"},
			"foo" + sep,
		},
		{
			[]string{sep + "foo" + sep, sep + "bar"},
			sep,
		},
	}

	for _, tc := range cases {
		actual := longestCommonPrefix(tc.Input)
		if actual != tc.Output {
			t.Fatalf("bad: %#v\n\n%#v", actual, tc.Input)
		}
	}
}
<|endoftext|>


<commit_before>package github

import (
	"context"
)

type Repo struct {
	Name *string `json:"name, omitempty"`
}

func (github *Client) Repos(user string) ([]*Repo, error) {
	ctx := context.Background()

	repos, _, err := github.client.Repositories.List(ctx, user, nil)
	if err != nil {
		return nil, err
	}

	result := make([]*Repo, 0)
	for _, r := range repos {
		result = append(result, &Repo{r.Name})
	}

	return result, nil
}

func (github *Client) Repo(user string, repoName string) (*Repo, error) {
	ctx := context.Background()

	repo, _, err := github.client.Repositories.Get(ctx, user, repoName)
	if err != nil {
		return nil, err
	}

	return &Repo{repo.Name}, nil
}
<commit_msg>Update struct field on json tag<commit_after>package github

import (
	"context"
)

type Repo struct {
	Name *string `json:"name"`
}

func (github *Client) Repos(user string) ([]*Repo, error) {
	ctx := context.Background()

	repos, _, err := github.client.Repositories.List(ctx, user, nil)
	if err != nil {
		return nil, err
	}

	result := make([]*Repo, 0)
	for _, r := range repos {
		result = append(result, &Repo{r.Name})
	}

	return result, nil
}

func (github *Client) Repo(user string, repoName string) (*Repo, error) {
	ctx := context.Background()

	repo, _, err := github.client.Repositories.Get(ctx, user, repoName)
	if err != nil {
		return nil, err
	}

	return &Repo{repo.Name}, nil
}
<|endoftext|>


<commit_before>package gitmedia

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

const Version = "0.2.0"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		TempDir = filepath.Join(LocalMediaDir, "tmp")
		queueDir = setupQueueDir()

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}
	}
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	if len(dir) == 1 && dir[0] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

	if err != nil {
		return "", "", err
	}

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<commit_msg>ンンン ンンン ンン<commit_after>package gitmedia

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

const Version = "0.1.0"

var (
	LargeSizeThreshold = 5 * 1024 * 1024
	TempDir            = filepath.Join(os.TempDir(), "git-media")
	LocalWorkingDir    string
	LocalGitDir        string
	LocalMediaDir      string
	LocalLogDir        string
	checkedTempDir     string
)

func TempFile(prefix string) (*os.File, error) {
	if checkedTempDir != TempDir {
		if err := os.MkdirAll(TempDir, 0774); err != nil {
			return nil, err
		}
		checkedTempDir = TempDir
	}

	return ioutil.TempFile(TempDir, prefix)
}

func ResetTempDir() error {
	checkedTempDir = ""
	return os.RemoveAll(TempDir)
}

func LocalMediaPath(sha string) (string, error) {
	path := filepath.Join(LocalMediaDir, sha[0:2], sha[2:4])
	if err := os.MkdirAll(path, 0744); err != nil {
		return "", fmt.Errorf("Error trying to create local media directory in '%s': %s", path, err)
	}

	return filepath.Join(path, sha), nil
}

func Environ() []string {
	osEnviron := os.Environ()
	env := make([]string, 4, len(osEnviron)+4)
	env[0] = fmt.Sprintf("LocalWorkingDir=%s", LocalWorkingDir)
	env[1] = fmt.Sprintf("LocalGitDir=%s", LocalGitDir)
	env[2] = fmt.Sprintf("LocalMediaDir=%s", LocalMediaDir)
	env[3] = fmt.Sprintf("TempDir=%s", TempDir)

	for _, e := range osEnviron {
		if !strings.Contains(e, "GIT_") {
			continue
		}
		env = append(env, e)
	}

	return env
}

func InRepo() bool {
	return LocalWorkingDir != ""
}

func init() {
	var err error
	LocalWorkingDir, LocalGitDir, err = resolveGitDir()
	if err == nil {
		LocalMediaDir = filepath.Join(LocalGitDir, "media")
		LocalLogDir = filepath.Join(LocalMediaDir, "logs")
		TempDir = filepath.Join(LocalMediaDir, "tmp")
		queueDir = setupQueueDir()

		if err := os.MkdirAll(TempDir, 0744); err != nil {
			panic(fmt.Errorf("Error trying to create temp directory in '%s': %s", TempDir, err))
		}
	}
}

func resolveGitDir() (string, string, error) {
	wd, err := os.Getwd()
	if err != nil {
		return "", "", err
	}

	return recursiveResolveGitDir(wd)
}

func recursiveResolveGitDir(dir string) (string, string, error) {
	if len(dir) == 1 && dir[0] == os.PathSeparator {
		return "", "", fmt.Errorf("Git repository not found")
	}

	if filepath.Base(dir) == gitExt {
		return filepath.Dir(dir), dir, nil
	}

	gitDir := filepath.Join(dir, gitExt)
	if info, err := os.Stat(gitDir); err == nil {
		if info.IsDir() {
			return dir, gitDir, nil
		} else {
			return processDotGitFile(gitDir)
		}
	}

	return recursiveResolveGitDir(filepath.Dir(dir))
}

func processDotGitFile(file string) (string, string, error) {
	f, err := os.Open(file)
	defer f.Close()

	if err != nil {
		return "", "", err
	}

	data := make([]byte, 512)
	n, err := f.Read(data)
	if err != nil {
		return "", "", err
	}

	contents := string(data[0:n])
	wd, _ := os.Getwd()
	if strings.HasPrefix(contents, gitPtrPrefix) {
		dir := strings.TrimSpace(strings.Split(contents, gitPtrPrefix)[1])
		absDir, _ := filepath.Abs(dir)
		return wd, absDir, nil
	}

	return wd, "", nil
}

const (
	gitExt       = ".git"
	gitPtrPrefix = "gitdir: "
)
<|endoftext|>