<commit_before>//Package gogtm enables access to gt.m database
package gogtm

/*
#cgo CFLAGS: -I/opt/fis/6.3-000A
#cgo LDFLAGS: -L/opt/fis/6.3-000A -lgtmshr
#include <gtmxc_types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define maxstr 1048576

#ifndef NULL
#define NULL ((void *) 0)
#endif

#define CALLGTM(xyz) status = xyz ;		\
	if (0 != status ) {				\
		gtm_zstatus( msg, 2048 );			\
		snprintf(errmsg, 2048, "Failure of %s with error: %s\n", #xyz, msg); \
		return (int) status; \
	}

int cip_init(char *errmsg, int maxmsglen) {
	gtm_char_t msg[maxmsglen], err[maxmsglen];
	gtm_string_t gtminit_str;
	ci_name_descriptor gtminit;
	gtm_status_t status;

	gtminit_str.address = "gtminit";
	gtminit_str.length = sizeof("gtminit")-1;
	gtminit.rtn_name=gtminit_str;
	gtminit.handle = NULL;

	errmsg[0] = '\0';
	err[0] = '\0';

	CALLGTM (gtm_cip( &gtminit, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_init error: [%s]\n", err);
		return 100;
	}
	return 0;
} // end of cip_init

int cip_set(char *s_global, char *s_value, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmset_str, p_value;
	ci_name_descriptor gtmset;
	gtm_status_t status;

	gtmset_str.address = "gtmset";
	gtmset_str.length = sizeof("gtmset")-1;
	gtmset.rtn_name=gtmset_str;
	gtmset.handle = NULL;

	err[0] = '\0';

	p_value.address = ( gtm_char_t *) s_value; p_value.length = strlen(s_value);
	CALLGTM( gtm_cip( &gtmset, s_global, &p_value, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_set error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_set

int cip_get(char *s_global, char *s_opt, char *s_ret, char *errmsg, int maxmsglen, int maxretlen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmget_str, p_opt;
	ci_name_descriptor gtmget;
	gtm_status_t status;

	gtmget_str.address = "gtmget";
	gtmget_str.length = sizeof("gtmget")-1;
	gtmget.rtn_name=gtmget_str;
	gtmget.handle = NULL;

	err[0] = '\0';

	p_opt.address = ( gtm_char_t *) s_opt; p_opt.length = strlen(s_opt);

	CALLGTM( gtm_cip( &gtmget, s_global, &p_opt, s_ret, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_get error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_get

int cip_kill(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmkill_str;
	ci_name_descriptor gtmkill;
	gtm_status_t status;

	gtmkill_str.address = "gtmkill";
	gtmkill_str.length = sizeof("gtmkill")-1;
	gtmkill.rtn_name=gtmkill_str;
	gtmkill.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmkill, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_kill error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_kill

int cip_zkill(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmzkill_str;
	ci_name_descriptor gtmzkill;
	gtm_status_t status;

	gtmzkill_str.address = "gtmzkill";
	gtmzkill_str.length = sizeof("gtmzkill")-1;
	gtmzkill.rtn_name=gtmzkill_str;
	gtmzkill.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmzkill, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_zkill error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_zkill

int cip_xecute(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmxecute_str;
	ci_name_descriptor gtmxecute;
	gtm_status_t status;

	gtmxecute_str.address = "gtmxecute";
	gtmxecute_str.length = sizeof("gtmxecute")-1;
	gtmxecute.rtn_name=gtmxecute_str;
	gtmxecute.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmxecute, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_xecute error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_xecute

int cip_order(char *s_global, char *s_ret, char *errmsg, int maxmsglen, int maxretlen, char *direction) {
        gtm_char_t err[maxmsglen], msg[maxmsglen];
        gtm_string_t gtmorder_str, p_opt;
        ci_name_descriptor gtmorder;
        gtm_status_t status;

        gtmorder_str.address = "gtmorder";
        gtmorder_str.length = sizeof("gtmorder")-1;
        gtmorder.rtn_name=gtmorder_str;
        gtmorder.handle = NULL;

        err[0] = '\0';

        CALLGTM( gtm_cip( &gtmorder, s_global, direction, s_ret, &err));

        if (0 != strlen( err )){
                snprintf(errmsg, maxmsglen, "cip_order error: [%s]\n", err);
                fprintf( stderr, "error set: %s", err);
                return 100;
        }
        return 0;
} // end of cip_order

*/
import "C"

import (
  "unsafe"
  "errors"
//  "fmt"
//  "strconv"
)

//maxmsglen maximum length of message from gt.m
const maxmsglen = 2048

//maxretlen maximum length of value retrieved from gt.m
const maxretlen = 1048576

//Set saves value to global in gt.m db
//Sample usage: gogtm.Set("^test","value")
func Set(global string, val string) (error){

  if len(global) < 1 {
    return errors.New("Set failed - you must provide glvn")
  }

  _global := C.CString(global)
  _val := C.CString(val)
  errmsg := make([]byte, maxmsglen)

  defer C.free(unsafe.Pointer(_global))
  defer C.free(unsafe.Pointer(_val))

  result := C.cip_set(_global, _val, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("Set failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of Set

func Get(global string, opt string) (string, error){

  if len(global) < 1 {
    return "", errors.New("Get failed - you must provide glvn")
  }

  _global := C.CString(global)
  _opt := C.CString(opt)
  _ret := make([]byte, maxretlen)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))
  defer C.free(unsafe.Pointer(_opt))

  p := C.malloc(C.size_t(maxmsglen))
  defer C.free(p)

  result := C.cip_get(_global, _opt, (*C.char)(unsafe.Pointer(&_ret[0])), (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)), maxretlen)

  if result != 0 {
    return "", errors.New("Get failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return string(_ret), nil
} //end of Get

func Start() (error) {
  {
  result := C.gtm_init()
  if result != 0 {
    return errors.New("gtm_init failed: " + string(result))
  }
  }
  errmsg := C.CString("")
  defer C.free(unsafe.Pointer(errmsg))

  result := C.cip_init(errmsg, maxmsglen)
  if result != 0 {
    return errors.New("CIP Init failed: " + string(result) + "Error MSG: " + C.GoString(errmsg))
  }
  return nil
} // end of Start

func Stop() (error){

  result := C.gtm_exit()

  if result != 0 {
    return errors.New("gtm_exit failed: " + string(result))
  }
  return nil
} // end of Stop

//Kill deletes global variable and its descendant nodes
func Kill(global string) (error){

  if len(global) < 1 {
    return errors.New("Kill failed - you must provide [glvn | (glvn[,...]) | *lname | *lvn ]")
  }

  _global := C.CString(global)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))

  result := C.cip_kill(_global, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("Kill failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of Kill

//ZKill deletes global variable and its descendant nodes
func ZKill(global string) (error){

  if len(global) < 1 {
    return errors.New("ZKill failed - you must provide glvn")
  }

  _global := C.CString(global)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))

  result := C.cip_zkill(_global, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("ZKill failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of ZKill

//Xecute runs the M code
func Xecute(code string) (error){

  if len(code) < 1 {
    return errors.New("Xecute failed - you must provide some code")
  }

  _code := C.CString(code)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_code))

  result := C.cip_xecute(_code, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("Xecute failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of Xecute

func Order(global string, dir string) (string, error){

  if len(global) < 1 {
    return "", errors.New("Order failed - you must provide glvn")
  }

  if dir != "-1" {
    dir = "1"
  }

  _global := C.CString(global)
  _dir := C.CString(dir)
  _ret := make([]byte, maxretlen)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))
  defer C.free(unsafe.Pointer(_dir))

  result := C.cip_order(_global, (*C.char)(unsafe.Pointer(&_ret[0])), (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)), maxretlen, _dir)

  if result != 0 {
    return "", errors.New("Get failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return string(_ret), nil
} //end of Order
<commit_msg>new gtm version<commit_after>//Package gogtm enables access to gt.m database
package gogtm

/*
#cgo CFLAGS: -I/opt/fis/6.3-001A
#cgo LDFLAGS: -L/opt/fis/6.3-001A -lgtmshr
#include <gtmxc_types.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define maxstr 1048576

#ifndef NULL
#define NULL ((void *) 0)
#endif

#define CALLGTM(xyz) status = xyz ;		\
	if (0 != status ) {				\
		gtm_zstatus( msg, 2048 );			\
		snprintf(errmsg, 2048, "Failure of %s with error: %s\n", #xyz, msg); \
		return (int) status; \
	}

int cip_init(char *errmsg, int maxmsglen) {
	gtm_char_t msg[maxmsglen], err[maxmsglen];
	gtm_string_t gtminit_str;
	ci_name_descriptor gtminit;
	gtm_status_t status;

	gtminit_str.address = "gtminit";
	gtminit_str.length = sizeof("gtminit")-1;
	gtminit.rtn_name=gtminit_str;
	gtminit.handle = NULL;

	errmsg[0] = '\0';
	err[0] = '\0';

	CALLGTM (gtm_cip( &gtminit, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_init error: [%s]\n", err);
		return 100;
	}
	return 0;
} // end of cip_init

int cip_set(char *s_global, char *s_value, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmset_str, p_value;
	ci_name_descriptor gtmset;
	gtm_status_t status;

	gtmset_str.address = "gtmset";
	gtmset_str.length = sizeof("gtmset")-1;
	gtmset.rtn_name=gtmset_str;
	gtmset.handle = NULL;

	err[0] = '\0';

	p_value.address = ( gtm_char_t *) s_value; p_value.length = strlen(s_value);
	CALLGTM( gtm_cip( &gtmset, s_global, &p_value, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_set error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_set

int cip_get(char *s_global, char *s_opt, char *s_ret, char *errmsg, int maxmsglen, int maxretlen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmget_str, p_opt;
	ci_name_descriptor gtmget;
	gtm_status_t status;

	gtmget_str.address = "gtmget";
	gtmget_str.length = sizeof("gtmget")-1;
	gtmget.rtn_name=gtmget_str;
	gtmget.handle = NULL;

	err[0] = '\0';

	p_opt.address = ( gtm_char_t *) s_opt; p_opt.length = strlen(s_opt);

	CALLGTM( gtm_cip( &gtmget, s_global, &p_opt, s_ret, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_get error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_get

int cip_kill(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmkill_str;
	ci_name_descriptor gtmkill;
	gtm_status_t status;

	gtmkill_str.address = "gtmkill";
	gtmkill_str.length = sizeof("gtmkill")-1;
	gtmkill.rtn_name=gtmkill_str;
	gtmkill.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmkill, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_kill error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_kill

int cip_zkill(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmzkill_str;
	ci_name_descriptor gtmzkill;
	gtm_status_t status;

	gtmzkill_str.address = "gtmzkill";
	gtmzkill_str.length = sizeof("gtmzkill")-1;
	gtmzkill.rtn_name=gtmzkill_str;
	gtmzkill.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmzkill, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_zkill error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_zkill

int cip_xecute(char *s_global, char *errmsg, int maxmsglen) {
	gtm_char_t err[maxmsglen], msg[maxmsglen];
	gtm_string_t gtmxecute_str;
	ci_name_descriptor gtmxecute;
	gtm_status_t status;

	gtmxecute_str.address = "gtmxecute";
	gtmxecute_str.length = sizeof("gtmxecute")-1;
	gtmxecute.rtn_name=gtmxecute_str;
	gtmxecute.handle = NULL;

	err[0] = '\0';

	CALLGTM( gtm_cip( &gtmxecute, s_global, &err));

	if (0 != strlen( err )){
		snprintf(errmsg, maxmsglen, "cip_xecute error: [%s]\n", err);
		fprintf( stderr, "error set: %s", err);
		return 100;
	}
	return 0;
} // end of cip_xecute

int cip_order(char *s_global, char *s_ret, char *errmsg, int maxmsglen, int maxretlen, char *direction) {
        gtm_char_t err[maxmsglen], msg[maxmsglen];
        gtm_string_t gtmorder_str, p_opt;
        ci_name_descriptor gtmorder;
        gtm_status_t status;

        gtmorder_str.address = "gtmorder";
        gtmorder_str.length = sizeof("gtmorder")-1;
        gtmorder.rtn_name=gtmorder_str;
        gtmorder.handle = NULL;

        err[0] = '\0';

        CALLGTM( gtm_cip( &gtmorder, s_global, direction, s_ret, &err));

        if (0 != strlen( err )){
                snprintf(errmsg, maxmsglen, "cip_order error: [%s]\n", err);
                fprintf( stderr, "error set: %s", err);
                return 100;
        }
        return 0;
} // end of cip_order

*/
import "C"

import (
  "unsafe"
  "errors"
//  "fmt"
//  "strconv"
)

//maxmsglen maximum length of message from gt.m
const maxmsglen = 2048

//maxretlen maximum length of value retrieved from gt.m
const maxretlen = 1048576

//Set saves value to global in gt.m db
//Sample usage: gogtm.Set("^test","value")
func Set(global string, val string) (error){

  if len(global) < 1 {
    return errors.New("Set failed - you must provide glvn")
  }

  _global := C.CString(global)
  _val := C.CString(val)
  errmsg := make([]byte, maxmsglen)

  defer C.free(unsafe.Pointer(_global))
  defer C.free(unsafe.Pointer(_val))

  result := C.cip_set(_global, _val, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("Set failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of Set

func Get(global string, opt string) (string, error){

  if len(global) < 1 {
    return "", errors.New("Get failed - you must provide glvn")
  }

  _global := C.CString(global)
  _opt := C.CString(opt)
  _ret := make([]byte, maxretlen)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))
  defer C.free(unsafe.Pointer(_opt))

  p := C.malloc(C.size_t(maxmsglen))
  defer C.free(p)

  result := C.cip_get(_global, _opt, (*C.char)(unsafe.Pointer(&_ret[0])), (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)), maxretlen)

  if result != 0 {
    return "", errors.New("Get failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return string(_ret), nil
} //end of Get

func Start() (error) {
  {
  result := C.gtm_init()
  if result != 0 {
    return errors.New("gtm_init failed: " + string(result))
  }
  }
  errmsg := C.CString("")
  defer C.free(unsafe.Pointer(errmsg))

  result := C.cip_init(errmsg, maxmsglen)
  if result != 0 {
    return errors.New("CIP Init failed: " + string(result) + "Error MSG: " + C.GoString(errmsg))
  }
  return nil
} // end of Start

func Stop() (error){

  result := C.gtm_exit()

  if result != 0 {
    return errors.New("gtm_exit failed: " + string(result))
  }
  return nil
} // end of Stop

//Kill deletes global variable and its descendant nodes
func Kill(global string) (error){

  if len(global) < 1 {
    return errors.New("Kill failed - you must provide [glvn | (glvn[,...]) | *lname | *lvn ]")
  }

  _global := C.CString(global)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))

  result := C.cip_kill(_global, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("Kill failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of Kill

//ZKill deletes global variable and its descendant nodes
func ZKill(global string) (error){

  if len(global) < 1 {
    return errors.New("ZKill failed - you must provide glvn")
  }

  _global := C.CString(global)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))

  result := C.cip_zkill(_global, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("ZKill failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of ZKill

//Xecute runs the M code
func Xecute(code string) (error){

  if len(code) < 1 {
    return errors.New("Xecute failed - you must provide some code")
  }

  _code := C.CString(code)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_code))

  result := C.cip_xecute(_code, (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)))

  if result != 0 {
    return errors.New("Xecute failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return nil
}  // end of Xecute

func Order(global string, dir string) (string, error){

  if len(global) < 1 {
    return "", errors.New("Order failed - you must provide glvn")
  }

  if dir != "-1" {
    dir = "1"
  }

  _global := C.CString(global)
  _dir := C.CString(dir)
  _ret := make([]byte, maxretlen)
  errmsg := make([]byte, maxmsglen)
  defer C.free(unsafe.Pointer(_global))
  defer C.free(unsafe.Pointer(_dir))

  result := C.cip_order(_global, (*C.char)(unsafe.Pointer(&_ret[0])), (*C.char)(unsafe.Pointer(&errmsg[0])), C.int(len(errmsg)), maxretlen, _dir)

  if result != 0 {
    return "", errors.New("Get failed: " + string(result) + "Error message: " + string(errmsg))
  }
  return string(_ret), nil
} //end of Order
<|endoftext|>


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

package docker

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

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

var _ builder.Builder = &dockerBuilder{}

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

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

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

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

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

package docker

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

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

var _ builder.Builder = &dockerBuilder{}

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

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

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

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

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


<commit_before>package aws

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/glacier"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSGlacierVault_basic(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckGlacierVaultDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccGlacierVault_basic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGlacierVaultExists("aws_glacier_vault.test"),
				),
			},
		},
	})
}

func TestAccAWSGlacierVault_full(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckGlacierVaultDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccGlacierVault_full,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGlacierVaultExists("aws_glacier_vault.full"),
				),
			},
		},
	})
}

func TestAccAWSGlacierVault_RemoveNotifications(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckGlacierVaultDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccGlacierVault_full,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGlacierVaultExists("aws_glacier_vault.full"),
				),
			},
			resource.TestStep{
				Config: testAccGlacierVault_withoutNotification,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGlacierVaultExists("aws_glacier_vault.full"),
					testAccCheckVaultNotificationsMissing("aws_glacier_vault.full"),
				),
			},
		},
	})
}

func TestDiffGlacierVaultTags(t *testing.T) {
	cases := []struct {
		Old, New map[string]interface{}
		Create   map[string]string
		Remove   []string
	}{
		// Basic add/remove
		{
			Old: map[string]interface{}{
				"foo": "bar",
			},
			New: map[string]interface{}{
				"bar": "baz",
			},
			Create: map[string]string{
				"bar": "baz",
			},
			Remove: []string{
				"foo",
			},
		},

		// Modify
		{
			Old: map[string]interface{}{
				"foo": "bar",
			},
			New: map[string]interface{}{
				"foo": "baz",
			},
			Create: map[string]string{
				"foo": "baz",
			},
			Remove: []string{
				"foo",
			},
		},
	}

	for i, tc := range cases {
		c, r := diffGlacierVaultTags(mapGlacierVaultTags(tc.Old), mapGlacierVaultTags(tc.New))

		if !reflect.DeepEqual(c, tc.Create) {
			t.Fatalf("%d: bad create: %#v", i, c)
		}
		if !reflect.DeepEqual(r, tc.Remove) {
			t.Fatalf("%d: bad remove: %#v", i, r)
		}
	}
}

func testAccCheckGlacierVaultExists(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		glacierconn := testAccProvider.Meta().(*AWSClient).glacierconn
		out, err := glacierconn.DescribeVault(&glacier.DescribeVaultInput{
			VaultName: aws.String(rs.Primary.ID),
		})

		if err != nil {
			return err
		}

		if out.VaultARN == nil {
			return fmt.Errorf("No Glacier Vault Found")
		}

		if *out.VaultName != rs.Primary.ID {
			return fmt.Errorf("Glacier Vault Mismatch - existing: %q, state: %q",
				*out.VaultName, rs.Primary.ID)
		}

		return nil
	}
}

func testAccCheckVaultNotificationsMissing(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		glacierconn := testAccProvider.Meta().(*AWSClient).glacierconn
		out, err := glacierconn.GetVaultNotifications(&glacier.GetVaultNotificationsInput{
			VaultName: aws.String(rs.Primary.ID),
		})

		if awserr, ok := err.(awserr.Error); ok && awserr.Code() != "ResourceNotFoundException" {
			return fmt.Errorf("Expected ResourceNotFoundException for Vault %s Notification Block but got %s", rs.Primary.ID, awserr.Code())
		}

		if out.VaultNotificationConfig != nil {
			return fmt.Errorf("Vault Notification Block has been found for %s", rs.Primary.ID)
		}

		return nil
	}

}

func testAccCheckGlacierVaultDestroy(s *terraform.State) error {
	if len(s.RootModule().Resources) > 0 {
		return fmt.Errorf("Expected all resources to be gone, but found: %#v",
			s.RootModule().Resources)
	}

	return nil
}

const testAccGlacierVault_basic = `
resource "aws_glacier_vault" "test" {
  name = "my_test_vault"
}
`

const testAccGlacierVault_full = `
resource "aws_sns_topic" "aws_sns_topic" {
  name = "glacier-sns-topic"
}

resource "aws_glacier_vault" "full" {
  name = "my_test_vault"
  notification {
  	sns_topic = "${aws_sns_topic.aws_sns_topic.arn}"
  	events = ["ArchiveRetrievalCompleted","InventoryRetrievalCompleted"]
  }
  tags {
    Test="Test1"
  }
}
`

const testAccGlacierVault_withoutNotification = `
resource "aws_sns_topic" "aws_sns_topic" {
  name = "glacier-sns-topic"
}

resource "aws_glacier_vault" "full" {
  name = "my_test_vault"
  tags {
    Test="Test1"
  }
}
`
<commit_msg>provider/aws: fix CheckDestroy on glacier vault<commit_after>package aws

import (
	"fmt"
	"reflect"
	"testing"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/awserr"
	"github.com/aws/aws-sdk-go/service/glacier"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccAWSGlacierVault_basic(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckGlacierVaultDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccGlacierVault_basic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGlacierVaultExists("aws_glacier_vault.test"),
				),
			},
		},
	})
}

func TestAccAWSGlacierVault_full(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckGlacierVaultDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccGlacierVault_full,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGlacierVaultExists("aws_glacier_vault.full"),
				),
			},
		},
	})
}

func TestAccAWSGlacierVault_RemoveNotifications(t *testing.T) {
	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckGlacierVaultDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccGlacierVault_full,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGlacierVaultExists("aws_glacier_vault.full"),
				),
			},
			resource.TestStep{
				Config: testAccGlacierVault_withoutNotification,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckGlacierVaultExists("aws_glacier_vault.full"),
					testAccCheckVaultNotificationsMissing("aws_glacier_vault.full"),
				),
			},
		},
	})
}

func TestDiffGlacierVaultTags(t *testing.T) {
	cases := []struct {
		Old, New map[string]interface{}
		Create   map[string]string
		Remove   []string
	}{
		// Basic add/remove
		{
			Old: map[string]interface{}{
				"foo": "bar",
			},
			New: map[string]interface{}{
				"bar": "baz",
			},
			Create: map[string]string{
				"bar": "baz",
			},
			Remove: []string{
				"foo",
			},
		},

		// Modify
		{
			Old: map[string]interface{}{
				"foo": "bar",
			},
			New: map[string]interface{}{
				"foo": "baz",
			},
			Create: map[string]string{
				"foo": "baz",
			},
			Remove: []string{
				"foo",
			},
		},
	}

	for i, tc := range cases {
		c, r := diffGlacierVaultTags(mapGlacierVaultTags(tc.Old), mapGlacierVaultTags(tc.New))

		if !reflect.DeepEqual(c, tc.Create) {
			t.Fatalf("%d: bad create: %#v", i, c)
		}
		if !reflect.DeepEqual(r, tc.Remove) {
			t.Fatalf("%d: bad remove: %#v", i, r)
		}
	}
}

func testAccCheckGlacierVaultExists(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		glacierconn := testAccProvider.Meta().(*AWSClient).glacierconn
		out, err := glacierconn.DescribeVault(&glacier.DescribeVaultInput{
			VaultName: aws.String(rs.Primary.ID),
		})

		if err != nil {
			return err
		}

		if out.VaultARN == nil {
			return fmt.Errorf("No Glacier Vault Found")
		}

		if *out.VaultName != rs.Primary.ID {
			return fmt.Errorf("Glacier Vault Mismatch - existing: %q, state: %q",
				*out.VaultName, rs.Primary.ID)
		}

		return nil
	}
}

func testAccCheckVaultNotificationsMissing(name string) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.RootModule().Resources[name]
		if !ok {
			return fmt.Errorf("Not found: %s", name)
		}

		if rs.Primary.ID == "" {
			return fmt.Errorf("No ID is set")
		}

		glacierconn := testAccProvider.Meta().(*AWSClient).glacierconn
		out, err := glacierconn.GetVaultNotifications(&glacier.GetVaultNotificationsInput{
			VaultName: aws.String(rs.Primary.ID),
		})

		if awserr, ok := err.(awserr.Error); ok && awserr.Code() != "ResourceNotFoundException" {
			return fmt.Errorf("Expected ResourceNotFoundException for Vault %s Notification Block but got %s", rs.Primary.ID, awserr.Code())
		}

		if out.VaultNotificationConfig != nil {
			return fmt.Errorf("Vault Notification Block has been found for %s", rs.Primary.ID)
		}

		return nil
	}

}

func testAccCheckGlacierVaultDestroy(s *terraform.State) error {
	conn := testAccProvider.Meta().(*AWSClient).glacierconn

	for _, rs := range s.RootModule().Resources {
		if rs.Type != "aws_glacier_vault" {
			continue
		}

		input := &glacier.DescribeVaultInput{
			VaultName: aws.String(rs.Primary.ID),
		}
		if _, err := conn.DescribeVault(input); err != nil {
			// Verify the error is what we want
			if ae, ok := err.(awserr.Error); ok && ae.Code() == "ResourceNotFoundException" {
				continue
			}

			return err
		}
		return fmt.Errorf("still exists")
	}
	return nil
}

const testAccGlacierVault_basic = `
resource "aws_glacier_vault" "test" {
  name = "my_test_vault"
}
`

const testAccGlacierVault_full = `
resource "aws_sns_topic" "aws_sns_topic" {
  name = "glacier-sns-topic"
}

resource "aws_glacier_vault" "full" {
  name = "my_test_vault"
  notification {
  	sns_topic = "${aws_sns_topic.aws_sns_topic.arn}"
  	events = ["ArchiveRetrievalCompleted","InventoryRetrievalCompleted"]
  }
  tags {
    Test="Test1"
  }
}
`

const testAccGlacierVault_withoutNotification = `
resource "aws_sns_topic" "aws_sns_topic" {
  name = "glacier-sns-topic"
}

resource "aws_glacier_vault" "full" {
  name = "my_test_vault"
  tags {
    Test="Test1"
  }
}
`
<|endoftext|>


<commit_before>package start

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

	flag "github.com/ogier/pflag"
)

// Add adds a command to either the global Commands map, or, if the command has a parent value, to its parent command as a subcommand.
func Add(cmd *Command) error {
	return Commands.Add(cmd)
}

// Add for CommandMap adds a command to a list of commands.
func (c *CommandMap) Add(cmd *Command) error {
	if cmd == nil {
		return errors.New("Add: Parameter cmd must not be nil.")
	}
	cmd.init()
	if cmd.Parent == "" {
		// Add a top-level command.
		if _, alreadyExists := (*c)[cmd.Name]; alreadyExists {
			return errors.New("Add: command " + cmd.Name + " already exists.")
		}
		(*c)[cmd.Name] = cmd
		return nil
	}
	// Add a child command.
	if _, ok := Commands[cmd.Parent]; ok == false {
		return errors.New("Add: Parent command not found for subcommand " +
			cmd.Name + ".")
	}
	return Commands[cmd.Parent].Add(cmd)
}

// Add for Command adds a subcommand to a command.
func (cmd *Command) Add(subcmd *Command) error {
	cmd.init()
	subcmd.init()
	if _, alreadyExists := (*cmd).children[subcmd.Name]; alreadyExists {
		return errors.New("Add: subcommand " + subcmd.Name +
			" already exists for command " + cmd.Name + ".")
	}
	(*cmd).children[subcmd.Name] = subcmd
	return nil
}

// Usage prints a description of the application and the short help string
// of every command, when called with a nil argument.
// When called with a command as parameter, Usage prints this command's
// long help string as well as the short help strings of the available
// subcommands.
// Parse() or Up() must be called before invoking Usage().
func Usage(cmd *Command) error {
	if cmd == nil {
		applicationUsage()
	} else {
		err := commandUsage(cmd)
		if err != nil {
			fmt.Println(err)
		}
	}
	fmt.Println()
	return nil
}

func applicationUsage() {
	fmt.Println()
	fmt.Println(filepath.Base(os.Args[0]))
	fmt.Println()
	if len(Description) > 0 {
		fmt.Println(Description)
		fmt.Println()
	}
	if len(Commands) > 0 {
		width := maxCmdNameLen()
		fmt.Println("Available commands:")
		fmt.Println()
		for _, c := range Commands {
			fmt.Printf("%-*s  %s\n", width, c.Name, c.Short)
		}
	}
	globalFlags := checkFlags(nil)
	if len(globalFlags) > 0 {
		fmt.Println("Available global flags:")
		flagUsage(nil)
	}
}

func commandUsage(cmd *Command) error {
	if cmd.Parent != "" {
		fmt.Printf("%v ", cmd.Parent)
	}
	fmt.Printf("%v\n\n%v\n", cmd.Name, cmd.Long)
	if len(cmd.Flags) > 0 {
		if err := Parse(); err != nil {
			return err
		}
		fmt.Println()
		fmt.Println("Command-specific flags:")
		fmt.Println()
		flagUsage(cmd.Flags)
	}
	return nil
}

func flagUsage(flagNames []string) {
	flagUsageList := [][]string{}
	var flagNamesAndDefault string
	var width int
	for _, flagName := range flagNames {
		flg := flag.Lookup(flagName)
		if flg == nil {
			panic("Flag '" + flagName + "' does not exist.")
		}
		flagNamesAndDefault = fmt.Sprintf("-%s, --%s=%s", flg.Shorthand, flagName, flg.Value) // TODO -> pflag specific "Shorthand"
		if width < len(flagNamesAndDefault) {
			width = len(flagNamesAndDefault)
		}
		flagUsageList = append(flagUsageList, []string{flagNamesAndDefault, flg.Usage})
	}
	for _, flg := range flagUsageList {
		fmt.Printf("%-*s  %s\n", width, flg[0], flg[1])

	}
}

// maxCmdNameLen returns the length of the longest command name.
func maxCmdNameLen() int {
	maxLength := 0
	for _, cmd := range Commands {
		length := len(cmd.Name)
		if length > maxLength {
			maxLength = length
		}
	}
	return maxLength
}

// init initializes the children map.
// Calling init more than once for the same cmd should be safe.
func (cmd *Command) init() *Command {
	if len(cmd.children) == 0 {
		cmd.children = make(CommandMap)
	}
	cmd.registerPrivateFlags()
	return cmd
}

// registerPrivateFlags adds the command's flags to the global PrivateFlags map.
func (cmd *Command) registerPrivateFlags() {
	for _, f := range cmd.Flags {
		privateFlags[f] = true
	}
}

// If c is nil, then checkFlags returns all *global* flags.
// If c exists, then checkFlags returns a list of *private* flags that
// c has rejected as not being its own flags.
func checkFlags(c *Command) map[string]bool {
	notMyFlags := make(map[string]bool)
	// visit all flags that were passed in via command line:
	flag.Visit(func(f *flag.Flag) {
		isNotMyFlag := true
		if c != nil {
			for _, myFlag := range c.Flags {
				if f.Name == myFlag {
					isNotMyFlag = false // yes, f is among my flags
				}
			}
		}
		if isNotMyFlag {
			for pf := range privateFlags {
				if f.Name == pf {
					notMyFlags[pf] = true
				}
			}
		}
	})
	return notMyFlags
}

// readCommand extracts the command (and any subcommand, if applicable) from the
// list of arguments.
// Parameter args is the list of arguments *after* being parsed by flag.Parse().
// The first item of args is expected to be a command name. If that command has
// subcommands defined, the second item must contain the name of a subcommand.
// If any error occurs, readCommand returns an error and the pre-defined Usage
// command.
func readCommand(args []string) (*Command, error) {
	var cmd, subcmd *Command
	var ok bool
	if len(args) == 0 {
		Usage(nil)
		os.Exit(0)
	}
	var name = args[0]
	if cmd, ok = Commands[name]; ok {
		// command found. Remove it from the argument list.
		args = args[1:]
		if len(cmd.children) > 0 {
			var subname = args[0]
			subcmd, ok = cmd.children[subname]
			if ok {
				// subcommand found.
				args = args[1:]
				cmd = subcmd
			} else {
				// no subcommand passed in, so cmd should have a Cmd to execute
				if cmd.Cmd == nil {
					errmsg := "Command " + cmd.Name + " requires one of these subcommands: "
					for _, n := range cmd.children {
						errmsg += n.Name + ", "
					}
					return &Command{
						Cmd: Usage,
					}, errors.New(errmsg)
				}
			}
		} else {
			cmd = Commands[name]
		}
		cmd.Args = args
		notMyFlags := checkFlags(cmd)
		if len(notMyFlags) > 0 {
			errmsg := fmt.Sprintf("Unknown flags: %v", notMyFlags)
			return &Command{
				Cmd: Usage,
			}, errors.New(errmsg)
		}
		return cmd, nil
	}
	return &Command{
		Cmd: Usage,
	}, nil
}
<commit_msg>Changed: var description is now private Changed: initial empty line in command usage output Changed: Usage(nil), os.Exit() -> return command that calls Usage(nil) Changed: When readCommand fails within a command, the failing command is passed to Usage() via closure.<commit_after>package start

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

	flag "github.com/ogier/pflag"
)

// Add adds a command to either the global Commands map, or, if the command has a parent value, to its parent command as a subcommand.
func Add(cmd *Command) error {
	return Commands.Add(cmd)
}

// Add for CommandMap adds a command to a list of commands.
func (c *CommandMap) Add(cmd *Command) error {
	if cmd == nil {
		return errors.New("Add: Parameter cmd must not be nil.")
	}
	cmd.init()
	if cmd.Parent == "" {
		// Add a top-level command.
		if _, alreadyExists := (*c)[cmd.Name]; alreadyExists {
			return errors.New("Add: command " + cmd.Name + " already exists.")
		}
		(*c)[cmd.Name] = cmd
		return nil
	}
	// Add a child command.
	if _, ok := Commands[cmd.Parent]; ok == false {
		return errors.New("Add: Parent command not found for subcommand " +
			cmd.Name + ".")
	}
	return Commands[cmd.Parent].Add(cmd)
}

// Add for Command adds a subcommand to a command.
func (cmd *Command) Add(subcmd *Command) error {
	cmd.init()
	subcmd.init()
	if _, alreadyExists := (*cmd).children[subcmd.Name]; alreadyExists {
		return errors.New("Add: subcommand " + subcmd.Name +
			" already exists for command " + cmd.Name + ".")
	}
	(*cmd).children[subcmd.Name] = subcmd
	return nil
}

// Usage prints a description of the application and the short help string
// of every command, when called with a nil argument.
// When called with a command as parameter, Usage prints this command's
// long help string as well as the short help strings of the available
// subcommands.
// Parse() or Up() must be called before invoking Usage().
func Usage(cmd *Command) error {
	if cmd == nil {
		applicationUsage()
	} else {
		err := commandUsage(cmd)
		if err != nil {
			fmt.Println(err)
		}
	}
	fmt.Println()
	return nil
}

func applicationUsage() {
	fmt.Println()
	fmt.Println(filepath.Base(os.Args[0]))
	fmt.Println()
	if len(description) > 0 {
		fmt.Println(description)
		fmt.Println()
	}
	if len(Commands) > 0 {
		width := maxCmdNameLen()
		fmt.Println("Available commands:")
		fmt.Println()
		for _, c := range Commands {
			fmt.Printf("%-*s  %s\n", width, c.Name, c.Short)
		}
	}
	globalFlags := checkFlags(nil)
	if len(globalFlags) > 0 {
		fmt.Println("Available global flags:")
		flagUsage(nil)
	}
}

func commandUsage(cmd *Command) error {
	fmt.Println()
	if cmd.Parent != "" {
		fmt.Printf("%v ", cmd.Parent)
	}
	fmt.Printf("%v\n\n%v\n", cmd.Name, cmd.Long)
	if len(cmd.Flags) > 0 {
		if err := Parse(); err != nil {
			return err
		}
		fmt.Println()
		fmt.Println("Command-specific flags:")
		fmt.Println()
		flagUsage(cmd.Flags)
	}
	return nil
}

func flagUsage(flagNames []string) {
	flagUsageList := [][]string{}
	var flagNamesAndDefault string
	var width int
	for _, flagName := range flagNames {
		flg := flag.Lookup(flagName)
		if flg == nil {
			panic("Flag '" + flagName + "' does not exist.")
		}
		flagNamesAndDefault = fmt.Sprintf("-%s, --%s=%s", flg.Shorthand, flagName, flg.Value) // TODO -> pflag specific "Shorthand"
		if width < len(flagNamesAndDefault) {
			width = len(flagNamesAndDefault)
		}
		flagUsageList = append(flagUsageList, []string{flagNamesAndDefault, flg.Usage})
	}
	for _, flg := range flagUsageList {
		fmt.Printf("%-*s  %s\n", width, flg[0], flg[1])

	}
}

// maxCmdNameLen returns the length of the longest command name.
func maxCmdNameLen() int {
	maxLength := 0
	for _, cmd := range Commands {
		length := len(cmd.Name)
		if length > maxLength {
			maxLength = length
		}
	}
	return maxLength
}

// init initializes the children map.
// Calling init more than once for the same cmd should be safe.
func (cmd *Command) init() *Command {
	if len(cmd.children) == 0 {
		cmd.children = make(CommandMap)
	}
	cmd.registerPrivateFlags()
	return cmd
}

// registerPrivateFlags adds the command's flags to the global PrivateFlags map.
func (cmd *Command) registerPrivateFlags() {
	for _, f := range cmd.Flags {
		privateFlags[f] = true
	}
}

// If c is nil, then checkFlags returns all *global* flags.
// If c exists, then checkFlags returns a list of *private* flags that
// c has rejected as not being its own flags.
func checkFlags(c *Command) map[string]bool {
	notMyFlags := make(map[string]bool)
	// visit all flags that were passed in via command line:
	flag.Visit(func(f *flag.Flag) {
		isNotMyFlag := true
		if c != nil {
			for _, myFlag := range c.Flags {
				if f.Name == myFlag {
					isNotMyFlag = false // yes, f is among my flags
				}
			}
		}
		if isNotMyFlag {
			for pf := range privateFlags {
				if f.Name == pf {
					notMyFlags[pf] = true
				}
			}
		}
	})
	return notMyFlags
}

// readCommand extracts the command (and any subcommand, if applicable) from the
// list of arguments.
// Parameter args is the list of arguments *after* being parsed by flag.Parse().
// The first item of args is expected to be a command name. If that command has
// subcommands defined, the second item must contain the name of a subcommand.
// If any error occurs, readCommand returns an error and the pre-defined Usage
// command.
func readCommand(args []string) (*Command, error) {
	var cmd, subcmd *Command
	var ok bool
	if len(args) == 0 {
		Usage(cmd)
		return &Command{
			Cmd: Usage,
		}, nil
	}
	var name = args[0]
	if cmd, ok = Commands[name]; ok {
		// command found. Remove it from the argument list.
		args = args[1:]
		if len(cmd.children) > 0 {
			var subname = args[0]
			subcmd, ok = cmd.children[subname]
			if ok {
				// subcommand found.
				args = args[1:]
				cmd = subcmd
			} else {
				// no subcommand passed in, so cmd should have a Cmd to execute
				if cmd.Cmd == nil {
					errmsg := "Command " + cmd.Name + " requires one of these subcommands: "
					for _, n := range cmd.children {
						errmsg += n.Name + ", "
					}
					return &Command{
						Cmd: func(cmd *Command) error { return Usage(cmd) },
					}, errors.New(errmsg)
				}
			}
		} else {
			cmd = Commands[name]
		}
		cmd.Args = args
		notMyFlags := checkFlags(cmd)
		if len(notMyFlags) > 0 {
			errmsg := fmt.Sprintf("Unknown flags: %v", notMyFlags)
			return &Command{
				Cmd: func(cmd *Command) error { return Usage(cmd) },
			}, errors.New(errmsg)
		}
		return cmd, nil
	}
	return &Command{
		Cmd: Usage,
	}, nil
}
<|endoftext|>


<commit_before>package db

import(
    "log"
    "os"
    _ "sync"
    "database/sql"
	_ "github.com/furio/widserve/db/uid"

	"gopkg.in/gorp.v1"
	"github.com/mattn/go-sqlite3"
	"github.com/go-sql-driver/mysql"
)

// Force godeps
var _ = mysql.ErrBusyBuffer
var _ = sqlite3.SQLiteConn{}

type DataSource interface {
    GetWidget(id string) Widget;
}

type DatabaseSource struct {
    orm *gorp.DbMap
}

type DbType int
const (
    Local DbType = iota
    MySQL
)

const tableName string = "widgets"

func GetDataSource(dbType DbType, config map[string]string) DataSource {
    outDb := DatabaseSource{}

    if (dbType == Local) {
        db, err := sql.Open("sqlite3", "/tmp/widget_db.bin") // config["dbSource"]
        if (err != nil) {
            return nil
        }

        outDb.orm = &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
    } else if (dbType == MySQL) {
        db, err := sql.Open("mysql", "user:password@/dbname") // config["dbSource"]
        if (err != nil) {
            return nil
        }

        outDb.orm = &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
    }

    // Bind table
    outDb.orm.AddTableWithName(Widget{}, tableName).SetKeys(false, "WidgetID")

    // create DB
    createDb(outDb, dbType)

    // If from config
    outDb.orm.TraceOn("[gorp]", log.New(os.Stdout, "db:", log.Lmicroseconds))

    return outDb
}

func mapTable(dbSource DatabaseSource) {
    // Had issue with inline mapping

    table := dbSource.orm.AddTableWithName(Widget{}, tableName)
    table.SetKeys(false, "WidgetID")
    table.ColMap("WidgetID").SetNotNull(false).SetMaxSize(255)
    table.ColMap("ApiKey").SetNotNull(false).SetMaxSize(255)
    table.ColMap("ApiPath").SetNotNull(false).SetMaxSize(1024)
    table.ColMap("Created")
    table.ColMap("CacheElapse")
    table.ColMap("NextCheck")
}

func createDb(dbSource DatabaseSource, dbType DbType) bool {
    err := dbSource.orm.CreateTablesIfNotExists()

    if (err == nil) {
        if (dbType == Local) {
            res,err := dbSource.orm.Db.Exec("CREATE INDEX IF NOT EXISTS nextcheckindex ON " + tableName + "(NextCheck)")
            log.Println(res)
            log.Println(err)
            res,err = dbSource.orm.Db.Exec("CREATE INDEX IF NOT EXISTS cachedurationindex ON " + tableName + "(CacheElapse)")
            log.Println(res)
            log.Println(err)
            res,err = dbSource.orm.Db.Exec("CREATE INDEX IF NOT EXISTS apikeyindex ON " + tableName + "(ApiKey)")
            log.Println(res)
            log.Println(err)
        } else if (dbType == MySQL) {
            mySqlIndex := "SELECT COUNT(1) IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema=DATABASE() AND table_name=? AND index_name=?"

            i64, err := dbSource.orm.SelectInt(mySqlIndex, tableName, "nextcheckindex")
            if (err == nil && i64 == 1) {
                dbSource.orm.Exec("CREATE INDEX nextcheckindex ON " + tableName + "(NextCheck)")
            }

            i64, err = dbSource.orm.SelectInt(mySqlIndex, tableName, "cachedurationindex")
            if (err == nil && i64 == 1) {
                dbSource.orm.Exec("CREATE INDEX cachedurationindex ON " + tableName + "(CacheElapse)")
            }

            i64, err = dbSource.orm.SelectInt(mySqlIndex, tableName, "apikeyindex")
            if (err == nil && i64 == 1) {
                dbSource.orm.Exec("CREATE INDEX apikeyindex ON " + tableName + "(ApiKey)")
            }
        }
    }

    return err == nil
}

func (this DatabaseSource) GetWidget(id string) Widget {
    p1, _ := this.orm.Get(Widget{}, id)

    return p1.(Widget)
}<commit_msg>Db stuff<commit_after>package db

import(
    "log"
    "os"
    _ "sync"
    "database/sql"
	_ "github.com/furio/widserve/db/uid"

	"gopkg.in/gorp.v1"
	"github.com/mattn/go-sqlite3"
	"github.com/go-sql-driver/mysql"
)

// Force godeps
var _ = mysql.ErrBusyBuffer
var _ = sqlite3.SQLiteConn{}

type DataSource interface {
    GetWidget(id string) Widget;
}

type DatabaseSource struct {
    orm *gorp.DbMap
}

type DbType int
const (
    Local DbType = iota
    MySQL
)

const tableName string = "widgets"

func GetDataSource(dbType DbType, config map[string]string) DataSource {
    outDb := DatabaseSource{}

    if (dbType == Local) {
        db, err := sql.Open("sqlite3", "/tmp/widget_db.bin") // config["dbSource"]
        if (err != nil) {
            return nil
        }

        outDb.orm = &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
    } else if (dbType == MySQL) {
        db, err := sql.Open("mysql", "user:password@/dbname") // config["dbSource"]
        if (err != nil) {
            return nil
        }

        outDb.orm = &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
    }

    // Bind table
    mapTable(outDb)

    // create DB
    createDb(outDb, dbType)

    // If from config
    outDb.orm.TraceOn("[gorp]", log.New(os.Stdout, "db:", log.Lmicroseconds))

    return outDb
}

func mapTable(dbSource DatabaseSource) {
    // Had issue with inline mapping

    table := dbSource.orm.AddTableWithName(Widget{}, tableName)
    table.SetKeys(false, "WidgetID")
    table.ColMap("WidgetID").SetNotNull(true).SetMaxSize(255)
    table.ColMap("ApiKey").SetNotNull(true).SetMaxSize(255)
    table.ColMap("ApiPath").SetNotNull(true).SetMaxSize(1024)
    table.ColMap("Created")
    table.ColMap("CacheElapse")
    table.ColMap("NextCheck")
}

func createDb(dbSource DatabaseSource, dbType DbType) bool {
    err := dbSource.orm.CreateTablesIfNotExists()

    if (err == nil) {
        if (dbType == Local) {
            dbSource.orm.Db.Exec("CREATE INDEX IF NOT EXISTS nextcheckindex ON " + tableName + "(NextCheck)")
            dbSource.orm.Db.Exec("CREATE INDEX IF NOT EXISTS cachedurationindex ON " + tableName + "(CacheElapse)")
            dbSource.orm.Db.Exec("CREATE INDEX IF NOT EXISTS apikeyindex ON " + tableName + "(ApiKey)")
        } else if (dbType == MySQL) {
            mySqlIndex := "SELECT COUNT(1) IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema=DATABASE() AND table_name=? AND index_name=?"

            i64, err := dbSource.orm.SelectInt(mySqlIndex, tableName, "nextcheckindex")
            if (err == nil && i64 == 1) {
                dbSource.orm.Db.Exec("CREATE INDEX nextcheckindex ON " + tableName + "(NextCheck)")
            }

            i64, err = dbSource.orm.SelectInt(mySqlIndex, tableName, "cachedurationindex")
            if (err == nil && i64 == 1) {
                dbSource.orm.Db.Exec("CREATE INDEX cachedurationindex ON " + tableName + "(CacheElapse)")
            }

            i64, err = dbSource.orm.SelectInt(mySqlIndex, tableName, "apikeyindex")
            if (err == nil && i64 == 1) {
                dbSource.orm.Db.Exec("CREATE INDEX apikeyindex ON " + tableName + "(ApiKey)")
            }
        }
    }

    return err == nil
}

func (this DatabaseSource) GetWidget(id string) Widget {
    p1, _ := this.orm.Get(Widget{}, id)

    return p1.(Widget)
}<|endoftext|>


<commit_before>package main

import (
	// stdlib
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"path/filepath"
	"regexp"
	"text/template"

	// external
	"github.com/VictorLowther/go-git/git"
	"github.com/russross/blackfriday"
)

const (
	GOIKIVERSION = "0.0.1"
)

var (
	displayVersion bool
	config         Config
	templates      *template.Template
	validPath      *regexp.Regexp
	validLink      *regexp.Regexp
	repo           *git.Repo
)

type Config struct {
	Port    int
	Host    string
	DataDir string
}

type Page struct {
	Title       string
	Body        string
	Description string
}

func init() {
	flag.IntVar(&config.Port, "port", 4567, "Bind port")
	flag.StringVar(&config.Host, "host", "0.0.0.0", "Hostname or IP address to listen on")
	flag.StringVar(&config.DataDir, "data-dir", "./data", "Directory for page data")
	flag.BoolVar(&displayVersion, "version", false, "Display version and exit")

	templates = template.Must(template.ParseFiles("templates/edit.html", "templates/view.html"))
	validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9/]+)$")
	validLink = regexp.MustCompile(`\[([^\]]+)]\(\)`)
}

func (p *Page) save() error {
	filename := buildFilename(p.Title)
	err := ioutil.WriteFile(filepath.Join(config.DataDir, filename), []byte(p.Body), 0600)
	if err != nil {
		return err
	}

	stdOut, stdErr := gitAdd(filename)
	if stdErr.Len() > 0 {
		return fmt.Errorf("Unable to add %s", filename)
	}
	log.Println("add:", stdOut)

	message := p.Description
	if len(message) == 0 {
		message = fmt.Sprintf("Update %s", filename)
	}
	stdOut, stdErr = gitCommit(message)
	if stdErr.Len() > 0 {
		return fmt.Errorf("Unable to commit message: %s", message)
	}
	log.Println("commit:", stdOut)

	return nil
}

func buildFilename(title string) string {
	return title + ".txt"
}

func loadPage(title string, revision string) (*Page, error) {
	filename := buildFilename(title)
	if len(revision) == 0 {
		revision = "HEAD"
	}
	body, err := gitShow(filename, revision)
	if err.Len() > 0 {
		return &Page{Title: title, Body: body.String()}, fmt.Errorf("Unable to load page content from %s at %s\n", filename, revision)
	}
	return &Page{Title: title, Body: body.String()}, nil
}

func gitShow(file string, revision string) (out, err *bytes.Buffer) {
	res, out, err := repo.Git("show", fmt.Sprintf("%s:%s", revision, file))
	runErr := res.Run()
	if runErr != nil {
		log.Println("Unable to load revision %s from %s, error: %v\n", revision, file, runErr)
	}
	return
}

func gitAdd(file string) (out, err *bytes.Buffer) {
	res, out, err := repo.Git("add", file)
	runErr := res.Run()
	if runErr != nil {
		log.Printf("Unable to add file %s, error: %v\n", file, runErr)
	}
	return
}

func gitCommit(message string) (out, err *bytes.Buffer) {
	res, out, err := repo.Git("commit", "-m", message)
	runErr := res.Run()
	if runErr != nil {
		log.Println("Unable to commit message %s, error: %v\n", message, runErr)
	}
	return
}

func gitLog(file string) (out, err *bytes.Buffer) {
	res, out, err := repo.Git("log", "--pretty=format:%h %ad %s", "--date=relative", file)
	runErr := res.Run()
	if runErr != nil {
		log.Println("Unable to load log of %s, error: %v\n", file, runErr)
	}
	return
}

func processLinks(content []byte) []byte {
	return validLink.ReplaceAllFunc(content, func(match []byte) []byte {
		return validLink.ReplaceAll(match, []byte("[$1]($1)"))
	})
}

func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title, "HEAD")
	if err != nil {
		http.Redirect(w, r, "/edit/"+title, http.StatusFound)
		return
	}

	content := []byte(p.Body)
	content = processLinks(content)
	content = blackfriday.MarkdownCommon(content)
	p.Body = string(content)

	renderTemplate(w, "view", p)
}

func editHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title, "HEAD")
	if err != nil {
		p = &Page{Title: title}
	}
	renderTemplate(w, "edit", p)
}

func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
	body := r.FormValue("body")
	description := r.FormValue("description")
	p := &Page{Title: title, Body: body, Description: description}
	err := p.save()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/view/"+title, http.StatusFound)
}

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
	err := templates.ExecuteTemplate(w, tmpl+".html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path
		if path == "/" {
			path = "/view/FrontPage"
		}
		fmt.Println(path)
		m := validPath.FindStringSubmatch(path)
		if m == nil {
			http.NotFound(w, r)
			return
		}
		fn(w, r, m[2])
	}
}

func main() {
	flag.Parse()

	// Display version and exit
	if displayVersion {
		fmt.Println("Goiki", GOIKIVERSION)
		return
	}

	// Load repo
	var err error
	if repo, err = git.Open(config.DataDir); err != nil {
		log.Fatalf("Unable to open the repo at %s. Please check to make sure it exists and is initialized.\n%v", config.DataDir, err)
	}

	// Define routes
	http.Handle("/static/", http.FileServer(http.Dir("./")))
	http.HandleFunc("/", makeHandler(viewHandler))
	http.HandleFunc("/view/", makeHandler(viewHandler))
	http.HandleFunc("/edit/", makeHandler(editHandler))
	http.HandleFunc("/save/", makeHandler(saveHandler))

	l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.Host, config.Port))
	if err != nil {
		log.Fatal(err)
	}

	s := &http.Server{}
	s.Serve(l)
	return
}
<commit_msg>Println -> Printf<commit_after>package main

import (
	// stdlib
	"bytes"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"path/filepath"
	"regexp"
	"text/template"

	// external
	"github.com/VictorLowther/go-git/git"
	"github.com/russross/blackfriday"
)

const (
	GOIKIVERSION = "0.0.1"
)

var (
	displayVersion bool
	config         Config
	templates      *template.Template
	validPath      *regexp.Regexp
	validLink      *regexp.Regexp
	repo           *git.Repo
)

type Config struct {
	Port    int
	Host    string
	DataDir string
}

type Page struct {
	Title       string
	Body        string
	Description string
}

func init() {
	flag.IntVar(&config.Port, "port", 4567, "Bind port")
	flag.StringVar(&config.Host, "host", "0.0.0.0", "Hostname or IP address to listen on")
	flag.StringVar(&config.DataDir, "data-dir", "./data", "Directory for page data")
	flag.BoolVar(&displayVersion, "version", false, "Display version and exit")

	templates = template.Must(template.ParseFiles("templates/edit.html", "templates/view.html"))
	validPath = regexp.MustCompile("^/(edit|save|view)/([a-zA-Z0-9/]+)$")
	validLink = regexp.MustCompile(`\[([^\]]+)]\(\)`)
}

func (p *Page) save() error {
	filename := buildFilename(p.Title)
	err := ioutil.WriteFile(filepath.Join(config.DataDir, filename), []byte(p.Body), 0600)
	if err != nil {
		return err
	}

	stdOut, stdErr := gitAdd(filename)
	if stdErr.Len() > 0 {
		return fmt.Errorf("Unable to add %s", filename)
	}
	log.Println("add:", stdOut)

	message := p.Description
	if len(message) == 0 {
		message = fmt.Sprintf("Update %s", filename)
	}
	stdOut, stdErr = gitCommit(message)
	if stdErr.Len() > 0 {
		return fmt.Errorf("Unable to commit message: %s", message)
	}
	log.Println("commit:", stdOut)

	return nil
}

func buildFilename(title string) string {
	return title + ".txt"
}

func loadPage(title string, revision string) (*Page, error) {
	filename := buildFilename(title)
	if len(revision) == 0 {
		revision = "HEAD"
	}
	body, err := gitShow(filename, revision)
	if err.Len() > 0 {
		return &Page{Title: title, Body: body.String()}, fmt.Errorf("Unable to load page content from %s at %s\n", filename, revision)
	}
	return &Page{Title: title, Body: body.String()}, nil
}

func gitShow(file string, revision string) (out, err *bytes.Buffer) {
	res, out, err := repo.Git("show", fmt.Sprintf("%s:%s", revision, file))
	runErr := res.Run()
	if runErr != nil {
		log.Printf("Unable to load revision %s from %s, error: %v\n", revision, file, runErr)
	}
	return
}

func gitAdd(file string) (out, err *bytes.Buffer) {
	res, out, err := repo.Git("add", file)
	runErr := res.Run()
	if runErr != nil {
		log.Printf("Unable to add file %s, error: %v\n", file, runErr)
	}
	return
}

func gitCommit(message string) (out, err *bytes.Buffer) {
	res, out, err := repo.Git("commit", "-m", message)
	runErr := res.Run()
	if runErr != nil {
		log.Println("Unable to commit message %s, error: %v\n", message, runErr)
	}
	return
}

func gitLog(file string) (out, err *bytes.Buffer) {
	res, out, err := repo.Git("log", "--pretty=format:%h %ad %s", "--date=relative", file)
	runErr := res.Run()
	if runErr != nil {
		log.Println("Unable to load log of %s, error: %v\n", file, runErr)
	}
	return
}

func processLinks(content []byte) []byte {
	return validLink.ReplaceAllFunc(content, func(match []byte) []byte {
		return validLink.ReplaceAll(match, []byte("[$1]($1)"))
	})
}

func viewHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title, "HEAD")
	if err != nil {
		http.Redirect(w, r, "/edit/"+title, http.StatusFound)
		return
	}

	content := []byte(p.Body)
	content = processLinks(content)
	content = blackfriday.MarkdownCommon(content)
	p.Body = string(content)

	renderTemplate(w, "view", p)
}

func editHandler(w http.ResponseWriter, r *http.Request, title string) {
	p, err := loadPage(title, "HEAD")
	if err != nil {
		p = &Page{Title: title}
	}
	renderTemplate(w, "edit", p)
}

func saveHandler(w http.ResponseWriter, r *http.Request, title string) {
	body := r.FormValue("body")
	description := r.FormValue("description")
	p := &Page{Title: title, Body: body, Description: description}
	err := p.save()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	http.Redirect(w, r, "/view/"+title, http.StatusFound)
}

func renderTemplate(w http.ResponseWriter, tmpl string, p *Page) {
	err := templates.ExecuteTemplate(w, tmpl+".html", p)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
	}
}

func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		path := r.URL.Path
		if path == "/" {
			path = "/view/FrontPage"
		}
		fmt.Println(path)
		m := validPath.FindStringSubmatch(path)
		if m == nil {
			http.NotFound(w, r)
			return
		}
		fn(w, r, m[2])
	}
}

func main() {
	flag.Parse()

	// Display version and exit
	if displayVersion {
		fmt.Println("Goiki", GOIKIVERSION)
		return
	}

	// Load repo
	var err error
	if repo, err = git.Open(config.DataDir); err != nil {
		log.Fatalf("Unable to open the repo at %s. Please check to make sure it exists and is initialized.\n%v", config.DataDir, err)
	}

	// Define routes
	http.Handle("/static/", http.FileServer(http.Dir("./")))
	http.HandleFunc("/", makeHandler(viewHandler))
	http.HandleFunc("/view/", makeHandler(viewHandler))
	http.HandleFunc("/edit/", makeHandler(editHandler))
	http.HandleFunc("/save/", makeHandler(saveHandler))

	l, err := net.Listen("tcp", fmt.Sprintf("%s:%d", config.Host, config.Port))
	if err != nil {
		log.Fatal(err)
	}

	s := &http.Server{}
	s.Serve(l)
	return
}
<|endoftext|>


<commit_before>package libvirt

import (
	"errors"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/common"
	commonssh "github.com/mitchellh/packer/common/ssh"
	"github.com/mitchellh/packer/helper/communicator"
	"github.com/mitchellh/packer/helper/config"
	"github.com/mitchellh/packer/packer"
	"github.com/mitchellh/packer/template/interpolate"
)

const BuilderId = "vtolstov.libvirt"

type Builder struct {
	config Config
	runner multistep.Runner
}

type Config struct {
	common.PackerConfig `mapstructure:",squash"`
	Comm                communicator.Config `mapstructure:",squash"`
	DomainType          string              `mapstructure:"domain_type"`
	BootCommand         []string            `mapstructure:"boot_command"`
	MemorySize          uint                `mapstructure:"memory_size"`
	Arch                string              `mapstructure:"arch"`
	DiskName            string              `mapstructure:"disk_name"`
	DiskType            string              `mapstructure:"disk_type"`
	DiskSize            uint                `mapstructure:"disk_size"`
	FloppyFiles         []string            `mapstructure:"floppy_files"`
	HTTPDir             string              `mapstructure:"http_directory"`
	HTTPPortMin         uint                `mapstructure:"http_port_min"`
	HTTPPortMax         uint                `mapstructure:"http_port_max"`
	ISOUrl              string              `mapstructure:"iso_url"`
	OutputDir           string              `mapstructure:"output_directory"`
	ShutdownCommand     string              `mapstructure:"shutdown_command"`
	SSHHostPortMin      uint                `mapstructure:"ssh_host_port_min"`
	SSHHostPortMax      uint                `mapstructure:"ssh_host_port_max"`
	SSHKeyPath          string              `mapstructure:"ssh_key_path"`
	SSHPassword         string              `mapstructure:"ssh_password"`
	SSHPort             uint                `mapstructure:"ssh_port"`
	SSHUser             string              `mapstructure:"ssh_username"`
	VMName              string              `mapstructure:"vm_name"`

	DomainXml   string `mapstructure:"domain_xml"`
	VolumeXml   string `mapstructure:"volume_xml"`
	PoolName    string `mapstructure:"pool_name"`
	PoolXml     string `mapstructure:"pool_xml"`
	NetworkName string `mapstructure:"network_name"`
	NetworkXml  string `mapstructure:"network_xml"`
	NetworkType string `mapstructure:"network_type"`
	LibvirtUrl  string `mapstructure:"libvirt_url"`

	RawBootWait        string `mapstructure:"boot_wait"`
	RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
	RawSSHWaitTimeout  string `mapstructure:"ssh_wait_timeout"`

	bootWait        time.Duration ``
	shutdownTimeout time.Duration ``
	sshWaitTimeout  time.Duration ``
	ctx             interpolate.Context
}

func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
	var errs *packer.MultiError
	warnings := make([]string, 0)

	err := config.Decode(&b.config, &config.DecodeOpts{
		Interpolate:        true,
		InterpolateContext: &b.config.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"boot_command",
				"qemuargs",
			},
		},
	}, raws...)
	if err != nil {
		return nil, err
	}

	if b.config.MemorySize < 1 {
		b.config.MemorySize = 512
	}

	if b.config.DomainType == "" {
		b.config.DomainType = "kvm"
	}

	if b.config.DiskType == "" {
		b.config.DiskType = "raw"
	}

	if b.config.DiskSize == 0 {
		b.config.DiskSize = 5000
	}

	if b.config.PoolXml == "" {
		b.config.PoolXml = PackerPool
	}

	if b.config.PoolName == "" {
		b.config.PoolName = "packer"
	}

	if b.config.NetworkName == "" {
		b.config.NetworkName = "packer"
	}

	if b.config.VolumeXml == "" {
		b.config.VolumeXml = PackerVolume
	}

	if b.config.NetworkType == "" {
		b.config.NetworkType = "user"
	}

	if b.config.NetworkType != "user" {
		if b.config.NetworkXml == "" {
			b.config.NetworkXml = PackerNetwork
		}
	}

	if b.config.DomainXml == "" {
		b.config.DomainXml = PackerQemuXML
	}

	if b.config.FloppyFiles == nil {
		b.config.FloppyFiles = make([]string, 0)
	}

	if b.config.HTTPPortMin == 0 {
		b.config.HTTPPortMin = 8000
	}

	if b.config.HTTPPortMax == 0 {
		b.config.HTTPPortMax = 9000
	}

	if b.config.OutputDir == "" {
		b.config.OutputDir = fmt.Sprintf("output-%s", b.config.PackerBuildName)
	}

	if b.config.RawBootWait == "" {
		b.config.RawBootWait = "10s"
	}

	if b.config.SSHHostPortMin == 0 {
		b.config.SSHHostPortMin = 2222
	}

	if b.config.SSHHostPortMax == 0 {
		b.config.SSHHostPortMax = 4444
	}

	if b.config.SSHPort == 0 {
		b.config.SSHPort = 22
	}

	if b.config.VMName == "" {
		b.config.VMName = fmt.Sprintf("packer-%s", b.config.PackerBuildName)
	}

	if b.config.DiskName == "" {
		b.config.DiskName = b.config.VMName
	}

	/*
		// Errors
		templates := map[string]*string{
			"disk_name":        &b.config.DiskName,
			"http_directory":   &b.config.HTTPDir,
			"output_directory": &b.config.OutputDir,
			"shutdown_command": &b.config.ShutdownCommand,
			"ssh_password":     &b.config.SSHPassword,
			"ssh_username":     &b.config.SSHUser,
			"vm_name":          &b.config.VMName,
			"boot_wait":        &b.config.RawBootWait,
			"shutdown_timeout": &b.config.RawShutdownTimeout,
			"ssh_wait_timeout": &b.config.RawSSHWaitTimeout,
			"domain_xml":       &b.config.DomainXml,
			"volume_xml":       &b.config.VolumeXml,
			"pool_name":        &b.config.PoolName,
			"pool_xml":         &b.config.PoolXml,
			"network_name":     &b.config.NetworkName,
			"network_xml":      &b.config.NetworkXml,
		}
	*/
	b.config.ISOUrl, err = common.DownloadableURL(b.config.ISOUrl)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed to parse iso_url: %s", err))
	}

	if b.config.HTTPPortMin > b.config.HTTPPortMax {
		errs = packer.MultiErrorAppend(
			errs, errors.New("http_port_min must be less than http_port_max"))
	}

	if !b.config.PackerForce {
		if _, err := os.Stat(b.config.OutputDir); err == nil {
			errs = packer.MultiErrorAppend(
				errs,
				fmt.Errorf("Output directory '%s' already exists. It must not exist.", b.config.OutputDir))
		}
	}

	b.config.bootWait, err = time.ParseDuration(b.config.RawBootWait)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing boot_wait: %s", err))
	}

	if b.config.RawShutdownTimeout == "" {
		b.config.RawShutdownTimeout = "5m"
	}

	if b.config.RawSSHWaitTimeout == "" {
		b.config.RawSSHWaitTimeout = "20m"
	}

	b.config.shutdownTimeout, err = time.ParseDuration(b.config.RawShutdownTimeout)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err))
	}

	if b.config.SSHKeyPath != "" {
		if _, err := os.Stat(b.config.SSHKeyPath); err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
		} else if _, err := commonssh.FileSigner(b.config.SSHKeyPath); err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
		}
	}

	if b.config.SSHHostPortMin > b.config.SSHHostPortMax {
		errs = packer.MultiErrorAppend(
			errs, errors.New("ssh_host_port_min must be less than ssh_host_port_max"))
	}

	if b.config.SSHUser == "" && !strings.HasPrefix(b.config.LibvirtUrl, "lxc") {
		errs = packer.MultiErrorAppend(
			errs, errors.New("An ssh_username must be specified."))
	}

	b.config.sshWaitTimeout, err = time.ParseDuration(b.config.RawSSHWaitTimeout)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing ssh_wait_timeout: %s", err))
	}

	// Warnings
	if b.config.ShutdownCommand == "" {
		warnings = append(warnings,
			"A shutdown_command was not specified. Without a shutdown command, Packer\n"+
				"will forcibly halt the virtual machine, which may result in data loss.")
	}

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

	return warnings, nil
}

func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
	// Check we have the required tools

	steps := []multistep.Step{
		new(stepPrepareOutputDir),
		&common.StepCreateFloppy{
			Files: b.config.FloppyFiles,
		},
		new(stepHTTPServer),
		new(stepCreatePool),
		new(stepCreateNetwork),
		new(stepCreateVolume),
		new(stepCreateDomain),
		new(stepRun),
		new(stepTypeBootCommand),
		&communicator.StepConnect{
			Config:    &b.config.Comm,
			Host:      commHost,
			SSHConfig: sshConfig,
			SSHPort:   commPort,
		},
		// can we upload any guest helpers?
		new(common.StepProvision),
		new(stepShutdown),
		// compact disk?
	}
	/*
	   ▶       ▶       new(stepDownloadVolume),
	   ▶       ▶       new(stepDeleteVolume),

	*/
	// Setup the state bag
	state := &multistep.BasicStateBag{}
	state.Put("cache", cache)
	state.Put("config", &b.config)
	state.Put("hook", hook)
	state.Put("ui", ui)

	// Run
	if b.config.PackerDebug {
		b.runner = &multistep.DebugRunner{
			Steps:   steps,
			PauseFn: common.MultistepDebugFn(ui),
		}
	} else {
		b.runner = &multistep.BasicRunner{Steps: steps}
	}

	b.runner.Run(state)

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

	// If we were interrupted or cancelled, then just exit.
	if _, ok := state.GetOk(multistep.StateCancelled); ok {
		return nil, errors.New("Build was cancelled.")
	}

	if _, ok := state.GetOk(multistep.StateHalted); ok {
		return nil, errors.New("Build was halted.")
	}

	// Compile the artifact list
	files := make([]string, 0, 5)
	visit := func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			files = append(files, path)
		}

		return err
	}

	if err := filepath.Walk(b.config.OutputDir, visit); err != nil {
		return nil, err
	}

	artifact := &Artifact{
		name:  b.config.VMName,
		dir:   b.config.OutputDir,
		f:     files,
		state: make(map[string]interface{}),
	}

	artifact.state["diskType"] = b.config.DiskType
	artifact.state["diskSize"] = b.config.DiskSize
	artifact.state["domainType"] = "kvm"

	return artifact, nil
}

func (b *Builder) Cancel() {
	if b.runner != nil {
		log.Println("Cancelling the step runner...")
		b.runner.Cancel()
	}
}
<commit_msg>fix<commit_after>package libvirt

import (
	"errors"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"time"

	"github.com/mitchellh/multistep"
	"github.com/mitchellh/packer/common"
	commonssh "github.com/mitchellh/packer/common/ssh"
	"github.com/mitchellh/packer/helper/communicator"
	"github.com/mitchellh/packer/helper/config"
	"github.com/mitchellh/packer/packer"
	"github.com/mitchellh/packer/template/interpolate"
)

const BuilderId = "vtolstov.libvirt"

type Builder struct {
	config Config
	runner multistep.Runner
}

type Config struct {
	common.PackerConfig `mapstructure:",squash"`
	Comm                communicator.Config `mapstructure:",squash"`

	DomainType      string   `mapstructure:"domain_type"`
	BootCommand     []string `mapstructure:"boot_command"`
	MemorySize      uint     `mapstructure:"memory_size"`
	Arch            string   `mapstructure:"arch"`
	DiskName        string   `mapstructure:"disk_name"`
	DiskType        string   `mapstructure:"disk_type"`
	DiskSize        uint     `mapstructure:"disk_size"`
	FloppyFiles     []string `mapstructure:"floppy_files"`
	HTTPDir         string   `mapstructure:"http_directory"`
	HTTPPortMin     uint     `mapstructure:"http_port_min"`
	HTTPPortMax     uint     `mapstructure:"http_port_max"`
	ISOUrl          string   `mapstructure:"iso_url"`
	OutputDir       string   `mapstructure:"output_directory"`
	ShutdownCommand string   `mapstructure:"shutdown_command"`
	SSHHostPortMin  uint     `mapstructure:"ssh_host_port_min"`
	SSHHostPortMax  uint     `mapstructure:"ssh_host_port_max"`
	SSHKeyPath      string   `mapstructure:"ssh_key_path"`
	SSHPassword     string   `mapstructure:"ssh_password"`
	SSHPort         uint     `mapstructure:"ssh_port"`
	SSHUser         string   `mapstructure:"ssh_username"`
	VMName          string   `mapstructure:"vm_name"`

	DomainXml   string `mapstructure:"domain_xml"`
	VolumeXml   string `mapstructure:"volume_xml"`
	PoolName    string `mapstructure:"pool_name"`
	PoolXml     string `mapstructure:"pool_xml"`
	NetworkName string `mapstructure:"network_name"`
	NetworkXml  string `mapstructure:"network_xml"`
	NetworkType string `mapstructure:"network_type"`
	LibvirtUrl  string `mapstructure:"libvirt_url"`

	RawBootWait        string `mapstructure:"boot_wait"`
	RawShutdownTimeout string `mapstructure:"shutdown_timeout"`
	RawSSHWaitTimeout  string `mapstructure:"ssh_wait_timeout"`

	bootWait        time.Duration ``
	shutdownTimeout time.Duration ``
	sshWaitTimeout  time.Duration ``
	ctx             interpolate.Context
}

func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
	var errs *packer.MultiError
	warnings := make([]string, 0)

	err := config.Decode(&b.config, &config.DecodeOpts{
		Interpolate:        true,
		InterpolateContext: &b.config.ctx,
		InterpolateFilter: &interpolate.RenderFilter{
			Exclude: []string{
				"boot_command",
				"qemuargs",
			},
		},
	}, raws...)
	if err != nil {
		return nil, err
	}

	if es := b.config.Comm.Prepare(&b.config.ctx); len(es) > 0 {
		errs = packer.MultiErrorAppend(errs, es...)
	}

	if b.config.MemorySize < 1 {
		b.config.MemorySize = 512
	}

	if b.config.DomainType == "" {
		b.config.DomainType = "kvm"
	}

	if b.config.DiskType == "" {
		b.config.DiskType = "raw"
	}

	if b.config.DiskSize == 0 {
		b.config.DiskSize = 5000
	}

	if b.config.PoolXml == "" {
		b.config.PoolXml = PackerPool
	}

	if b.config.PoolName == "" {
		b.config.PoolName = "packer"
	}

	if b.config.NetworkName == "" {
		b.config.NetworkName = "packer"
	}

	if b.config.VolumeXml == "" {
		b.config.VolumeXml = PackerVolume
	}

	if b.config.NetworkType == "" {
		b.config.NetworkType = "user"
	}

	if b.config.NetworkType != "user" {
		if b.config.NetworkXml == "" {
			b.config.NetworkXml = PackerNetwork
		}
	}

	if b.config.DomainXml == "" {
		b.config.DomainXml = PackerQemuXML
	}

	if b.config.FloppyFiles == nil {
		b.config.FloppyFiles = make([]string, 0)
	}

	if b.config.HTTPPortMin == 0 {
		b.config.HTTPPortMin = 8000
	}

	if b.config.HTTPPortMax == 0 {
		b.config.HTTPPortMax = 9000
	}

	if b.config.OutputDir == "" {
		b.config.OutputDir = fmt.Sprintf("output-%s", b.config.PackerBuildName)
	}

	if b.config.RawBootWait == "" {
		b.config.RawBootWait = "10s"
	}

	if b.config.SSHHostPortMin == 0 {
		b.config.SSHHostPortMin = 2222
	}

	if b.config.SSHHostPortMax == 0 {
		b.config.SSHHostPortMax = 4444
	}

	if b.config.SSHPort == 0 {
		b.config.SSHPort = 22
	}

	if b.config.VMName == "" {
		b.config.VMName = fmt.Sprintf("packer-%s", b.config.PackerBuildName)
	}

	if b.config.DiskName == "" {
		b.config.DiskName = b.config.VMName
	}

	/*
		// Errors
		templates := map[string]*string{
			"disk_name":        &b.config.DiskName,
			"http_directory":   &b.config.HTTPDir,
			"output_directory": &b.config.OutputDir,
			"shutdown_command": &b.config.ShutdownCommand,
			"ssh_password":     &b.config.SSHPassword,
			"ssh_username":     &b.config.SSHUser,
			"vm_name":          &b.config.VMName,
			"boot_wait":        &b.config.RawBootWait,
			"shutdown_timeout": &b.config.RawShutdownTimeout,
			"ssh_wait_timeout": &b.config.RawSSHWaitTimeout,
			"domain_xml":       &b.config.DomainXml,
			"volume_xml":       &b.config.VolumeXml,
			"pool_name":        &b.config.PoolName,
			"pool_xml":         &b.config.PoolXml,
			"network_name":     &b.config.NetworkName,
			"network_xml":      &b.config.NetworkXml,
		}
	*/
	b.config.ISOUrl, err = common.DownloadableURL(b.config.ISOUrl)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed to parse iso_url: %s", err))
	}

	if b.config.HTTPPortMin > b.config.HTTPPortMax {
		errs = packer.MultiErrorAppend(
			errs, errors.New("http_port_min must be less than http_port_max"))
	}

	if !b.config.PackerForce {
		if _, err := os.Stat(b.config.OutputDir); err == nil {
			errs = packer.MultiErrorAppend(
				errs,
				fmt.Errorf("Output directory '%s' already exists. It must not exist.", b.config.OutputDir))
		}
	}

	b.config.bootWait, err = time.ParseDuration(b.config.RawBootWait)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing boot_wait: %s", err))
	}

	if b.config.RawShutdownTimeout == "" {
		b.config.RawShutdownTimeout = "5m"
	}

	if b.config.RawSSHWaitTimeout == "" {
		b.config.RawSSHWaitTimeout = "20m"
	}

	b.config.shutdownTimeout, err = time.ParseDuration(b.config.RawShutdownTimeout)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing shutdown_timeout: %s", err))
	}

	if b.config.SSHKeyPath != "" {
		if _, err := os.Stat(b.config.SSHKeyPath); err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
		} else if _, err := commonssh.FileSigner(b.config.SSHKeyPath); err != nil {
			errs = packer.MultiErrorAppend(
				errs, fmt.Errorf("ssh_key_path is invalid: %s", err))
		}
	}

	if b.config.SSHHostPortMin > b.config.SSHHostPortMax {
		errs = packer.MultiErrorAppend(
			errs, errors.New("ssh_host_port_min must be less than ssh_host_port_max"))
	}

	if b.config.SSHUser == "" && !strings.HasPrefix(b.config.LibvirtUrl, "lxc") {
		errs = packer.MultiErrorAppend(
			errs, errors.New("An ssh_username must be specified."))
	}

	b.config.sshWaitTimeout, err = time.ParseDuration(b.config.RawSSHWaitTimeout)
	if err != nil {
		errs = packer.MultiErrorAppend(
			errs, fmt.Errorf("Failed parsing ssh_wait_timeout: %s", err))
	}

	// Warnings
	if b.config.ShutdownCommand == "" {
		warnings = append(warnings,
			"A shutdown_command was not specified. Without a shutdown command, Packer\n"+
				"will forcibly halt the virtual machine, which may result in data loss.")
	}

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

	return warnings, nil
}

func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) {
	// Check we have the required tools

	steps := []multistep.Step{
		new(stepPrepareOutputDir),
		&common.StepCreateFloppy{
			Files: b.config.FloppyFiles,
		},
		new(stepHTTPServer),
		new(stepCreatePool),
		new(stepCreateNetwork),
		new(stepCreateVolume),
		new(stepCreateDomain),
		new(stepRun),
		new(stepTypeBootCommand),
		&communicator.StepConnect{
			Config:    &b.config.Comm,
			Host:      commHost,
			SSHConfig: sshConfig,
			SSHPort:   commPort,
		},
		// can we upload any guest helpers?
		new(common.StepProvision),
		new(stepShutdown),
		// compact disk?
	}
	/*
	   ▶       ▶       new(stepDownloadVolume),
	   ▶       ▶       new(stepDeleteVolume),

	*/
	// Setup the state bag
	state := &multistep.BasicStateBag{}
	state.Put("cache", cache)
	state.Put("config", &b.config)
	state.Put("hook", hook)
	state.Put("ui", ui)

	// Run
	if b.config.PackerDebug {
		b.runner = &multistep.DebugRunner{
			Steps:   steps,
			PauseFn: common.MultistepDebugFn(ui),
		}
	} else {
		b.runner = &multistep.BasicRunner{Steps: steps}
	}

	b.runner.Run(state)

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

	// If we were interrupted or cancelled, then just exit.
	if _, ok := state.GetOk(multistep.StateCancelled); ok {
		return nil, errors.New("Build was cancelled.")
	}

	if _, ok := state.GetOk(multistep.StateHalted); ok {
		return nil, errors.New("Build was halted.")
	}

	// Compile the artifact list
	files := make([]string, 0, 5)
	visit := func(path string, info os.FileInfo, err error) error {
		if !info.IsDir() {
			files = append(files, path)
		}

		return err
	}

	if err := filepath.Walk(b.config.OutputDir, visit); err != nil {
		return nil, err
	}

	artifact := &Artifact{
		name:  b.config.VMName,
		dir:   b.config.OutputDir,
		f:     files,
		state: make(map[string]interface{}),
	}

	artifact.state["diskType"] = b.config.DiskType
	artifact.state["diskSize"] = b.config.DiskSize
	artifact.state["domainType"] = "kvm"

	return artifact, nil
}

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