<commit_before>package main

import (
	"flag"
	"fmt"
	"testing"
	"net/http"
)

var edgeHost = flag.String("edgeHost", "www.gov.uk", "Hostname of edge")

// Should redirect from HTTP to HTTPS without hitting origin.
func TestProtocolRedirect(t *testing.T) {
	sourceUrl := fmt.Sprintf("http://%s/foo/bar", *edgeHost)
	destUrl := fmt.Sprintf("https://%s/foo/bar", *edgeHost)

	client := &http.Transport{}
	req, _ := http.NewRequest("GET", sourceUrl, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != 301 {
		t.Errorf("Status code expected 301, got %d", resp.StatusCode)
	}
	if d := resp.Header.Get("Location"); d != destUrl {
		t.Errorf("Location header expected %s, got %s", destUrl, d)
	}

	t.Error("Not implemented test to confirm that it doesn't hit origin")
}

// Should return 403 for PURGE requests from IPs not in the whitelist.
func TestRestrictPurgeRequests(t *testing.T) {
	t.Error("Not implemented")
}

// Should create an X-Forwarded-For header containing the client's IP.
func TestHeaderCreateXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should append client's IP to existing X-Forwarded-For header.
func TestHeaderAppendXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should create a True-Client-IP header containing the client's IP
// address, discarding the value provided in the original request.
func TestHeaderUnspoofableClientIP(t *testing.T) {
	t.Error("Not implemented")
}

// Should not modify Host header from original request.
func TestHeaderHostUnmodified(t *testing.T) {
	t.Error("Not implemented")
}

// Should set a default TTL if the response doesn't set one.
func TestDefaultTTL(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin is down and
// object is beyond TTL but still in cache.
func TestFailoverOriginDownServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin returns a 5xx
// response and object is beyond TTL but still in cache.
func TestFailoverOrigin5xxServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin is down and object is not in
// cache (active or stale).
func TestFailoverOriginDownUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin returns 5xx response and object
// is not in cache (active or stale).
func TestFailoverOrigin5xxUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror are
// down.
func TestFailoverOriginDownFirstMirrorDownUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror return
// 5xx responses.
func TestFailoverOrigin5xxFirstMirror5xxUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should not fallback to mirror if origin returns a 5xx response with a
// No-Fallback header.
func TestFailoverNoFallbackHeader(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Set-Cookie a header.
func TestNoCacheHeaderSetCookie(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Cache-Control: private header.
func TestNoCacheHeaderCacheControlPrivate(t *testing.T) {
	t.Error("Not implemented")
}
<commit_msg>go fmt import order.<commit_after>package main

import (
	"flag"
	"fmt"
	"net/http"
	"testing"
)

var edgeHost = flag.String("edgeHost", "www.gov.uk", "Hostname of edge")

// Should redirect from HTTP to HTTPS without hitting origin.
func TestProtocolRedirect(t *testing.T) {
	sourceUrl := fmt.Sprintf("http://%s/foo/bar", *edgeHost)
	destUrl := fmt.Sprintf("https://%s/foo/bar", *edgeHost)

	client := &http.Transport{}
	req, _ := http.NewRequest("GET", sourceUrl, nil)
	resp, err := client.RoundTrip(req)

	if err != nil {
		t.Fatal(err)
	}
	if resp.StatusCode != 301 {
		t.Errorf("Status code expected 301, got %d", resp.StatusCode)
	}
	if d := resp.Header.Get("Location"); d != destUrl {
		t.Errorf("Location header expected %s, got %s", destUrl, d)
	}

	t.Error("Not implemented test to confirm that it doesn't hit origin")
}

// Should return 403 for PURGE requests from IPs not in the whitelist.
func TestRestrictPurgeRequests(t *testing.T) {
	t.Error("Not implemented")
}

// Should create an X-Forwarded-For header containing the client's IP.
func TestHeaderCreateXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should append client's IP to existing X-Forwarded-For header.
func TestHeaderAppendXFF(t *testing.T) {
	t.Error("Not implemented")
}

// Should create a True-Client-IP header containing the client's IP
// address, discarding the value provided in the original request.
func TestHeaderUnspoofableClientIP(t *testing.T) {
	t.Error("Not implemented")
}

// Should not modify Host header from original request.
func TestHeaderHostUnmodified(t *testing.T) {
	t.Error("Not implemented")
}

// Should set a default TTL if the response doesn't set one.
func TestDefaultTTL(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin is down and
// object is beyond TTL but still in cache.
func TestFailoverOriginDownServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should serve stale object and not hit mirror(s) if origin returns a 5xx
// response and object is beyond TTL but still in cache.
func TestFailoverOrigin5xxServeStale(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin is down and object is not in
// cache (active or stale).
func TestFailoverOriginDownUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to first mirror if origin returns 5xx response and object
// is not in cache (active or stale).
func TestFailoverOrigin5xxUseFirstMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror are
// down.
func TestFailoverOriginDownFirstMirrorDownUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should fallback to second mirror if both origin and first mirror return
// 5xx responses.
func TestFailoverOrigin5xxFirstMirror5xxUseSecondMirror(t *testing.T) {
	t.Error("Not implemented")
}

// Should not fallback to mirror if origin returns a 5xx response with a
// No-Fallback header.
func TestFailoverNoFallbackHeader(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Set-Cookie a header.
func TestNoCacheHeaderSetCookie(t *testing.T) {
	t.Error("Not implemented")
}

// Should not cache a response with a Cache-Control: private header.
func TestNoCacheHeaderCacheControlPrivate(t *testing.T) {
	t.Error("Not implemented")
}
<|endoftext|>


<commit_before><commit_msg>Trigger the joypad interrupt when buttons are pressed<commit_after><|endoftext|>


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

package walk

import (
	"syscall"
	"unsafe"
)

import . "github.com/lxn/go-winapi"

const notifyIconWindowClass = `\o/ Walk_NotifyIcon_Class \o/`

var notifyIconWindowClassRegistered bool

func notifyIconWndProc(hwnd HWND, msg uint32, wParam, lParam uintptr) (result uintptr) {
	// Retrieve our *NotifyIcon from the message window.
	ptr := GetWindowLongPtr(hwnd, GWLP_USERDATA)
	ni := (*NotifyIcon)(unsafe.Pointer(ptr))

	switch lParam {
	case WM_LBUTTONDOWN:
		ni.publishMouseEvent(&ni.mouseDownPublisher, LeftButton)

	case WM_LBUTTONUP:
		ni.publishMouseEvent(&ni.mouseUpPublisher, LeftButton)

	case WM_RBUTTONDOWN:
		ni.publishMouseEvent(&ni.mouseDownPublisher, RightButton)

	case WM_RBUTTONUP:
		ni.publishMouseEvent(&ni.mouseUpPublisher, RightButton)

		SendMessage(hwnd, msg, wParam, WM_CONTEXTMENU)

	case WM_CONTEXTMENU:
		if ni.contextMenu.Actions().Len() == 0 {
			break
		}

		SetForegroundWindow(hwnd)

		var p POINT
		if !GetCursorPos(&p) {
			lastError("GetCursorPos")
		}

		actionId := uint16(TrackPopupMenuEx(
			ni.contextMenu.hMenu,
			TPM_NOANIMATION|TPM_RETURNCMD,
			p.X,
			p.Y,
			hwnd,
			nil))
		if actionId != 0 {
			if action, ok := actionsById[actionId]; ok {
				action.raiseTriggered()
			}
		}

		return 0
	}

	return DefWindowProc(hwnd, msg, wParam, lParam)
}

// NotifyIcon represents an icon in the taskbar notification area.
type NotifyIcon struct {
	id                 uint32
	hWnd               HWND
	contextMenu        *Menu
	icon               *Icon
	toolTip            string
	visible            bool
	mouseDownPublisher MouseEventPublisher
	mouseUpPublisher   MouseEventPublisher
}

// NewNotifyIcon creates and returns a new NotifyIcon.
//
// The NotifyIcon is initially not visible.
func NewNotifyIcon() (*NotifyIcon, error) {
	ensureRegisteredWindowClass(notifyIconWindowClass, &notifyIconWindowClassRegistered)

	// Create the message-only window for the NotifyIcon.
	hWnd := CreateWindowEx(
		0,
		syscall.StringToUTF16Ptr(notifyIconWindowClass),
		nil,
		0,
		0,
		0,
		0,
		0,
		HWND_MESSAGE,
		0,
		0,
		nil)
	if hWnd == 0 {
		return nil, lastError("CreateWindowEx")
	}

	// Add our notify icon to the status area and make sure it is hidden.
	nid := NOTIFYICONDATA{
		HWnd:             hWnd,
		UFlags:           NIF_MESSAGE | NIF_STATE,
		DwState:          NIS_HIDDEN,
		DwStateMask:      NIS_HIDDEN,
		UCallbackMessage: notifyIconMessageId,
	}
	nid.CbSize = uint32(unsafe.Sizeof(nid))

	if !Shell_NotifyIcon(NIM_ADD, &nid) {
		return nil, newError("Shell_NotifyIcon")
	}

	// We want XP-compatible message behavior.
	nid.UVersion = NOTIFYICON_VERSION

	if !Shell_NotifyIcon(NIM_SETVERSION, &nid) {
		return nil, newError("Shell_NotifyIcon")
	}

	// Create and initialize the NotifyIcon already.
	menu, err := NewMenu()
	if err != nil {
		return nil, err
	}

	ni := &NotifyIcon{
		id:          nid.UID,
		hWnd:        hWnd,
		contextMenu: menu,
	}

	// Set our *NotifyIcon as user data for the message window.
	SetWindowLongPtr(hWnd, GWLP_USERDATA, uintptr(unsafe.Pointer(ni)))

	return ni, nil
}

func (ni *NotifyIcon) notifyIconData() *NOTIFYICONDATA {
	nid := &NOTIFYICONDATA{
		UID:  ni.id,
		HWnd: ni.hWnd,
	}
	nid.CbSize = uint32(unsafe.Sizeof(*nid))

	return nid
}

// Dispose releases the operating system resources associated with the
// NotifyIcon.
//
// The associated Icon is not disposed of.
func (ni *NotifyIcon) Dispose() error {
	if ni.hWnd == 0 {
		return nil
	}

	nid := ni.notifyIconData()

	if !Shell_NotifyIcon(NIM_DELETE, nid) {
		return newError("Shell_NotifyIcon")
	}

	if !DestroyWindow(ni.hWnd) {
		return lastError("DestroyWindow")
	}
	ni.hWnd = 0

	return nil
}

// ContextMenu returns the context menu of the NotifyIcon.
func (ni *NotifyIcon) ContextMenu() *Menu {
	return ni.contextMenu
}

// Icon returns the Icon of the NotifyIcon.
func (ni *NotifyIcon) Icon() *Icon {
	return ni.icon
}

// SetIcon sets the Icon of the NotifyIcon.
func (ni *NotifyIcon) SetIcon(icon *Icon) error {
	if icon == ni.icon {
		return nil
	}

	nid := ni.notifyIconData()
	nid.UFlags = NIF_ICON
	if icon == nil {
		nid.HIcon = 0
	} else {
		nid.HIcon = icon.hIcon
	}

	if !Shell_NotifyIcon(NIM_MODIFY, nid) {
		return newError("Shell_NotifyIcon")
	}

	ni.icon = icon

	return nil
}

// ToolTip returns the tool tip text of the NotifyIcon.
func (ni *NotifyIcon) ToolTip() string {
	return ni.toolTip
}

// SetToolTip sets the tool tip text of the NotifyIcon.
func (ni *NotifyIcon) SetToolTip(toolTip string) error {
	if toolTip == ni.toolTip {
		return nil
	}

	nid := ni.notifyIconData()
	nid.UFlags = NIF_TIP
	copy(nid.SzTip[:], syscall.StringToUTF16(toolTip))

	if !Shell_NotifyIcon(NIM_MODIFY, nid) {
		return newError("Shell_NotifyIcon")
	}

	ni.toolTip = toolTip

	return nil
}

// Visible returns if the NotifyIcon is visible.
func (ni *NotifyIcon) Visible() bool {
	return ni.visible
}

// SetVisible sets if the NotifyIcon is visible.
func (ni *NotifyIcon) SetVisible(visible bool) error {
	if visible == ni.visible {
		return nil
	}

	nid := ni.notifyIconData()
	nid.UFlags = NIF_STATE
	nid.DwStateMask = NIS_HIDDEN
	if !visible {
		nid.DwState = NIS_HIDDEN
	}

	if !Shell_NotifyIcon(NIM_MODIFY, nid) {
		return newError("Shell_NotifyIcon")
	}

	ni.visible = visible

	return nil
}

func (ni *NotifyIcon) publishMouseEvent(publisher *MouseEventPublisher, button MouseButton) {
	var p POINT
	if !GetCursorPos(&p) {
		lastError("GetCursorPos")
	}

	publisher.Publish(int(p.X), int(p.Y), button)
}

// MouseDown returns the event that is published when a mouse button is pressed
// while the cursor is over the NotifyIcon.
func (ni *NotifyIcon) MouseDown() *MouseEvent {
	return ni.mouseDownPublisher.Event()
}

// MouseDown returns the event that is published when a mouse button is released
// while the cursor is over the NotifyIcon.
func (ni *NotifyIcon) MouseUp() *MouseEvent {
	return ni.mouseUpPublisher.Event()
}
<commit_msg>NotifyIcon: Add support for balloon messages.<commit_after>// Copyright 2011 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package walk

import (
	"syscall"
	"unsafe"
)

import . "github.com/lxn/go-winapi"

const notifyIconWindowClass = `\o/ Walk_NotifyIcon_Class \o/`

var notifyIconWindowClassRegistered bool

func notifyIconWndProc(hwnd HWND, msg uint32, wParam, lParam uintptr) (result uintptr) {
	// Retrieve our *NotifyIcon from the message window.
	ptr := GetWindowLongPtr(hwnd, GWLP_USERDATA)
	ni := (*NotifyIcon)(unsafe.Pointer(ptr))

	switch lParam {
	case WM_LBUTTONDOWN:
		ni.publishMouseEvent(&ni.mouseDownPublisher, LeftButton)

	case WM_LBUTTONUP:
		ni.publishMouseEvent(&ni.mouseUpPublisher, LeftButton)

	case WM_RBUTTONDOWN:
		ni.publishMouseEvent(&ni.mouseDownPublisher, RightButton)

	case WM_RBUTTONUP:
		ni.publishMouseEvent(&ni.mouseUpPublisher, RightButton)

		SendMessage(hwnd, msg, wParam, WM_CONTEXTMENU)

	case WM_CONTEXTMENU:
		if ni.contextMenu.Actions().Len() == 0 {
			break
		}

		SetForegroundWindow(hwnd)

		var p POINT
		if !GetCursorPos(&p) {
			lastError("GetCursorPos")
		}

		actionId := uint16(TrackPopupMenuEx(
			ni.contextMenu.hMenu,
			TPM_NOANIMATION|TPM_RETURNCMD,
			p.X,
			p.Y,
			hwnd,
			nil))
		if actionId != 0 {
			if action, ok := actionsById[actionId]; ok {
				action.raiseTriggered()
			}
		}

		return 0
	}

	return DefWindowProc(hwnd, msg, wParam, lParam)
}

// NotifyIcon represents an icon in the taskbar notification area.
type NotifyIcon struct {
	id                 uint32
	hWnd               HWND
	contextMenu        *Menu
	icon               *Icon
	toolTip            string
	visible            bool
	mouseDownPublisher MouseEventPublisher
	mouseUpPublisher   MouseEventPublisher
}

// NewNotifyIcon creates and returns a new NotifyIcon.
//
// The NotifyIcon is initially not visible.
func NewNotifyIcon() (*NotifyIcon, error) {
	ensureRegisteredWindowClass(notifyIconWindowClass, &notifyIconWindowClassRegistered)

	// Create the message-only window for the NotifyIcon.
	hWnd := CreateWindowEx(
		0,
		syscall.StringToUTF16Ptr(notifyIconWindowClass),
		nil,
		0,
		0,
		0,
		0,
		0,
		HWND_MESSAGE,
		0,
		0,
		nil)
	if hWnd == 0 {
		return nil, lastError("CreateWindowEx")
	}

	// Add our notify icon to the status area and make sure it is hidden.
	nid := NOTIFYICONDATA{
		HWnd:             hWnd,
		UFlags:           NIF_MESSAGE | NIF_STATE,
		DwState:          NIS_HIDDEN,
		DwStateMask:      NIS_HIDDEN,
		UCallbackMessage: notifyIconMessageId,
	}
	nid.CbSize = uint32(unsafe.Sizeof(nid))

	if !Shell_NotifyIcon(NIM_ADD, &nid) {
		return nil, newError("Shell_NotifyIcon")
	}

	// We want XP-compatible message behavior.
	nid.UVersion = NOTIFYICON_VERSION

	if !Shell_NotifyIcon(NIM_SETVERSION, &nid) {
		return nil, newError("Shell_NotifyIcon")
	}

	// Create and initialize the NotifyIcon already.
	menu, err := NewMenu()
	if err != nil {
		return nil, err
	}

	ni := &NotifyIcon{
		id:          nid.UID,
		hWnd:        hWnd,
		contextMenu: menu,
	}

	// Set our *NotifyIcon as user data for the message window.
	SetWindowLongPtr(hWnd, GWLP_USERDATA, uintptr(unsafe.Pointer(ni)))

	return ni, nil
}

func (ni *NotifyIcon) notifyIconData() *NOTIFYICONDATA {
	nid := &NOTIFYICONDATA{
		UID:  ni.id,
		HWnd: ni.hWnd,
	}
	nid.CbSize = uint32(unsafe.Sizeof(*nid))

	return nid
}

// Dispose releases the operating system resources associated with the
// NotifyIcon.
//
// The associated Icon is not disposed of.
func (ni *NotifyIcon) Dispose() error {
	if ni.hWnd == 0 {
		return nil
	}

	nid := ni.notifyIconData()

	if !Shell_NotifyIcon(NIM_DELETE, nid) {
		return newError("Shell_NotifyIcon")
	}

	if !DestroyWindow(ni.hWnd) {
		return lastError("DestroyWindow")
	}
	ni.hWnd = 0

	return nil
}

func (ni *NotifyIcon) showMessage(title, info string, iconType uint32) error {
	nid := ni.notifyIconData()
	nid.UFlags = NIF_INFO
	nid.DwInfoFlags = iconType
	copy(nid.SzInfoTitle[:], syscall.StringToUTF16(title))
	copy(nid.SzInfo[:], syscall.StringToUTF16(info))

	if !Shell_NotifyIcon(NIM_MODIFY, nid) {
		return newError("Shell_NotifyIcon")
	}

	return nil
}

// ShowMessage displays a neutral message balloon above the NotifyIcon.
//
// The NotifyIcon must be visible before calling this method.
func (ni *NotifyIcon) ShowMessage(title, info string) error {
	return ni.showMessage(title, info, NIIF_NONE)
}

// ShowInfo displays an info message balloon above the NotifyIcon.
//
// The NotifyIcon must be visible before calling this method.
func (ni *NotifyIcon) ShowInfo(title, info string) error {
	return ni.showMessage(title, info, NIIF_INFO)
}

// ShowWarning displays a warning message balloon above the NotifyIcon.
//
// The NotifyIcon must be visible before calling this method.
func (ni *NotifyIcon) ShowWarning(title, info string) error {
	return ni.showMessage(title, info, NIIF_WARNING)
}

// ShowError displays an error message balloon above the NotifyIcon.
//
// The NotifyIcon must be visible before calling this method.
func (ni *NotifyIcon) ShowError(title, info string) error {
	return ni.showMessage(title, info, NIIF_ERROR)
}

// ShowCustom displays a custom icon message balloon above the NotifyIcon.
//
// The NotifyIcon must be visible before calling this method.
func (ni *NotifyIcon) ShowCustom(title, info string) error {
	return ni.showMessage(title, info, NIIF_USER)
}

// ContextMenu returns the context menu of the NotifyIcon.
func (ni *NotifyIcon) ContextMenu() *Menu {
	return ni.contextMenu
}

// Icon returns the Icon of the NotifyIcon.
func (ni *NotifyIcon) Icon() *Icon {
	return ni.icon
}

// SetIcon sets the Icon of the NotifyIcon.
func (ni *NotifyIcon) SetIcon(icon *Icon) error {
	if icon == ni.icon {
		return nil
	}

	nid := ni.notifyIconData()
	nid.UFlags = NIF_ICON
	if icon == nil {
		nid.HIcon = 0
	} else {
		nid.HIcon = icon.hIcon
	}

	if !Shell_NotifyIcon(NIM_MODIFY, nid) {
		return newError("Shell_NotifyIcon")
	}

	ni.icon = icon

	return nil
}

// ToolTip returns the tool tip text of the NotifyIcon.
func (ni *NotifyIcon) ToolTip() string {
	return ni.toolTip
}

// SetToolTip sets the tool tip text of the NotifyIcon.
func (ni *NotifyIcon) SetToolTip(toolTip string) error {
	if toolTip == ni.toolTip {
		return nil
	}

	nid := ni.notifyIconData()
	nid.UFlags = NIF_TIP
	copy(nid.SzTip[:], syscall.StringToUTF16(toolTip))

	if !Shell_NotifyIcon(NIM_MODIFY, nid) {
		return newError("Shell_NotifyIcon")
	}

	ni.toolTip = toolTip

	return nil
}

// Visible returns if the NotifyIcon is visible.
func (ni *NotifyIcon) Visible() bool {
	return ni.visible
}

// SetVisible sets if the NotifyIcon is visible.
func (ni *NotifyIcon) SetVisible(visible bool) error {
	if visible == ni.visible {
		return nil
	}

	nid := ni.notifyIconData()
	nid.UFlags = NIF_STATE
	nid.DwStateMask = NIS_HIDDEN
	if !visible {
		nid.DwState = NIS_HIDDEN
	}

	if !Shell_NotifyIcon(NIM_MODIFY, nid) {
		return newError("Shell_NotifyIcon")
	}

	ni.visible = visible

	return nil
}

func (ni *NotifyIcon) publishMouseEvent(publisher *MouseEventPublisher, button MouseButton) {
	var p POINT
	if !GetCursorPos(&p) {
		lastError("GetCursorPos")
	}

	publisher.Publish(int(p.X), int(p.Y), button)
}

// MouseDown returns the event that is published when a mouse button is pressed
// while the cursor is over the NotifyIcon.
func (ni *NotifyIcon) MouseDown() *MouseEvent {
	return ni.mouseDownPublisher.Event()
}

// MouseDown returns the event that is published when a mouse button is released
// while the cursor is over the NotifyIcon.
func (ni *NotifyIcon) MouseUp() *MouseEvent {
	return ni.mouseUpPublisher.Event()
}
<|endoftext|>


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

// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris

package os

import (
	"internal/syscall/unix"
	"io"
	"syscall"
)

func RemoveAll(path string) error {
	if path == "" {
		// fail silently to retain compatibility with previous behavior
		// of RemoveAll. See issue 28830.
		return nil
	}

	// The rmdir system call does not permit removing ".",
	// so we don't permit it either.
	if endsWithDot(path) {
		return syscall.EINVAL
	}

	// RemoveAll recurses by deleting the path base from
	// its parent directory
	parentDir, base := splitPath(path)

	parent, err := Open(parentDir)
	if IsNotExist(err) {
		// If parent does not exist, base cannot exist. Fail silently
		return nil
	}
	if err != nil {
		return err
	}
	defer parent.Close()

	return removeAllFrom(parent, base)
}

func removeAllFrom(parent *File, path string) error {
	parentFd := int(parent.Fd())
	// Simple case: if Unlink (aka remove) works, we're done.
	err := unix.Unlinkat(parentFd, path, 0)
	if err == nil || IsNotExist(err) {
		return nil
	}

	// If not a "is directory" error, we have a problem
	if err != syscall.EISDIR && err != syscall.EPERM {
		return err
	}

	// Is this a directory we need to recurse into?
	var statInfo syscall.Stat_t
	statErr := unix.Fstatat(parentFd, path, &statInfo, unix.AT_SYMLINK_NOFOLLOW)
	if statErr != nil {
		return statErr
	}
	if statInfo.Mode&syscall.S_IFMT != syscall.S_IFDIR {
		// Not a directory; return the error from the Remove
		return err
	}

	// Remove the directory's entries
	var recurseErr error
	for {
		const request = 1024

		// Open the directory to recurse into
		file, err := openFdAt(parentFd, path)
		if err != nil {
			if IsNotExist(err) {
				return nil
			}
			return err
		}

		names, readErr := file.Readdirnames(request)
		// Errors other than EOF should stop us from continuing
		if readErr != nil && readErr != io.EOF {
			file.Close()
			if IsNotExist(readErr) {
				return nil
			}
			return readErr
		}

		for _, name := range names {
			err := removeAllFrom(file, name)
			if err != nil {
				recurseErr = err
			}
		}

		// Removing files from the directory may have caused
		// the OS to reshuffle it. Simply calling Readdirnames
		// again may skip some entries. The only reliable way
		// to avoid this is to close and re-open the
		// directory. See issue 20841.
		file.Close()

		// Finish when the end of the directory is reached
		if len(names) < request {
			break
		}
	}

	// Remove the directory itself
	unlinkError := unix.Unlinkat(parentFd, path, unix.AT_REMOVEDIR)
	if unlinkError == nil || IsNotExist(unlinkError) {
		return nil
	}

	if recurseErr != nil {
		return recurseErr
	}
	return unlinkError
}

func openFdAt(fd int, path string) (*File, error) {
	fd, err := unix.Openat(fd, path, O_RDONLY, 0)
	if err != nil {
		return nil, err
	}

	return NewFile(uintptr(fd), path), nil
}

// endsWithDot returns whether the final component of path is ".".
func endsWithDot(path string) bool {
	if path == "." {
		return true
	}
	if len(path) >= 2 && path[len(path)-1] == '.' && IsPathSeparator(path[len(path)-2]) {
		return true
	}
	return false
}
<commit_msg>os: return PathError on RemoveAll with trailing dots<commit_after>// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris

package os

import (
	"internal/syscall/unix"
	"io"
	"syscall"
)

func RemoveAll(path string) error {
	if path == "" {
		// fail silently to retain compatibility with previous behavior
		// of RemoveAll. See issue 28830.
		return nil
	}

	// The rmdir system call does not permit removing ".",
	// so we don't permit it either.
	if endsWithDot(path) {
		return &PathError{"RemoveAll", path, syscall.EINVAL}
	}

	// RemoveAll recurses by deleting the path base from
	// its parent directory
	parentDir, base := splitPath(path)

	parent, err := Open(parentDir)
	if IsNotExist(err) {
		// If parent does not exist, base cannot exist. Fail silently
		return nil
	}
	if err != nil {
		return err
	}
	defer parent.Close()

	return removeAllFrom(parent, base)
}

func removeAllFrom(parent *File, path string) error {
	parentFd := int(parent.Fd())
	// Simple case: if Unlink (aka remove) works, we're done.
	err := unix.Unlinkat(parentFd, path, 0)
	if err == nil || IsNotExist(err) {
		return nil
	}

	// If not a "is directory" error, we have a problem
	if err != syscall.EISDIR && err != syscall.EPERM {
		return err
	}

	// Is this a directory we need to recurse into?
	var statInfo syscall.Stat_t
	statErr := unix.Fstatat(parentFd, path, &statInfo, unix.AT_SYMLINK_NOFOLLOW)
	if statErr != nil {
		return statErr
	}
	if statInfo.Mode&syscall.S_IFMT != syscall.S_IFDIR {
		// Not a directory; return the error from the Remove
		return err
	}

	// Remove the directory's entries
	var recurseErr error
	for {
		const request = 1024

		// Open the directory to recurse into
		file, err := openFdAt(parentFd, path)
		if err != nil {
			if IsNotExist(err) {
				return nil
			}
			return err
		}

		names, readErr := file.Readdirnames(request)
		// Errors other than EOF should stop us from continuing
		if readErr != nil && readErr != io.EOF {
			file.Close()
			if IsNotExist(readErr) {
				return nil
			}
			return readErr
		}

		for _, name := range names {
			err := removeAllFrom(file, name)
			if err != nil {
				recurseErr = err
			}
		}

		// Removing files from the directory may have caused
		// the OS to reshuffle it. Simply calling Readdirnames
		// again may skip some entries. The only reliable way
		// to avoid this is to close and re-open the
		// directory. See issue 20841.
		file.Close()

		// Finish when the end of the directory is reached
		if len(names) < request {
			break
		}
	}

	// Remove the directory itself
	unlinkError := unix.Unlinkat(parentFd, path, unix.AT_REMOVEDIR)
	if unlinkError == nil || IsNotExist(unlinkError) {
		return nil
	}

	if recurseErr != nil {
		return recurseErr
	}
	return unlinkError
}

func openFdAt(fd int, path string) (*File, error) {
	fd, err := unix.Openat(fd, path, O_RDONLY, 0)
	if err != nil {
		return nil, err
	}

	return NewFile(uintptr(fd), path), nil
}

// endsWithDot returns whether the final component of path is ".".
func endsWithDot(path string) bool {
	if path == "." {
		return true
	}
	if len(path) >= 2 && path[len(path)-1] == '.' && IsPathSeparator(path[len(path)-2]) {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>// Copyright 2016 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package sublime

import (
	"io/ioutil"
	"os"
	"path"

	"github.com/limetext/lime-backend/lib"
	"github.com/limetext/lime-backend/lib/keys"
	"github.com/limetext/lime-backend/lib/log"
	"github.com/limetext/lime-backend/lib/packages"
	"github.com/limetext/text"
)

// A sublime package
type pkg struct {
	dir string
	text.HasSettings
	keys.HasKeyBindings
	platformSet *text.HasSettings
	defaultSet  *text.HasSettings
	defaultKB   *keys.HasKeyBindings
	plugins     map[string]*plugin
	// TODO: themes, snippets, etc more info on iss#71
}

func newPKG(dir string) packages.Package {
	return &pkg{
		dir:         dir,
		platformSet: new(text.HasSettings),
		defaultSet:  new(text.HasSettings),
		defaultKB:   new(keys.HasKeyBindings),
		plugins:     make(map[string]*plugin),
	}
}

func (p *pkg) Load() {
	log.Debug("Loading package %s", p.Name())
	p.loadKeyBindings()
	p.loadSettings()
	p.loadPlugins()
}

func (p *pkg) Name() string {
	return p.dir
}

// TODO: how we should watch the package and the files containing?
func (p *pkg) FileCreated(name string) {
	p.loadPlugin(name)
}

func (p *pkg) loadPlugins() {
	log.Fine("Loading %s plugins", p.Name())
	fis, err := ioutil.ReadDir(p.Name())
	if err != nil {
		log.Warn("Error on reading directory %s, %s", p.Name(), err)
		return
	}
	for _, fi := range fis {
		if isPlugin(fi.Name()) {
			p.loadPlugin(path.Join(p.Name(), fi.Name()))
		}
	}
}

func (p *pkg) loadPlugin(fn string) {
	if _, exist := p.plugins[fn]; exist {
		return
	}

	pl := newPlugin(fn)
	pl.Load()

	p.plugins[fn] = pl.(*plugin)
}

func (p *pkg) loadKeyBindings() {
	log.Fine("Loading %s keybindings", p.Name())
	ed := backend.GetEditor()
	tmp := ed.KeyBindings().Parent()

	ed.KeyBindings().SetParent(p)
	p.KeyBindings().SetParent(p.defaultKB)
	p.defaultKB.KeyBindings().SetParent(tmp)

	pt := path.Join(p.dir, "Default.sublime-keymap")
	packages.NewJSONL(pt, p.defaultKB.KeyBindings())

	pt = path.Join(p.dir, "Default ("+ed.Plat()+").sublime-keymap")
	packages.NewJSONL(pt, p.KeyBindings())
}

func (p *pkg) loadSettings() {
	log.Fine("Loading %s settings", p.Name())
	ed := backend.GetEditor()
	tmp := ed.Settings().Parent()

	ed.Settings().SetParent(p)
	p.Settings().SetParent(p.platformSet)
	p.platformSet.Settings().SetParent(p.defaultSet)
	p.defaultSet.Settings().SetParent(tmp)

	pt := path.Join(p.dir, "Preferences.sublime-settings")
	packages.NewJSONL(pt, p.defaultSet.Settings())

	pt = path.Join(p.dir, "Preferences ("+ed.Plat()+").sublime-settings")
	packages.NewJSONL(pt, p.platformSet.Settings())

	pt = path.Join(ed.PackagesPath("user"), "Preferences.sublime-settings")
	packages.NewJSONL(pt, p.Settings())
}

// Any directory in sublime is a package
func isPKG(dir string) bool {
	fi, err := os.Stat(dir)
	if err != nil || !fi.IsDir() {
		return false
	}
	return true
}

var packageRecord *packages.Record = &packages.Record{isPKG, newPKG}

func init() {
	packages.Register(packageRecord)
}
<commit_msg>renamed defaultSet & platformSet variables<commit_after>// Copyright 2016 The lime Authors.
// Use of this source code is governed by a 2-clause
// BSD-style license that can be found in the LICENSE file.

package sublime

import (
	"io/ioutil"
	"os"
	"path"

	"github.com/limetext/lime-backend/lib"
	"github.com/limetext/lime-backend/lib/keys"
	"github.com/limetext/lime-backend/lib/log"
	"github.com/limetext/lime-backend/lib/packages"
	"github.com/limetext/text"
)

// A sublime package
type pkg struct {
	dir string
	text.HasSettings
	keys.HasKeyBindings
	platformSettings *text.HasSettings
	defaultSettings  *text.HasSettings
	defaultKB        *keys.HasKeyBindings
	plugins          map[string]*plugin
	// TODO: themes, snippets, etc more info on iss#71
}

func newPKG(dir string) packages.Package {
	return &pkg{
		dir:              dir,
		platformSettings: new(text.HasSettings),
		defaultSettings:  new(text.HasSettings),
		defaultKB:        new(keys.HasKeyBindings),
		plugins:          make(map[string]*plugin),
	}
}

func (p *pkg) Load() {
	log.Debug("Loading package %s", p.Name())
	p.loadKeyBindings()
	p.loadSettings()
	p.loadPlugins()
}

func (p *pkg) Name() string {
	return p.dir
}

// TODO: how we should watch the package and the files containing?
func (p *pkg) FileCreated(name string) {
	p.loadPlugin(name)
}

func (p *pkg) loadPlugins() {
	log.Fine("Loading %s plugins", p.Name())
	fis, err := ioutil.ReadDir(p.Name())
	if err != nil {
		log.Warn("Error on reading directory %s, %s", p.Name(), err)
		return
	}
	for _, fi := range fis {
		if isPlugin(fi.Name()) {
			p.loadPlugin(path.Join(p.Name(), fi.Name()))
		}
	}
}

func (p *pkg) loadPlugin(fn string) {
	if _, exist := p.plugins[fn]; exist {
		return
	}

	pl := newPlugin(fn)
	pl.Load()

	p.plugins[fn] = pl.(*plugin)
}

func (p *pkg) loadKeyBindings() {
	log.Fine("Loading %s keybindings", p.Name())
	ed := backend.GetEditor()
	tmp := ed.KeyBindings().Parent()

	ed.KeyBindings().SetParent(p)
	p.KeyBindings().SetParent(p.defaultKB)
	p.defaultKB.KeyBindings().SetParent(tmp)

	pt := path.Join(p.Name(), "Default.sublime-keymap")
	packages.NewJSONL(pt, p.defaultKB.KeyBindings())

	pt = path.Join(p.Name(), "Default ("+ed.Plat()+").sublime-keymap")
	packages.NewJSONL(pt, p.KeyBindings())
}

func (p *pkg) loadSettings() {
	log.Fine("Loading %s settings", p.Name())
	ed := backend.GetEditor()
	tmp := ed.Settings().Parent()

	ed.Settings().SetParent(p)
	p.Settings().SetParent(p.platformSettings)
	p.platformSettings.Settings().SetParent(p.defaultSettings)
	p.defaultSettings.Settings().SetParent(tmp)

	pt := path.Join(p.Name(), "Preferences.sublime-settings")
	packages.NewJSONL(pt, p.defaultSettings.Settings())

	pt = path.Join(p.Name(), "Preferences ("+ed.Plat()+").sublime-settings")
	packages.NewJSONL(pt, p.platformSettings.Settings())

	pt = path.Join(ed.PackagesPath("user"), "Preferences.sublime-settings")
	packages.NewJSONL(pt, p.Settings())
}

// Any directory in sublime is a package
func isPKG(dir string) bool {
	fi, err := os.Stat(dir)
	if err != nil || !fi.IsDir() {
		return false
	}
	return true
}

var packageRecord *packages.Record = &packages.Record{isPKG, newPKG}

func init() {
	packages.Register(packageRecord)
}
<|endoftext|>


<commit_before>// +build appengine

package rest

import (
	"github.com/bradberger/context"

	"google.golang.org/appengine/log"
)

// Criticalf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed
var Criticalf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Criticalf(ctx, format, args...)
}

// Debugf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed
var Debugf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Debugf(ctx, format, args...)
}

// Errorf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed
var Errorf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Errorf(ctx, format, args...)
}

// Infof is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed
var Infof LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Infof(ctx, format, args...)
}

// Warningf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed
var Warningf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Warningf(ctx, format, args...)
}

// Fatalf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed
var Fatalf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Fatalf(ctx, format, args...)
}
<commit_msg>Removes invalid function<commit_after>// +build appengine

package rest

import (
	"github.com/bradberger/context"

	"google.golang.org/appengine/log"
)

// Criticalf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed
var Criticalf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Criticalf(ctx, format, args...)
}

// Debugf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed
var Debugf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Debugf(ctx, format, args...)
}

// Errorf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed
var Errorf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Errorf(ctx, format, args...)
}

// Infof is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed
var Infof LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Infof(ctx, format, args...)
}

// Warningf is shorthand for the appeninge/log func with the same name, with the added advantage that it's a variable and can be overridden if needed
var Warningf LogFunc = func(ctx context.Context, format string, args ...interface{}) {
	log.Warningf(ctx, format, args...)
}
<|endoftext|>


<commit_before>package logger

import (
	"bytes"
	"fmt"
	"github.com/mgutz/ansi"
)

//Info output a green text line
func Info(f string, args ...interface{}) {
	fmt.Printf(Colorize(f, "green")+"\n", args...)
}

//Warn output a red text line
func Warn(f string, args ...interface{}) {
	fmt.Printf(Colorize(f, "red")+"\n", args...)
}

//Colorize use the Ansi module to colorize output
func Colorize(str, style string) string {
	return ansi.Color(str, style)
}

//FormatTextProtocol replace NULL by a line break for output formatting
func FormatTextProtocol(protocol []byte) []byte {
	return bytes.Trim(bytes.Replace(protocol, []byte("\x00"), []byte("\n"), -1), "\n")
}
<commit_msg>[TASK] Add Debug function in Logger module<commit_after>package logger

import (
	"bytes"
	"fmt"
	"github.com/mgutz/ansi"
)

var (
	debugize = ansi.ColorFunc("green+h:black")
	greenize = ansi.ColorFunc("green")
	redize   = ansi.ColorFunc("red")
)

//Debug output a debug text
func Debug(f string, args ...interface{}) {
	fmt.Printf(debugize("[DEBUG] "+f)+"\n", args...)
}

//Info output a green text line
func Info(f string, args ...interface{}) {
	fmt.Printf(greenize(f)+"\n", args...)
}

//Warn output a red text line
func Warn(f string, args ...interface{}) {
	fmt.Printf(redize(f)+"\n", args...)
}

//Colorize use the Ansi module to colorize output
func Colorize(str, style string) string {
	return ansi.Color(str, style)
}

//FormatTextProtocol replace NULL by a line break for output formatting
func FormatTextProtocol(protocol []byte) []byte {
	return bytes.Trim(bytes.Replace(protocol, []byte("\x00"), []byte("\n"), -1), "\n")
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"fmt"
	goquery "github.com/PuerkitoBio/goquery"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"time"
)

func checkError(err error) {
	if err != nil {
		panic(err)
		os.Exit(1)
	}
}

func getCurrentDirectory() string {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	checkError(err)
	return dir
}

type Currency struct {
	Name   string
	Source string
}

type Email struct {
	Addr string
}

type Config struct {
	Currencys    []Currency
	Emails       []Email
	SMTPServer   string
	SMTPMail     string
	SMTPPassword string
}

func main() {
	mailBody := time.Now().Format("060102")
	var cfg Config
	var err error
	//fmt.Println(getCurrentDirectory())
	cfgFile, err := os.Open(getCurrentDirectory() + `/config.json`)
	checkError(err)
	defer cfgFile.Close()
	cfgJSON, _ := ioutil.ReadAll(cfgFile)
	json.Unmarshal(cfgJSON, &cfg)

	fmt.Println("\n ** Currencys:")
	for _, currency := range cfg.Currencys {
		fmt.Println(currency.Name + " | " + currency.Source)
		docEachCurrency, err := goquery.NewDocument(currency.Source)
		checkError(err)
		selEachCurrency := docEachCurrency.Find(`div.rate`).First()
		//fmt.Println(selEachCurrency.Text())
		eachCurrency := regexp.MustCompile(`\s`).
			ReplaceAllString(selEachCurrency.Text(), ``)
		if matched, _ := regexp.MatchString(`\d+\.\d+\/\d+\.\d+.*`, eachCurrency); matched {
			fmt.Println(`    ** match a format`)
			fmt.Println(eachCurrency)
			eachCurrency = regexp.MustCompile(`.*\/(\d+\.\d+).*`).
				ReplaceAllString(eachCurrency, `$1`)
			fmt.Println(eachCurrency)
		} else {
			fmt.Println(`    ** not match the format`)
			fmt.Println(eachCurrency)
			eachCurrency = regexp.MustCompile(`.*(\d+\.\d+).*`).
				ReplaceAllString(eachCurrency, `$1`)
			fmt.Println(eachCurrency)
			f, err := strconv.ParseFloat(eachCurrency, 32)
			checkError(err)
			eachCurrency = strconv.FormatFloat(1/f, 'f', 4, 32)
		}
		eachCurrency = currency.Name + ": " + eachCurrency
		mailBody += "\r\n" + eachCurrency
	}
	fmt.Println("\n ** mailBody:\n" + mailBody)

	fmt.Println("\n ** Emails:")
	for _, email := range cfg.Emails {
		fmt.Println(email.Addr)
		fmt.Println(" *** send email")
		for i := 0; i < 10; i++ {
			err = sendToMail(
				cfg.SMTPMail,     /*fromMail*/
				"银联汇率",           /*fromName*/
				cfg.SMTPPassword, /*password*/
				cfg.SMTPServer,   /*smtpServer*/
				email.Addr,
				"",     /*toName*/
				"常见币种", /*subject*/
				mailBody)
			if err == nil {
				fmt.Println("Send mail success!")
				break
			} else {
				fmt.Printf("Send mail fail! Retry %d\n", i)
			}
		}
		checkError(err)
	}
}
<commit_msg>\n is better<commit_after>package main

import (
	"encoding/json"
	"fmt"
	goquery "github.com/PuerkitoBio/goquery"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"time"
)

func checkError(err error) {
	if err != nil {
		panic(err)
		os.Exit(1)
	}
}

func getCurrentDirectory() string {
	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	checkError(err)
	return dir
}

type Currency struct {
	Name   string
	Source string
}

type Email struct {
	Addr string
}

type Config struct {
	Currencys    []Currency
	Emails       []Email
	SMTPServer   string
	SMTPMail     string
	SMTPPassword string
}

func main() {
	mailBody := time.Now().Format("060102")
	var cfg Config
	var err error
	//fmt.Println(getCurrentDirectory())
	cfgFile, err := os.Open(getCurrentDirectory() + `/config.json`)
	checkError(err)
	defer cfgFile.Close()
	cfgJSON, _ := ioutil.ReadAll(cfgFile)
	json.Unmarshal(cfgJSON, &cfg)

	fmt.Println("\n ** Currencys:")
	for _, currency := range cfg.Currencys {
		fmt.Println(currency.Name + " | " + currency.Source)
		docEachCurrency, err := goquery.NewDocument(currency.Source)
		checkError(err)
		selEachCurrency := docEachCurrency.Find(`div.rate`).First()
		//fmt.Println(selEachCurrency.Text())
		eachCurrency := regexp.MustCompile(`\s`).
			ReplaceAllString(selEachCurrency.Text(), ``)
		if matched, _ := regexp.MatchString(`\d+\.\d+\/\d+\.\d+.*`, eachCurrency); matched {
			fmt.Println(`    ** match a format`)
			fmt.Println(eachCurrency)
			eachCurrency = regexp.MustCompile(`.*\/(\d+\.\d+).*`).
				ReplaceAllString(eachCurrency, `$1`)
			fmt.Println(eachCurrency)
		} else {
			fmt.Println(`    ** not match the format`)
			fmt.Println(eachCurrency)
			eachCurrency = regexp.MustCompile(`.*(\d+\.\d+).*`).
				ReplaceAllString(eachCurrency, `$1`)
			fmt.Println(eachCurrency)
			f, err := strconv.ParseFloat(eachCurrency, 32)
			checkError(err)
			eachCurrency = strconv.FormatFloat(1/f, 'f', 4, 32)
		}
		eachCurrency = currency.Name + ": " + eachCurrency
		mailBody += "\n" + eachCurrency
	}
	fmt.Println("\n ** mailBody:\n" + mailBody)

	fmt.Println("\n ** Emails:")
	for _, email := range cfg.Emails {
		fmt.Println(email.Addr)
		fmt.Println(" *** send email")
		for i := 0; i < 10; i++ {
			err = sendToMail(
				cfg.SMTPMail,     /*fromMail*/
				"银联汇率",           /*fromName*/
				cfg.SMTPPassword, /*password*/
				cfg.SMTPServer,   /*smtpServer*/
				email.Addr,
				"",     /*toName*/
				"常见币种", /*subject*/
				mailBody)
			if err == nil {
				fmt.Println("Send mail success!")
				break
			} else {
				fmt.Printf("Send mail fail! Retry %d\n", i)
			}
		}
		checkError(err)
	}
}
<|endoftext|>


<commit_before>package ogdat

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"
)

const (
	Info    = 1 << iota
	Warning = 1 << iota
	Error   = 1 << iota
)

const (
	StructuralError  = 0x8000
	NoDataatUrlError = 0x4000
	FetchableUrl     = 0x2000
	FetchSuccess     = 0x1000
)

var isolangfilemap map[string]*ISO6392Lang = nil

type ISO6392Lang struct {
	Code, Identifier string
}

func CheckISOLanguage(lang string) bool {
	const iso639file = "ISO-639-2_utf-8.txt"
	if isolangfilemap == nil {
		var err error
		if isolangfilemap, err = loadisolanguagefile(iso639file); err != nil {
			panic(fmt.Sprintf("Can not load ISO language file '%s'", iso639file))
		}
	}
	_, ok := isolangfilemap[lang]
	return ok
}

// copmpare input against a slice of check strings.
// input will first be converted to lower-case, and any occurence of "-" is removed.
// The slice of checks will be iterated over,
// individual elements of check will not be converted or have their "-" removed.
func CheckEncodingString(input string, check []string) bool {
	input = strings.ToLower(strings.Replace(input, "-", "", -1))
	for _, val := range check {
		if input == val {
			return true
		}
	}
	return false
}

func loadisolanguagefile(filename string) (isolangfilemap map[string]*ISO6392Lang, _ error) {

	reader, err := os.Open(filename)
	if err != nil {
		return nil, err
	}

	defer reader.Close()
	isolangfilemap = make(map[string]*ISO6392Lang)
	csvreader := csv.NewReader(reader)
	csvreader.Comma = '|'

	for record, err := csvreader.Read(); err != io.EOF; record, err = csvreader.Read() {
		isorecord := &ISO6392Lang{Code: record[0], Identifier: record[3]}
		isolangfilemap[isorecord.Code] = isorecord
		if len(record[1]) > 0 {
			isorecord = &ISO6392Lang{Code: record[1], Identifier: record[3]}
			isolangfilemap[record[1]] = isorecord
		}
	}
	log.Printf("Info: Read %d ISO language records", len(isolangfilemap))

	return
}

var ianaencmap map[string]struct{} = nil

// CheckIANAEncoding will try to match and input of enc against the specified encodings found at http://www.iana.org/assignments/character-sets/character-sets.xml
// The file at http://www.iana.org/assignments/character-sets/character-sets.xml is retrieved by a shell scripte,
// converted to all-lower case and sorted for unique entries. Thus the encoding enc against which will be checked,
// is converted to lower case and then compared to the IANA-encodings
func CheckIANAEncoding(enc string) bool {
	const ianaencfile = "character-sets.txt"
	if ianaencmap == nil {
		var err error
		if ianaencmap, err = loadianaencodingfile(ianaencfile); err != nil {
			panic(fmt.Sprintf("Can not load IANA encoding definition file '%s': %s", ianaencfile, err))
		}
	}
	enc = strings.ToLower(enc)
	_, ok := ianaencmap[enc]
	if !ok {
		enc = strings.Replace(enc, "-", "", -1)
		_, ok = ianaencmap[enc]
	}
	return ok
}

func loadianaencodingfile(filename string) (ianamap map[string]struct{}, _ error) {
	reader, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer reader.Close()

	ianamap = make(map[string]struct{})
	bufreader := bufio.NewReader(reader)
	delim := byte('\n')

	for line, err := bufreader.ReadString(delim); err != io.EOF; line, err = bufreader.ReadString(delim) {
		// ReadString includes the delimeter, get rid of it
		line = line[:len(line)-1]
		// normalize by lower casing
		line = strings.ToLower(line)

		ianamap[line] = struct{}{}
	}
	log.Printf("Info: Read %d IANA encoding names", len(ianamap))
	return
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

type CheckInfo struct {
	Status, Position int
	Context          string
}

func (c *CheckInfo) Error() string {
	return c.Context
}

func strrange(minrange, maxrange, idx int, s string) string {
	if minrange > maxrange {
		panic("minrange > maxrange")
	}

	if idx > len(s) {
		idx = len(s)
	}

	var prepend string
	start := idx + minrange
	if start < 0 {
		start = 0
	} else {
		prepend = "..."
	}

	var postpone string
	end := idx + maxrange
	if end > len(s) {
		end = len(s)
	} else {
		postpone = "..."
	}
	middle := s[start:end]
	if !utf8.ValidString(middle) {
		var s string
		for len(middle) > 0 {
			r, size := utf8.DecodeRuneInString(middle)
			s += string(r)
			middle = middle[size:]
		}
		middle = s
	}
	return prepend + middle + postpone
}

var regexphtmlcodecheck = regexp.MustCompile(`</{0,1}\w+.*('|"|)>`)
var regexphtmlescape = regexp.MustCompile(`&\w{1,10};|&#\d{1,6};`)
var regexpurlencode = regexp.MustCompile(`%[0-9a-fA-F][0-9a-fA-F]`)
var regexpposixescape = regexp.MustCompile(`\\n|\\b|\\v|\\t|\\r`)

// return values are:
// ok = false indicates sthg. was wrong in which case error will not be nil
//
// error: if is of type CheckError:
// Status: 1 = Info, 2 = Warning, 3 = Error
// Position: beginning position of offending input
// message: An error message describing the problem
func CheckOGDTextStringForSaneCharacters(str string) (ok bool, _ error) {
	if !utf8.ValidString(str) {
		return false, &CheckInfo{Error, 0, "Zeichenfolge ist nicht durchgängig gültig als UTF8 kodiert"}
	}
	for idx, val := range str {
		if val == unicode.ReplacementChar {
			return false, &CheckInfo{Error, idx, fmt.Sprintf("Ungültige Unicode-Sequenz: '0x%x' (Bereich '%s')", val, strrange(-20, 20, idx, str))}
		}
	}

	if idx := regexphtmlcodecheck.FindStringIndex(str); idx != nil {
		return false, &CheckInfo{Warning, idx[0], fmt.Sprintf("Mögliche HTML-Sequenz: '%s'", strrange(-10, 10, idx[0], str))}
	}
	if idx := regexphtmlescape.FindStringIndex(str); idx != nil {
		return false, &CheckInfo{Warning, idx[0], fmt.Sprintf("Mögliche HTML-Escapes: '%s'", strrange(-8, 8, idx[0], str))}
	}
	if idx := regexpurlencode.FindStringIndex(str); idx != nil {
		return false, &CheckInfo{Warning, idx[0], fmt.Sprintf("Mögliche Url-Escapes: '%s'", strrange(-6, 6, idx[0], str))}
	}
	if idx := regexpposixescape.FindStringIndex(str); idx != nil {
		return false, &CheckInfo{Warning, idx[0], fmt.Sprintf("Mögliche Posix-Escapes: '%s'", strrange(-6, 6, idx[0], str))}
	}
	return true, nil
}

var regexpEMail = regexp.MustCompile(`(?i)^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$`)

func FetchHead(url string) (bool, CheckInfo) {

	var info CheckInfo
	var err error
	var resp *http.Response

	for i := 0; i < 2; i++ {
		if i == 0 {
			resp, err = http.Head(url)
		} else {
			resp, err = http.Get(url)
		}
		if err != nil || resp.StatusCode != 200 {
			continue
		} else {
			break
		}
	}

	if err != nil {
		info = CheckInfo{Status: Error | FetchableUrl | NoDataatUrlError, Position: -1, Context: fmt.Sprintf("'%s': URL kann nicht aufgelöst werden: '%s'", url, err)}
	} else if sc := resp.StatusCode; sc != 200 {
		info = CheckInfo{Status: Error | FetchableUrl | NoDataatUrlError, Position: -1, Context: fmt.Sprintf("'%s': Request liefert nicht-OK Statuscode '%d'", url, sc)}
	} else {
		info = CheckInfo{Status: Info | FetchableUrl | FetchSuccess, Position: -1, Context: url}
	}

	return (info.Status & (Info | FetchSuccess)) == (Info | FetchSuccess), info
}

func CheckUrl(url string, followhttplink bool) (bool, []CheckInfo) {
	// it's a contact point if it's a http-link (starts with "http(s)" )
	var checkmessages []CheckInfo
	if len(url) >= 4 && url[:4] == "http" {
		urlinfo := CheckInfo{Info | FetchableUrl, -1, url}
		checkmessages = append(checkmessages, urlinfo)

		ok := true
		if followhttplink {
			ok, urlinfo = FetchHead(urlinfo.Context)
			checkmessages = append(checkmessages, urlinfo)
		}
		return ok, checkmessages
	}
	// it's a contact point if it's an email address
	if idx := regexpEMail.FindStringIndex(url); idx != nil {
		return true, nil
	}

	if len(url) == 0 {
		checkmessages = append(checkmessages, CheckInfo{Status: Error, Position: -1, Context: "kein Wert für Link angegeben (Länge 0)"})
		return false, checkmessages
	}

	checkmessages = append(checkmessages, CheckInfo{Status: Warning, Position: -1, Context: fmt.Sprintf("vermutlich keine gültige Web- oder E-Mail Adresse: '%s' (Auszug)", url[:min(20, len(url))])})

	return false, checkmessages
}

func CheckDataPortalUrl(url string, followhttplink bool) (bool, []CheckInfo) {
	const checkDataPortalUrlstrpart = `://data.`

	ok1, checkmessages := CheckUrl(url, followhttplink)
	ok2 := strings.Contains(url, checkDataPortalUrlstrpart)
	if !ok2 {
		checkmessages = append(checkmessages, CheckInfo{Status: Warning, Position: -1, Context: fmt.Sprintf("Link zum ursprünglichen Datenportal folgt nicht der Konvention ress://data.[....]: %s (Auszug)", url[:min(20, len(url))])})
	}

	return ok1 == true && ok2 == true, checkmessages
}

type CheckMessage struct {
	Type    int // 1 = Info, 2 = Warning, 4 = Error, ...
	Text    string
	OGDID   int
	Context string
}

func AppendcheckerrorTocheckmessage(msgs []CheckMessage, checkresults []CheckInfo, ID int, prepend string) []CheckMessage {
	for _, result := range checkresults {
		msgs = append(msgs, CheckMessage{
			Type:  result.Status,
			OGDID: ID,
			Text:  prepend + result.Context})
	}
	return msgs
}

func Loadogdatspec(version, filename string) (*OGDSet, error) {
	reader, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer reader.Close()

	csvreader := csv.NewReader(reader)
	csvreader.Comma = '|'
	csvreader.LazyQuotes = true

	// Read the first line and use it as the labels for the items to load
	record, err := csvreader.Read()
	if err != nil {
		return nil, err
	}

	set := &OGDSet{Label: record}

	spec := make([]*Beschreibung, 0)
	for record, err = csvreader.Read(); err != io.EOF; record, err = csvreader.Read() {
		id, _ := strconv.Atoi(record[0])
		var occ Occurrence
		switch record[12][0] {
		case 'R':
			occ = OccRequired
		case 'O':
			occ = OccOptional
		}
		descrecord := NewBeschreibung(id, occ, version)

		descrecord.Bezeichner = record[1]
		descrecord.OGD_Kurzname = record[2]
		descrecord.CKAN_Feld = record[3]
		descrecord.Anzahl = record[4]
		descrecord.Definition_DE = record[5]
		descrecord.Erlauterung = record[6]
		descrecord.Beispiel = record[7]
		descrecord.ONA2270 = record[8]
		descrecord.ISO19115 = record[9]
		descrecord.RDFProperty = record[10]
		descrecord.Definition_EN = record[11]

		spec = append(spec, descrecord)
	}
	set.Beschreibung = spec
	log.Printf("Info: Read %d %s specification records", len(spec), version)

	return set, nil
}
<commit_msg>do not enclose links in Quotation marks and do not append them with a colon<commit_after>package ogdat

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"regexp"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"
)

const (
	Info    = 1 << iota
	Warning = 1 << iota
	Error   = 1 << iota
)

const (
	StructuralError  = 0x8000
	NoDataatUrlError = 0x4000
	FetchableUrl     = 0x2000
	FetchSuccess     = 0x1000
)

var isolangfilemap map[string]*ISO6392Lang = nil

type ISO6392Lang struct {
	Code, Identifier string
}

func CheckISOLanguage(lang string) bool {
	const iso639file = "ISO-639-2_utf-8.txt"
	if isolangfilemap == nil {
		var err error
		if isolangfilemap, err = loadisolanguagefile(iso639file); err != nil {
			panic(fmt.Sprintf("Can not load ISO language file '%s'", iso639file))
		}
	}
	_, ok := isolangfilemap[lang]
	return ok
}

// copmpare input against a slice of check strings.
// input will first be converted to lower-case, and any occurence of "-" is removed.
// The slice of checks will be iterated over,
// individual elements of check will not be converted or have their "-" removed.
func CheckEncodingString(input string, check []string) bool {
	input = strings.ToLower(strings.Replace(input, "-", "", -1))
	for _, val := range check {
		if input == val {
			return true
		}
	}
	return false
}

func loadisolanguagefile(filename string) (isolangfilemap map[string]*ISO6392Lang, _ error) {

	reader, err := os.Open(filename)
	if err != nil {
		return nil, err
	}

	defer reader.Close()
	isolangfilemap = make(map[string]*ISO6392Lang)
	csvreader := csv.NewReader(reader)
	csvreader.Comma = '|'

	for record, err := csvreader.Read(); err != io.EOF; record, err = csvreader.Read() {
		isorecord := &ISO6392Lang{Code: record[0], Identifier: record[3]}
		isolangfilemap[isorecord.Code] = isorecord
		if len(record[1]) > 0 {
			isorecord = &ISO6392Lang{Code: record[1], Identifier: record[3]}
			isolangfilemap[record[1]] = isorecord
		}
	}
	log.Printf("Info: Read %d ISO language records", len(isolangfilemap))

	return
}

var ianaencmap map[string]struct{} = nil

// CheckIANAEncoding will try to match and input of enc against the specified encodings found at http://www.iana.org/assignments/character-sets/character-sets.xml
// The file at http://www.iana.org/assignments/character-sets/character-sets.xml is retrieved by a shell scripte,
// converted to all-lower case and sorted for unique entries. Thus the encoding enc against which will be checked,
// is converted to lower case and then compared to the IANA-encodings
func CheckIANAEncoding(enc string) bool {
	const ianaencfile = "character-sets.txt"
	if ianaencmap == nil {
		var err error
		if ianaencmap, err = loadianaencodingfile(ianaencfile); err != nil {
			panic(fmt.Sprintf("Can not load IANA encoding definition file '%s': %s", ianaencfile, err))
		}
	}
	enc = strings.ToLower(enc)
	_, ok := ianaencmap[enc]
	if !ok {
		enc = strings.Replace(enc, "-", "", -1)
		_, ok = ianaencmap[enc]
	}
	return ok
}

func loadianaencodingfile(filename string) (ianamap map[string]struct{}, _ error) {
	reader, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer reader.Close()

	ianamap = make(map[string]struct{})
	bufreader := bufio.NewReader(reader)
	delim := byte('\n')

	for line, err := bufreader.ReadString(delim); err != io.EOF; line, err = bufreader.ReadString(delim) {
		// ReadString includes the delimeter, get rid of it
		line = line[:len(line)-1]
		// normalize by lower casing
		line = strings.ToLower(line)

		ianamap[line] = struct{}{}
	}
	log.Printf("Info: Read %d IANA encoding names", len(ianamap))
	return
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

type CheckInfo struct {
	Status, Position int
	Context          string
}

func (c *CheckInfo) Error() string {
	return c.Context
}

func strrange(minrange, maxrange, idx int, s string) string {
	if minrange > maxrange {
		panic("minrange > maxrange")
	}

	if idx > len(s) {
		idx = len(s)
	}

	var prepend string
	start := idx + minrange
	if start < 0 {
		start = 0
	} else {
		prepend = "..."
	}

	var postpone string
	end := idx + maxrange
	if end > len(s) {
		end = len(s)
	} else {
		postpone = "..."
	}
	middle := s[start:end]
	if !utf8.ValidString(middle) {
		var s string
		for len(middle) > 0 {
			r, size := utf8.DecodeRuneInString(middle)
			s += string(r)
			middle = middle[size:]
		}
		middle = s
	}
	return prepend + middle + postpone
}

var regexphtmlcodecheck = regexp.MustCompile(`</{0,1}\w+.*('|"|)>`)
var regexphtmlescape = regexp.MustCompile(`&\w{1,10};|&#\d{1,6};`)
var regexpurlencode = regexp.MustCompile(`%[0-9a-fA-F][0-9a-fA-F]`)
var regexpposixescape = regexp.MustCompile(`\\n|\\b|\\v|\\t|\\r`)

// return values are:
// ok = false indicates sthg. was wrong in which case error will not be nil
//
// error: if is of type CheckError:
// Status: 1 = Info, 2 = Warning, 3 = Error
// Position: beginning position of offending input
// message: An error message describing the problem
func CheckOGDTextStringForSaneCharacters(str string) (ok bool, _ error) {
	if !utf8.ValidString(str) {
		return false, &CheckInfo{Error, 0, "Zeichenfolge ist nicht durchgängig gültig als UTF8 kodiert"}
	}
	for idx, val := range str {
		if val == unicode.ReplacementChar {
			return false, &CheckInfo{Error, idx, fmt.Sprintf("Ungültige Unicode-Sequenz: '0x%x' (Bereich '%s')", val, strrange(-20, 20, idx, str))}
		}
	}

	if idx := regexphtmlcodecheck.FindStringIndex(str); idx != nil {
		return false, &CheckInfo{Warning, idx[0], fmt.Sprintf("Mögliche HTML-Sequenz: '%s'", strrange(-10, 10, idx[0], str))}
	}
	if idx := regexphtmlescape.FindStringIndex(str); idx != nil {
		return false, &CheckInfo{Warning, idx[0], fmt.Sprintf("Mögliche HTML-Escapes: '%s'", strrange(-8, 8, idx[0], str))}
	}
	if idx := regexpurlencode.FindStringIndex(str); idx != nil {
		return false, &CheckInfo{Warning, idx[0], fmt.Sprintf("Mögliche Url-Escapes: '%s'", strrange(-6, 6, idx[0], str))}
	}
	if idx := regexpposixescape.FindStringIndex(str); idx != nil {
		return false, &CheckInfo{Warning, idx[0], fmt.Sprintf("Mögliche Posix-Escapes: '%s'", strrange(-6, 6, idx[0], str))}
	}
	return true, nil
}

var regexpEMail = regexp.MustCompile(`(?i)^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$`)

func FetchHead(url string) (bool, CheckInfo) {

	var info CheckInfo
	var err error
	var resp *http.Response

	for i := 0; i < 2; i++ {
		if i == 0 {
			resp, err = http.Head(url)
		} else {
			resp, err = http.Get(url)
		}
		if err != nil || resp.StatusCode != 200 {
			continue
		} else {
			break
		}
	}

	if err != nil {
		info = CheckInfo{Status: Error | FetchableUrl | NoDataatUrlError, Position: -1, Context: fmt.Sprintf("%s URL kann nicht aufgelöst werden: %s", url, err)}
	} else if sc := resp.StatusCode; sc != 200 {
		info = CheckInfo{Status: Error | FetchableUrl | NoDataatUrlError, Position: -1, Context: fmt.Sprintf("%s liefert nicht-OK Status-Code '%d'", url, sc)}
	} else {
		info = CheckInfo{Status: Info | FetchableUrl | FetchSuccess, Position: -1, Context: url}
	}

	return (info.Status & (Info | FetchSuccess)) == (Info | FetchSuccess), info
}

func CheckUrl(url string, followhttplink bool) (bool, []CheckInfo) {
	// it's a contact point if it's a http-link (starts with "http(s)" )
	var checkmessages []CheckInfo
	if len(url) >= 4 && url[:4] == "http" {
		urlinfo := CheckInfo{Info | FetchableUrl, -1, url}
		checkmessages = append(checkmessages, urlinfo)

		ok := true
		if followhttplink {
			ok, urlinfo = FetchHead(urlinfo.Context)
			checkmessages = append(checkmessages, urlinfo)
		}
		return ok, checkmessages
	}
	// it's a contact point if it's an email address
	if idx := regexpEMail.FindStringIndex(url); idx != nil {
		return true, nil
	}

	if len(url) == 0 {
		checkmessages = append(checkmessages, CheckInfo{Status: Error, Position: -1, Context: "kein Wert für Link angegeben (Länge 0)"})
		return false, checkmessages
	}

	checkmessages = append(checkmessages, CheckInfo{Status: Warning, Position: -1, Context: fmt.Sprintf("vermutlich keine gültige Web- oder E-Mail Adresse: '%s' (Auszug)", url[:min(20, len(url))])})

	return false, checkmessages
}

func CheckDataPortalUrl(url string, followhttplink bool) (bool, []CheckInfo) {
	const checkDataPortalUrlstrpart = `://data.`

	ok1, checkmessages := CheckUrl(url, followhttplink)
	ok2 := strings.Contains(url, checkDataPortalUrlstrpart)
	if !ok2 {
		checkmessages = append(checkmessages, CheckInfo{Status: Warning, Position: -1, Context: fmt.Sprintf("Link zum ursprünglichen Datenportal folgt nicht der Konvention ress://data.[....]: %s (Auszug)", url[:min(20, len(url))])})
	}

	return ok1 == true && ok2 == true, checkmessages
}

type CheckMessage struct {
	Type    int // 1 = Info, 2 = Warning, 4 = Error, ...
	Text    string
	OGDID   int
	Context string
}

func AppendcheckerrorTocheckmessage(msgs []CheckMessage, checkresults []CheckInfo, ID int, prepend string) []CheckMessage {
	for _, result := range checkresults {
		msgs = append(msgs, CheckMessage{
			Type:  result.Status,
			OGDID: ID,
			Text:  prepend + result.Context})
	}
	return msgs
}

func Loadogdatspec(version, filename string) (*OGDSet, error) {
	reader, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer reader.Close()

	csvreader := csv.NewReader(reader)
	csvreader.Comma = '|'
	csvreader.LazyQuotes = true

	// Read the first line and use it as the labels for the items to load
	record, err := csvreader.Read()
	if err != nil {
		return nil, err
	}

	set := &OGDSet{Label: record}

	spec := make([]*Beschreibung, 0)
	for record, err = csvreader.Read(); err != io.EOF; record, err = csvreader.Read() {
		id, _ := strconv.Atoi(record[0])
		var occ Occurrence
		switch record[12][0] {
		case 'R':
			occ = OccRequired
		case 'O':
			occ = OccOptional
		}
		descrecord := NewBeschreibung(id, occ, version)

		descrecord.Bezeichner = record[1]
		descrecord.OGD_Kurzname = record[2]
		descrecord.CKAN_Feld = record[3]
		descrecord.Anzahl = record[4]
		descrecord.Definition_DE = record[5]
		descrecord.Erlauterung = record[6]
		descrecord.Beispiel = record[7]
		descrecord.ONA2270 = record[8]
		descrecord.ISO19115 = record[9]
		descrecord.RDFProperty = record[10]
		descrecord.Definition_EN = record[11]

		spec = append(spec, descrecord)
	}
	set.Beschreibung = spec
	log.Printf("Info: Read %d %s specification records", len(spec), version)

	return set, nil
}
<|endoftext|>


<commit_before>package saml

import (
	"fmt"
	"io/ioutil"
	"os"
)

func GenerateAuthnRequest(publicCertificate, privateKey, idpSSOUrl, idpSSODescriptorUrl,
idpPublicCertificate, assertionConsumerServiceUrl string) (string, error) {

	//Create a temporary file for the public certificate
	publicCertificateFile, err := ioutil.TempFile(os.TempDir(), "publicCertificate")
	if err != nil {
		return "", err
	}
	publicCertificatePath := publicCertificateFile.Name()
	defer deleteTempFile(publicCertificatePath)

	//Create a temporary file for the private key
	privateKeyFile, err := ioutil.TempFile(os.TempDir(), "privateKey")
	if err != nil {
		return "", err
	}
	privateKeyPath := privateKeyFile.Name()
	defer deleteTempFile(privateKeyPath)

	//Create a temporary file for the idp public certificate
	idpPublicCertificateFile, err := ioutil.TempFile(os.TempDir(), "privateKey")
	if err != nil {
		return "", err
	}
	idpPublicCertificatePath := idpPublicCertificateFile.Name()
	defer deleteTempFile(idpPublicCertificatePath)

	sp := ServiceProviderSettings{
		PublicCertPath:              publicCertificatePath,
		PrivateKeyPath:              privateKeyPath,
		IDPSSOURL:                   idpSSOUrl,
		IDPSSODescriptorURL:         idpSSODescriptorUrl,
		IDPPublicCertPath:           idpPublicCertificatePath,
		AssertionConsumerServiceURL: assertionConsumerServiceUrl,
	}
	err = sp.Init()
	if err != nil {
		return "", err
	}

	// generate the AuthnRequest and then get a base64 encoded string of the XML
	authnRequest := sp.GetAuthnRequest()
	b64XML, err := authnRequest.EncodedSignedString(sp.PrivateKeyPath)
	if err != nil {
		return "", err
	}
	return b64XML, nil
}

func GenerateSamlResponse(response *Response, publicCertificate, privateKey, idpSSOUrl,
idpSSODescriptorUrl, idpPublicCertificate, assertionConsumerServiceUrl string) (error) {

	//Create a temporary file for the public certificate
	publicCertificateFile, err := ioutil.TempFile(os.TempDir(), "publicCertificate")
	if err != nil {
		return err
	}
	publicCertificatePath := publicCertificateFile.Name()
	defer deleteTempFile(publicCertificatePath)

	//Create a temporary file for the private key
	privateKeyFile, err := ioutil.TempFile(os.TempDir(), "privateKey")
	if err != nil {
		return err
	}
	privateKeyPath := privateKeyFile.Name()
	defer deleteTempFile(privateKeyPath)

	//Create a temporary file for the idp public certificate
	idpPublicCertificateFile, err := ioutil.TempFile(os.TempDir(), "privateKey")
	if err != nil {
		return  err
	}
	idpPublicCertificatePath := idpPublicCertificateFile.Name()
	defer deleteTempFile(idpPublicCertificatePath)

	sp := ServiceProviderSettings{
		PublicCertPath:              publicCertificatePath,
		PrivateKeyPath:              privateKeyPath,
		IDPSSOURL:                   idpSSOUrl,
		IDPSSODescriptorURL:         idpSSODescriptorUrl,
		IDPPublicCertPath:           idpPublicCertificatePath,
		AssertionConsumerServiceURL: assertionConsumerServiceUrl,
	}
	sp.Init()
	if err != nil {
		return err
	}

	err = response.Validate(&sp)
	if err != nil {
		return fmt.Errorf("SAMLResponse validation: "+err.Error())
	}
	return nil
}<commit_msg>picked a bad name for the idp certificate file<commit_after>package saml

import (
	"fmt"
	"io/ioutil"
	"os"
)

func GenerateAuthnRequest(publicCertificate, privateKey, idpSSOUrl, idpSSODescriptorUrl,
idpPublicCertificate, assertionConsumerServiceUrl string) (string, error) {

	//Create a temporary file for the public certificate
	publicCertificateFile, err := ioutil.TempFile(os.TempDir(), "publicCertificate")
	if err != nil {
		return "", err
	}
	publicCertificatePath := publicCertificateFile.Name()
	defer deleteTempFile(publicCertificatePath)

	//Create a temporary file for the private key
	privateKeyFile, err := ioutil.TempFile(os.TempDir(), "privateKey")
	if err != nil {
		return "", err
	}
	privateKeyPath := privateKeyFile.Name()
	defer deleteTempFile(privateKeyPath)

	//Create a temporary file for the idp public certificate
	idpPublicCertificateFile, err := ioutil.TempFile(os.TempDir(), "privateKey")
	if err != nil {
		return "", err
	}
	idpPublicCertificatePath := idpPublicCertificateFile.Name()
	defer deleteTempFile(idpPublicCertificatePath)

	sp := ServiceProviderSettings{
		PublicCertPath:              publicCertificatePath,
		PrivateKeyPath:              privateKeyPath,
		IDPSSOURL:                   idpSSOUrl,
		IDPSSODescriptorURL:         idpSSODescriptorUrl,
		IDPPublicCertPath:           idpPublicCertificatePath,
		AssertionConsumerServiceURL: assertionConsumerServiceUrl,
	}
	err = sp.Init()
	if err != nil {
		return "", err
	}

	// generate the AuthnRequest and then get a base64 encoded string of the XML
	authnRequest := sp.GetAuthnRequest()
	b64XML, err := authnRequest.EncodedSignedString(sp.PrivateKeyPath)
	if err != nil {
		return "", err
	}
	return b64XML, nil
}

func GenerateSamlResponse(response *Response, publicCertificate, privateKey, idpSSOUrl,
idpSSODescriptorUrl, idpPublicCertificate, assertionConsumerServiceUrl string) (error) {

	//Create a temporary file for the public certificate
	publicCertificateFile, err := ioutil.TempFile(os.TempDir(), "publicCertificate")
	if err != nil {
		return err
	}
	publicCertificatePath := publicCertificateFile.Name()
	defer deleteTempFile(publicCertificatePath)

	//Create a temporary file for the private key
	privateKeyFile, err := ioutil.TempFile(os.TempDir(), "privateKey")
	if err != nil {
		return err
	}
	privateKeyPath := privateKeyFile.Name()
	defer deleteTempFile(privateKeyPath)

	//Create a temporary file for the idp public certificate
	idpPublicCertificateFile, err := ioutil.TempFile(os.TempDir(), "idpPublicCertificate")
	if err != nil {
		return  err
	}
	idpPublicCertificatePath := idpPublicCertificateFile.Name()
	defer deleteTempFile(idpPublicCertificatePath)

	sp := ServiceProviderSettings{
		PublicCertPath:              publicCertificatePath,
		PrivateKeyPath:              privateKeyPath,
		IDPSSOURL:                   idpSSOUrl,
		IDPSSODescriptorURL:         idpSSODescriptorUrl,
		IDPPublicCertPath:           idpPublicCertificatePath,
		AssertionConsumerServiceURL: assertionConsumerServiceUrl,
	}
	sp.Init()
	if err != nil {
		return err
	}

	err = response.Validate(&sp)
	if err != nil {
		return fmt.Errorf("SAMLResponse validation: "+err.Error())
	}
	return nil
}<|endoftext|>


<commit_before>package cfclient

import (
	"encoding/json"
	"io/ioutil"
	"net/url"

	"github.com/pkg/errors"
)

type ServicesResponse struct {
	Count     int                `json:"total_results"`
	Pages     int                `json:"total_pages"`
	NextUrl   string             `json:"next_url"`
	Resources []ServicesResource `json:"resources"`
}

type ServicesResource struct {
	Meta   Meta    `json:"metadata"`
	Entity Service `json:"entity"`
}

type Service struct {
	Guid                 string   `json:"guid"`
	Label                string   `json:"label"`
	CreatedAt            string   `json:"created_at"`
	UpdatedAt            string   `json:"updated_at"`
	Description          string   `json:"description"`
	Active               bool     `json:"active"`
	Bindable             bool     `json:"bindable"`
	ServiceBrokerGuid    string   `json:"service_broker_guid"`
	PlanUpdateable       bool     `json:"plan_updateable"`
	Tags                 []string `json:"tags"`
	UniqueID             string   `json:"unique_id"`
	Extra                string   `json:"extra"`
	Requires             []string `json:"requires"`
	InstancesRetrievable bool     `json:"instances_retrievable"`
	BindingsRetrievable  bool     `json:"bindings_retrievable"`
	c                    *Client
}

type ServiceSummary struct {
	Guid              string          `json:"guid"`
	Name              string          `json:"name"`
	BoundAppCount     int             `json:"bound_app_count"`
	DashboardURL      string          `json:"dashboard_url"`
	ServiceBrokerName string          `json:"service_broker_name"`
	MaintenanceInfo   MaintenanceInfo `json:"maintenance_info"`
	ServicePlan       struct {
		Guid            string          `json:"guid"`
		Name            string          `json:"name"`
		MaintenanceInfo MaintenanceInfo `json:"maintenance_info"`
		Service         struct {
			Guid     string `json:"guid"`
			Label    string `json:"label"`
			Provider string `json:"provider"`
			Version  string `json:"version"`
		} `json:"service"`
	} `json:"service_plan"`
}

type MaintenanceInfo struct {
	Version     string `json:"version"`
	Description string `json:"description"`
}

func (c *Client) GetServiceByGuid(guid string) (Service, error) {
	var serviceRes ServicesResource
	r := c.NewRequest("GET", "/v2/services/"+guid)
	resp, err := c.DoRequest(r)
	if err != nil {
		return Service{}, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return Service{}, err
	}
	err = json.Unmarshal(body, &serviceRes)
	if err != nil {
		return Service{}, err
	}
	serviceRes.Entity.Guid = serviceRes.Meta.Guid
	serviceRes.Entity.CreatedAt = serviceRes.Meta.CreatedAt
	serviceRes.Entity.UpdatedAt = serviceRes.Meta.UpdatedAt
	return serviceRes.Entity, nil

}

func (c *Client) ListServicesByQuery(query url.Values) ([]Service, error) {
	var services []Service
	requestUrl := "/v2/services?" + query.Encode()
	for {
		var serviceResp ServicesResponse
		r := c.NewRequest("GET", requestUrl)
		resp, err := c.DoRequest(r)
		if err != nil {
			return nil, errors.Wrap(err, "Error requesting services")
		}
		resBody, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, errors.Wrap(err, "Error reading services request:")
		}

		err = json.Unmarshal(resBody, &serviceResp)
		if err != nil {
			return nil, errors.Wrap(err, "Error unmarshaling services")
		}
		for _, service := range serviceResp.Resources {
			service.Entity.Guid = service.Meta.Guid
			service.Entity.CreatedAt = service.Meta.CreatedAt
			service.Entity.UpdatedAt = service.Meta.UpdatedAt
			service.Entity.c = c
			services = append(services, service.Entity)
		}
		requestUrl = serviceResp.NextUrl
		if requestUrl == "" {
			break
		}
	}
	return services, nil
}

func (c *Client) ListServices() ([]Service, error) {
	return c.ListServicesByQuery(nil)
}
<commit_msg>Add ServiceBrokerName field to Service struct<commit_after>package cfclient

import (
	"encoding/json"
	"io/ioutil"
	"net/url"

	"github.com/pkg/errors"
)

type ServicesResponse struct {
	Count     int                `json:"total_results"`
	Pages     int                `json:"total_pages"`
	NextUrl   string             `json:"next_url"`
	Resources []ServicesResource `json:"resources"`
}

type ServicesResource struct {
	Meta   Meta    `json:"metadata"`
	Entity Service `json:"entity"`
}

type Service struct {
	Guid                 string   `json:"guid"`
	Label                string   `json:"label"`
	CreatedAt            string   `json:"created_at"`
	UpdatedAt            string   `json:"updated_at"`
	Description          string   `json:"description"`
	Active               bool     `json:"active"`
	Bindable             bool     `json:"bindable"`
	ServiceBrokerGuid    string   `json:"service_broker_guid"`
	ServiceBrokerName    string   `json:"service_broker_name"`
	PlanUpdateable       bool     `json:"plan_updateable"`
	Tags                 []string `json:"tags"`
	UniqueID             string   `json:"unique_id"`
	Extra                string   `json:"extra"`
	Requires             []string `json:"requires"`
	InstancesRetrievable bool     `json:"instances_retrievable"`
	BindingsRetrievable  bool     `json:"bindings_retrievable"`
	c                    *Client
}

type ServiceSummary struct {
	Guid              string          `json:"guid"`
	Name              string          `json:"name"`
	BoundAppCount     int             `json:"bound_app_count"`
	DashboardURL      string          `json:"dashboard_url"`
	ServiceBrokerName string          `json:"service_broker_name"`
	MaintenanceInfo   MaintenanceInfo `json:"maintenance_info"`
	ServicePlan       struct {
		Guid            string          `json:"guid"`
		Name            string          `json:"name"`
		MaintenanceInfo MaintenanceInfo `json:"maintenance_info"`
		Service         struct {
			Guid     string `json:"guid"`
			Label    string `json:"label"`
			Provider string `json:"provider"`
			Version  string `json:"version"`
		} `json:"service"`
	} `json:"service_plan"`
}

type MaintenanceInfo struct {
	Version     string `json:"version"`
	Description string `json:"description"`
}

func (c *Client) GetServiceByGuid(guid string) (Service, error) {
	var serviceRes ServicesResource
	r := c.NewRequest("GET", "/v2/services/"+guid)
	resp, err := c.DoRequest(r)
	if err != nil {
		return Service{}, err
	}
	body, err := ioutil.ReadAll(resp.Body)
	defer resp.Body.Close()
	if err != nil {
		return Service{}, err
	}
	err = json.Unmarshal(body, &serviceRes)
	if err != nil {
		return Service{}, err
	}
	serviceRes.Entity.Guid = serviceRes.Meta.Guid
	serviceRes.Entity.CreatedAt = serviceRes.Meta.CreatedAt
	serviceRes.Entity.UpdatedAt = serviceRes.Meta.UpdatedAt
	return serviceRes.Entity, nil

}

func (c *Client) ListServicesByQuery(query url.Values) ([]Service, error) {
	var services []Service
	requestUrl := "/v2/services?" + query.Encode()
	for {
		var serviceResp ServicesResponse
		r := c.NewRequest("GET", requestUrl)
		resp, err := c.DoRequest(r)
		if err != nil {
			return nil, errors.Wrap(err, "Error requesting services")
		}
		resBody, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return nil, errors.Wrap(err, "Error reading services request:")
		}

		err = json.Unmarshal(resBody, &serviceResp)
		if err != nil {
			return nil, errors.Wrap(err, "Error unmarshaling services")
		}
		for _, service := range serviceResp.Resources {
			service.Entity.Guid = service.Meta.Guid
			service.Entity.CreatedAt = service.Meta.CreatedAt
			service.Entity.UpdatedAt = service.Meta.UpdatedAt
			service.Entity.c = c
			services = append(services, service.Entity)
		}
		requestUrl = serviceResp.NextUrl
		if requestUrl == "" {
			break
		}
	}
	return services, nil
}

func (c *Client) ListServices() ([]Service, error) {
	return c.ListServicesByQuery(nil)
}
<|endoftext|>


<commit_before>package pop

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"sync"

	_ "github.com/lib/pq"
	"github.com/markbates/going/defaults"
	. "github.com/markbates/pop/columns"
	"github.com/markbates/pop/fizz"
	"github.com/markbates/pop/fizz/translators"
	"github.com/pkg/errors"
)

var _ dialect = &postgresql{}

type postgresql struct {
	translateCache    map[string]string
	mu                sync.Mutex
	ConnectionDetails *ConnectionDetails
}

func (p *postgresql) Details() *ConnectionDetails {
	return p.ConnectionDetails
}

func (p *postgresql) Create(s store, model *Model, cols Columns) error {
	keyType := model.PrimaryKeyType()
	switch keyType {
	case "int", "int64":
		cols.Remove("id")
		id := struct {
			ID int `db:"id"`
		}{}
		w := cols.Writeable()
		query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s) returning id", model.TableName(), w.String(), w.SymbolizedString())
		Log(query)
		stmt, err := s.PrepareNamed(query)
		if err != nil {
			return errors.WithStack(err)
		}
		err = stmt.Get(&id, model.Value)
		if err != nil {
			return errors.WithStack(err)
		}
		model.setID(id.ID)
		return nil
	case "UUID":
		return genericCreate(s, model, cols)
	}
	return errors.Errorf("can not use %s as a primary key type!", keyType)
}

func (p *postgresql) Update(s store, model *Model, cols Columns) error {
	return genericUpdate(s, model, cols)
}

func (p *postgresql) Destroy(s store, model *Model) error {
	return genericDestroy(s, model)
}

func (p *postgresql) SelectOne(s store, model *Model, query Query) error {
	return genericSelectOne(s, model, query)
}

func (p *postgresql) SelectMany(s store, models *Model, query Query) error {
	return genericSelectMany(s, models, query)
}

func (p *postgresql) CreateDB() error {
	// createdb -h db -p 5432 -U postgres enterprise_development
	deets := p.ConnectionDetails
	cmd := exec.Command("psql", "-c", fmt.Sprintf("create database `%s`", deets.Database), p.urlWithoutDb())
	Log(strings.Join(cmd.Args, " "))
	comboOut, err := cmd.CombinedOutput()
	if err != nil {
		err = fmt.Errorf("%s: %s", err.Error(), string(comboOut))
		return errors.Wrapf(err, "error creating PostgreSQL database %s", deets.Database)
	}

	fmt.Printf("created database %s\n", deets.Database)
	return nil
}

func (p *postgresql) DropDB() error {
	deets := p.ConnectionDetails
	cmd := exec.Command("psql", p.urlWithoutDb(), "-c", fmt.Sprintf("drop database %s", deets.Database))
	Log(strings.Join(cmd.Args, " "))
	comboOut, err := cmd.CombinedOutput()
	if err != nil {
		err = fmt.Errorf("%s: %s", err.Error(), string(comboOut))
		return errors.Wrapf(err, "error dropping PostgreSQL database %s", deets.Database)
	}
	fmt.Printf("dropped database %s\n", deets.Database)
	return nil
}

func (m *postgresql) URL() string {
	c := m.ConnectionDetails
	if c.URL != "" {
		return c.URL
	}
	ssl := defaults.String(c.Options["sslmode"], "disable")

	s := "postgres://%s:%s@%s:%s/%s?sslmode=%s"
	return fmt.Sprintf(s, c.User, c.Password, c.Host, c.Port, c.Database, ssl)
}

func (m *postgresql) urlWithoutDb() string {
	c := m.ConnectionDetails
	ssl := defaults.String(c.Options["sslmode"], "disable")

	s := "postgres://%s:%s@%s:%s/?sslmode=%s"
	return fmt.Sprintf(s, c.User, c.Password, c.Host, c.Port, ssl)
}

func (m *postgresql) MigrationURL() string {
	return m.URL()
}

func (p *postgresql) TranslateSQL(sql string) string {
	defer p.mu.Unlock()
	p.mu.Lock()

	if csql, ok := p.translateCache[sql]; ok {
		return csql
	}
	curr := 1
	out := make([]byte, 0, len(sql))
	for i := 0; i < len(sql); i++ {
		if sql[i] == '?' {
			str := "$" + strconv.Itoa(curr)
			for _, char := range str {
				out = append(out, byte(char))
			}
			curr += 1
		} else {
			out = append(out, sql[i])
		}
	}
	csql := string(out)
	p.translateCache[sql] = csql
	return csql
}

func (p *postgresql) FizzTranslator() fizz.Translator {
	return translators.NewPostgres()
}

func (p *postgresql) Lock(fn func() error) error {
	return fn()
}

func (p *postgresql) DumpSchema(w io.Writer) error {
	cmd := exec.Command("pg_dump", "-s", fmt.Sprintf("--dbname=%s", p.URL()))
	Log(strings.Join(cmd.Args, " "))
	cmd.Stdout = w
	cmd.Stderr = os.Stderr

	err := cmd.Run()
	if err != nil {
		return err
	}

	fmt.Printf("dumped schema for %s\n", p.Details().Database)
	return nil
}

func (p *postgresql) LoadSchema(r io.Reader) error {
	cmd := exec.Command("psql", p.URL())
	in, err := cmd.StdinPipe()
	if err != nil {
		return err
	}
	go func() {
		defer in.Close()
		io.Copy(in, r)
	}()
	Log(strings.Join(cmd.Args, " "))

	bb := &bytes.Buffer{}
	cmd.Stdout = bb
	cmd.Stderr = bb

	err = cmd.Start()
	if err != nil {
		return errors.WithMessage(err, bb.String())
	}

	err = cmd.Wait()
	if err != nil {
		return errors.WithMessage(err, bb.String())
	}

	fmt.Printf("loaded schema for %s\n", p.Details().Database)
	return nil
}

func (p *postgresql) TruncateAll(tx *Connection) error {
	return tx.RawQuery(pgTruncate).Exec()
}

func newPostgreSQL(deets *ConnectionDetails) dialect {
	cd := &postgresql{
		ConnectionDetails: deets,
		translateCache:    map[string]string{},
		mu:                sync.Mutex{},
	}
	return cd
}

const pgTruncate = `DO
$func$
BEGIN
   EXECUTE
  (SELECT 'TRUNCATE TABLE '
       || string_agg(quote_ident(schemaname) || '.' || quote_ident(tablename), ', ')
       || ' CASCADE'
   FROM   pg_tables
   WHERE  schemaname = 'public'
   );
END
$func$;`
<commit_msg>Apparently double quotes are the way to do this in postgresql<commit_after>package pop

import (
	"bytes"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"
	"sync"

	_ "github.com/lib/pq"
	"github.com/markbates/going/defaults"
	. "github.com/markbates/pop/columns"
	"github.com/markbates/pop/fizz"
	"github.com/markbates/pop/fizz/translators"
	"github.com/pkg/errors"
)

var _ dialect = &postgresql{}

type postgresql struct {
	translateCache    map[string]string
	mu                sync.Mutex
	ConnectionDetails *ConnectionDetails
}

func (p *postgresql) Details() *ConnectionDetails {
	return p.ConnectionDetails
}

func (p *postgresql) Create(s store, model *Model, cols Columns) error {
	keyType := model.PrimaryKeyType()
	switch keyType {
	case "int", "int64":
		cols.Remove("id")
		id := struct {
			ID int `db:"id"`
		}{}
		w := cols.Writeable()
		query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s) returning id", model.TableName(), w.String(), w.SymbolizedString())
		Log(query)
		stmt, err := s.PrepareNamed(query)
		if err != nil {
			return errors.WithStack(err)
		}
		err = stmt.Get(&id, model.Value)
		if err != nil {
			return errors.WithStack(err)
		}
		model.setID(id.ID)
		return nil
	case "UUID":
		return genericCreate(s, model, cols)
	}
	return errors.Errorf("can not use %s as a primary key type!", keyType)
}

func (p *postgresql) Update(s store, model *Model, cols Columns) error {
	return genericUpdate(s, model, cols)
}

func (p *postgresql) Destroy(s store, model *Model) error {
	return genericDestroy(s, model)
}

func (p *postgresql) SelectOne(s store, model *Model, query Query) error {
	return genericSelectOne(s, model, query)
}

func (p *postgresql) SelectMany(s store, models *Model, query Query) error {
	return genericSelectMany(s, models, query)
}

func (p *postgresql) CreateDB() error {
	// createdb -h db -p 5432 -U postgres enterprise_development
	deets := p.ConnectionDetails
	cmd := exec.Command("psql", "-c", fmt.Sprintf("create database \"%s\"", deets.Database), p.urlWithoutDb())
	Log(strings.Join(cmd.Args, " "))
	comboOut, err := cmd.CombinedOutput()
	if err != nil {
		err = fmt.Errorf("%s: %s", err.Error(), string(comboOut))
		return errors.Wrapf(err, "error creating PostgreSQL database %s", deets.Database)
	}

	fmt.Printf("created database %s\n", deets.Database)
	return nil
}

func (p *postgresql) DropDB() error {
	deets := p.ConnectionDetails
	cmd := exec.Command("psql", p.urlWithoutDb(), "-c", fmt.Sprintf("drop database %s", deets.Database))
	Log(strings.Join(cmd.Args, " "))
	comboOut, err := cmd.CombinedOutput()
	if err != nil {
		err = fmt.Errorf("%s: %s", err.Error(), string(comboOut))
		return errors.Wrapf(err, "error dropping PostgreSQL database %s", deets.Database)
	}
	fmt.Printf("dropped database %s\n", deets.Database)
	return nil
}

func (m *postgresql) URL() string {
	c := m.ConnectionDetails
	if c.URL != "" {
		return c.URL
	}
	ssl := defaults.String(c.Options["sslmode"], "disable")

	s := "postgres://%s:%s@%s:%s/%s?sslmode=%s"
	return fmt.Sprintf(s, c.User, c.Password, c.Host, c.Port, c.Database, ssl)
}

func (m *postgresql) urlWithoutDb() string {
	c := m.ConnectionDetails
	ssl := defaults.String(c.Options["sslmode"], "disable")

	s := "postgres://%s:%s@%s:%s/?sslmode=%s"
	return fmt.Sprintf(s, c.User, c.Password, c.Host, c.Port, ssl)
}

func (m *postgresql) MigrationURL() string {
	return m.URL()
}

func (p *postgresql) TranslateSQL(sql string) string {
	defer p.mu.Unlock()
	p.mu.Lock()

	if csql, ok := p.translateCache[sql]; ok {
		return csql
	}
	curr := 1
	out := make([]byte, 0, len(sql))
	for i := 0; i < len(sql); i++ {
		if sql[i] == '?' {
			str := "$" + strconv.Itoa(curr)
			for _, char := range str {
				out = append(out, byte(char))
			}
			curr += 1
		} else {
			out = append(out, sql[i])
		}
	}
	csql := string(out)
	p.translateCache[sql] = csql
	return csql
}

func (p *postgresql) FizzTranslator() fizz.Translator {
	return translators.NewPostgres()
}

func (p *postgresql) Lock(fn func() error) error {
	return fn()
}

func (p *postgresql) DumpSchema(w io.Writer) error {
	cmd := exec.Command("pg_dump", "-s", fmt.Sprintf("--dbname=%s", p.URL()))
	Log(strings.Join(cmd.Args, " "))
	cmd.Stdout = w
	cmd.Stderr = os.Stderr

	err := cmd.Run()
	if err != nil {
		return err
	}

	fmt.Printf("dumped schema for %s\n", p.Details().Database)
	return nil
}

func (p *postgresql) LoadSchema(r io.Reader) error {
	cmd := exec.Command("psql", p.URL())
	in, err := cmd.StdinPipe()
	if err != nil {
		return err
	}
	go func() {
		defer in.Close()
		io.Copy(in, r)
	}()
	Log(strings.Join(cmd.Args, " "))

	bb := &bytes.Buffer{}
	cmd.Stdout = bb
	cmd.Stderr = bb

	err = cmd.Start()
	if err != nil {
		return errors.WithMessage(err, bb.String())
	}

	err = cmd.Wait()
	if err != nil {
		return errors.WithMessage(err, bb.String())
	}

	fmt.Printf("loaded schema for %s\n", p.Details().Database)
	return nil
}

func (p *postgresql) TruncateAll(tx *Connection) error {
	return tx.RawQuery(pgTruncate).Exec()
}

func newPostgreSQL(deets *ConnectionDetails) dialect {
	cd := &postgresql{
		ConnectionDetails: deets,
		translateCache:    map[string]string{},
		mu:                sync.Mutex{},
	}
	return cd
}

const pgTruncate = `DO
$func$
BEGIN
   EXECUTE
  (SELECT 'TRUNCATE TABLE '
       || string_agg(quote_ident(schemaname) || '.' || quote_ident(tablename), ', ')
       || ' CASCADE'
   FROM   pg_tables
   WHERE  schemaname = 'public'
   );
END
$func$;`
<|endoftext|>