<commit_before>// +build js

package main

import (
	"context"
	"net/url"
	"strconv"
	"strings"
	"sync"

	"github.com/flimzy/jqeventrouter"
	"github.com/flimzy/log"
	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/jquery"

	"github.com/FlashbackSRS/flashback/config"
	"github.com/FlashbackSRS/flashback/fserve"
	"github.com/FlashbackSRS/flashback/iframes"
	"github.com/FlashbackSRS/flashback/model"
	"github.com/FlashbackSRS/flashback/oauth2"
	"github.com/FlashbackSRS/flashback/util"

	_ "github.com/FlashbackSRS/flashback/controllers/anki" // Anki model controllers
	"github.com/FlashbackSRS/flashback/webclient/handlers/auth"
	"github.com/FlashbackSRS/flashback/webclient/handlers/general"
	"github.com/FlashbackSRS/flashback/webclient/handlers/import"
	"github.com/FlashbackSRS/flashback/webclient/handlers/l10n"
	"github.com/FlashbackSRS/flashback/webclient/handlers/login"
	"github.com/FlashbackSRS/flashback/webclient/handlers/logout"
	"github.com/FlashbackSRS/flashback/webclient/handlers/study"
	synchandler "github.com/FlashbackSRS/flashback/webclient/handlers/sync"
)

// Some spiffy shortcuts
var jQuery = jquery.NewJQuery
var jQMobile *js.Object
var document *js.Object = js.Global.Get("document")

func main() {
	log.Debug("Starting main()\n")

	confJSON := document.Call("getElementById", "config").Get("innerText").String()
	conf, err := config.NewFromJSON([]byte(confJSON))
	if err != nil {
		panic(err)
	}

	jQuery(document).On("mobileinit", func() {
		MobileInit()
	})

	var wg sync.WaitGroup

	// Call any async init functions first
	initCordova(&wg)
	// meanwhile, all the synchronous ones
	initjQuery()
	iframes.Init()

	// Wait for the above modules to initialize before we initialize jQuery Mobile
	wg.Wait()

	RouterInit(conf)

	// This is what actually loads jQuery Mobile. We have to register our 'mobileinit'
	// event handler above first, though, as part of RouterInit
	js.Global.Call("loadjqueryMobile")
	log.Debug("main() finished\n")
}

func initjQuery() {
	log.Debug("Initializing jQuery\n")
	js.Global.Get("jQuery").Set("cors", true)
	jQuery(js.Global).On("resize", resizeContent)
	jQuery(js.Global).On("orentationchange", resizeContent)
	jQuery(document).On("pagecontainertransition", resizeContent)
	log.Debug("jQuery init complete\n")
}

func resizeContent() {
	screenHt := js.Global.Get("jQuery").Get("mobile").Call("getScreenHeight").Int()
	header := jQuery(".ui-header:visible")
	headerHt := header.OuterHeight()
	if header.HasClass("ui-header-fixed") {
		headerHt = headerHt - 1
	}
	footer := jQuery(".ui-footer:visible")
	footerHt := footer.OuterHeight()
	if footer.HasClass("ui-footer-fixed") {
		footerHt = footerHt - 1
	}
	jQuery(".ui-content").SetHeight(strconv.Itoa(screenHt - headerHt - footerHt))
}

func RouterInit(conf *config.Conf) {
	log.Debug("Initializing router\n")
	appURL, err := url.Parse(conf.GetString("flashback_app"))
	if err != nil {
		panic(err)
	}
	prefix := strings.TrimSuffix(appURL.Path, "/")

	repo, err := model.New(context.TODO(), conf.GetString("flashback_api"), conf.GetString("flashback_app"))
	if err != nil {
		panic(err)
	}

	fserve.Register(repo)

	langSet := l10n_handler.Init(conf.GetString("flashback_app"))

	// beforechange -- Just check auth
	beforeChange := jqeventrouter.NullHandler()
	checkAuth := auth.CheckAuth(repo)
	jqeventrouter.Listen("pagecontainerbeforechange", general.JQMRouteOnce(general.CleanFacebookURI(checkAuth(beforeChange))))

	// beforetransition
	beforeTransition := jqeventrouter.NewEventMux()
	beforeTransition.SetUriFunc(getJqmUri)

	providers := map[string]string{
		"facebook": oauth2.FacebookURL(conf.GetString("facebook_client_id"), conf.GetString("flashback_app")),
	}

	beforeTransition.HandleFunc(prefix+"/login.html", loginhandler.BeforeTransition(providers))
	beforeTransition.HandleFunc(prefix+"/callback.html", loginhandler.BTCallback(repo, providers))
	beforeTransition.HandleFunc(prefix+"/logout.html", logouthandler.BeforeTransition(repo))
	beforeTransition.HandleFunc(prefix+"/import.html", importhandler.BeforeTransition(repo))
	beforeTransition.HandleFunc(prefix+"/study.html", studyhandler.BeforeTransition(repo))
	jqeventrouter.Listen("pagecontainerbeforetransition", beforeTransition)

	// beforeshow
	beforeShow := jqeventrouter.NullHandler()
	setupSyncButton := synchandler.SetupSyncButton(repo)
	jqeventrouter.Listen("pagecontainerbeforeshow", l10n_handler.LocalizePage(langSet, setupSyncButton(beforeShow)))
	log.Debug("Router init complete\n")
}

func getJqmUri(_ *jquery.Event, ui *js.Object) string {
	return util.JqmTargetUri(ui)
}

// MobileInit is run after jQuery Mobile's 'mobileinit' event has fired
func MobileInit() {
	jQMobile = js.Global.Get("jQuery").Get("mobile")

	// Disable hash features
	jQMobile.Set("hashListeningEnabled", false)
	jQMobile.Set("pushStateEnabled", false)
	jQMobile.Get("changePage").Get("defaults").Set("changeHash", false)

	// 	DebugEvents()

	jQuery(document).One("pagecreate", func(event *jquery.Event) {
		// This should only be executed once, to initialize our "external"
		// panel. This is the kind of thing that should go in document.ready,
		// but I don't have any guarantee that document.ready will run after
		// mobileinit.
		jQuery("body>[data-role='panel']").Underlying().Call("panel").Call("enhanceWithin")
	})
}

func ConsoleEvent(name string, event *jquery.Event, data *js.Object) {
	page := data.Get("toPage").String()
	if page == "[object Object]" {
		page = data.Get("toPage").Call("jqmData", "url").String()
	}
	log.Debugf("Event: %s, Current page: %s", name, page)
}

func ConsolePageEvent(name string, event *jquery.Event) {
	log.Debugf("Event: %s", name)
}

func DebugEvents() {
	events := []string{"pagecontainerbeforehide", "pagecontainerbeforechange", "pagecontainerbeforeload", "pagecontainerbeforeshow",
		"pagecontainerbeforetransition", "pagecontainerchange", "pagecontainerchangefailed", "pagecontainercreate", "pagecontainerhide",
		"pagecontainerload", "pagecontainerloadfailed", "pagecontainerremove", "pagecontainershow", "pagecontainertransition"}
	for _, event := range events {
		copy := event // Necessary for each iterration to have an effectively uinque closure
		jQuery(document).On(event, func(e *jquery.Event, d *js.Object) {
			ConsoleEvent(copy, e, d)
		})
	}
	pageEvents := []string{"beforecreate", "create"}
	for _, event := range pageEvents {
		copy := event
		jQuery(document).On(event, func(e *jquery.Event) {
			ConsolePageEvent(copy, e)
		})
	}
}
<commit_msg>Init repo outside of router init<commit_after>// +build js

package main

import (
	"context"
	"net/url"
	"strconv"
	"strings"
	"sync"

	"github.com/flimzy/jqeventrouter"
	"github.com/flimzy/log"
	"github.com/gopherjs/gopherjs/js"
	"github.com/gopherjs/jquery"

	"github.com/FlashbackSRS/flashback/config"
	"github.com/FlashbackSRS/flashback/fserve"
	"github.com/FlashbackSRS/flashback/iframes"
	"github.com/FlashbackSRS/flashback/model"
	"github.com/FlashbackSRS/flashback/oauth2"
	"github.com/FlashbackSRS/flashback/util"

	_ "github.com/FlashbackSRS/flashback/controllers/anki" // Anki model controllers
	"github.com/FlashbackSRS/flashback/webclient/handlers/auth"
	"github.com/FlashbackSRS/flashback/webclient/handlers/general"
	"github.com/FlashbackSRS/flashback/webclient/handlers/import"
	"github.com/FlashbackSRS/flashback/webclient/handlers/l10n"
	"github.com/FlashbackSRS/flashback/webclient/handlers/login"
	"github.com/FlashbackSRS/flashback/webclient/handlers/logout"
	"github.com/FlashbackSRS/flashback/webclient/handlers/study"
	synchandler "github.com/FlashbackSRS/flashback/webclient/handlers/sync"
)

// Some spiffy shortcuts
var jQuery = jquery.NewJQuery
var jQMobile *js.Object
var document *js.Object = js.Global.Get("document")

func main() {
	log.Debug("Starting main()\n")

	confJSON := document.Call("getElementById", "config").Get("innerText").String()
	conf, err := config.NewFromJSON([]byte(confJSON))
	if err != nil {
		panic(err)
	}

	jQuery(document).On("mobileinit", func() {
		MobileInit()
	})

	repo, err := model.New(context.TODO(), conf.GetString("flashback_api"), conf.GetString("flashback_app"))
	if err != nil {
		panic(err)
	}

	var wg sync.WaitGroup

	// Call any async init functions first
	initCordova(&wg)
	// meanwhile, all the synchronous ones
	initjQuery()
	iframes.Init()

	// Wait for the above modules to initialize before we initialize jQuery Mobile
	wg.Wait()

	RouterInit(repo, conf)

	// This is what actually loads jQuery Mobile. We have to register our 'mobileinit'
	// event handler above first, though, as part of RouterInit
	js.Global.Call("loadjqueryMobile")
	log.Debug("main() finished\n")
}

func initjQuery() {
	log.Debug("Initializing jQuery\n")
	js.Global.Get("jQuery").Set("cors", true)
	jQuery(js.Global).On("resize", resizeContent)
	jQuery(js.Global).On("orentationchange", resizeContent)
	jQuery(document).On("pagecontainertransition", resizeContent)
	log.Debug("jQuery init complete\n")
}

func resizeContent() {
	screenHt := js.Global.Get("jQuery").Get("mobile").Call("getScreenHeight").Int()
	header := jQuery(".ui-header:visible")
	headerHt := header.OuterHeight()
	if header.HasClass("ui-header-fixed") {
		headerHt = headerHt - 1
	}
	footer := jQuery(".ui-footer:visible")
	footerHt := footer.OuterHeight()
	if footer.HasClass("ui-footer-fixed") {
		footerHt = footerHt - 1
	}
	jQuery(".ui-content").SetHeight(strconv.Itoa(screenHt - headerHt - footerHt))
}

func RouterInit(repo *model.Repo, conf *config.Conf) {
	log.Debug("Initializing router\n")
	appURL, err := url.Parse(conf.GetString("flashback_app"))
	if err != nil {
		panic(err)
	}
	prefix := strings.TrimSuffix(appURL.Path, "/")

	fserve.Register(repo)

	langSet := l10n_handler.Init(conf.GetString("flashback_app"))

	// beforechange -- Just check auth
	beforeChange := jqeventrouter.NullHandler()
	checkAuth := auth.CheckAuth(repo)
	jqeventrouter.Listen("pagecontainerbeforechange", general.JQMRouteOnce(general.CleanFacebookURI(checkAuth(beforeChange))))

	// beforetransition
	beforeTransition := jqeventrouter.NewEventMux()
	beforeTransition.SetUriFunc(getJqmUri)

	providers := map[string]string{
		"facebook": oauth2.FacebookURL(conf.GetString("facebook_client_id"), conf.GetString("flashback_app")),
	}

	beforeTransition.HandleFunc(prefix+"/login.html", loginhandler.BeforeTransition(providers))
	beforeTransition.HandleFunc(prefix+"/callback.html", loginhandler.BTCallback(repo, providers))
	beforeTransition.HandleFunc(prefix+"/logout.html", logouthandler.BeforeTransition(repo))
	beforeTransition.HandleFunc(prefix+"/import.html", importhandler.BeforeTransition(repo))
	beforeTransition.HandleFunc(prefix+"/study.html", studyhandler.BeforeTransition(repo))
	jqeventrouter.Listen("pagecontainerbeforetransition", beforeTransition)

	// beforeshow
	beforeShow := jqeventrouter.NullHandler()
	setupSyncButton := synchandler.SetupSyncButton(repo)
	jqeventrouter.Listen("pagecontainerbeforeshow", l10n_handler.LocalizePage(langSet, setupSyncButton(beforeShow)))
	log.Debug("Router init complete\n")
}

func getJqmUri(_ *jquery.Event, ui *js.Object) string {
	return util.JqmTargetUri(ui)
}

// MobileInit is run after jQuery Mobile's 'mobileinit' event has fired
func MobileInit() {
	jQMobile = js.Global.Get("jQuery").Get("mobile")

	// Disable hash features
	jQMobile.Set("hashListeningEnabled", false)
	jQMobile.Set("pushStateEnabled", false)
	jQMobile.Get("changePage").Get("defaults").Set("changeHash", false)

	// 	DebugEvents()

	jQuery(document).One("pagecreate", func(event *jquery.Event) {
		// This should only be executed once, to initialize our "external"
		// panel. This is the kind of thing that should go in document.ready,
		// but I don't have any guarantee that document.ready will run after
		// mobileinit.
		jQuery("body>[data-role='panel']").Underlying().Call("panel").Call("enhanceWithin")
	})
}

func ConsoleEvent(name string, event *jquery.Event, data *js.Object) {
	page := data.Get("toPage").String()
	if page == "[object Object]" {
		page = data.Get("toPage").Call("jqmData", "url").String()
	}
	log.Debugf("Event: %s, Current page: %s", name, page)
}

func ConsolePageEvent(name string, event *jquery.Event) {
	log.Debugf("Event: %s", name)
}

func DebugEvents() {
	events := []string{"pagecontainerbeforehide", "pagecontainerbeforechange", "pagecontainerbeforeload", "pagecontainerbeforeshow",
		"pagecontainerbeforetransition", "pagecontainerchange", "pagecontainerchangefailed", "pagecontainercreate", "pagecontainerhide",
		"pagecontainerload", "pagecontainerloadfailed", "pagecontainerremove", "pagecontainershow", "pagecontainertransition"}
	for _, event := range events {
		copy := event // Necessary for each iterration to have an effectively uinque closure
		jQuery(document).On(event, func(e *jquery.Event, d *js.Object) {
			ConsoleEvent(copy, e, d)
		})
	}
	pageEvents := []string{"beforecreate", "create"}
	for _, event := range pageEvents {
		copy := event
		jQuery(document).On(event, func(e *jquery.Event) {
			ConsolePageEvent(copy, e)
		})
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2011 Google Inc.

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

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

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

package main

import (
	"bytes"
	"exec"
	"flag"
	"fmt"
	"http"
	"http/cgi"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"template"
	"time"
)

const defaultAddr = ":31798" // default webserver address

var h1TitlePattern = regexp.MustCompile(`<h1>(.+)</h1>`)

var (
	httpAddr            = flag.String("http", defaultAddr, "HTTP service address (e.g., '"+defaultAddr+"')")
	httpsAddr           = flag.String("https", "", "HTTPS service address")
	root                = flag.String("root", "", "Website root (parent of 'static', 'content', and 'tmpl")
	gitwebScript        = flag.String("gitwebscript", "/usr/lib/cgi-bin/gitweb.cgi", "Path to gitweb.cgi, or blank to disable.")
	gitwebFiles         = flag.String("gitwebfiles", "/usr/share/gitweb/static", "Path to gitweb's static files.")
	logDir              = flag.String("logdir", "", "Directory to write log files to (one per hour), or empty to not log.")
	logStdout           = flag.Bool("logstdout", true, "Write to stdout?")
	tlsCertFile         = flag.String("tlscert", "", "TLS cert file")
	tlsKeyFile          = flag.String("tlskey", "", "TLS private key file")
	gerritUser          = flag.String("gerrituser", "ubuntu", "Gerrit host's username")
	gerritHost          = flag.String("gerrithost", "gerrit-proxy", "Gerrit host, or empty.")
	pageHtml, errorHtml *template.Template
)

var fmap = template.FormatterMap{
	"":         textFmt,
	"html":     htmlFmt,
	"html-esc": htmlEscFmt,
}

// Template formatter for "" (default) format.
func textFmt(w io.Writer, format string, x ...interface{}) {
	writeAny(w, false, x[0])
}

// Template formatter for "html" format.
func htmlFmt(w io.Writer, format string, x ...interface{}) {
	writeAny(w, true, x[0])
}

// Template formatter for "html-esc" format.
func htmlEscFmt(w io.Writer, format string, x ...interface{}) {
	var buf bytes.Buffer
	writeAny(&buf, false, x[0])
	template.HTMLEscape(w, buf.Bytes())
}

// Write anything to w; optionally html-escaped.
func writeAny(w io.Writer, html bool, x interface{}) {
	switch v := x.(type) {
	case []byte:
		writeText(w, v, html)
	case string:
		writeText(w, []byte(v), html)
	default:
		if html {
			var buf bytes.Buffer
			fmt.Fprint(&buf, x)
			writeText(w, buf.Bytes(), true)
		} else {
			fmt.Fprint(w, x)
		}
	}
}

// Write text to w; optionally html-escaped.
func writeText(w io.Writer, text []byte, html bool) {
	if html {
		template.HTMLEscape(w, text)
		return
	}
	w.Write(text)
}

func applyTemplate(t *template.Template, name string, data interface{}) []byte {
	var buf bytes.Buffer
	if err := t.Execute(&buf, data); err != nil {
		log.Printf("%s.Execute: %s", name, err)
	}
	return buf.Bytes()
}

func servePage(w http.ResponseWriter, title, subtitle string, content []byte) {
	d := struct {
		Title    string
		Subtitle string
		Content  []byte
	}{
		title,
		subtitle,
		content,
	}

	if err := pageHtml.Execute(w, &d); err != nil {
		log.Printf("godocHTML.Execute: %s", err)
	}
}

func readTemplate(name string) *template.Template {
	fileName := filepath.Join(*root, "tmpl", name)
	data, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Fatalf("ReadFile %s: %v", fileName, err)
	}
	t, err := template.Parse(string(data), fmap)
	if err != nil {
		log.Fatalf("%s: %v", fileName, err)
	}
	return t
}

func readTemplates() {
	pageHtml = readTemplate("page.html")
	errorHtml = readTemplate("error.html")
}

func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
	contents := applyTemplate(errorHtml, "errorHtml", err) // err may contain an absolute path!
	w.WriteHeader(http.StatusNotFound)
	servePage(w, "File "+relpath, "", contents)
}

func mainHandler(rw http.ResponseWriter, req *http.Request) {
	relPath := req.URL.Path[1:] // serveFile URL paths start with '/'
	if strings.Contains(relPath, "..") {
		return
	}

	if strings.HasPrefix(relPath, "gw/") {
		path := relPath[3:]
		http.Redirect(rw, req, "/code/?p=camlistore.git;f="+path+";hb=master", http.StatusFound)
		return
	}

	absPath := filepath.Join(*root, "content", relPath)
	fi, err := os.Lstat(absPath)
	if err != nil {
		log.Print(err)
		serveError(rw, req, relPath, err)
		return
	}
	if fi.IsDirectory() {
		relPath += "/index.html"
		absPath = filepath.Join(*root, "content", relPath)
		fi, err = os.Lstat(absPath)
		if err != nil {
			log.Print(err)
			serveError(rw, req, relPath, err)
			return
		}
	}

	switch {
	case fi.IsRegular():
		serveFile(rw, req, relPath, absPath)
	}
}

func serveFile(rw http.ResponseWriter, req *http.Request, relPath, absPath string) {
	data, err := ioutil.ReadFile(absPath)
	if err != nil {
		serveError(rw, req, absPath, err)
		return
	}

	title := ""
	if m := h1TitlePattern.FindSubmatch(data); len(m) > 1 {
		title = string(m[1])
	}

	servePage(rw, title, "", data)
}

type gitwebHandler struct {
	Cgi    http.Handler
	Static http.Handler
}

func (h *gitwebHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	if r.URL.RawPath == "/code/" ||
		strings.HasPrefix(r.URL.RawPath, "/code/?") {
		h.Cgi.ServeHTTP(rw, r)
	} else {
		h.Static.ServeHTTP(rw, r)
	}
}

type noWwwHandler struct {
	Handler http.Handler
}

func (h *noWwwHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	host := strings.ToLower(r.Host)
	if host == "www.camlistore.org" {
		http.Redirect(rw, r, "http://camlistore.org"+r.URL.RawPath, http.StatusFound)
		return
	}
	h.Handler.ServeHTTP(rw, r)
}

func fixupGitwebFiles() {
	fi, err := os.Stat(*gitwebFiles)
	if err != nil || !fi.IsDirectory() {
		if *gitwebFiles == "/usr/share/gitweb/static" {
			// Old Debian/Ubuntu location
			*gitwebFiles = "/usr/share/gitweb"
		}
	}
}

func main() {
	flag.Parse()
	readTemplates()

	if *root == "" {
		var err os.Error
		*root, err = os.Getwd()
		if err != nil {
			log.Fatalf("Failed to getwd: %v", err)
		}
	}

	fixupGitwebFiles()

	latestGits := filepath.Join(*root, "latestgits")
	os.Mkdir(latestGits, 0700)
	if *gerritHost != "" {
		go rsyncFromGerrit(latestGits)
	}

	mux := http.DefaultServeMux
	mux.Handle("/favicon.ico", http.FileServer(filepath.Join(*root, "static"), "/"))
	mux.Handle("/robots.txt", http.FileServer(filepath.Join(*root, "static"), "/"))
	mux.Handle("/static/", http.FileServer(filepath.Join(*root, "static"), "/static/"))
	mux.Handle("/talks/", http.FileServer(filepath.Join(*root, "talks"), "/talks/"))

	gerritUrl, _ := http.ParseURL("http://gerrit-proxy:8000/")
	var gerritHandler http.Handler = http.NewSingleHostReverseProxy(gerritUrl)
	if *httpsAddr != "" {
		proxyHandler := gerritHandler
		gerritHandler = http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
			if req.TLS != nil {
				proxyHandler.ServeHTTP(rw, req)
				return
			}
			http.Redirect(rw, req, "https://camlistore.org"+req.URL.RawPath, http.StatusFound)
		})
	}
	mux.Handle("/r/", gerritHandler)

	testCgi := &cgi.Handler{Path: filepath.Join(*root, "test.cgi"),
		Root: "/test.cgi",
	}
	mux.Handle("/test.cgi", testCgi)
	mux.Handle("/test.cgi/foo", testCgi)

	mux.Handle("/code", http.RedirectHandler("/code/", http.StatusFound))
	if *gitwebScript != "" {
		env := os.Environ()
		env = append(env, "GITWEB_CONFIG="+filepath.Join(*root, "gitweb-camli.conf"))
		env = append(env, "CAMWEB_ROOT="+filepath.Join(*root))
		env = append(env, "CAMWEB_GITDIR="+latestGits)
		mux.Handle("/code/", &fixUpGitwebUrls{&gitwebHandler{
			Cgi: &cgi.Handler{
				Path: *gitwebScript,
				Root: "/code/",
				Env:  env,
			},
			Static: http.FileServer(*gitwebFiles, "/code/"),
		}})
	}
	mux.HandleFunc("/", mainHandler)

	var handler http.Handler = &noWwwHandler{Handler: mux}
	if *logDir != "" || *logStdout {
		handler = NewLoggingHandler(handler, *logDir, *logStdout)
	}

	errch := make(chan os.Error)

	httpServer := &http.Server{
		Addr:         *httpAddr,
		Handler:      handler,
		ReadTimeout:  connTimeoutNanos,
		WriteTimeout: connTimeoutNanos,
	}
	go func() {
		errch <- httpServer.ListenAndServe()
	}()

	if *httpsAddr != "" {
		httpsServer := new(http.Server)
		*httpsServer = *httpServer
		httpsServer.Addr = *httpsAddr
		go func() {
			errch <- httpsServer.ListenAndServeTLS(*tlsCertFile, *tlsKeyFile)
		}()
	}

	log.Fatalf("Serve error: %v", <-errch)
}

const connTimeoutNanos = 15e9

type fixUpGitwebUrls struct {
	handler http.Handler
}

// Not sure what's making these broken URLs like:
//
//   http://localhost:8080/code/?p=camlistore.git%3Bf=doc/json-signing/json-signing.txt%3Bhb=master
//
// ... but something is.  Maybe Buzz?  For now just re-write them
// . Doesn't seem to be a bug in the CGI implementation, though, which
// is what I'd originally suspected.
func (fu *fixUpGitwebUrls) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	oldUrl := req.RawURL
	newUrl := strings.Replace(oldUrl, "%3B", ";", -1)
	if newUrl == oldUrl {
		fu.handler.ServeHTTP(rw, req)
		return
	}
	http.Redirect(rw, req, newUrl, http.StatusFound)
}

func rsyncFromGerrit(dest string) {
	for {
		err := exec.Command("rsync", "-avPW", *gerritUser+"@"+*gerritHost+":gerrit/git", dest+"/").Run()
		if err != nil {
			log.Printf("rsync from gerrit = %v", err)
		}
		time.Sleep(10e9)
	}
}
<commit_msg>missing rsync trailing slash<commit_after>/*
Copyright 2011 Google Inc.

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

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

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

package main

import (
	"bytes"
	"exec"
	"flag"
	"fmt"
	"http"
	"http/cgi"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"template"
	"time"
)

const defaultAddr = ":31798" // default webserver address

var h1TitlePattern = regexp.MustCompile(`<h1>(.+)</h1>`)

var (
	httpAddr            = flag.String("http", defaultAddr, "HTTP service address (e.g., '"+defaultAddr+"')")
	httpsAddr           = flag.String("https", "", "HTTPS service address")
	root                = flag.String("root", "", "Website root (parent of 'static', 'content', and 'tmpl")
	gitwebScript        = flag.String("gitwebscript", "/usr/lib/cgi-bin/gitweb.cgi", "Path to gitweb.cgi, or blank to disable.")
	gitwebFiles         = flag.String("gitwebfiles", "/usr/share/gitweb/static", "Path to gitweb's static files.")
	logDir              = flag.String("logdir", "", "Directory to write log files to (one per hour), or empty to not log.")
	logStdout           = flag.Bool("logstdout", true, "Write to stdout?")
	tlsCertFile         = flag.String("tlscert", "", "TLS cert file")
	tlsKeyFile          = flag.String("tlskey", "", "TLS private key file")
	gerritUser          = flag.String("gerrituser", "ubuntu", "Gerrit host's username")
	gerritHost          = flag.String("gerrithost", "gerrit-proxy", "Gerrit host, or empty.")
	pageHtml, errorHtml *template.Template
)

var fmap = template.FormatterMap{
	"":         textFmt,
	"html":     htmlFmt,
	"html-esc": htmlEscFmt,
}

// Template formatter for "" (default) format.
func textFmt(w io.Writer, format string, x ...interface{}) {
	writeAny(w, false, x[0])
}

// Template formatter for "html" format.
func htmlFmt(w io.Writer, format string, x ...interface{}) {
	writeAny(w, true, x[0])
}

// Template formatter for "html-esc" format.
func htmlEscFmt(w io.Writer, format string, x ...interface{}) {
	var buf bytes.Buffer
	writeAny(&buf, false, x[0])
	template.HTMLEscape(w, buf.Bytes())
}

// Write anything to w; optionally html-escaped.
func writeAny(w io.Writer, html bool, x interface{}) {
	switch v := x.(type) {
	case []byte:
		writeText(w, v, html)
	case string:
		writeText(w, []byte(v), html)
	default:
		if html {
			var buf bytes.Buffer
			fmt.Fprint(&buf, x)
			writeText(w, buf.Bytes(), true)
		} else {
			fmt.Fprint(w, x)
		}
	}
}

// Write text to w; optionally html-escaped.
func writeText(w io.Writer, text []byte, html bool) {
	if html {
		template.HTMLEscape(w, text)
		return
	}
	w.Write(text)
}

func applyTemplate(t *template.Template, name string, data interface{}) []byte {
	var buf bytes.Buffer
	if err := t.Execute(&buf, data); err != nil {
		log.Printf("%s.Execute: %s", name, err)
	}
	return buf.Bytes()
}

func servePage(w http.ResponseWriter, title, subtitle string, content []byte) {
	d := struct {
		Title    string
		Subtitle string
		Content  []byte
	}{
		title,
		subtitle,
		content,
	}

	if err := pageHtml.Execute(w, &d); err != nil {
		log.Printf("godocHTML.Execute: %s", err)
	}
}

func readTemplate(name string) *template.Template {
	fileName := filepath.Join(*root, "tmpl", name)
	data, err := ioutil.ReadFile(fileName)
	if err != nil {
		log.Fatalf("ReadFile %s: %v", fileName, err)
	}
	t, err := template.Parse(string(data), fmap)
	if err != nil {
		log.Fatalf("%s: %v", fileName, err)
	}
	return t
}

func readTemplates() {
	pageHtml = readTemplate("page.html")
	errorHtml = readTemplate("error.html")
}

func serveError(w http.ResponseWriter, r *http.Request, relpath string, err os.Error) {
	contents := applyTemplate(errorHtml, "errorHtml", err) // err may contain an absolute path!
	w.WriteHeader(http.StatusNotFound)
	servePage(w, "File "+relpath, "", contents)
}

func mainHandler(rw http.ResponseWriter, req *http.Request) {
	relPath := req.URL.Path[1:] // serveFile URL paths start with '/'
	if strings.Contains(relPath, "..") {
		return
	}

	if strings.HasPrefix(relPath, "gw/") {
		path := relPath[3:]
		http.Redirect(rw, req, "/code/?p=camlistore.git;f="+path+";hb=master", http.StatusFound)
		return
	}

	absPath := filepath.Join(*root, "content", relPath)
	fi, err := os.Lstat(absPath)
	if err != nil {
		log.Print(err)
		serveError(rw, req, relPath, err)
		return
	}
	if fi.IsDirectory() {
		relPath += "/index.html"
		absPath = filepath.Join(*root, "content", relPath)
		fi, err = os.Lstat(absPath)
		if err != nil {
			log.Print(err)
			serveError(rw, req, relPath, err)
			return
		}
	}

	switch {
	case fi.IsRegular():
		serveFile(rw, req, relPath, absPath)
	}
}

func serveFile(rw http.ResponseWriter, req *http.Request, relPath, absPath string) {
	data, err := ioutil.ReadFile(absPath)
	if err != nil {
		serveError(rw, req, absPath, err)
		return
	}

	title := ""
	if m := h1TitlePattern.FindSubmatch(data); len(m) > 1 {
		title = string(m[1])
	}

	servePage(rw, title, "", data)
}

type gitwebHandler struct {
	Cgi    http.Handler
	Static http.Handler
}

func (h *gitwebHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	if r.URL.RawPath == "/code/" ||
		strings.HasPrefix(r.URL.RawPath, "/code/?") {
		h.Cgi.ServeHTTP(rw, r)
	} else {
		h.Static.ServeHTTP(rw, r)
	}
}

type noWwwHandler struct {
	Handler http.Handler
}

func (h *noWwwHandler) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
	host := strings.ToLower(r.Host)
	if host == "www.camlistore.org" {
		http.Redirect(rw, r, "http://camlistore.org"+r.URL.RawPath, http.StatusFound)
		return
	}
	h.Handler.ServeHTTP(rw, r)
}

func fixupGitwebFiles() {
	fi, err := os.Stat(*gitwebFiles)
	if err != nil || !fi.IsDirectory() {
		if *gitwebFiles == "/usr/share/gitweb/static" {
			// Old Debian/Ubuntu location
			*gitwebFiles = "/usr/share/gitweb"
		}
	}
}

func main() {
	flag.Parse()
	readTemplates()

	if *root == "" {
		var err os.Error
		*root, err = os.Getwd()
		if err != nil {
			log.Fatalf("Failed to getwd: %v", err)
		}
	}

	fixupGitwebFiles()

	latestGits := filepath.Join(*root, "latestgits")
	os.Mkdir(latestGits, 0700)
	if *gerritHost != "" {
		go rsyncFromGerrit(latestGits)
	}

	mux := http.DefaultServeMux
	mux.Handle("/favicon.ico", http.FileServer(filepath.Join(*root, "static"), "/"))
	mux.Handle("/robots.txt", http.FileServer(filepath.Join(*root, "static"), "/"))
	mux.Handle("/static/", http.FileServer(filepath.Join(*root, "static"), "/static/"))
	mux.Handle("/talks/", http.FileServer(filepath.Join(*root, "talks"), "/talks/"))

	gerritUrl, _ := http.ParseURL("http://gerrit-proxy:8000/")
	var gerritHandler http.Handler = http.NewSingleHostReverseProxy(gerritUrl)
	if *httpsAddr != "" {
		proxyHandler := gerritHandler
		gerritHandler = http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
			if req.TLS != nil {
				proxyHandler.ServeHTTP(rw, req)
				return
			}
			http.Redirect(rw, req, "https://camlistore.org"+req.URL.RawPath, http.StatusFound)
		})
	}
	mux.Handle("/r/", gerritHandler)

	testCgi := &cgi.Handler{Path: filepath.Join(*root, "test.cgi"),
		Root: "/test.cgi",
	}
	mux.Handle("/test.cgi", testCgi)
	mux.Handle("/test.cgi/foo", testCgi)

	mux.Handle("/code", http.RedirectHandler("/code/", http.StatusFound))
	if *gitwebScript != "" {
		env := os.Environ()
		env = append(env, "GITWEB_CONFIG="+filepath.Join(*root, "gitweb-camli.conf"))
		env = append(env, "CAMWEB_ROOT="+filepath.Join(*root))
		env = append(env, "CAMWEB_GITDIR="+latestGits)
		mux.Handle("/code/", &fixUpGitwebUrls{&gitwebHandler{
			Cgi: &cgi.Handler{
				Path: *gitwebScript,
				Root: "/code/",
				Env:  env,
			},
			Static: http.FileServer(*gitwebFiles, "/code/"),
		}})
	}
	mux.HandleFunc("/", mainHandler)

	var handler http.Handler = &noWwwHandler{Handler: mux}
	if *logDir != "" || *logStdout {
		handler = NewLoggingHandler(handler, *logDir, *logStdout)
	}

	errch := make(chan os.Error)

	httpServer := &http.Server{
		Addr:         *httpAddr,
		Handler:      handler,
		ReadTimeout:  connTimeoutNanos,
		WriteTimeout: connTimeoutNanos,
	}
	go func() {
		errch <- httpServer.ListenAndServe()
	}()

	if *httpsAddr != "" {
		httpsServer := new(http.Server)
		*httpsServer = *httpServer
		httpsServer.Addr = *httpsAddr
		go func() {
			errch <- httpsServer.ListenAndServeTLS(*tlsCertFile, *tlsKeyFile)
		}()
	}

	log.Fatalf("Serve error: %v", <-errch)
}

const connTimeoutNanos = 15e9

type fixUpGitwebUrls struct {
	handler http.Handler
}

// Not sure what's making these broken URLs like:
//
//   http://localhost:8080/code/?p=camlistore.git%3Bf=doc/json-signing/json-signing.txt%3Bhb=master
//
// ... but something is.  Maybe Buzz?  For now just re-write them
// . Doesn't seem to be a bug in the CGI implementation, though, which
// is what I'd originally suspected.
func (fu *fixUpGitwebUrls) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	oldUrl := req.RawURL
	newUrl := strings.Replace(oldUrl, "%3B", ";", -1)
	if newUrl == oldUrl {
		fu.handler.ServeHTTP(rw, req)
		return
	}
	http.Redirect(rw, req, newUrl, http.StatusFound)
}

func rsyncFromGerrit(dest string) {
	for {
		err := exec.Command("rsync", "-avPW", *gerritUser+"@"+*gerritHost+":gerrit/git/", dest+"/").Run()
		if err != nil {
			log.Printf("rsync from gerrit = %v", err)
		}
		time.Sleep(10e9)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net"
	"strings"
)

// Listener will listen on 2 ports and forward data from one to another
type Listener struct {
	from, to string
}

func waitForConn(ln net.Listener, port string, p Pipe) {
	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Printf("[error] accept failed: %s\n", err)
		} else {
			log.Printf("accepted new connection on %s\n", port)
			p.Wait(conn, port)
			if err := <-p.receiveError; err != nil {
				conn.Close()
			}
		}
	}
}

func listen(port string, pipe Pipe, block bool) error {
	if !strings.Contains(port, ":") {
		port = ":" + port
	}
	ln, err := net.Listen("tcp", port)
	if err != nil {
		return err
	}
	log.Printf("Listening on %s\n", port)
	if block {
		waitForConn(ln, port, pipe)
	} else {
		go waitForConn(ln, port, pipe)
	}
	return nil
}

// Listen on two ports and creates a custom Pipe between them
func (l Listener) Listen() error {
	fromCh := make(chan []byte)
	toCh := make(chan []byte)
	if err := listen(l.from, InitPipe(fromCh, toCh), false); err != nil {
		return err
	}
	if err := listen(l.to, InitPipe(toCh, fromCh), true); err != nil {
		return err
	}
	return nil
}
<commit_msg>rename port to addr<commit_after>package main

import (
	"log"
	"net"
	"strings"
)

// Listener will listen on 2 ports and forward data from one to another
type Listener struct {
	from, to string
}

func waitForConn(ln net.Listener, addr string, p Pipe) {
	for {
		conn, err := ln.Accept()
		if err != nil {
			log.Printf("[error] accept failed: %s\n", err)
		} else {
			log.Printf("accepted new connection on %s\n", addr)
			p.Wait(conn, addr)
			if err := <-p.receiveError; err != nil {
				conn.Close()
			}
		}
	}
}

func listen(addr string, pipe Pipe, block bool) error {
	if !strings.Contains(addr, ":") {
		addr = ":" + addr
	}
	ln, err := net.Listen("tcp", addr)
	if err != nil {
		return err
	}
	log.Printf("Listening on %s\n", addr)
	if block {
		waitForConn(ln, addr, pipe)
	} else {
		go waitForConn(ln, addr, pipe)
	}
	return nil
}

// Listen on two ports and creates a custom Pipe between them
func (l Listener) Listen() error {
	fromCh := make(chan []byte)
	toCh := make(chan []byte)
	if err := listen(l.from, InitPipe(fromCh, toCh), false); err != nil {
		return err
	}
	if err := listen(l.to, InitPipe(toCh, fromCh), true); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package main

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

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/pkg/integration/checker"
	"github.com/go-check/check"
)

func (s *DockerSuite) TestApiNetworkGetDefaults(c *check.C) {
	// By default docker daemon creates 3 networks. check if they are present
	defaults := []string{"bridge", "host", "none"}
	for _, nn := range defaults {
		c.Assert(isNetworkAvailable(c, nn), checker.Equals, true)
	}
}

func (s *DockerSuite) TestApiNetworkCreateDelete(c *check.C) {
	// Create a network
	name := "testnetwork"
	config := types.NetworkCreate{
		Name:           name,
		CheckDuplicate: true,
	}
	id := createNetwork(c, config, true)
	c.Assert(isNetworkAvailable(c, name), checker.Equals, true)

	// POST another network with same name and CheckDuplicate must fail
	createNetwork(c, config, false)

	// delete the network and make sure it is deleted
	deleteNetwork(c, id, true)
	c.Assert(isNetworkAvailable(c, name), checker.Equals, false)
}

func (s *DockerSuite) TestApiNetworkFilter(c *check.C) {
	nr := getNetworkResource(c, getNetworkIDByName(c, "bridge"))
	c.Assert(nr.Name, checker.Equals, "bridge")
}

func (s *DockerSuite) TestApiNetworkInspect(c *check.C) {
	// Inspect default bridge network
	nr := getNetworkResource(c, "bridge")
	c.Assert(nr.Name, checker.Equals, "bridge")

	// run a container and attach it to the default bridge network
	out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
	containerID := strings.TrimSpace(out)
	containerIP := findContainerIP(c, "test", "bridge")

	// inspect default bridge network again and make sure the container is connected
	nr = getNetworkResource(c, nr.ID)
	c.Assert(nr.Driver, checker.Equals, "bridge")
	c.Assert(nr.Scope, checker.Equals, "local")
	c.Assert(nr.IPAM.Driver, checker.Equals, "default")
	c.Assert(len(nr.Containers), checker.Equals, 1)
	c.Assert(nr.Containers[containerID], checker.NotNil)

	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
	c.Assert(err, checker.IsNil)
	c.Assert(ip.String(), checker.Equals, containerIP)

	// IPAM configuration inspect
	ipam := network.IPAM{
		Driver: "default",
		Config: []network.IPAMConfig{{Subnet: "172.28.0.0/16", IPRange: "172.28.5.0/24", Gateway: "172.28.5.254"}},
	}
	config := types.NetworkCreate{
		Name:    "br0",
		Driver:  "bridge",
		IPAM:    ipam,
		Options: map[string]string{"foo": "bar", "opts": "dopts"},
	}
	id0 := createNetwork(c, config, true)
	c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, true)

	nr = getNetworkResource(c, id0)
	c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
	c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16")
	c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24")
	c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254")
	c.Assert(nr.Options["foo"], checker.Equals, "bar")
	c.Assert(nr.Options["opts"], checker.Equals, "dopts")

	// delete the network and make sure it is deleted
	deleteNetwork(c, id0, true)
	c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, false)
}

func (s *DockerSuite) TestApiNetworkConnectDisconnect(c *check.C) {
	// Create test network
	name := "testnetwork"
	config := types.NetworkCreate{
		Name: name,
	}
	id := createNetwork(c, config, true)
	nr := getNetworkResource(c, id)
	c.Assert(nr.Name, checker.Equals, name)
	c.Assert(nr.ID, checker.Equals, id)
	c.Assert(len(nr.Containers), checker.Equals, 0)

	// run a container
	out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
	containerID := strings.TrimSpace(out)

	// connect the container to the test network
	connectNetwork(c, nr.ID, containerID)

	// inspect the network to make sure container is connected
	nr = getNetworkResource(c, nr.ID)
	c.Assert(len(nr.Containers), checker.Equals, 1)
	c.Assert(nr.Containers[containerID], checker.NotNil)

	// check if container IP matches network inspect
	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
	c.Assert(err, checker.IsNil)
	containerIP := findContainerIP(c, "test", "testnetwork")
	c.Assert(ip.String(), checker.Equals, containerIP)

	// disconnect container from the network
	disconnectNetwork(c, nr.ID, containerID)
	nr = getNetworkResource(c, nr.ID)
	c.Assert(nr.Name, checker.Equals, name)
	c.Assert(len(nr.Containers), checker.Equals, 0)

	// delete the network
	deleteNetwork(c, nr.ID, true)
}

func (s *DockerSuite) TestApiNetworkIpamMultipleBridgeNetworks(c *check.C) {
	// test0 bridge network
	ipam0 := network.IPAM{
		Driver: "default",
		Config: []network.IPAMConfig{{Subnet: "192.178.0.0/16", IPRange: "192.178.128.0/17", Gateway: "192.178.138.100"}},
	}
	config0 := types.NetworkCreate{
		Name:   "test0",
		Driver: "bridge",
		IPAM:   ipam0,
	}
	id0 := createNetwork(c, config0, true)
	c.Assert(isNetworkAvailable(c, "test0"), checker.Equals, true)

	ipam1 := network.IPAM{
		Driver: "default",
		Config: []network.IPAMConfig{{Subnet: "192.178.128.0/17", Gateway: "192.178.128.1"}},
	}
	// test1 bridge network overlaps with test0
	config1 := types.NetworkCreate{
		Name:   "test1",
		Driver: "bridge",
		IPAM:   ipam1,
	}
	createNetwork(c, config1, false)
	c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, false)

	ipam2 := network.IPAM{
		Driver: "default",
		Config: []network.IPAMConfig{{Subnet: "192.169.0.0/16", Gateway: "192.169.100.100"}},
	}
	// test2 bridge network does not overlap
	config2 := types.NetworkCreate{
		Name:   "test2",
		Driver: "bridge",
		IPAM:   ipam2,
	}
	createNetwork(c, config2, true)
	c.Assert(isNetworkAvailable(c, "test2"), checker.Equals, true)

	// remove test0 and retry to create test1
	deleteNetwork(c, id0, true)
	createNetwork(c, config1, true)
	c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, true)

	// for networks w/o ipam specified, docker will choose proper non-overlapping subnets
	createNetwork(c, types.NetworkCreate{Name: "test3"}, true)
	c.Assert(isNetworkAvailable(c, "test3"), checker.Equals, true)
	createNetwork(c, types.NetworkCreate{Name: "test4"}, true)
	c.Assert(isNetworkAvailable(c, "test4"), checker.Equals, true)
	createNetwork(c, types.NetworkCreate{Name: "test5"}, true)
	c.Assert(isNetworkAvailable(c, "test5"), checker.Equals, true)

	for i := 1; i < 6; i++ {
		deleteNetwork(c, fmt.Sprintf("test%d", i), true)
	}
}

func (s *DockerSuite) TestApiCreateDeletePredefinedNetworks(c *check.C) {
	createDeletePredefinedNetwork(c, "bridge")
	createDeletePredefinedNetwork(c, "none")
	createDeletePredefinedNetwork(c, "host")
}

func createDeletePredefinedNetwork(c *check.C, name string) {
	// Create pre-defined network
	config := types.NetworkCreate{
		Name:           name,
		CheckDuplicate: true,
	}
	shouldSucceed := false
	createNetwork(c, config, shouldSucceed)
	deleteNetwork(c, name, shouldSucceed)
}

func isNetworkAvailable(c *check.C, name string) bool {
	status, body, err := sockRequest("GET", "/networks", nil)
	c.Assert(status, checker.Equals, http.StatusOK)
	c.Assert(err, checker.IsNil)

	nJSON := []types.NetworkResource{}
	err = json.Unmarshal(body, &nJSON)
	c.Assert(err, checker.IsNil)

	for _, n := range nJSON {
		if n.Name == name {
			return true
		}
	}
	return false
}

func getNetworkIDByName(c *check.C, name string) string {
	var (
		v          = url.Values{}
		filterArgs = filters.NewArgs()
	)
	filterArgs.Add("name", name)
	filterJSON, err := filters.ToParam(filterArgs)
	c.Assert(err, checker.IsNil)
	v.Set("filters", filterJSON)

	status, body, err := sockRequest("GET", "/networks?"+v.Encode(), nil)
	c.Assert(status, checker.Equals, http.StatusOK)
	c.Assert(err, checker.IsNil)

	nJSON := []types.NetworkResource{}
	err = json.Unmarshal(body, &nJSON)
	c.Assert(err, checker.IsNil)
	c.Assert(len(nJSON), checker.Equals, 1)

	return nJSON[0].ID
}

func getNetworkResource(c *check.C, id string) *types.NetworkResource {
	_, obj, err := sockRequest("GET", "/networks/"+id, nil)
	c.Assert(err, checker.IsNil)

	nr := types.NetworkResource{}
	err = json.Unmarshal(obj, &nr)
	c.Assert(err, checker.IsNil)

	return &nr
}

func createNetwork(c *check.C, config types.NetworkCreate, shouldSucceed bool) string {
	status, resp, err := sockRequest("POST", "/networks/create", config)
	if !shouldSucceed {
		c.Assert(status, checker.Not(checker.Equals), http.StatusCreated)
		return ""
	}

	c.Assert(status, checker.Equals, http.StatusCreated)
	c.Assert(err, checker.IsNil)

	var nr types.NetworkCreateResponse
	err = json.Unmarshal(resp, &nr)
	c.Assert(err, checker.IsNil)

	return nr.ID
}

func connectNetwork(c *check.C, nid, cid string) {
	config := types.NetworkConnect{
		Container: cid,
	}

	status, _, err := sockRequest("POST", "/networks/"+nid+"/connect", config)
	c.Assert(status, checker.Equals, http.StatusOK)
	c.Assert(err, checker.IsNil)
}

func disconnectNetwork(c *check.C, nid, cid string) {
	config := types.NetworkConnect{
		Container: cid,
	}

	status, _, err := sockRequest("POST", "/networks/"+nid+"/disconnect", config)
	c.Assert(status, checker.Equals, http.StatusOK)
	c.Assert(err, checker.IsNil)
}

func deleteNetwork(c *check.C, id string, shouldSucceed bool) {
	status, _, err := sockRequest("DELETE", "/networks/"+id, nil)
	if !shouldSucceed {
		c.Assert(status, checker.Not(checker.Equals), http.StatusOK)
		return
	}
	c.Assert(status, checker.Equals, http.StatusOK)
	c.Assert(err, checker.IsNil)
}
<commit_msg>Add network create api test on CheckDuplicate<commit_after>package main

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

	"github.com/docker/docker/api/types"
	"github.com/docker/docker/api/types/filters"
	"github.com/docker/docker/api/types/network"
	"github.com/docker/docker/pkg/integration/checker"
	"github.com/go-check/check"
)

func (s *DockerSuite) TestApiNetworkGetDefaults(c *check.C) {
	// By default docker daemon creates 3 networks. check if they are present
	defaults := []string{"bridge", "host", "none"}
	for _, nn := range defaults {
		c.Assert(isNetworkAvailable(c, nn), checker.Equals, true)
	}
}

func (s *DockerSuite) TestApiNetworkCreateDelete(c *check.C) {
	// Create a network
	name := "testnetwork"
	config := types.NetworkCreate{
		Name:           name,
		CheckDuplicate: true,
	}
	id := createNetwork(c, config, true)
	c.Assert(isNetworkAvailable(c, name), checker.Equals, true)

	// delete the network and make sure it is deleted
	deleteNetwork(c, id, true)
	c.Assert(isNetworkAvailable(c, name), checker.Equals, false)
}

func (s *DockerSuite) TestApiNetworkCreateCheckDuplicate(c *check.C) {
	name := "testcheckduplicate"
	configOnCheck := types.NetworkCreate{
		Name:           name,
		CheckDuplicate: true,
	}
	configNotCheck := types.NetworkCreate{
		Name:           name,
		CheckDuplicate: false,
	}

	// Creating a new network first
	createNetwork(c, configOnCheck, true)
	c.Assert(isNetworkAvailable(c, name), checker.Equals, true)

	// Creating another network with same name and CheckDuplicate must fail
	createNetwork(c, configOnCheck, false)

	// Creating another network with same name and not CheckDuplicate must succeed
	createNetwork(c, configNotCheck, true)
}

func (s *DockerSuite) TestApiNetworkFilter(c *check.C) {
	nr := getNetworkResource(c, getNetworkIDByName(c, "bridge"))
	c.Assert(nr.Name, checker.Equals, "bridge")
}

func (s *DockerSuite) TestApiNetworkInspect(c *check.C) {
	// Inspect default bridge network
	nr := getNetworkResource(c, "bridge")
	c.Assert(nr.Name, checker.Equals, "bridge")

	// run a container and attach it to the default bridge network
	out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
	containerID := strings.TrimSpace(out)
	containerIP := findContainerIP(c, "test", "bridge")

	// inspect default bridge network again and make sure the container is connected
	nr = getNetworkResource(c, nr.ID)
	c.Assert(nr.Driver, checker.Equals, "bridge")
	c.Assert(nr.Scope, checker.Equals, "local")
	c.Assert(nr.IPAM.Driver, checker.Equals, "default")
	c.Assert(len(nr.Containers), checker.Equals, 1)
	c.Assert(nr.Containers[containerID], checker.NotNil)

	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
	c.Assert(err, checker.IsNil)
	c.Assert(ip.String(), checker.Equals, containerIP)

	// IPAM configuration inspect
	ipam := network.IPAM{
		Driver: "default",
		Config: []network.IPAMConfig{{Subnet: "172.28.0.0/16", IPRange: "172.28.5.0/24", Gateway: "172.28.5.254"}},
	}
	config := types.NetworkCreate{
		Name:    "br0",
		Driver:  "bridge",
		IPAM:    ipam,
		Options: map[string]string{"foo": "bar", "opts": "dopts"},
	}
	id0 := createNetwork(c, config, true)
	c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, true)

	nr = getNetworkResource(c, id0)
	c.Assert(len(nr.IPAM.Config), checker.Equals, 1)
	c.Assert(nr.IPAM.Config[0].Subnet, checker.Equals, "172.28.0.0/16")
	c.Assert(nr.IPAM.Config[0].IPRange, checker.Equals, "172.28.5.0/24")
	c.Assert(nr.IPAM.Config[0].Gateway, checker.Equals, "172.28.5.254")
	c.Assert(nr.Options["foo"], checker.Equals, "bar")
	c.Assert(nr.Options["opts"], checker.Equals, "dopts")

	// delete the network and make sure it is deleted
	deleteNetwork(c, id0, true)
	c.Assert(isNetworkAvailable(c, "br0"), checker.Equals, false)
}

func (s *DockerSuite) TestApiNetworkConnectDisconnect(c *check.C) {
	// Create test network
	name := "testnetwork"
	config := types.NetworkCreate{
		Name: name,
	}
	id := createNetwork(c, config, true)
	nr := getNetworkResource(c, id)
	c.Assert(nr.Name, checker.Equals, name)
	c.Assert(nr.ID, checker.Equals, id)
	c.Assert(len(nr.Containers), checker.Equals, 0)

	// run a container
	out, _ := dockerCmd(c, "run", "-d", "--name", "test", "busybox", "top")
	containerID := strings.TrimSpace(out)

	// connect the container to the test network
	connectNetwork(c, nr.ID, containerID)

	// inspect the network to make sure container is connected
	nr = getNetworkResource(c, nr.ID)
	c.Assert(len(nr.Containers), checker.Equals, 1)
	c.Assert(nr.Containers[containerID], checker.NotNil)

	// check if container IP matches network inspect
	ip, _, err := net.ParseCIDR(nr.Containers[containerID].IPv4Address)
	c.Assert(err, checker.IsNil)
	containerIP := findContainerIP(c, "test", "testnetwork")
	c.Assert(ip.String(), checker.Equals, containerIP)

	// disconnect container from the network
	disconnectNetwork(c, nr.ID, containerID)
	nr = getNetworkResource(c, nr.ID)
	c.Assert(nr.Name, checker.Equals, name)
	c.Assert(len(nr.Containers), checker.Equals, 0)

	// delete the network
	deleteNetwork(c, nr.ID, true)
}

func (s *DockerSuite) TestApiNetworkIpamMultipleBridgeNetworks(c *check.C) {
	// test0 bridge network
	ipam0 := network.IPAM{
		Driver: "default",
		Config: []network.IPAMConfig{{Subnet: "192.178.0.0/16", IPRange: "192.178.128.0/17", Gateway: "192.178.138.100"}},
	}
	config0 := types.NetworkCreate{
		Name:   "test0",
		Driver: "bridge",
		IPAM:   ipam0,
	}
	id0 := createNetwork(c, config0, true)
	c.Assert(isNetworkAvailable(c, "test0"), checker.Equals, true)

	ipam1 := network.IPAM{
		Driver: "default",
		Config: []network.IPAMConfig{{Subnet: "192.178.128.0/17", Gateway: "192.178.128.1"}},
	}
	// test1 bridge network overlaps with test0
	config1 := types.NetworkCreate{
		Name:   "test1",
		Driver: "bridge",
		IPAM:   ipam1,
	}
	createNetwork(c, config1, false)
	c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, false)

	ipam2 := network.IPAM{
		Driver: "default",
		Config: []network.IPAMConfig{{Subnet: "192.169.0.0/16", Gateway: "192.169.100.100"}},
	}
	// test2 bridge network does not overlap
	config2 := types.NetworkCreate{
		Name:   "test2",
		Driver: "bridge",
		IPAM:   ipam2,
	}
	createNetwork(c, config2, true)
	c.Assert(isNetworkAvailable(c, "test2"), checker.Equals, true)

	// remove test0 and retry to create test1
	deleteNetwork(c, id0, true)
	createNetwork(c, config1, true)
	c.Assert(isNetworkAvailable(c, "test1"), checker.Equals, true)

	// for networks w/o ipam specified, docker will choose proper non-overlapping subnets
	createNetwork(c, types.NetworkCreate{Name: "test3"}, true)
	c.Assert(isNetworkAvailable(c, "test3"), checker.Equals, true)
	createNetwork(c, types.NetworkCreate{Name: "test4"}, true)
	c.Assert(isNetworkAvailable(c, "test4"), checker.Equals, true)
	createNetwork(c, types.NetworkCreate{Name: "test5"}, true)
	c.Assert(isNetworkAvailable(c, "test5"), checker.Equals, true)

	for i := 1; i < 6; i++ {
		deleteNetwork(c, fmt.Sprintf("test%d", i), true)
	}
}

func (s *DockerSuite) TestApiCreateDeletePredefinedNetworks(c *check.C) {
	createDeletePredefinedNetwork(c, "bridge")
	createDeletePredefinedNetwork(c, "none")
	createDeletePredefinedNetwork(c, "host")
}

func createDeletePredefinedNetwork(c *check.C, name string) {
	// Create pre-defined network
	config := types.NetworkCreate{
		Name:           name,
		CheckDuplicate: true,
	}
	shouldSucceed := false
	createNetwork(c, config, shouldSucceed)
	deleteNetwork(c, name, shouldSucceed)
}

func isNetworkAvailable(c *check.C, name string) bool {
	status, body, err := sockRequest("GET", "/networks", nil)
	c.Assert(status, checker.Equals, http.StatusOK)
	c.Assert(err, checker.IsNil)

	nJSON := []types.NetworkResource{}
	err = json.Unmarshal(body, &nJSON)
	c.Assert(err, checker.IsNil)

	for _, n := range nJSON {
		if n.Name == name {
			return true
		}
	}
	return false
}

func getNetworkIDByName(c *check.C, name string) string {
	var (
		v          = url.Values{}
		filterArgs = filters.NewArgs()
	)
	filterArgs.Add("name", name)
	filterJSON, err := filters.ToParam(filterArgs)
	c.Assert(err, checker.IsNil)
	v.Set("filters", filterJSON)

	status, body, err := sockRequest("GET", "/networks?"+v.Encode(), nil)
	c.Assert(status, checker.Equals, http.StatusOK)
	c.Assert(err, checker.IsNil)

	nJSON := []types.NetworkResource{}
	err = json.Unmarshal(body, &nJSON)
	c.Assert(err, checker.IsNil)
	c.Assert(len(nJSON), checker.Equals, 1)

	return nJSON[0].ID
}

func getNetworkResource(c *check.C, id string) *types.NetworkResource {
	_, obj, err := sockRequest("GET", "/networks/"+id, nil)
	c.Assert(err, checker.IsNil)

	nr := types.NetworkResource{}
	err = json.Unmarshal(obj, &nr)
	c.Assert(err, checker.IsNil)

	return &nr
}

func createNetwork(c *check.C, config types.NetworkCreate, shouldSucceed bool) string {
	status, resp, err := sockRequest("POST", "/networks/create", config)
	if !shouldSucceed {
		c.Assert(status, checker.Not(checker.Equals), http.StatusCreated)
		return ""
	}

	c.Assert(status, checker.Equals, http.StatusCreated)
	c.Assert(err, checker.IsNil)

	var nr types.NetworkCreateResponse
	err = json.Unmarshal(resp, &nr)
	c.Assert(err, checker.IsNil)

	return nr.ID
}

func connectNetwork(c *check.C, nid, cid string) {
	config := types.NetworkConnect{
		Container: cid,
	}

	status, _, err := sockRequest("POST", "/networks/"+nid+"/connect", config)
	c.Assert(status, checker.Equals, http.StatusOK)
	c.Assert(err, checker.IsNil)
}

func disconnectNetwork(c *check.C, nid, cid string) {
	config := types.NetworkConnect{
		Container: cid,
	}

	status, _, err := sockRequest("POST", "/networks/"+nid+"/disconnect", config)
	c.Assert(status, checker.Equals, http.StatusOK)
	c.Assert(err, checker.IsNil)
}

func deleteNetwork(c *check.C, id string, shouldSucceed bool) {
	status, _, err := sockRequest("DELETE", "/networks/"+id, nil)
	if !shouldSucceed {
		c.Assert(status, checker.Not(checker.Equals), http.StatusOK)
		return
	}
	c.Assert(status, checker.Equals, http.StatusOK)
	c.Assert(err, checker.IsNil)
}
<|endoftext|>


<commit_before>package atlas

import (
	"reflect"
	"strings"
)

func (x *BuilderCore) StructMap() *BuilderStructMap {
	return &BuilderStructMap{x.entry}
}

type BuilderStructMap struct {
	entry *AtlasEntry
}

func (x *BuilderStructMap) Complete() AtlasEntry {
	return *x.entry
}

/*
	Add a field to the mapping based on its name.

	Given a struct:

		struct{
			X int
			Y struct{ Z int }
		}

	`AddField("X", {"x", ...}) will cause that field to be serialized as key "x";
	`AddField("Y.Z", {"z", ...})` will cause that *nested* field to be serialized
	as key "z" in the same object (e.g. "x" and "z" will be siblings).

	Returns the mutated builder for convenient call chaining.

	If the fieldName string doesn't map onto the structure type info,
	a panic will be raised.
*/
func (x *BuilderStructMap) AddField(fieldName string, mapping StructMapEntry) *BuilderStructMap {
	fieldNameSplit := strings.Split(fieldName, ".")
	rr, err := fieldNameToReflectRoute(nil, fieldNameSplit)
	if err != nil {
		panic(err) // REVIEW: now that we have the builder obj, we could just curry these into it until 'Complete' is called (or, thus, 'MustComplete'!).
	}
	mapping.reflectRoute = rr
	x.entry.StructMap.Fields = append(x.entry.StructMap.Fields, mapping)
	return x
}

func fieldNameToReflectRoute(rt reflect.Type, fieldNameSplit []string) (rr reflectRoute, err error) {
	for _, fn := range fieldNameSplit {
		rf, ok := rt.FieldByName(fn)
		if !ok {
			return nil, ErrStructureMismatch{rt.Name(), "does not have field named " + fn}
		}
		rr = append(rr, rf.Index...)
	}
	return rr, nil
}
<commit_msg>Fix NPE from incomplete StructMapBuilder method.<commit_after>package atlas

import (
	"reflect"
	"strings"
)

func (x *BuilderCore) StructMap() *BuilderStructMap {
	return &BuilderStructMap{x.entry}
}

type BuilderStructMap struct {
	entry *AtlasEntry
}

func (x *BuilderStructMap) Complete() AtlasEntry {
	return *x.entry
}

/*
	Add a field to the mapping based on its name.

	Given a struct:

		struct{
			X int
			Y struct{ Z int }
		}

	`AddField("X", {"x", ...}) will cause that field to be serialized as key "x";
	`AddField("Y.Z", {"z", ...})` will cause that *nested* field to be serialized
	as key "z" in the same object (e.g. "x" and "z" will be siblings).

	Returns the mutated builder for convenient call chaining.

	If the fieldName string doesn't map onto the structure type info,
	a panic will be raised.
*/
func (x *BuilderStructMap) AddField(fieldName string, mapping StructMapEntry) *BuilderStructMap {
	fieldNameSplit := strings.Split(fieldName, ".")
	rr, err := fieldNameToReflectRoute(x.entry.Type, fieldNameSplit)
	if err != nil {
		panic(err) // REVIEW: now that we have the builder obj, we could just curry these into it until 'Complete' is called (or, thus, 'MustComplete'!).
	}
	mapping.reflectRoute = rr
	x.entry.StructMap.Fields = append(x.entry.StructMap.Fields, mapping)
	return x
}

func fieldNameToReflectRoute(rt reflect.Type, fieldNameSplit []string) (rr reflectRoute, err error) {
	for _, fn := range fieldNameSplit {
		rf, ok := rt.FieldByName(fn)
		if !ok {
			return nil, ErrStructureMismatch{rt.Name(), "does not have field named " + fn}
		}
		rr = append(rr, rf.Index...)
	}
	return rr, nil
}
<|endoftext|>


<commit_before>package lily

// Author João Nuno.
//
// joaonrb@gmail.com
//

import (
	"fmt"
	"github.com/op/go-logging"
	"io"
	"os"
	"os/signal"
	"strings"
	"syscall"
)

var log = logging.MustGetLogger("lily")

func init() {
	log.ExtraCalldepth = 1
}

const (
	loggerPermissions = 0666
)

const (
	CONSOLE = "console" // Console logging
	FILE    = "file"    // File Logging
)

const (
	CRITICAL = "critical" // Critical level
	ERROR    = "error"    // Error level
	WARNING  = "warning"  // Warning level
	INFO     = "info"     // Info level
	DEBUG    = "debug"    // Debug level
)

// Log default settings
const (
	defaultLoggerType   = "console"
	defaultLoggerPath   = ""
	defaultLoggerLayout = "%{level:.4s} %{time:2006-01-02 15:04:05.000} %{shortfile} %{message}"
	defaultLoggerLevel  = INFO
)

var (
	// Logging map of levels
	LOGGING_LEVELS = map[string]logging.Level{
		CRITICAL: logging.CRITICAL,
		ERROR:    logging.ERROR,
		WARNING:  logging.WARNING,
		INFO:     logging.INFO,
		DEBUG:    logging.DEBUG,
	}
)

// Critical logging
func Critical(message string, args ...interface{}) {
	log.Criticalf(message, args...)
}

// Error logging
func Error(message string, args ...interface{}) {
	log.Errorf(message, args...)
}

// Warning logging
func Warning(message string, args ...interface{}) {
	log.Warningf(message, args...)
}

// Info logging
func Info(message string, args ...interface{}) {
	log.Infof(message, args...)
}

// Notice logging
func Notice(message string, args ...interface{}) {
	log.Noticef(message, args...)
}

// Debug logging
func Debug(message string, args ...interface{}) {
	log.Debugf(message, args...)
}

// Load logger
func LoadLogger(loggers []SLogger) {
	var out io.Writer
	goLoggers := make([]logging.Backend, 0)
	for _, loggerSettings := range loggers {
		switch loggerSettings.Type {
		case CONSOLE:
			out = os.Stdout
		case FILE:
			out = OpenRotatoryWriter(loggerSettings.Path)
		}
		logger := logging.NewLogBackend(out, "", 0)
		beFormatter := logging.NewBackendFormatter(logger, logging.MustStringFormatter(loggerSettings.Layout))
		beLevel := logging.AddModuleLevel(beFormatter)

		// Set Level
		lowerCaseLevel := strings.ToLower(loggerSettings.Level)
		levelNumber := LOGGING_LEVELS[lowerCaseLevel]
		beLevel.SetLevel(levelNumber, "")
		goLoggers = append(goLoggers, beLevel)
	}
	log.SetBackend(logging.MultiLogger(goLoggers...))
}

// Rotate writer
type RotatoryWriter struct {
	doRotation bool
	file       *os.File
	filePath   string
}

// Open the writer
func OpenRotatoryWriter(path string) io.Writer {
	out, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, loggerPermissions)
	if err != nil {
		panic(
			fmt.Errorf(
				"Failed to open log file %s with permissions %d: %s", path, loggerPermissions, err,
			),
		)
	}
	rotatoryWriter := &RotatoryWriter{doRotation: false, file: out, filePath: path}
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGUSR1)
	go func(rot *RotatoryWriter) {
		for {
			<-c
			rotatoryWriter.doRotation = true
			Info("Rotate order caught for file '%s'", path)
		}
	}(rotatoryWriter)
	return rotatoryWriter
}

// Write on file
func (writer *RotatoryWriter) Write(p []byte) (n int, err error) {
	if writer.doRotation {
		writer.doRotation = false
		writer.file.Close()
		out, err := os.OpenFile(writer.filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, loggerPermissions)
		if err != nil {
			panic(
				fmt.Errorf(
					"Failed to open log file %s with permissions %d: %s", writer.filePath, loggerPermissions, err,
				),
			)
		}
		writer.file = out
	}
	return writer.file.Write(p)
}
<commit_msg>gofmt<commit_after>package lily

// Author João Nuno.
//
// joaonrb@gmail.com
//

import (
	"fmt"
	"github.com/op/go-logging"
	"io"
	"os"
	"os/signal"
	"strings"
	"syscall"
)

var log = logging.MustGetLogger("lily")

func init() {
	log.ExtraCalldepth = 1
}

const (
	loggerPermissions = 0666
)

const (
	CONSOLE = "console" // console logging
	FILE    = "file"    // file Logging
)

const (
	CRITICAL = "critical" // critical level
	ERROR    = "error"    // error level
	WARNING  = "warning"  // warning level
	INFO     = "info"     // info level
	DEBUG    = "debug"    // debug level
)

// Log default settings
const (
	defaultLoggerType   = "console"
	defaultLoggerPath   = ""
	defaultLoggerLayout = "%{level:.4s} %{time:2006-01-02 15:04:05.000} %{shortfile} %{message}"
	defaultLoggerLevel  = INFO
)

var (
	// Logging map of levels
	LOGGING_LEVELS = map[string]logging.Level{
		CRITICAL: logging.CRITICAL,
		ERROR:    logging.ERROR,
		WARNING:  logging.WARNING,
		INFO:     logging.INFO,
		DEBUG:    logging.DEBUG,
	}
)

// Critical logging
func Critical(message string, args ...interface{}) {
	log.Criticalf(message, args...)
}

// Error logging
func Error(message string, args ...interface{}) {
	log.Errorf(message, args...)
}

// Warning logging
func Warning(message string, args ...interface{}) {
	log.Warningf(message, args...)
}

// Info logging
func Info(message string, args ...interface{}) {
	log.Infof(message, args...)
}

// Notice logging
func Notice(message string, args ...interface{}) {
	log.Noticef(message, args...)
}

// Debug logging
func Debug(message string, args ...interface{}) {
	log.Debugf(message, args...)
}

// Load logger
func LoadLogger(loggers []SLogger) {
	var out io.Writer
	goLoggers := make([]logging.Backend, 0)
	for _, loggerSettings := range loggers {
		switch loggerSettings.Type {
		case CONSOLE:
			out = os.Stdout
		case FILE:
			out = OpenRotatoryWriter(loggerSettings.Path)
		}
		logger := logging.NewLogBackend(out, "", 0)
		beFormatter := logging.NewBackendFormatter(logger, logging.MustStringFormatter(loggerSettings.Layout))
		beLevel := logging.AddModuleLevel(beFormatter)

		// Set Level
		lowerCaseLevel := strings.ToLower(loggerSettings.Level)
		levelNumber := LOGGING_LEVELS[lowerCaseLevel]
		beLevel.SetLevel(levelNumber, "")
		goLoggers = append(goLoggers, beLevel)
	}
	log.SetBackend(logging.MultiLogger(goLoggers...))
}

// Rotate writer
type RotatoryWriter struct {
	doRotation bool
	file       *os.File
	filePath   string
}

// Open the writer
func OpenRotatoryWriter(path string) io.Writer {
	out, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_APPEND, loggerPermissions)
	if err != nil {
		panic(
			fmt.Errorf(
				"Failed to open log file %s with permissions %d: %s", path, loggerPermissions, err,
			),
		)
	}
	rotatoryWriter := &RotatoryWriter{doRotation: false, file: out, filePath: path}
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGUSR1)
	go func(rot *RotatoryWriter) {
		for {
			<-c
			rotatoryWriter.doRotation = true
			Info("Rotate order caught for file '%s'", path)
		}
	}(rotatoryWriter)
	return rotatoryWriter
}

// Write on file
func (writer *RotatoryWriter) Write(p []byte) (n int, err error) {
	if writer.doRotation {
		writer.doRotation = false
		writer.file.Close()
		out, err := os.OpenFile(writer.filePath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, loggerPermissions)
		if err != nil {
			panic(
				fmt.Errorf(
					"Failed to open log file %s with permissions %d: %s", writer.filePath, loggerPermissions, err,
				),
			)
		}
		writer.file = out
	}
	return writer.file.Write(p)
}
<|endoftext|>


<commit_before>package events

import (
	"fmt"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
	"unsafe"
)

// DefaultLogger is the default logger used by the Log function. This may be
// overwritten by the program to change the default route for log events.
var DefaultLogger = Logger{
	Handler:      Discard,
	EnableSource: true,
	EnableDebug:  true,
}

// Log emits a log event to the default logger.
func Log(format string, args ...interface{}) {
	DefaultLogger.log(1, format, args...)
}

// Debug emits a debug event to the default logger.
func Debug(format string, args ...interface{}) {
	DefaultLogger.debug(1, format, args...)
}

// A Logger is a wrapper around an event handler which exposes a Log method for
// formatting event messages before sending them to the handler.
//
// The format supported by the Log method is a superset of the fmt-style format,
// where the 'verbs' may include a column-surrounded value representing the name
// of the matching argument.
//
// The Log method also makes a special case when it gets an events.Args as last
// argument, it doesn't use it to format the message and instead simply append
// it to the event's argument list.
//
// Here's an example with the defalut logger:
//
//	events.Log("Hello %:name:s!", "Luke", events.Args{
//		{"from", "Han"},
//	})
//
// Which produces an event that looks like this:
//
//	events.Event{
//		Message: "Hello Luke!",
//		Args:    events.Args{{"name", "Luke"}, {"from", "Han"}},
//		...
//	}
//
// Logger instances are safe to use concurrently from multiple goroutines.
type Logger struct {
	// Handler is the event handler receiving events from the logger.
	Handler Handler

	// Args is a list of arguments that get automatically injected into every
	// events produced by the logger.
	Args Args

	// CallDepth is used to adjust which caller the logger should report its
	// events are coming from.
	// Leaving to zero means reporting the direct caller of the logger's
	// methods.
	CallDepth int

	// EnableSource controls whether the logger should report the program counter
	// address of its caller on the events it produces.
	// This has a significant impact on the performance of the logger's Log and
	// Debug method but also provides very important insights, be mindful about
	// turning it on or off.
	EnableSource bool

	// EnableDebug controls whether calls to Debug produces events.
	EnableDebug bool
}

// Log formats an event and sends it to the logger's handler.
func (l *Logger) Log(format string, args ...interface{}) {
	l.log(1, format, args...)
}

func (l *Logger) log(depth int, format string, args ...interface{}) {
	var s = logPool.Get().(*logState)
	var a Args

	if l.EnableSource {
		var pc [1]uintptr
		runtime.Callers(l.CallDepth+depth+2, pc[:])

		if pc[0] != 0 {
			file, line := SourceForPC(pc[0])
			s.src = append(s.src, file...)
			s.src = append(s.src, ':')
			s.src = strconv.AppendUint(s.src, uint64(line), 10)
		}
	}

	if n := len(args); n != 0 {
		if s, ok := args[n-1].(Args); ok {
			a, args = s, args[:n-1]
		}
	}

	s.e.Args = append(s.e.Args, l.Args...)
	s.fmt, s.e.Args = appendFormat(s.fmt, s.e.Args, format, args)
	s.e.Args = append(s.e.Args, a...)

	fmt.Fprintf(s, string(s.fmt), args...)

	s.e.Message = stringNoCopy(s.msg)
	s.e.Source = stringNoCopy(s.src)
	s.e.Debug = l.EnableDebug
	s.e.Time = time.Now()

	l.Handler.HandleEvent(&s.e)

	s.e.Message = ""
	s.e.Source = ""
	s.e.Args = s.e.Args[:0]

	s.fmt = s.fmt[:0]
	s.msg = s.msg[:0]
	s.src = s.src[:0]

	logPool.Put(s)
	return

}

// Debug is like Log but only produces events if the logger has debugging
// enabled.
func (l *Logger) Debug(format string, args ...interface{}) {
	l.debug(1, format, args...)
}

func (l *Logger) debug(depth int, format string, args ...interface{}) {
	if l.EnableDebug {
		l.log(depth+1, format, args...)
	}
}

// With returns a new Logger which is a copy of l augmented with args.
func (l *Logger) With(args Args) *Logger {
	var newArgs Args
	var newLen = len(l.Args) + len(args)

	if newLen != 0 {
		newArgs = make(Args, 0, newLen)
		newArgs = append(newArgs, l.Args...)
		newArgs = append(newArgs, args...)
	}

	return &Logger{
		Args:         newArgs,
		Handler:      l.Handler,
		EnableSource: l.EnableSource,
		EnableDebug:  l.EnableDebug,
	}
}

// logState is used to build events produced by Logger instances.
type logState struct {
	e   Event
	fmt []byte
	msg []byte
	src []byte
}

func (s *logState) Write(b []byte) (n int, err error) {
	s.msg = append(s.msg, b...)
	n = len(b)
	return
}

var logPool = sync.Pool{
	New: func() interface{} {
		return &logState{
			e:   Event{Args: make(Args, 0, 8)},
			fmt: make([]byte, 0, 512),
			msg: make([]byte, 0, 512),
			src: make([]byte, 0, 512),
		}
	},
}

func appendFormat(dstFmt []byte, dstArgs Args, srcFmt string, srcArgs []interface{}) ([]byte, Args) {
	for i, n := 0, len(srcFmt); i != n; {
		off := strings.IndexByte(srcFmt[i:], '%')
		if off < 0 {
			dstFmt = append(dstFmt, srcFmt[i:]...)
			break
		}
		off++
		dstFmt = append(dstFmt, srcFmt[i:i+off]...)

		if i += off; i != n && srcFmt[i] == '%' { // escaped '%'
			dstFmt = append(dstFmt, '%')
			i++
			continue
		}

		var key string
		var val interface{}
	fmtLoop:
		for i != n {
			switch c := srcFmt[i]; c {
			default:
				dstFmt = append(dstFmt, c)
				i++
				if ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) {
					break fmtLoop
				}
				continue

			case ':': // extract the argument name from the format string
				if i++; i == n {
					dstFmt = append(dstFmt, ':')
					i = n
					break fmtLoop
				}

				j := strings.IndexByte(srcFmt[i:], ':')
				if j < 0 {
					dstFmt = append(dstFmt, srcFmt[i-1:]...)
					i = n
					break fmtLoop
				}

				key = srcFmt[i : i+j]
				i += j + 1
			}
		}

		if len(srcArgs) == 0 {
			val = missing
		} else {
			val, srcArgs = srcArgs[0], srcArgs[1:]
		}

		dstArgs = append(dstArgs, Arg{key, val})
	}

	return dstFmt, dstArgs
}

var (
	// Prevents Go from doing a memory allocation when there is a missing argument.
	missing interface{} = "MISSING"
)

func stringNoCopy(b []byte) string {
	if len(b) == 0 {
		return ""
	}
	return *(*string)(unsafe.Pointer(&reflect.StringHeader{
		Data: uintptr(unsafe.Pointer(&b[0])),
		Len:  len(b),
	}))
}
<commit_msg>make events.DefaultLogger a *events.Logger<commit_after>package events

import (
	"fmt"
	"reflect"
	"runtime"
	"strconv"
	"strings"
	"sync"
	"time"
	"unsafe"
)

// DefaultLogger is the default logger used by the Log function. This may be
// overwritten by the program to change the default route for log events.
var DefaultLogger = NewLogger(Discard)

// Log emits a log event to the default logger.
func Log(format string, args ...interface{}) {
	DefaultLogger.log(1, format, args...)
}

// Debug emits a debug event to the default logger.
func Debug(format string, args ...interface{}) {
	DefaultLogger.debug(1, format, args...)
}

// A Logger is a wrapper around an event handler which exposes a Log method for
// formatting event messages before sending them to the handler.
//
// The format supported by the Log method is a superset of the fmt-style format,
// where the 'verbs' may include a column-surrounded value representing the name
// of the matching argument.
//
// The Log method also makes a special case when it gets an events.Args as last
// argument, it doesn't use it to format the message and instead simply append
// it to the event's argument list.
//
// Here's an example with the defalut logger:
//
//	events.Log("Hello %:name:s!", "Luke", events.Args{
//		{"from", "Han"},
//	})
//
// Which produces an event that looks like this:
//
//	events.Event{
//		Message: "Hello Luke!",
//		Args:    events.Args{{"name", "Luke"}, {"from", "Han"}},
//		...
//	}
//
// Logger instances are safe to use concurrently from multiple goroutines.
type Logger struct {
	// Handler is the event handler receiving events from the logger.
	Handler Handler

	// Args is a list of arguments that get automatically injected into every
	// events produced by the logger.
	Args Args

	// CallDepth is used to adjust which caller the logger should report its
	// events are coming from.
	// Leaving to zero means reporting the direct caller of the logger's
	// methods.
	CallDepth int

	// EnableSource controls whether the logger should report the program counter
	// address of its caller on the events it produces.
	// This has a significant impact on the performance of the logger's Log and
	// Debug method but also provides very important insights, be mindful about
	// turning it on or off.
	EnableSource bool

	// EnableDebug controls whether calls to Debug produces events.
	EnableDebug bool
}

// NewLogger allocates and returns a new logger which sends events to handler.
func NewLogger(handler Handler) *Logger {
	return &Logger{
		Handler:      handler,
		EnableSource: true,
		EnableDebug:  true,
	}
}

// Log formats an event and sends it to the logger's handler.
func (l *Logger) Log(format string, args ...interface{}) {
	l.log(1, format, args...)
}

func (l *Logger) log(depth int, format string, args ...interface{}) {
	var s = logPool.Get().(*logState)
	var a Args

	if l.EnableSource {
		var pc [1]uintptr
		runtime.Callers(l.CallDepth+depth+2, pc[:])

		if pc[0] != 0 {
			file, line := SourceForPC(pc[0])
			s.src = append(s.src, file...)
			s.src = append(s.src, ':')
			s.src = strconv.AppendUint(s.src, uint64(line), 10)
		}
	}

	if n := len(args); n != 0 {
		if s, ok := args[n-1].(Args); ok {
			a, args = s, args[:n-1]
		}
	}

	s.e.Args = append(s.e.Args, l.Args...)
	s.fmt, s.e.Args = appendFormat(s.fmt, s.e.Args, format, args)
	s.e.Args = append(s.e.Args, a...)

	fmt.Fprintf(s, string(s.fmt), args...)

	s.e.Message = stringNoCopy(s.msg)
	s.e.Source = stringNoCopy(s.src)
	s.e.Debug = l.EnableDebug
	s.e.Time = time.Now()

	l.Handler.HandleEvent(&s.e)

	s.e.Message = ""
	s.e.Source = ""
	s.e.Args = s.e.Args[:0]

	s.fmt = s.fmt[:0]
	s.msg = s.msg[:0]
	s.src = s.src[:0]

	logPool.Put(s)
	return

}

// Debug is like Log but only produces events if the logger has debugging
// enabled.
func (l *Logger) Debug(format string, args ...interface{}) {
	l.debug(1, format, args...)
}

func (l *Logger) debug(depth int, format string, args ...interface{}) {
	if l.EnableDebug {
		l.log(depth+1, format, args...)
	}
}

// With returns a new Logger which is a copy of l augmented with args.
func (l *Logger) With(args Args) *Logger {
	var newArgs Args
	var newLen = len(l.Args) + len(args)

	if newLen != 0 {
		newArgs = make(Args, 0, newLen)
		newArgs = append(newArgs, l.Args...)
		newArgs = append(newArgs, args...)
	}

	return &Logger{
		Args:         newArgs,
		Handler:      l.Handler,
		EnableSource: l.EnableSource,
		EnableDebug:  l.EnableDebug,
	}
}

// logState is used to build events produced by Logger instances.
type logState struct {
	e   Event
	fmt []byte
	msg []byte
	src []byte
}

func (s *logState) Write(b []byte) (n int, err error) {
	s.msg = append(s.msg, b...)
	n = len(b)
	return
}

var logPool = sync.Pool{
	New: func() interface{} {
		return &logState{
			e:   Event{Args: make(Args, 0, 8)},
			fmt: make([]byte, 0, 512),
			msg: make([]byte, 0, 512),
			src: make([]byte, 0, 512),
		}
	},
}

func appendFormat(dstFmt []byte, dstArgs Args, srcFmt string, srcArgs []interface{}) ([]byte, Args) {
	for i, n := 0, len(srcFmt); i != n; {
		off := strings.IndexByte(srcFmt[i:], '%')
		if off < 0 {
			dstFmt = append(dstFmt, srcFmt[i:]...)
			break
		}
		off++
		dstFmt = append(dstFmt, srcFmt[i:i+off]...)

		if i += off; i != n && srcFmt[i] == '%' { // escaped '%'
			dstFmt = append(dstFmt, '%')
			i++
			continue
		}

		var key string
		var val interface{}
	fmtLoop:
		for i != n {
			switch c := srcFmt[i]; c {
			default:
				dstFmt = append(dstFmt, c)
				i++
				if ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) {
					break fmtLoop
				}
				continue

			case ':': // extract the argument name from the format string
				if i++; i == n {
					dstFmt = append(dstFmt, ':')
					i = n
					break fmtLoop
				}

				j := strings.IndexByte(srcFmt[i:], ':')
				if j < 0 {
					dstFmt = append(dstFmt, srcFmt[i-1:]...)
					i = n
					break fmtLoop
				}

				key = srcFmt[i : i+j]
				i += j + 1
			}
		}

		if len(srcArgs) == 0 {
			val = missing
		} else {
			val, srcArgs = srcArgs[0], srcArgs[1:]
		}

		dstArgs = append(dstArgs, Arg{key, val})
	}

	return dstFmt, dstArgs
}

var (
	// Prevents Go from doing a memory allocation when there is a missing argument.
	missing interface{} = "MISSING"
)

func stringNoCopy(b []byte) string {
	if len(b) == 0 {
		return ""
	}
	return *(*string)(unsafe.Pointer(&reflect.StringHeader{
		Data: uintptr(unsafe.Pointer(&b[0])),
		Len:  len(b),
	}))
}
<|endoftext|>


<commit_before>package main

import (
  "os"
  "fmt"
  "log"
  "net/http"
  "encoding/json"
  "regexp"
)

var linkListRegex = regexp.MustCompile("<([A-Za-z0-9\\:\\.\\/\\=\\?\\{\\}]*)>; rel=\"([A-Za-z]*)\"")

func main() {
  if os.Getenv("GHE_SERVER") == ""  {
    log.Fatal("Missing environment variable GHE_SERVER")
    return
  }
  if os.Getenv("GHE_WHITE_LIST_ORG") == "" {
    log.Fatal("Missing environment variable GHE_WHITE_LIST_ORG")
    return
  }
  if os.Getenv("GHE_PERSONAL_ACCESS_TOKEN") == "" {
    log.Fatal("Missing environment variable GHE_PERSONAL_ACCESS_TOKEN")
    return
  }

  whiteListUrl := fmt.Sprintf("https://%s/api/v3/orgs/%s/members", os.Getenv("GHE_SERVER"), os.Getenv("GHE_WHITE_LIST_ORG"))
  userUrl := fmt.Sprintf("https://%s/api/v3/users", os.Getenv("GHE_SERVER"))
  pat := os.Getenv("GHE_PERSONAL_ACCESS_TOKEN")

  whiteListUsers  := getUserMap(whiteListUrl, pat)
  allUsers  := getUserList(userUrl, pat)

  suspendCounter := 0
  for _, user := range allUsers {
    if user.Type == "User" {
      _, ok := whiteListUsers[user.Id]
      if !ok {
        suspend(user, pat)
        suspendCounter ++
      }
    }
  }

  log.Printf("Suspended %d users\n", suspendCounter)
}

func suspend(user User, pat string) {
  var url = fmt.Sprintf("https://%s/api/v3/users/%s/suspended", os.Getenv("GHE_SERVER"), user.Login)

  log.Printf("Suspend %s with %s\n", user.Login, url)

  req, err := http.NewRequest("PUT", url, nil)
  if err != nil {
    log.Fatal("Failed while building the HTTP client: ", err)
    return
  }

  // Provide authentication
  req.Header.Add("Authorization", fmt.Sprintf("token %s", pat))
  req.Header.Add("Content-Length", "0")

  client := &http.Client{}

  resp, doErr := client.Do(req)
  if doErr != nil {
    log.Fatal("Failed executing HTTP request: ", doErr)
    return
  }

  // Close when method returns
  defer resp.Body.Close()
}

/*
 * Get the users as a map using Id as a key
 */
func getUserMap(url, pat string) map[int]User {
  userArray := getUserList(url, pat)
  var userMap map[int]User = make(map[int]User)

  for _, user := range userArray {
    // Filtering out orgs
    if user.Type == "User" {
      userMap[user.Id] = user
    }
  }

  return userMap
}

/*
 * Get the users (including orgs) in an array
 */
func getUserList(url, pat string) []User {
  log.Printf("Retrieving users with %s", url)
  // Build the request
  req, err := http.NewRequest("GET", url, nil)
  if err != nil {
    log.Fatal("Failed while building the HTTP client: ", err)
    return nil
  }

  // Provide authentication
  req.Header.Add("Authorization", fmt.Sprintf("token %s", pat))

  client := &http.Client{}

  resp, doErr := client.Do(req)
  if doErr != nil {
    log.Fatal("Failed executing HTTP request: ", doErr)
    return nil
  }

  // Close when method returns
  defer resp.Body.Close()

  var userArray []User

  // Decode the JSON array
  decodeErr := json.NewDecoder(resp.Body).Decode(&userArray)
  if decodeErr != nil {
  	log.Fatal(decodeErr)
    return nil
  } else {
    // Working the pagination as described in https://developer.github.com/guides/traversing-with-pagination/
    // linkHeader := <https://gheserver.com/api/v3/users?since=35>; rel="next", <https://gheserver.com/api/v3/users{?since}>; rel="first"
    linkHeader := resp.Header.Get("Link")

    if linkHeader != "" {
      linkArray := linkListRegex.FindAllStringSubmatch(linkHeader, -1)
      /*
      linkArray := [["<https://gheserver.com/api/v3/users?since=35>; rel=next", "https://gheserver.com/api/v3/users?since=35", "next"],
       ["<https://gheserver.com/api/v3/users{?since}>; rel="first", "https://gheserver.com/api/v3/users{?since}, "first"]]
      */
      for _, linkElement := range linkArray {
        if linkElement[2] == "next" {
          // Getting the next page of users and appending to the current array
          userArray = append(userArray, getUserList(linkElement[1], pat)...)
          break
        }
	    }
    }
    return userArray
  }
}
<commit_msg>More context when unmarshalling users<commit_after>package main

import (
  "os"
  "fmt"
  "log"
  "net/http"
  "encoding/json"
  "regexp"
)

var linkListRegex = regexp.MustCompile("<([A-Za-z0-9\\:\\.\\/\\=\\?\\{\\}]*)>; rel=\"([A-Za-z]*)\"")

func main() {
  if os.Getenv("GHE_SERVER") == ""  {
    log.Fatal("Missing environment variable GHE_SERVER")
    return
  }
  if os.Getenv("GHE_WHITE_LIST_ORG") == "" {
    log.Fatal("Missing environment variable GHE_WHITE_LIST_ORG")
    return
  }
  if os.Getenv("GHE_PERSONAL_ACCESS_TOKEN") == "" {
    log.Fatal("Missing environment variable GHE_PERSONAL_ACCESS_TOKEN")
    return
  }

  whiteListUrl := fmt.Sprintf("https://%s/api/v3/orgs/%s/members", os.Getenv("GHE_SERVER"), os.Getenv("GHE_WHITE_LIST_ORG"))
  userUrl := fmt.Sprintf("https://%s/api/v3/users", os.Getenv("GHE_SERVER"))
  pat := os.Getenv("GHE_PERSONAL_ACCESS_TOKEN")

  whiteListUsers  := getUserMap(whiteListUrl, pat)
  allUsers  := getUserList(userUrl, pat)

  suspendCounter := 0
  for _, user := range allUsers {
    if user.Type == "User" {
      _, ok := whiteListUsers[user.Id]
      if !ok {
        suspend(user, pat)
        suspendCounter ++
      }
    }
  }

  log.Printf("Suspended %d users\n", suspendCounter)
}

func suspend(user User, pat string) {
  var url = fmt.Sprintf("https://%s/api/v3/users/%s/suspended", os.Getenv("GHE_SERVER"), user.Login)

  log.Printf("Suspend %s with %s\n", user.Login, url)

  req, err := http.NewRequest("PUT", url, nil)
  if err != nil {
    log.Fatal("Failed while building the HTTP client: ", err)
    return
  }

  // Provide authentication
  req.Header.Add("Authorization", fmt.Sprintf("token %s", pat))
  req.Header.Add("Content-Length", "0")

  client := &http.Client{}

  resp, doErr := client.Do(req)
  if doErr != nil {
    log.Fatal("Failed executing HTTP request: ", doErr)
    return
  }

  // Close when method returns
  defer resp.Body.Close()
}

/*
 * Get the users as a map using Id as a key
 */
func getUserMap(url, pat string) map[int]User {
  userArray := getUserList(url, pat)
  var userMap map[int]User = make(map[int]User)

  for _, user := range userArray {
    // Filtering out orgs
    if user.Type == "User" {
      userMap[user.Id] = user
    }
  }

  return userMap
}

/*
 * Get the users (including orgs) in an array
 */
func getUserList(url, pat string) []User {
  log.Printf("Retrieving users with %s", url)
  // Build the request
  req, err := http.NewRequest("GET", url, nil)
  if err != nil {
    log.Fatal("Failed while building the HTTP client: ", err)
    return nil
  }

  // Provide authentication
  req.Header.Add("Authorization", fmt.Sprintf("token %s", pat))

  client := &http.Client{}

  resp, doErr := client.Do(req)
  if doErr != nil {
    log.Fatal("Failed executing HTTP request: ", doErr)
    return nil
  }

  // Close when method returns
  defer resp.Body.Close()

  var userArray []User

  // Decode the JSON array
  decodeErr := json.NewDecoder(resp.Body).Decode(&userArray)
  if decodeErr != nil {
  	log.Fatal(decodeErr, " - Response was:", resp.Body)
    return nil
  } else {
    // Working the pagination as described in https://developer.github.com/guides/traversing-with-pagination/
    // linkHeader := <https://gheserver.com/api/v3/users?since=35>; rel="next", <https://gheserver.com/api/v3/users{?since}>; rel="first"
    linkHeader := resp.Header.Get("Link")

    if linkHeader != "" {
      linkArray := linkListRegex.FindAllStringSubmatch(linkHeader, -1)
      /*
      linkArray := [["<https://gheserver.com/api/v3/users?since=35>; rel=next", "https://gheserver.com/api/v3/users?since=35", "next"],
       ["<https://gheserver.com/api/v3/users{?since}>; rel="first", "https://gheserver.com/api/v3/users{?since}, "first"]]
      */
      for _, linkElement := range linkArray {
        if linkElement[2] == "next" {
          // Getting the next page of users and appending to the current array
          userArray = append(userArray, getUserList(linkElement[1], pat)...)
          break
        }
	    }
    }
    return userArray
  }
}
<|endoftext|>


<commit_before>package gotwilio

import (
	"fmt"
	"net/url"

	"github.com/gorilla/schema"
)

// LookupReq Go-representation of Twilio REST API's lookup request.
// https://www.twilio.com/docs/api/rest/lookups#lookups-query-parameters
type LookupReq struct {
	PhoneNumber string
	Type        string
	CountryCode string
}

// Lookup Go-representation of Twilio REST API's lookup.
// https://www.twilio.com/docs/api/rest/lookups
type Lookup struct {
	Carrier *struct {
		ErrorCode         *int   `json:"error_code"`
		MobileCountryCode string `json:"mobile_country_code"`
		MobileNetworkCode string `json:"mobile_network_code"`
		Name              string `json:"name"`
		Type              string `json:"type"`
	} `json:"carrier"`
	CountryCode    string `json:"country_code"`
	NationalFormat string `json:"national_format"`
	PhoneNumber    string `json:"phone_number"`
	URL            string `json:"url"`
}

// SubmitLookup sends a lookup request populating form fields only if they
// contain a non-zero value.
func (twilio *Twilio) SubmitLookup(req LookupReq) (Lookup, error) {
	encoder := schema.NewEncoder()
	values := url.Values{}

	if err := encoder.Encode(req, values); err != nil {
		return Lookup{}, err
	}
	fmt.Println(req)

	url := fmt.Sprintf("%s/PhoneNumbers/%s?%s", twilio.LookupURL, req.PhoneNumber, values.Encode())
	res := Lookup{}
	err := twilio.getJSON(url, &res)
	return res, err
}

// LookupNoCarrier looks up a phone number's details without the carrier
func (twilio *Twilio) LookupNoCarrier(phoneNumber string) (Lookup, error) {
	req := LookupReq{PhoneNumber: phoneNumber}
	return twilio.SubmitLookup(req)
}
<commit_msg>remove extraneous log<commit_after>package gotwilio

import (
	"fmt"
	"net/url"

	"github.com/gorilla/schema"
)

// LookupReq Go-representation of Twilio REST API's lookup request.
// https://www.twilio.com/docs/api/rest/lookups#lookups-query-parameters
type LookupReq struct {
	PhoneNumber string
	Type        string
	CountryCode string
}

// Lookup Go-representation of Twilio REST API's lookup.
// https://www.twilio.com/docs/api/rest/lookups
type Lookup struct {
	Carrier *struct {
		ErrorCode         *int   `json:"error_code"`
		MobileCountryCode string `json:"mobile_country_code"`
		MobileNetworkCode string `json:"mobile_network_code"`
		Name              string `json:"name"`
		Type              string `json:"type"`
	} `json:"carrier"`
	CountryCode    string `json:"country_code"`
	NationalFormat string `json:"national_format"`
	PhoneNumber    string `json:"phone_number"`
	URL            string `json:"url"`
}

// SubmitLookup sends a lookup request populating form fields only if they
// contain a non-zero value.
func (twilio *Twilio) SubmitLookup(req LookupReq) (Lookup, error) {
	encoder := schema.NewEncoder()
	values := url.Values{}

	if err := encoder.Encode(req, values); err != nil {
		return Lookup{}, err
	}

	url := fmt.Sprintf("%s/PhoneNumbers/%s?%s", twilio.LookupURL, req.PhoneNumber, values.Encode())
	res := Lookup{}
	err := twilio.getJSON(url, &res)
	return res, err
}

// LookupNoCarrier looks up a phone number's details without the carrier
func (twilio *Twilio) LookupNoCarrier(phoneNumber string) (Lookup, error) {
	req := LookupReq{PhoneNumber: phoneNumber}
	return twilio.SubmitLookup(req)
}
<|endoftext|>