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

package themefiles

const ScreenCss = `
html {
    min-height: 100%;
    font-size: 100%;
    overflow-y: scroll;
    -webkit-text-size-adjust: 100%;
    -ms-text-size-adjust: 100%;
}

body {
    color: #444;
    font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', "Hiragino Sans GB", "STXihei", "微软雅黑", serif;
    font-size: 12px;
    line-height: 1.5em;
    background: #fefefe;
    width: 75%;
    min-height: 100%;
    margin: 0px auto 10px auto;
    padding: 0 1em;
    outline: 1300px solid #FAFAFA;
}

body>nav.toplevel {
    text-align: right;
    font-size: 1.1em;
    margin: 0 0 15px 0;
    padding: 0;
    clear: both;
}

body>nav.toplevel>ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

body>nav.toplevel>ul>li {
    display: inline-block;
    border: 1px solid #000000;
    background-color: #FFFFFF;
    margin: -1px -5px 0 -2px;
    padding: 0px 10px;
    white-space: nowrap;
}

body>nav.toplevel>ul>li:last-child {
    border-right: 1px solid #000000;
    clear: both;
}

body>nav.toplevel>ul>li>a {
    font-family: "Helvetia", "Verdana", "Sans-Serif";
    color: #000000;
}

body>nav.toplevel>ul>li>a:hover {
    color: #06e;
}

body>nav.breadcrumb {
    font-size: 0.8em;
}

body>nav.breadcrumb>ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

body>nav.breadcrumb>ul>li {
    display: inline;
}

body>nav.breadcrumb>ul>li:after {
    content: "»";
}

body>nav.breadcrumb>ul>li:last-child:after {
    content: "";
}

body>nav.breadcrumb>ul>li>a {
    font-family: "Helvetia", "Verdana", "Sans-Serif";
}

a {
    color: #0645ad;
    text-decoration: none;
}

a:visited {
    color: #0b0080;
}

a:hover {
    color: #06e;
}

a:active {
    color: #faa700;
}

a:focus {
    outline: thin dotted;
}

a:hover, a:active {
    outline: 0;
}

span.backtick {
    border: 1px solid #EAEAEA;
    border-radius: 3px;
    background: #F8F8F8;
    padding: 0 3px 0 3px;
}

::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

::selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

a::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

a::selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

p {
    margin: 1em 0;
}

img {
    max-width: 100%;
}

h1,h2,h3,h4,h5,h6 {
    font-weight: normal;
    color: #111;
    line-height: 1em;
}

h4,h5,h6 {
    font-weight: bold;
}

h1 {
    font-size: 2.5em;
    margin: 0 0 15px 0;
}

h2 {
    font-size: 2em;
    border-bottom: 1px solid silver;
    padding-bottom: 5px;
}

h3 {
    font-size: 1.5em;
}

h4 {
    font-size: 1.2em;
}

h5 {
    font-size: 1em;
}

h6 {
    font-size: 0.9em;
}

blockquote {
    color: #666666;
    margin: 0;
    padding-left: 3em;
    border-left: 0.5em #EEE solid;
}

hr {
    display: block;
    height: 2px;
    border: 0;
    border-top: 1px solid #aaa;
    border-bottom: 1px solid #eee;
    margin: 1em 0;
    padding: 0;
}

pre , code, kbd, samp {
    color: #000;
    font-family: monospace;
    font-size: 0.88em;
    border-radius: 3px;
    background-color: #F8F8F8;
    border: 1px solid #CCC;
}

pre {
    white-space: pre;
    white-space: pre-wrap;
    word-wrap: break-word;
    padding: 5px 12px;
}

pre code {
    border: 0px !important;
    padding: 0;
}

code {
    padding: 0 3px 0 3px;
}

b, strong {
    font-weight: bold;
}

dfn {
    font-style: italic;
}

ins {
    background: #ff9;
    color: #000;
    text-decoration: none;
}

mark {
    background: #ff0;
    color: #000;
    font-style: italic;
    font-weight: bold;
}

sub, sup {
    font-size: 75%;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
}

sup {
    top: -0.5em;
}

sub {
    bottom: -0.25em;
}

ul, ol {
    margin: 0;
    padding: 0 0 0 2em;
}

li p:last-child {
    margin: 0;
}

dd {
    margin: 0 0 0 2em;
}

img {
    border: 0;
    -ms-interpolation-mode: bicubic;
    vertical-align: middle;
}

table {
    border-collapse: collapse;
    border-spacing: 0;
}

td {
    vertical-align: top;
}

article>.description {
    font-size: 1.2em;
}

.childs {
}

.childs>h1 {
    font-size: 1.2em;
}

.childs>.list {
    list-style: none;
    padding: 5px 0 5px 0;
    margin: 0 0 0 15px;
}

.childs>.list>.child {
    margin: 0 0 15px 0;
}

.childs>.list>.child:nth-child(odd) {
    background-color:#eee;
}

.childs>.list>.child:nth-child(even) {
    background-color:transparent;
}

.imagegallery>h1 {
    font-size: 1.2em;
}

.imagegallery ol {
    list-style: none;
    margin-left: 0;
}

.filelinks>h1 {
    font-size: 1.2em;
}

.filelinks ol {
    margin-left: 0;
}

.csv {
    margin: 20px 0 0 20px;
    overflow: auto;
}

.csv>h1 {
    font-size: 1.2em;
}

.csv>table
{
    font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
    font-size: 1.0em;
    margin: 10px 45px 10px 45px;
    text-align: left;
    border-collapse: collapse;
    border: 1px solid #69c;
}

.csv>table thead
{
    padding: 12px 17px 12px 17px;
    font-weight: normal;
    font-size: 1.2em;
    color: #039;
    border-bottom: 1px dashed #69c;
}

.csv>table td
{
    padding: 7px 17px 7px 17px;
    color: #669;
}

.csv>table tbody tr:hover td
{
    color: #339;
    background: #d0dafd;
}

.pdf {
    width: 80%;
    max-height: 80%;
}

.pdf>h1 {
    font-size: 1.2em;
}

.pdf .metadata {
    float: left;
    font-size: 1.0em;
    margin: 0 15px 0 0;
}

.pdf .metadata .entry {
    margin: 0 0 10px 0;
}

.pdf .previewarea {
    display: block;
    overflow: auto;
    box-shadow: 0 0 10px #000000;
}

.pdf .previewarea canvas {
    float: none;
}

.video>h1 {
    font-size: 1.2em;
}

.audio>h1 {
    font-size: 1.2em;
}

.presentation nav {
    float: left;
    margin: 25px 0 15px 0;
    width: 100%;
    text-align: center;
}

.presentation nav .controls {
    float: left;
}

.presentation nav .pager {
    display: inline;
    cursor: default;
}

.presentation nav .jumper {
    float: right;
}

.presentation .content {
    clear: left;
}

.presentation .slide {
    float: none;
    box-shadow: 0 0 10px #000000;
    padding: 10px;
}

@media only screen and (max-height: 500px) {
    body>article {
        min-height: 300px;
    }

    .presentation .slide {
        min-height: 220px;
    }
}

@media only screen and (min-height: 500px) {
    body>article {
        min-height: 500px;
    }

    .presentation .slide {
        min-height: 320px;
    }
}

@media only screen and (min-height: 600px) {
    body>article {
        min-height: 600px;
    }

    .presentation .slide {
        min-height: 420px;
    }
}

@media only screen and (min-height: 768px) {
    body>article {
        min-height: 768px;
    }

    .presentation .slide {
        min-height: 520px;
    }
}

@media only screen and (max-width: 480px) {
    body {
        font-size: 12px;
        width: 95%;
    }

    .presentation nav {
        margin: 25px 0 15px 0;
        width: 100%;
    }

    .presentation nav .pager {
        float: right;
    }

    .presentation nav .jumper {
        display: none;
    }
}

@media only screen and (min-width: 480px) {
    body {
        font-size: 14px;
        width: 95%;
    }
}

@media only screen and (min-width: 768px) {
    body {
        font-size: 16px;
        width: 95%;
    }
}

@media only screen and (min-width: 1024px) {
    body {
        font-size: 16px;
        width: 75%;
    }
}`
<commit_msg>Cleanup. Removed two unused css classes<commit_after>// Copyright 2013 Andreas Koch. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package themefiles

const ScreenCss = `
html {
    min-height: 100%;
    font-size: 100%;
    overflow-y: scroll;
    -webkit-text-size-adjust: 100%;
    -ms-text-size-adjust: 100%;
}

body {
    color: #444;
    font-family: Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman', "Hiragino Sans GB", "STXihei", "微软雅黑", serif;
    font-size: 12px;
    line-height: 1.5em;
    background: #fefefe;
    width: 75%;
    min-height: 100%;
    margin: 0px auto 10px auto;
    padding: 0 1em;
    outline: 1300px solid #FAFAFA;
}

body>nav.toplevel {
    text-align: right;
    font-size: 1.1em;
    margin: 0 0 15px 0;
    padding: 0;
    clear: both;
}

body>nav.toplevel>ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

body>nav.toplevel>ul>li {
    display: inline-block;
    border: 1px solid #000000;
    background-color: #FFFFFF;
    margin: -1px -5px 0 -2px;
    padding: 0px 10px;
    white-space: nowrap;
}

body>nav.toplevel>ul>li:last-child {
    border-right: 1px solid #000000;
    clear: both;
}

body>nav.toplevel>ul>li>a {
    font-family: "Helvetia", "Verdana", "Sans-Serif";
    color: #000000;
}

body>nav.toplevel>ul>li>a:hover {
    color: #06e;
}

body>nav.breadcrumb {
    font-size: 0.8em;
}

body>nav.breadcrumb>ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

body>nav.breadcrumb>ul>li {
    display: inline;
}

body>nav.breadcrumb>ul>li:after {
    content: "»";
}

body>nav.breadcrumb>ul>li:last-child:after {
    content: "";
}

body>nav.breadcrumb>ul>li>a {
    font-family: "Helvetia", "Verdana", "Sans-Serif";
}

a {
    color: #0645ad;
    text-decoration: none;
}

a:visited {
    color: #0b0080;
}

a:hover {
    color: #06e;
}

a:active {
    color: #faa700;
}

a:focus {
    outline: thin dotted;
}

a:hover, a:active {
    outline: 0;
}

span.backtick {
    border: 1px solid #EAEAEA;
    border-radius: 3px;
    background: #F8F8F8;
    padding: 0 3px 0 3px;
}

::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

::selection {
    background: rgba(255,255,0,0.3);
    color: #000;
}

a::-moz-selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

a::selection {
    background: rgba(255,255,0,0.3);
    color: #0645ad;
}

p {
    margin: 1em 0;
}

img {
    max-width: 100%;
}

h1,h2,h3,h4,h5,h6 {
    font-weight: normal;
    color: #111;
    line-height: 1em;
}

h4,h5,h6 {
    font-weight: bold;
}

h1 {
    font-size: 2.5em;
    margin: 0 0 15px 0;
}

h2 {
    font-size: 2em;
    border-bottom: 1px solid silver;
    padding-bottom: 5px;
}

h3 {
    font-size: 1.5em;
}

h4 {
    font-size: 1.2em;
}

h5 {
    font-size: 1em;
}

h6 {
    font-size: 0.9em;
}

blockquote {
    color: #666666;
    margin: 0;
    padding-left: 3em;
    border-left: 0.5em #EEE solid;
}

hr {
    display: block;
    height: 2px;
    border: 0;
    border-top: 1px solid #aaa;
    border-bottom: 1px solid #eee;
    margin: 1em 0;
    padding: 0;
}

pre , code, kbd, samp {
    color: #000;
    font-family: monospace;
    font-size: 0.88em;
    border-radius: 3px;
    background-color: #F8F8F8;
    border: 1px solid #CCC;
}

pre {
    white-space: pre;
    white-space: pre-wrap;
    word-wrap: break-word;
    padding: 5px 12px;
}

pre code {
    border: 0px !important;
    padding: 0;
}

code {
    padding: 0 3px 0 3px;
}

b, strong {
    font-weight: bold;
}

dfn {
    font-style: italic;
}

ins {
    background: #ff9;
    color: #000;
    text-decoration: none;
}

mark {
    background: #ff0;
    color: #000;
    font-style: italic;
    font-weight: bold;
}

sub, sup {
    font-size: 75%;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
}

sup {
    top: -0.5em;
}

sub {
    bottom: -0.25em;
}

ul, ol {
    margin: 0;
    padding: 0 0 0 2em;
}

li p:last-child {
    margin: 0;
}

dd {
    margin: 0 0 0 2em;
}

img {
    border: 0;
    -ms-interpolation-mode: bicubic;
    vertical-align: middle;
}

table {
    border-collapse: collapse;
    border-spacing: 0;
}

td {
    vertical-align: top;
}

article>.description {
    font-size: 1.2em;
}

.childs>.list {
    list-style: none;
    padding: 5px 0 5px 0;
    margin: 0 0 0 15px;
}

.childs>.list>.child {
    margin: 0 0 15px 0;
}

.childs>.list>.child:nth-child(odd) {
    background-color:#eee;
}

.childs>.list>.child:nth-child(even) {
    background-color:transparent;
}

.imagegallery>h1 {
    font-size: 1.2em;
}

.imagegallery ol {
    list-style: none;
    margin-left: 0;
}

.filelinks>h1 {
    font-size: 1.2em;
}

.filelinks ol {
    margin-left: 0;
}

.csv {
    margin: 20px 0 0 20px;
    overflow: auto;
}

.csv>h1 {
    font-size: 1.2em;
}

.csv>table
{
    font-family: "Lucida Sans Unicode", "Lucida Grande", Sans-Serif;
    font-size: 1.0em;
    margin: 10px 45px 10px 45px;
    text-align: left;
    border-collapse: collapse;
    border: 1px solid #69c;
}

.csv>table thead
{
    padding: 12px 17px 12px 17px;
    font-weight: normal;
    font-size: 1.2em;
    color: #039;
    border-bottom: 1px dashed #69c;
}

.csv>table td
{
    padding: 7px 17px 7px 17px;
    color: #669;
}

.csv>table tbody tr:hover td
{
    color: #339;
    background: #d0dafd;
}

.pdf {
    width: 80%;
    max-height: 80%;
}

.pdf>h1 {
    font-size: 1.2em;
}

.pdf .metadata {
    float: left;
    font-size: 1.0em;
    margin: 0 15px 0 0;
}

.pdf .metadata .entry {
    margin: 0 0 10px 0;
}

.pdf .previewarea {
    display: block;
    overflow: auto;
    box-shadow: 0 0 10px #000000;
}

.pdf .previewarea canvas {
    float: none;
}

.video>h1 {
    font-size: 1.2em;
}

.audio>h1 {
    font-size: 1.2em;
}

.presentation nav {
    float: left;
    margin: 25px 0 15px 0;
    width: 100%;
    text-align: center;
}

.presentation nav .controls {
    float: left;
}

.presentation nav .pager {
    display: inline;
    cursor: default;
}

.presentation nav .jumper {
    float: right;
}

.presentation .content {
    clear: left;
}

.presentation .slide {
    float: none;
    box-shadow: 0 0 10px #000000;
    padding: 10px;
}

@media only screen and (max-height: 500px) {
    body>article {
        min-height: 300px;
    }

    .presentation .slide {
        min-height: 220px;
    }
}

@media only screen and (min-height: 500px) {
    body>article {
        min-height: 500px;
    }

    .presentation .slide {
        min-height: 320px;
    }
}

@media only screen and (min-height: 600px) {
    body>article {
        min-height: 600px;
    }

    .presentation .slide {
        min-height: 420px;
    }
}

@media only screen and (min-height: 768px) {
    body>article {
        min-height: 768px;
    }

    .presentation .slide {
        min-height: 520px;
    }
}

@media only screen and (max-width: 480px) {
    body {
        font-size: 12px;
        width: 95%;
    }

    .presentation nav {
        margin: 25px 0 15px 0;
        width: 100%;
    }

    .presentation nav .pager {
        float: right;
    }

    .presentation nav .jumper {
        display: none;
    }
}

@media only screen and (min-width: 480px) {
    body {
        font-size: 14px;
        width: 95%;
    }
}

@media only screen and (min-width: 768px) {
    body {
        font-size: 16px;
        width: 95%;
    }
}

@media only screen and (min-width: 1024px) {
    body {
        font-size: 16px;
        width: 75%;
    }
}`
<|endoftext|>


<commit_before>package main

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

	lib "github.com/bazooka-ci/bazooka-lib"
)

type Generator struct {
	Config       *lib.Config
	OutputFolder string
	Index        int
}

func (g *Generator) GenerateDockerfile() error {
	err := os.MkdirAll(fmt.Sprintf("%s/%d", g.OutputFolder, g.Index), 0755)
	if err != nil {
		return err
	}

	var buffer bytes.Buffer

	buffer.WriteString(fmt.Sprintf("FROM %s\n\n", g.Config.FromImage))

	buffer.WriteString("ADD . /bazooka\n\n")
	buffer.WriteString("RUN chmod +x /bazooka/bazooka_run.sh\n\n")

	type buildPhase struct {
		name      string
		commands  []string
		beforeCmd []string
		runCmd    []string
	}

	phases := []*buildPhase{
		&buildPhase{
			name:      "before_install",
			commands:  g.Config.BeforeInstall,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_before_install.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit $rc",
				"fi",
			},
		},
		&buildPhase{
			name:      "install",
			commands:  g.Config.Install,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_install.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit $rc",
				"fi",
			},
		},
		&buildPhase{
			name:      "before_script",
			commands:  g.Config.BeforeScript,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_before_script.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit $rc",
				"fi",
			},
		},
		&buildPhase{
			name:      "script",
			commands:  g.Config.Script,
			beforeCmd: []string{"set -v"},
			runCmd:    g.getScriptRunCmd(),
		},
		&buildPhase{
			name:      "after_success",
			commands:  g.Config.AfterSuccess,
			beforeCmd: []string{"set -v"},
			runCmd:    []string{},
		},
		&buildPhase{
			name:      "after_failure",
			commands:  g.Config.AfterFailure,
			beforeCmd: []string{"set -v"},
			runCmd:    []string{},
		},
		&buildPhase{
			name:      "after_script",
			commands:  g.Config.AfterScript,
			beforeCmd: []string{"set -v"},
		},
	}

	var bufferRun bytes.Buffer
	bufferRun.WriteString("#!/bin/bash\n")
	for _, phase := range phases {
		if len(phase.commands) != 0 {
			var buffer bytes.Buffer
			buffer.WriteString("#!/bin/bash\n\n")
			for _, action := range phase.beforeCmd {
				buffer.WriteString(fmt.Sprintf("%s\n", action))
			}
			for _, action := range phase.commands {
				buffer.WriteString(fmt.Sprintf("%s\n", action))
			}
			err = ioutil.WriteFile(fmt.Sprintf("%s/%d/bazooka_%s.sh", g.OutputFolder, g.Index, phase.name), buffer.Bytes(), 0644)
			if err != nil {
				return err
			}
			if phase.runCmd == nil {
				bufferRun.WriteString(fmt.Sprintf("./bazooka_%s.sh\n", phase.name))
			} else {
				for _, action := range phase.runCmd {
					bufferRun.WriteString(fmt.Sprintf("%s\n", action))
				}
			}
		}
	}

	err = ioutil.WriteFile(fmt.Sprintf("%s/%d/bazooka_run.sh", g.OutputFolder, g.Index), bufferRun.Bytes(), 0644)
	if err != nil {
		return err
	}

	for _, phase := range phases {
		if len(phase.commands) != 0 {
			buffer.WriteString(fmt.Sprintf("RUN chmod +x /bazooka/bazooka_%s.sh\n\n", phase.name))
		}
	}

	for _, env := range g.Config.Env {
		envSplit := strings.Split(env, "=")
		buffer.WriteString(fmt.Sprintf("ENV %s %s\n", envSplit[0], envSplit[1]))
	}

	buffer.WriteString("WORKDIR /bazooka\n\n")

	buffer.WriteString("CMD ./bazooka_run.sh\n")

	err = ioutil.WriteFile(fmt.Sprintf("%s/%d/Dockerfile", g.OutputFolder, g.Index), buffer.Bytes(), 0644)
	if err != nil {
		return err
	}

	if len(g.Config.Services) > 0 {
		var servicesBuffer bytes.Buffer
		for _, service := range g.Config.Services {
			servicesBuffer.WriteString(fmt.Sprintf("%s\n", service))
		}
		err = ioutil.WriteFile(fmt.Sprintf("%s/%d/services", g.OutputFolder, g.Index), servicesBuffer.Bytes(), 0644)
	}
	return nil
}

func (g *Generator) getScriptRunCmd() []string {
	switch {
	case len(g.Config.AfterSuccess) != 0 && len(g.Config.AfterFailure) != 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? != 0 ]] ; then",
			"  ./bazooka_after_failure.sh",
			"else",
			"  ./bazooka_after_success.sh",
			"fi",
		}
	case len(g.Config.AfterSuccess) != 0 && len(g.Config.AfterFailure) == 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? == 0 ]] ; then",
			"  ./bazooka_after_success.sh",
			"fi",
		}
	case len(g.Config.AfterSuccess) == 0 && len(g.Config.AfterFailure) == 0:
		return nil
	case len(g.Config.AfterSuccess) == 0 && len(g.Config.AfterFailure) != 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? != 0 ]] ; then",
			"  ./bazooka_after_failure.sh",
			"fi",
		}
	default:
		return nil
	}
}
<commit_msg>Better error reporting when there is a problem with the generation<commit_after>package main

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

	lib "github.com/bazooka-ci/bazooka-lib"
)

type Generator struct {
	Config       *lib.Config
	OutputFolder string
	Index        int
}

func (g *Generator) GenerateDockerfile() error {
	err := os.MkdirAll(fmt.Sprintf("%s/%d", g.OutputFolder, g.Index), 0755)
	if err != nil {
		return err
	}

	var buffer bytes.Buffer

	buffer.WriteString(fmt.Sprintf("FROM %s\n\n", g.Config.FromImage))

	buffer.WriteString("ADD . /bazooka\n\n")
	buffer.WriteString("RUN chmod +x /bazooka/bazooka_run.sh\n\n")

	type buildPhase struct {
		name      string
		commands  []string
		beforeCmd []string
		runCmd    []string
	}

	phases := []*buildPhase{
		&buildPhase{
			name:      "before_install",
			commands:  g.Config.BeforeInstall,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_before_install.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit $rc",
				"fi",
			},
		},
		&buildPhase{
			name:      "install",
			commands:  g.Config.Install,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_install.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit $rc",
				"fi",
			},
		},
		&buildPhase{
			name:      "before_script",
			commands:  g.Config.BeforeScript,
			beforeCmd: []string{"set -ev"},
			runCmd: []string{
				"./bazooka_before_script.sh",
				"rc=$?",
				"if [[ $rc != 0 ]] ; then",
				"    exit $rc",
				"fi",
			},
		},
		&buildPhase{
			name:      "script",
			commands:  g.Config.Script,
			beforeCmd: []string{"set -v"},
			runCmd:    g.getScriptRunCmd(),
		},
		&buildPhase{
			name:      "after_success",
			commands:  g.Config.AfterSuccess,
			beforeCmd: []string{"set -v"},
			runCmd:    []string{},
		},
		&buildPhase{
			name:      "after_failure",
			commands:  g.Config.AfterFailure,
			beforeCmd: []string{"set -v"},
			runCmd:    []string{},
		},
		&buildPhase{
			name:      "after_script",
			commands:  g.Config.AfterScript,
			beforeCmd: []string{"set -v"},
		},
	}

	var bufferRun bytes.Buffer
	bufferRun.WriteString("#!/bin/bash\n")
	for _, phase := range phases {
		if len(phase.commands) != 0 {
			var buffer bytes.Buffer
			buffer.WriteString("#!/bin/bash\n\n")
			for _, action := range phase.beforeCmd {
				buffer.WriteString(fmt.Sprintf("%s\n", action))
			}
			for _, action := range phase.commands {
				buffer.WriteString(fmt.Sprintf("%s\n", action))
			}
			err = ioutil.WriteFile(fmt.Sprintf("%s/%d/bazooka_%s.sh", g.OutputFolder, g.Index, phase.name), buffer.Bytes(), 0644)
			if err != nil {
				return fmt.Errorf("Phase [%d/%s]: writing file failed: %v", g.Index, phase.name, err)
			}
			if phase.runCmd == nil {
				bufferRun.WriteString(fmt.Sprintf("./bazooka_%s.sh\n", phase.name))
			} else {
				for _, action := range phase.runCmd {
					bufferRun.WriteString(fmt.Sprintf("%s\n", action))
				}
			}
		}
	}

	err = ioutil.WriteFile(fmt.Sprintf("%s/%d/bazooka_run.sh", g.OutputFolder, g.Index), bufferRun.Bytes(), 0644)
	if err != nil {
		return fmt.Errorf("Phase [%d/run]: writing file failed: %v", g.Index, err)
	}

	for _, phase := range phases {
		if len(phase.commands) != 0 {
			buffer.WriteString(fmt.Sprintf("RUN chmod +x /bazooka/bazooka_%s.sh\n\n", phase.name))
		}
	}

	for _, env := range g.Config.Env {
		envSplit := strings.Split(env, "=")
		buffer.WriteString(fmt.Sprintf("ENV %s %s\n", envSplit[0], envSplit[1]))
	}

	buffer.WriteString("WORKDIR /bazooka\n\n")

	buffer.WriteString("CMD ./bazooka_run.sh\n")

	err = ioutil.WriteFile(fmt.Sprintf("%s/%d/Dockerfile", g.OutputFolder, g.Index), buffer.Bytes(), 0644)
	if err != nil {
		return err
	}

	if len(g.Config.Services) > 0 {
		var servicesBuffer bytes.Buffer
		for _, service := range g.Config.Services {
			servicesBuffer.WriteString(fmt.Sprintf("%s\n", service))
		}
		err = ioutil.WriteFile(fmt.Sprintf("%s/%d/services", g.OutputFolder, g.Index), servicesBuffer.Bytes(), 0644)
	}
	return nil
}

func (g *Generator) getScriptRunCmd() []string {
	switch {
	case len(g.Config.AfterSuccess) != 0 && len(g.Config.AfterFailure) != 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? != 0 ]] ; then",
			"  ./bazooka_after_failure.sh",
			"else",
			"  ./bazooka_after_success.sh",
			"fi",
		}
	case len(g.Config.AfterSuccess) != 0 && len(g.Config.AfterFailure) == 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? == 0 ]] ; then",
			"  ./bazooka_after_success.sh",
			"fi",
		}
	case len(g.Config.AfterSuccess) == 0 && len(g.Config.AfterFailure) == 0:
		return nil
	case len(g.Config.AfterSuccess) == 0 && len(g.Config.AfterFailure) != 0:
		return []string{
			"./bazooka_script.sh",
			"if [[ $? != 0 ]] ; then",
			"  ./bazooka_after_failure.sh",
			"fi",
		}
	default:
		return nil
	}
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015 @ z3q.net.
 * name : after_sales
 * author : jarryliu
 * date : 2016-07-16 14:41
 * description :
 * history :
 */
package afterSales

import (
	"go2o/core/domain/interface/order"
	"go2o/core/infrastructure/domain"
)

const (
	// 等待商户确认
	StatAwaitingVendor = 1 + iota
	// 商户拒绝售后
	StatDeclined
	// 调解状态
	StatIntercede
	// 同意,等待退货
	StatAwaitingReturnShip
	// 已收货,等待系统确认
	StatAwaitingConfirm
	// 已发货
	StatReturnShipped
	// 已退回
	StateRejected
	// 等待处理
	StateAwaitingProcess
	// 售后单已完成
	StatCompleted
	// 售后单已取消
	StatCancelled
)

const (
	// 退款申请(部分退款)
	TypeRefund = 1 + iota
	// 退货
	TypeReturn
	// 换货
	TypeExchange
	// 服务/维修
	TypeService
)

var (
	// 不需要平台确认的售后类型
	IgnoreConfirmTypes = []int{
		TypeExchange,
		TypeService,
	}
	ErrAfterSalesOrderCompleted *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_completed", "售后单已完成,无法进行操作!")

	ErrAfterSalesRejected *domain.DomainError = domain.NewDomainError(
		"err_after_sales_rejected", "售后单已被系统退回")

	ErrUnusualStat *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_unusual_stat", "不合法的售后单状态")

	ErrNoSuchOrderItem *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_no_such_order_item", "订单中不包括该商品")

	ErrOutOfQuantity *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_out_of_quantity", "超出数量")

	ErrReasonLength *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_reason_length", "原因不能少于10字")

	ErrNotConfirm *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_not_confirm", "售后单尚未确认")

	ErrHasCancelled *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_has_cancelled", "售后单已取消")

	ErrOrderAmount *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_amount", "售后单金额不能为零")

	ErrExchangeOrderNoShipping *domain.DomainError = domain.NewDomainError(
		"err_exhange_order_no_shipping", "换货单尚未发货给顾客")

	ErrNotReceive *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_not_receive", "尚未收货")

	ErrRefundAfterShipped *domain.DomainError = domain.NewDomainError(
		"err_after_sales_refund_after_shipped", "订单已经发货,只能进行退货或换货操作")

	ErrReturnAfterReceived *domain.DomainError = domain.NewDomainError(
		"err_after_sales_return_after_received", "订单已确认收货,只能进行换货操作")
)

type (
	// 售后单状态
	Stat int

	// 提交售后  -》 商户同意(拒绝) -》 系统确认(取消),或客服调解 -》
	// 开始发货  -》 确认收货       -》 处理售后     -》 完成

	// 售后单
	IAfterSalesOrder interface {
		// 获取领域编号
		GetDomainId() int

		// 获取售后单数据
		Value() AfterSalesOrder

		// 获取订单
		GetOrder() order.ISubOrder

		// 设置要退回货物信息
		SetItem(itemId int, quantity int) error

		// 提交售后申请
		Submit() (int, error)

		// 取消申请
		Cancel() error

		// 同意售后服务,部分操作在同意后,无需确认
		Agree() error

		// 拒绝售后服务
		Decline(reason string) error

		// 申请调解,只有在商户拒绝后才能申请
		RequestIntercede() error

		// 系统确认,泛化应有不同的实现
		Confirm() error

		// 退回售后单
		Reject(remark string) error

		// 退回商品
		ReturnShip(spName string, spOrder string, image string) error

		// 收货, 在商品已退回或尚未发货情况下(线下退货),可以执行此操作
		ReturnReceive() error

		// 处理售后单,处理完成后将变为已完成
		Process() error
	}

	IAfterSalesRep interface {
		// 创建售后单
		CreateAfterSalesOrder(v *AfterSalesOrder) IAfterSalesOrder

		// 获取售后单
		GetAfterSalesOrder(id int) IAfterSalesOrder

		// 获取订单的售后单
		GetAllOfSaleOrder(orderId int) []IAfterSalesOrder
	}

	// 售后单
	AfterSalesOrder struct {
		// 编号
		Id int `db:"id" pk:"yes" auto:"yes"`
		// 订单编号
		OrderId int `db:"order_id"`
		// 运营商编号
		VendorId int `db:"vendor_id"`
		// 购买者编号
		BuyerId int `db:"buyer_id"`
		// 类型，退货、换货、维修
		Type int `db:"type"`
		// 退货的商品项编号
		SnapshotId int `db:"snap_id"`
		// 商品数量
		Quantity int `db:"quantity"`
		// 售后原因
		Reason string `db:"reason"`
		// 联系人
		PersonName string `db:"person_name"`
		// 联系电话
		PersonPhone string `db:"person_phone"`
		// 退货的快递服务商编号
		ReturnSpName string `db:"rsp_name"`
		// 退货的快递单号
		ReturnSpOrder string `db:"rsp_order"`
		// 退货凭证
		ReturnSpImage string `db:"rsp_image"`
		// 备注(系统)
		Remark string `db:"remark"`
		// 运营商备注
		VendorRemark string `db:"vendor_remark"`
		// 售后单状态
		State int `db:"state"`
		// 提交时间
		CreateTime int64 `db:"create_time"`
		// 更新时间
		UpdateTime int64 `db:"update_time"`

		// 售后单数据,如退款单、退货单、换货单等
		Data interface{} `db:"-"`
		// 订单状态
		StateText string `db:"-"`
	}
)

// 返回售后状态说明
func (s Stat) String() string {
	switch s {
	case StatAwaitingVendor:
		return "等待商户确认"
	case StatDeclined:
		return "商户拒绝"
	case StatIntercede:
		return "客服处理中"
	case StatAwaitingReturnShip:
		return "等待退货"
	case StatReturnShipped:
		return "等待商户收货"
	case StatAwaitingConfirm:
		return "系统处理中"
	case StatCompleted:
		return "已完成"
	case StatCancelled:
		return "已取消"
	}
	return "-"
}
<commit_msg>after<commit_after>/**
 * Copyright 2015 @ z3q.net.
 * name : after_sales
 * author : jarryliu
 * date : 2016-07-16 14:41
 * description :
 * history :
 */
package afterSales

import (
	"go2o/core/domain/interface/order"
	"go2o/core/infrastructure/domain"
)

const (
	// 等待商户确认
	StatAwaitingVendor = 1 + iota
	// 商户拒绝售后
	StatDeclined
	// 调解状态
	StatIntercede
	// 同意,等待退货
	StatAwaitingReturnShip
	// 已收货,等待系统确认
	StatAwaitingConfirm
	// 已发货
	StatReturnShipped
	// 已退回
	StateRejected
	// 等待处理
	StateAwaitingProcess
	// 售后单已完成
	StatCompleted
	// 售后单已取消
	StatCancelled
)

const (
	// 退款申请(部分退款)
	TypeRefund = 1 + iota
	// 退货
	TypeReturn
	// 换货
	TypeExchange
	// 服务/维修
	TypeService
)

var (
	// 不需要平台确认的售后类型
	IgnoreConfirmTypes = []int{
		TypeExchange,
		TypeService,
	}
	ErrAfterSalesOrderCompleted *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_completed", "售后单已完成,无法进行操作!")

	ErrAfterSalesRejected *domain.DomainError = domain.NewDomainError(
		"err_after_sales_rejected", "售后单已被系统退回")

	ErrUnusualStat *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_unusual_stat", "不合法的售后单状态")

	ErrNoSuchOrderItem *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_no_such_order_item", "订单中不包括该商品")

	ErrOutOfQuantity *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_out_of_quantity", "超出数量")

	ErrReasonLength *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_reason_length", "原因不能少于10字")

	ErrNotConfirm *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_not_confirm", "售后单尚未确认")

	ErrHasCancelled *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_has_cancelled", "售后单已取消")

	ErrOrderAmount *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_amount", "售后单金额不能为零")

	ErrExchangeOrderNoShipping *domain.DomainError = domain.NewDomainError(
		"err_exhange_order_no_shipping", "换货单尚未发货给顾客")

	ErrNotReceive *domain.DomainError = domain.NewDomainError(
		"err_after_sales_order_not_receive", "尚未收货")

	ErrRefundAfterShipped *domain.DomainError = domain.NewDomainError(
		"err_after_sales_refund_after_shipped", "订单已经发货,只能进行退货或换货操作")

	ErrReturnAfterReceived *domain.DomainError = domain.NewDomainError(
		"err_after_sales_return_after_received", "订单已确认收货,只能进行换货操作")
)

type (
	// 售后单状态
	Stat int

	// 提交售后  -》 商户同意(拒绝) -》 系统确认(取消),或客服调解 -》
	// 开始发货  -》 确认收货       -》 处理售后     -》 完成

	// 售后单
	IAfterSalesOrder interface {
		// 获取领域编号
		GetDomainId() int

		// 获取售后单数据
		Value() AfterSalesOrder

		// 获取订单
		GetOrder() order.ISubOrder

		// 设置要退回货物信息
		SetItem(itemId int, quantity int) error

		// 提交售后申请
		Submit() (int, error)

		// 取消申请
		Cancel() error

		// 同意售后服务,部分操作在同意后,无需确认
		Agree() error

		// 拒绝售后服务
		Decline(reason string) error

		// 申请调解,只有在商户拒绝后才能申请
		RequestIntercede() error

		// 系统确认,泛化应有不同的实现
		Confirm() error

		// 退回售后单
		Reject(remark string) error

		// 退回商品
		ReturnShip(spName string, spOrder string, image string) error

		// 收货, 在商品已退回或尚未发货情况下(线下退货),可以执行此操作
		ReturnReceive() error

		// 处理售后单,处理完成后将变为已完成
		Process() error
	}

	IAfterSalesRep interface {
		// 创建售后单
		CreateAfterSalesOrder(v *AfterSalesOrder) IAfterSalesOrder

		// 获取售后单
		GetAfterSalesOrder(id int) IAfterSalesOrder

		// 获取订单的售后单
		GetAllOfSaleOrder(orderId int) []IAfterSalesOrder
	}

	// 售后单
	AfterSalesOrder struct {
		// 编号
		Id int `db:"id" pk:"yes" auto:"yes"`
		// 订单编号
		OrderId int `db:"order_id"`
		// 运营商编号
		VendorId int `db:"vendor_id"`
		// 购买者编号
		BuyerId int `db:"buyer_id"`
		// 类型，退货、换货、维修
		Type int `db:"type"`
		// 退货的商品项编号
		SnapshotId int `db:"snap_id"`
		// 商品数量
		Quantity int `db:"quantity"`
		// 售后原因
		Reason string `db:"reason"`
		// 联系人
		PersonName string `db:"person_name"`
		// 联系电话
		PersonPhone string `db:"person_phone"`
		// 退货的快递服务商编号
		ReturnSpName string `db:"rsp_name"`
		// 退货的快递单号
		ReturnSpOrder string `db:"rsp_order"`
		// 退货凭证
		ReturnSpImage string `db:"rsp_image"`
		// 备注(系统)
		Remark string `db:"remark"`
		// 运营商备注
		VendorRemark string `db:"vendor_remark"`
		// 售后单状态
		State int `db:"state"`
		// 提交时间
		CreateTime int64 `db:"create_time"`
		// 更新时间
		UpdateTime int64 `db:"update_time"`

		// 售后单数据,如退款单、退货单、换货单等
		Data interface{} `db:"-"`
		// 订单状态
		StateText string `db:"-"`
	}

	AfterSalesOrderNew struct{
		OrderNo string `db:"order_no"`
		ItemsInfo string `db:"items_info"`
		BuyerName string `db:"name"`
		BuyerId string `db:"usr"`
		ConsigneePerson string `db:"consignee_person"`  //收货人
		ConsigneePhone string `db:"consignee_phone"`    //电话
		ShippingAddress string `db:"shipping_address"`  //地址
		GoodsAmount int `db:"goods_amount"`
		FinalAmount int `db:"final_amount"`
		IsPaid int `db:"is_paid"`
	}
)

// 返回售后状态说明
func (s Stat) String() string {
	switch s {
	case StatAwaitingVendor:
		return "等待商户确认"
	case StatDeclined:
		return "商户拒绝"
	case StatIntercede:
		return "客服处理中"
	case StatAwaitingReturnShip:
		return "等待退货"
	case StatReturnShipped:
		return "等待商户收货"
	case StatAwaitingConfirm:
		return "系统处理中"
	case StatCompleted:
		return "已完成"
	case StatCancelled:
		return "已取消"
	}
	return "-"
}
<|endoftext|>


<commit_before>/*
   Copyright (c) 2014-2015, Percona LLC and/or its affiliates. All rights reserved.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package pct_test

import (
	"fmt"
	"github.com/percona/percona-agent/pct"
	. "gopkg.in/check.v1"
	"io/ioutil"
	"math/rand"
	"os"
	"path/filepath"
)

type TestSuite struct {
	testPidFile *pct.PidFile
	tmpFile     *os.File
}

var _ = Suite(&TestSuite{})

func (s *TestSuite) SetUpTest(c *C) {
	s.testPidFile = pct.NewPidFile()

}

func (s *TestSuite) TestGet(t *C) {
	t.Assert(s.testPidFile.Get(), Equals, "")
}

func getTmpFileName(t *C) (string, error) {
	tmpFile, err := ioutil.TempFile("", "")
	if err != nil {
		t.Logf("Could not get a valid tmp filename: %v", err)
		return "", err
	}
	return tmpFile.Name(), nil
}

func removeTmpFile(tmpFileName string, t *C) error {
	if err := os.Remove(tmpFileName); err != nil {
		t.Logf("Could not delete tmp file: %v", err)
		return err
	}
	return nil
}

func getRandFilename() string {
	return fmt.Sprintf("%v.pid", rand.Int())
}

func openCloseFile(tmpFileName string, t *C) error {
	tmpFile, err := os.Open(tmpFileName)
	if err != nil && os.IsNotExist(err) {
		t.Logf("PidFile not found")
		return err
	} else if err != nil {
		t.Logf("Could not open PidFile: %v", err)
		return err
	}
	tmpFile.Close()
	return nil
}

func (s *TestSuite) TestSet(t *C) {
	t.Assert(s.testPidFile.Set(""), Equals, nil)

	tmpFileName, err := getTmpFileName(t)
	if err != nil {
		t.Fail()
	}
	// Should fail, file already exists
	t.Assert(s.testPidFile.Set(tmpFileName), NotNil)

	// Remove the pid file from the fs
	if err := removeTmpFile(tmpFileName, t); err != nil {
		t.Fail()
	}

	t.Assert(s.testPidFile.Set(tmpFileName), Equals, nil)
	defer os.Remove(tmpFileName)

	if err := openCloseFile(tmpFileName, t); err != nil {
		t.Fail()
	}

	randPidFileName := getRandFilename()
	t.Assert(s.testPidFile.Set(randPidFileName), Equals, nil)
	fullPath := filepath.Join(pct.Basedir.Path(), randPidFileName)
	defer os.Remove(fullPath)
}

func (s *TestSuite) TestRemove(t *C) {
	t.Assert(s.testPidFile.Set(""), Equals, nil)
	t.Assert(s.testPidFile.Remove(), Equals, nil)

	tmpFilePath, err := getTmpFileName(t)
	if err != nil {
		t.Fail()
	}
	// We have a valid tmp file name now, remove it
	t.Assert(removeTmpFile(tmpFilePath, t), Equals, nil)

	t.Assert(s.testPidFile.Set(tmpFilePath), Equals, nil)
	t.Assert(s.testPidFile.Remove(), Equals, nil)
	_, err = os.Open(tmpFilePath)
	t.Assert(err, NotNil)

	t.Assert(s.testPidFile.Set(tmpFilePath), Equals, nil)
	t.Assert(removeTmpFile(tmpFilePath, t), Equals, nil)
	t.Assert(s.testPidFile.Remove(), Equals, nil)

	t.Assert(s.testPidFile.Set(tmpFilePath), Equals, nil)
	t.Assert(removeTmpFile(tmpFilePath, t), Equals, nil)
	t.Assert(s.testPidFile.Remove(), Equals, nil)
	if tmpFile, err := os.Open(tmpFilePath); err != nil && !os.IsNotExist(err) {
		tmpFile.Close()
		defer removeTmpFile(tmpFilePath, t)
		t.Errorf("Failed removal of PidFile: %v", err)
	}

}
<commit_msg>Improves pidfile tests<commit_after>/*
   Copyright (c) 2014-2015, Percona LLC and/or its affiliates. All rights reserved.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

package pct_test

import (
	"fmt"
	"github.com/percona/percona-agent/pct"
	. "gopkg.in/check.v1"
	"io/ioutil"
	"math/rand"
	"os"
	"path/filepath"
)

type TestSuite struct {
	basedir     string
	testPidFile *pct.PidFile
	tmpFile     *os.File
}

var _ = Suite(&TestSuite{})

func (s *TestSuite) SetUpSuite(t *C) {
	// We can't/shouldn't use /usr/local/percona/ (the default basedir), so use
	// a tmpdir instead with roughly the same structure.
	basedir, err := ioutil.TempDir("", "pidfile-test-")
	s.basedir = basedir
	t.Assert(err, IsNil)
	if err := pct.Basedir.Init(s.basedir); err != nil {
		t.Errorf("Could initialize tmp Basedir: %v", err)
	}
}

func (s *TestSuite) TearDownSuite(t *C) {
	if err := os.RemoveAll(s.basedir); err != nil {
		t.Error(err)
	}
}

func (s *TestSuite) SetUpTest(t *C) {
	s.testPidFile = pct.NewPidFile()

}

func (s *TestSuite) TestGet(t *C) {
	t.Assert(s.testPidFile.Get(), Equals, "")
}

func getTmpFileName(t *C) (string, error) {
	tmpFile, err := ioutil.TempFile("", "")
	if err != nil {
		t.Logf("Could not get a valid tmp filename: %v", err)
		return "", err
	}
	return tmpFile.Name(), nil
}

func removeTmpFile(tmpFileName string, t *C) error {
	if err := os.Remove(tmpFileName); err != nil {
		t.Logf("Could not delete tmp file: %v", err)
		return err
	}
	return nil
}

func getRandFilename() string {
	return fmt.Sprintf("%v.pid", rand.Int())
}

func openCloseFile(tmpFileName string, t *C) error {
	tmpFile, err := os.Open(tmpFileName)
	if err != nil && os.IsNotExist(err) {
		t.Logf("PidFile not found")
		return err
	} else if err != nil {
		t.Logf("Could not open PidFile: %v", err)
		return err
	}
	tmpFile.Close()
	return nil
}

func (s *TestSuite) TestSet(t *C) {
	t.Assert(s.testPidFile.Set(""), Equals, nil)

	tmpFileName, err := getTmpFileName(t)
	if err != nil {
		t.Fail()
	}
	// Should fail, file already exists
	t.Assert(s.testPidFile.Set(tmpFileName), NotNil)

	// Remove the pid file from the fs
	if err := removeTmpFile(tmpFileName, t); err != nil {
		t.Fail()
	}

	t.Assert(s.testPidFile.Set(tmpFileName), Equals, nil)
	defer os.Remove(tmpFileName)

	if err := openCloseFile(tmpFileName, t); err != nil {
		t.Fail()
	}

	randPidFileName := getRandFilename()
	t.Assert(s.testPidFile.Set(randPidFileName), Equals, nil)
	fullPath := filepath.Join(pct.Basedir.Path(), randPidFileName)
	defer os.Remove(fullPath)
}

func (s *TestSuite) TestRemove(t *C) {
	t.Assert(s.testPidFile.Set(""), Equals, nil)
	t.Assert(s.testPidFile.Remove(), Equals, nil)

	tmpFilePath, err := getTmpFileName(t)
	if err != nil {
		t.Fail()
	}
	// We have a valid tmp file name now, remove it
	t.Assert(removeTmpFile(tmpFilePath, t), Equals, nil)

	t.Assert(s.testPidFile.Set(tmpFilePath), Equals, nil)
	t.Assert(s.testPidFile.Remove(), Equals, nil)
	_, err = os.Open(tmpFilePath)
	t.Assert(err, NotNil)

	t.Assert(s.testPidFile.Set(tmpFilePath), Equals, nil)
	t.Assert(removeTmpFile(tmpFilePath, t), Equals, nil)
	t.Assert(s.testPidFile.Remove(), Equals, nil)

	t.Assert(s.testPidFile.Set(tmpFilePath), Equals, nil)
	t.Assert(removeTmpFile(tmpFilePath, t), Equals, nil)
	t.Assert(s.testPidFile.Remove(), Equals, nil)
	if tmpFile, err := os.Open(tmpFilePath); err != nil && !os.IsNotExist(err) {
		tmpFile.Close()
		defer removeTmpFile(tmpFilePath, t)
		t.Errorf("Failed removal of PidFile: %v", err)
	}

}
<|endoftext|>


<commit_before>package core

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/af83/edwig/audit"
	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
	"github.com/af83/edwig/siri"
)

type StopMonitoringRequestBroadcaster interface {
	RequestStopArea(request *siri.XMLStopMonitoringRequest) *siri.SIRIStopMonitoringResponse
}

type SIRIStopMonitoringRequestBroadcaster struct {
	model.ClockConsumer

	siriConnector
}

type SIRIStopMonitoringRequestBroadcasterFactory struct{}

func NewSIRIStopMonitoringRequestBroadcaster(partner *Partner) *SIRIStopMonitoringRequestBroadcaster {
	siriStopMonitoringRequestBroadcaster := &SIRIStopMonitoringRequestBroadcaster{}
	siriStopMonitoringRequestBroadcaster.partner = partner
	return siriStopMonitoringRequestBroadcaster
}

func (connector *SIRIStopMonitoringRequestBroadcaster) RemoteObjectIDKind() string {
	if connector.partner.Setting("siri-stop-monitoring-request-broadcaster.remote_objectid_kind") != "" {
		return connector.partner.Setting("siri-stop-monitoring-request-broadcaster.remote_objectid_kind")
	}
	return connector.partner.Setting("remote_objectid_kind")
}

func (connector *SIRIStopMonitoringRequestBroadcaster) getStopMonitoringDelivery(tx *model.Transaction, logStashEvent audit.LogStashEvent, request *siri.XMLStopMonitoringSubRequest) siri.SIRIStopMonitoringDelivery {
	objectidKind := connector.RemoteObjectIDKind()
	objectid := model.NewObjectID(objectidKind, request.MonitoringRef())
	stopArea, ok := tx.Model().StopAreas().FindByObjectId(objectid)
	if !ok {
		return siri.SIRIStopMonitoringDelivery{
			RequestMessageRef: request.MessageIdentifier(),
			Status:            false,
			ResponseTimestamp: connector.Clock().Now(),
			ErrorType:         "InvalidDataReferencesError",
			ErrorText:         fmt.Sprintf("StopArea not found: '%s'", objectid.Value()),
		}
	}

	if !stopArea.CollectedAlways {
		stopArea.CollectedUntil = connector.Clock().Now().Add(15 * time.Minute)
		logger.Log.Printf("StopArea %s will be collected until %v", stopArea.Id(), stopArea.CollectedUntil)
		stopArea.Save()
	}

	delivery := siri.SIRIStopMonitoringDelivery{
		RequestMessageRef: request.MessageIdentifier(),
		Status:            true,
		ResponseTimestamp: connector.Clock().Now(),
	}

	// Prepare StopVisit Selectors
	selectors := []model.StopVisitSelector{}
	if request.LineRef() != "" {
		lineSelectorObjectid := model.NewObjectID(connector.Partner().Setting("remote_objectid_kind"), request.LineRef())
		selectors = append(selectors, model.StopVisitSelectorByLine(lineSelectorObjectid))
	}
	if request.PreviewInterval() != 0 {
		duration := request.PreviewInterval()
		now := connector.Clock().Now()
		if !request.StartTime().IsZero() {
			now = request.StartTime()
		}
		selectors = append(selectors, model.StopVisitSelectorByTime(now, now.Add(duration)))
	}
	selector := model.CompositeStopVisitSelector(selectors)

	// Prepare Id Array for logstash
	var idArray []string

	// Find Descendants
	stopAreas := tx.Model().StopAreas().FindFamily(stopArea.Id())

	// Fill StopVisits
	for _, stopVisit := range tx.Model().StopVisits().FindFollowingByStopAreaIds(stopAreas) {
		if request.MaximumStopVisits() > 0 && len(idArray) >= request.MaximumStopVisits() {
			break
		}
		if !selector(stopVisit) {
			continue
		}

		idArray = append(idArray, string(stopVisit.Id()))

		var itemIdentifier string
		stopVisitId, ok := stopVisit.ObjectID(objectidKind)
		if ok {
			itemIdentifier = stopVisitId.Value()
		} else {
			defaultObjectID, ok := stopVisit.ObjectID("_default")
			if !ok {
				continue
			}
			itemIdentifier = fmt.Sprintf("RATPDev:Item::%s:LOC", defaultObjectID.HashValue())
		}

		schedules := stopVisit.Schedules

		vehicleJourney := stopVisit.VehicleJourney()
		if vehicleJourney == nil {
			logger.Log.Printf("Ignore StopVisit %s without Vehiclejourney", stopVisit.Id())
			continue
		}
		line := vehicleJourney.Line()
		if line == nil {
			logger.Log.Printf("Ignore StopVisit %s without Line", stopVisit.Id())
			continue
		}
		if _, ok := line.ObjectID(objectidKind); !ok {
			logger.Log.Printf("Ignore StopVisit %s without Line without correct ObjectID", stopVisit.Id())
			continue
		}

		vehicleJourneyId, ok := vehicleJourney.ObjectID(objectidKind)
		var dataVehicleJourneyRef string
		if ok {
			dataVehicleJourneyRef = vehicleJourneyId.Value()
		} else {
			defaultObjectID, ok := vehicleJourney.ObjectID("_default")
			if !ok {
				continue
			}
			dataVehicleJourneyRef = fmt.Sprintf("RATPDev:VehicleJourney::%s:LOC", defaultObjectID.HashValue())
		}

		modelDate := tx.Model().Date()

		lineObjectId, _ := line.ObjectID(objectidKind)

		stopPointRef, _ := tx.Model().StopAreas().Find(stopVisit.StopAreaId)
		stopPointRefObjectId, _ := stopPointRef.ObjectID(objectidKind)

		dataFrameGenerator := connector.SIRIPartner().IdentifierGenerator("data_frame_identifier")
		monitoredStopVisit := &siri.SIRIMonitoredStopVisit{
			ItemIdentifier: itemIdentifier,
			MonitoringRef:  objectid.Value(),
			StopPointRef:   stopPointRefObjectId.Value(),
			StopPointName:  stopPointRef.Name,

			VehicleJourneyName:     vehicleJourney.Name,
			LineRef:                lineObjectId.Value(),
			DatedVehicleJourneyRef: dataVehicleJourneyRef,
			DataFrameRef:           dataFrameGenerator.NewIdentifier(IdentifierAttributes{Id: modelDate.String()}),
			RecordedAt:             stopVisit.RecordedAt,
			PublishedLineName:      line.Name,
			DepartureStatus:        string(stopVisit.DepartureStatus),
			ArrivalStatus:          string(stopVisit.ArrivalStatus),
			Order:                  stopVisit.PassageOrder,
			VehicleAtStop:          stopVisit.VehicleAtStop,
			Attributes:             make(map[string]map[string]string),
			References:             make(map[string]map[string]model.Reference),
		}

		if stopVisit.ArrivalStatus != model.STOP_VISIT_ARRIVAL_CANCELLED && request.StopVisitTypes() != "departures" {
			monitoredStopVisit.AimedArrivalTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_AIMED).ArrivalTime()
			monitoredStopVisit.ExpectedArrivalTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_EXPECTED).ArrivalTime()
			monitoredStopVisit.ActualArrivalTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_ACTUAL).ArrivalTime()
		}

		if stopVisit.DepartureStatus != model.STOP_VISIT_DEPARTURE_CANCELLED && request.StopVisitTypes() != "arrivals" {
			monitoredStopVisit.AimedDepartureTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_AIMED).DepartureTime()
			monitoredStopVisit.ExpectedDepartureTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_EXPECTED).DepartureTime()
			monitoredStopVisit.ActualDepartureTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_ACTUAL).DepartureTime()
		}

		vehicleJourneyRefCopy := vehicleJourney.References.Copy()
		stopVisitRefCopy := stopVisit.References.Copy()

		connector.resolveVehiculeJourneyReferences(vehicleJourneyRefCopy, tx.Model().StopAreas())
		connector.resolveOperator(stopVisitRefCopy)

		connector.reformatReferences(vehicleJourney.ToFormat(), vehicleJourneyRefCopy)

		monitoredStopVisit.Attributes["StopVisitAttributes"] = stopVisit.Attributes
		monitoredStopVisit.References["StopVisitReferences"] = stopVisitRefCopy

		monitoredStopVisit.Attributes["VehicleJourneyAttributes"] = vehicleJourney.Attributes
		monitoredStopVisit.References["VehicleJourney"] = vehicleJourneyRefCopy

		delivery.MonitoredStopVisits = append(delivery.MonitoredStopVisits, monitoredStopVisit)
	}

	logStashEvent["StopVisitIds"] = strings.Join(idArray, ", ")

	return delivery
}

func (connector *SIRIStopMonitoringRequestBroadcaster) RequestStopArea(request *siri.XMLStopMonitoringRequest) *siri.SIRIStopMonitoringResponse {
	tx := connector.Partner().Referential().NewTransaction()
	defer tx.Close()

	logStashEvent := make(audit.LogStashEvent)
	defer audit.CurrentLogStash().WriteEvent(logStashEvent)

	logXMLStopMonitoringRequest(logStashEvent, request)

	response := new(siri.SIRIStopMonitoringResponse)
	response.Address = connector.Partner().Setting("local_url")
	response.ProducerRef = connector.Partner().Setting("remote_credential")
	if response.ProducerRef == "" {
		response.ProducerRef = "Edwig"
	}
	response.ResponseMessageIdentifier = connector.SIRIPartner().IdentifierGenerator("response_message_identifier").NewMessageIdentifier()

	response.SIRIStopMonitoringDelivery = connector.getStopMonitoringDelivery(tx, logStashEvent, &request.XMLStopMonitoringSubRequest)

	logSIRIStopMonitoringResponse(logStashEvent, response)

	return response
}

func (connector *SIRIStopMonitoringRequestBroadcaster) resolveOperator(references model.References) {
	operatorRef, _ := references["OperatorRef"]
	operator, ok := connector.Partner().Model().Operators().Find(model.OperatorId(operatorRef.Id))
	if !ok {
		return
	}

	obj, ok := operator.ObjectID(connector.Partner().Setting("remote_objectid_kind"))
	if !ok {
		return
	}
	references["OperatorRef"].ObjectId.SetValue(obj.Value())
}

func (connector *SIRIStopMonitoringRequestBroadcaster) resolveVehiculeJourneyReferences(references model.References, manager model.StopAreas) {
	toResolve := []string{"PlaceRef", "OriginRef", "DestinationRef"}

	for _, ref := range toResolve {
		if references[ref] == (model.Reference{}) {
			continue
		}
		if foundStopArea, ok := manager.Find(model.StopAreaId(references[ref].Id)); ok {
			obj, ok := foundStopArea.ObjectID(connector.RemoteObjectIDKind())
			if ok {
				tmp := references[ref]
				tmp.ObjectId = &obj
				references[ref] = tmp
				continue
			}
		}
		generator := connector.SIRIPartner().IdentifierGenerator("reference_stop_area_identifier")
		tmp := references[ref]
		tmp.ObjectId.SetValue(generator.NewIdentifier(IdentifierAttributes{Default: tmp.GetSha1()}))
	}
}

func (connector *SIRIStopMonitoringRequestBroadcaster) reformatReferences(toReformat []string, references model.References) {
	generator := connector.SIRIPartner().IdentifierGenerator("reference_identifier")
	for _, ref := range toReformat {
		if references[ref] != (model.Reference{}) {
			tmp := references[ref]
			tmp.ObjectId.SetValue(generator.NewIdentifier(IdentifierAttributes{Type: ref[:len(ref)-3], Default: tmp.GetSha1()}))
		}
	}
}

func (factory *SIRIStopMonitoringRequestBroadcasterFactory) Validate(apiPartner *APIPartner) bool {
	ok := apiPartner.ValidatePresenceOfSetting("remote_objectid_kind")
	ok = ok && apiPartner.ValidatePresenceOfSetting("local_credential")
	return ok
}

func (factory *SIRIStopMonitoringRequestBroadcasterFactory) CreateConnector(partner *Partner) Connector {
	return NewSIRIStopMonitoringRequestBroadcaster(partner)
}

func logXMLStopMonitoringRequest(logStashEvent audit.LogStashEvent, request *siri.XMLStopMonitoringRequest) {
	logStashEvent["Connector"] = "StopMonitoringRequestBroadcaster"
	logStashEvent["messageIdentifier"] = request.MessageIdentifier()
	logStashEvent["monitoringRef"] = request.MonitoringRef()
	logStashEvent["requestorRef"] = request.RequestorRef()
	logStashEvent["requestTimestamp"] = request.RequestTimestamp().String()
	logStashEvent["requestXML"] = request.RawXML()
}

func logSIRIStopMonitoringResponse(logStashEvent audit.LogStashEvent, response *siri.SIRIStopMonitoringResponse) {
	logStashEvent["address"] = response.Address
	logStashEvent["producerRef"] = response.ProducerRef
	logStashEvent["requestMessageRef"] = response.RequestMessageRef
	logStashEvent["responseMessageIdentifier"] = response.ResponseMessageIdentifier
	logStashEvent["responseTimestamp"] = response.ResponseTimestamp.String()
	logStashEvent["status"] = strconv.FormatBool(response.Status)
	if !response.Status {
		logStashEvent["errorType"] = response.ErrorType
		logStashEvent["errorNumber"] = strconv.Itoa(response.ErrorNumber)
		logStashEvent["errorText"] = response.ErrorText
	}
	xml, err := response.BuildXML()
	if err != nil {
		logStashEvent["responseXML"] = fmt.Sprintf("%v", err)
		return
	}
	logStashEvent["responseXML"] = xml
}
<commit_msg>fix forgotten identifiers<commit_after>package core

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/af83/edwig/audit"
	"github.com/af83/edwig/logger"
	"github.com/af83/edwig/model"
	"github.com/af83/edwig/siri"
)

type StopMonitoringRequestBroadcaster interface {
	RequestStopArea(request *siri.XMLStopMonitoringRequest) *siri.SIRIStopMonitoringResponse
}

type SIRIStopMonitoringRequestBroadcaster struct {
	model.ClockConsumer

	siriConnector
}

type SIRIStopMonitoringRequestBroadcasterFactory struct{}

func NewSIRIStopMonitoringRequestBroadcaster(partner *Partner) *SIRIStopMonitoringRequestBroadcaster {
	siriStopMonitoringRequestBroadcaster := &SIRIStopMonitoringRequestBroadcaster{}
	siriStopMonitoringRequestBroadcaster.partner = partner
	return siriStopMonitoringRequestBroadcaster
}

func (connector *SIRIStopMonitoringRequestBroadcaster) RemoteObjectIDKind() string {
	if connector.partner.Setting("siri-stop-monitoring-request-broadcaster.remote_objectid_kind") != "" {
		return connector.partner.Setting("siri-stop-monitoring-request-broadcaster.remote_objectid_kind")
	}
	return connector.partner.Setting("remote_objectid_kind")
}

func (connector *SIRIStopMonitoringRequestBroadcaster) getStopMonitoringDelivery(tx *model.Transaction, logStashEvent audit.LogStashEvent, request *siri.XMLStopMonitoringSubRequest) siri.SIRIStopMonitoringDelivery {
	objectidKind := connector.RemoteObjectIDKind()
	objectid := model.NewObjectID(objectidKind, request.MonitoringRef())
	stopArea, ok := tx.Model().StopAreas().FindByObjectId(objectid)
	if !ok {
		return siri.SIRIStopMonitoringDelivery{
			RequestMessageRef: request.MessageIdentifier(),
			Status:            false,
			ResponseTimestamp: connector.Clock().Now(),
			ErrorType:         "InvalidDataReferencesError",
			ErrorText:         fmt.Sprintf("StopArea not found: '%s'", objectid.Value()),
		}
	}

	if !stopArea.CollectedAlways {
		stopArea.CollectedUntil = connector.Clock().Now().Add(15 * time.Minute)
		logger.Log.Printf("StopArea %s will be collected until %v", stopArea.Id(), stopArea.CollectedUntil)
		stopArea.Save()
	}

	delivery := siri.SIRIStopMonitoringDelivery{
		RequestMessageRef: request.MessageIdentifier(),
		Status:            true,
		ResponseTimestamp: connector.Clock().Now(),
	}

	// Prepare StopVisit Selectors
	selectors := []model.StopVisitSelector{}
	if request.LineRef() != "" {
		lineSelectorObjectid := model.NewObjectID(connector.Partner().Setting("remote_objectid_kind"), request.LineRef())
		selectors = append(selectors, model.StopVisitSelectorByLine(lineSelectorObjectid))
	}
	if request.PreviewInterval() != 0 {
		duration := request.PreviewInterval()
		now := connector.Clock().Now()
		if !request.StartTime().IsZero() {
			now = request.StartTime()
		}
		selectors = append(selectors, model.StopVisitSelectorByTime(now, now.Add(duration)))
	}
	selector := model.CompositeStopVisitSelector(selectors)

	// Prepare Id Array for logstash
	var idArray []string

	// Find Descendants
	stopAreas := tx.Model().StopAreas().FindFamily(stopArea.Id())

	// Fill StopVisits
	referenceGenerator := connector.SIRIPartner().IdentifierGenerator("reference_identifier")
	for _, stopVisit := range tx.Model().StopVisits().FindFollowingByStopAreaIds(stopAreas) {
		if request.MaximumStopVisits() > 0 && len(idArray) >= request.MaximumStopVisits() {
			break
		}
		if !selector(stopVisit) {
			continue
		}

		idArray = append(idArray, string(stopVisit.Id()))

		var itemIdentifier string
		stopVisitId, ok := stopVisit.ObjectID(objectidKind)
		if ok {
			itemIdentifier = stopVisitId.Value()
		} else {
			defaultObjectID, ok := stopVisit.ObjectID("_default")
			if !ok {
				continue
			}
			itemIdentifier = referenceGenerator.NewIdentifier(IdentifierAttributes{Type: "Item", Default: defaultObjectID.HashValue()})
		}

		schedules := stopVisit.Schedules

		vehicleJourney := stopVisit.VehicleJourney()
		if vehicleJourney == nil {
			logger.Log.Printf("Ignore StopVisit %s without Vehiclejourney", stopVisit.Id())
			continue
		}
		line := vehicleJourney.Line()
		if line == nil {
			logger.Log.Printf("Ignore StopVisit %s without Line", stopVisit.Id())
			continue
		}
		if _, ok := line.ObjectID(objectidKind); !ok {
			logger.Log.Printf("Ignore StopVisit %s without Line without correct ObjectID", stopVisit.Id())
			continue
		}

		vehicleJourneyId, ok := vehicleJourney.ObjectID(objectidKind)
		var dataVehicleJourneyRef string
		if ok {
			dataVehicleJourneyRef = vehicleJourneyId.Value()
		} else {
			defaultObjectID, ok := vehicleJourney.ObjectID("_default")
			if !ok {
				continue
			}
			dataVehicleJourneyRef = referenceGenerator.NewIdentifier(IdentifierAttributes{Type: "VehicleJourney", Default: defaultObjectID.HashValue()})
		}

		modelDate := tx.Model().Date()

		lineObjectId, _ := line.ObjectID(objectidKind)

		stopPointRef, _ := tx.Model().StopAreas().Find(stopVisit.StopAreaId)
		stopPointRefObjectId, _ := stopPointRef.ObjectID(objectidKind)

		dataFrameGenerator := connector.SIRIPartner().IdentifierGenerator("data_frame_identifier")
		monitoredStopVisit := &siri.SIRIMonitoredStopVisit{
			ItemIdentifier: itemIdentifier,
			MonitoringRef:  objectid.Value(),
			StopPointRef:   stopPointRefObjectId.Value(),
			StopPointName:  stopPointRef.Name,

			VehicleJourneyName:     vehicleJourney.Name,
			LineRef:                lineObjectId.Value(),
			DatedVehicleJourneyRef: dataVehicleJourneyRef,
			DataFrameRef:           dataFrameGenerator.NewIdentifier(IdentifierAttributes{Id: modelDate.String()}),
			RecordedAt:             stopVisit.RecordedAt,
			PublishedLineName:      line.Name,
			DepartureStatus:        string(stopVisit.DepartureStatus),
			ArrivalStatus:          string(stopVisit.ArrivalStatus),
			Order:                  stopVisit.PassageOrder,
			VehicleAtStop:          stopVisit.VehicleAtStop,
			Attributes:             make(map[string]map[string]string),
			References:             make(map[string]map[string]model.Reference),
		}

		if stopVisit.ArrivalStatus != model.STOP_VISIT_ARRIVAL_CANCELLED && request.StopVisitTypes() != "departures" {
			monitoredStopVisit.AimedArrivalTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_AIMED).ArrivalTime()
			monitoredStopVisit.ExpectedArrivalTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_EXPECTED).ArrivalTime()
			monitoredStopVisit.ActualArrivalTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_ACTUAL).ArrivalTime()
		}

		if stopVisit.DepartureStatus != model.STOP_VISIT_DEPARTURE_CANCELLED && request.StopVisitTypes() != "arrivals" {
			monitoredStopVisit.AimedDepartureTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_AIMED).DepartureTime()
			monitoredStopVisit.ExpectedDepartureTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_EXPECTED).DepartureTime()
			monitoredStopVisit.ActualDepartureTime = schedules.Schedule(model.STOP_VISIT_SCHEDULE_ACTUAL).DepartureTime()
		}

		vehicleJourneyRefCopy := vehicleJourney.References.Copy()
		stopVisitRefCopy := stopVisit.References.Copy()

		connector.resolveVehiculeJourneyReferences(vehicleJourneyRefCopy, tx.Model().StopAreas())
		connector.resolveOperator(stopVisitRefCopy)

		connector.reformatReferences(vehicleJourney.ToFormat(), vehicleJourneyRefCopy)

		monitoredStopVisit.Attributes["StopVisitAttributes"] = stopVisit.Attributes
		monitoredStopVisit.References["StopVisitReferences"] = stopVisitRefCopy

		monitoredStopVisit.Attributes["VehicleJourneyAttributes"] = vehicleJourney.Attributes
		monitoredStopVisit.References["VehicleJourney"] = vehicleJourneyRefCopy

		delivery.MonitoredStopVisits = append(delivery.MonitoredStopVisits, monitoredStopVisit)
	}

	logStashEvent["StopVisitIds"] = strings.Join(idArray, ", ")

	return delivery
}

func (connector *SIRIStopMonitoringRequestBroadcaster) RequestStopArea(request *siri.XMLStopMonitoringRequest) *siri.SIRIStopMonitoringResponse {
	tx := connector.Partner().Referential().NewTransaction()
	defer tx.Close()

	logStashEvent := make(audit.LogStashEvent)
	defer audit.CurrentLogStash().WriteEvent(logStashEvent)

	logXMLStopMonitoringRequest(logStashEvent, request)

	response := new(siri.SIRIStopMonitoringResponse)
	response.Address = connector.Partner().Setting("local_url")
	response.ProducerRef = connector.Partner().Setting("remote_credential")
	if response.ProducerRef == "" {
		response.ProducerRef = "Edwig"
	}
	response.ResponseMessageIdentifier = connector.SIRIPartner().IdentifierGenerator("response_message_identifier").NewMessageIdentifier()

	response.SIRIStopMonitoringDelivery = connector.getStopMonitoringDelivery(tx, logStashEvent, &request.XMLStopMonitoringSubRequest)

	logSIRIStopMonitoringResponse(logStashEvent, response)

	return response
}

func (connector *SIRIStopMonitoringRequestBroadcaster) resolveOperator(references model.References) {
	operatorRef, _ := references["OperatorRef"]
	operator, ok := connector.Partner().Model().Operators().Find(model.OperatorId(operatorRef.Id))
	if !ok {
		return
	}

	obj, ok := operator.ObjectID(connector.Partner().Setting("remote_objectid_kind"))
	if !ok {
		return
	}
	references["OperatorRef"].ObjectId.SetValue(obj.Value())
}

func (connector *SIRIStopMonitoringRequestBroadcaster) resolveVehiculeJourneyReferences(references model.References, manager model.StopAreas) {
	toResolve := []string{"PlaceRef", "OriginRef", "DestinationRef"}

	for _, ref := range toResolve {
		if references[ref] == (model.Reference{}) {
			continue
		}
		if foundStopArea, ok := manager.Find(model.StopAreaId(references[ref].Id)); ok {
			obj, ok := foundStopArea.ObjectID(connector.RemoteObjectIDKind())
			if ok {
				tmp := references[ref]
				tmp.ObjectId = &obj
				references[ref] = tmp
				continue
			}
		}
		generator := connector.SIRIPartner().IdentifierGenerator("reference_stop_area_identifier")
		tmp := references[ref]
		tmp.ObjectId.SetValue(generator.NewIdentifier(IdentifierAttributes{Default: tmp.GetSha1()}))
	}
}

func (connector *SIRIStopMonitoringRequestBroadcaster) reformatReferences(toReformat []string, references model.References) {
	generator := connector.SIRIPartner().IdentifierGenerator("reference_identifier")
	for _, ref := range toReformat {
		if references[ref] != (model.Reference{}) {
			tmp := references[ref]
			tmp.ObjectId.SetValue(generator.NewIdentifier(IdentifierAttributes{Type: ref[:len(ref)-3], Default: tmp.GetSha1()}))
		}
	}
}

func (factory *SIRIStopMonitoringRequestBroadcasterFactory) Validate(apiPartner *APIPartner) bool {
	ok := apiPartner.ValidatePresenceOfSetting("remote_objectid_kind")
	ok = ok && apiPartner.ValidatePresenceOfSetting("local_credential")
	return ok
}

func (factory *SIRIStopMonitoringRequestBroadcasterFactory) CreateConnector(partner *Partner) Connector {
	return NewSIRIStopMonitoringRequestBroadcaster(partner)
}

func logXMLStopMonitoringRequest(logStashEvent audit.LogStashEvent, request *siri.XMLStopMonitoringRequest) {
	logStashEvent["Connector"] = "StopMonitoringRequestBroadcaster"
	logStashEvent["messageIdentifier"] = request.MessageIdentifier()
	logStashEvent["monitoringRef"] = request.MonitoringRef()
	logStashEvent["requestorRef"] = request.RequestorRef()
	logStashEvent["requestTimestamp"] = request.RequestTimestamp().String()
	logStashEvent["requestXML"] = request.RawXML()
}

func logSIRIStopMonitoringResponse(logStashEvent audit.LogStashEvent, response *siri.SIRIStopMonitoringResponse) {
	logStashEvent["address"] = response.Address
	logStashEvent["producerRef"] = response.ProducerRef
	logStashEvent["requestMessageRef"] = response.RequestMessageRef
	logStashEvent["responseMessageIdentifier"] = response.ResponseMessageIdentifier
	logStashEvent["responseTimestamp"] = response.ResponseTimestamp.String()
	logStashEvent["status"] = strconv.FormatBool(response.Status)
	if !response.Status {
		logStashEvent["errorType"] = response.ErrorType
		logStashEvent["errorNumber"] = strconv.Itoa(response.ErrorNumber)
		logStashEvent["errorText"] = response.ErrorText
	}
	xml, err := response.BuildXML()
	if err != nil {
		logStashEvent["responseXML"] = fmt.Sprintf("%v", err)
		return
	}
	logStashEvent["responseXML"] = xml
}
<|endoftext|>


<commit_before>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package admin

import (
	"errors"
	"net/http"

	"github.com/gorilla/rpc/v2"

	"github.com/ava-labs/avalanchego/api"
	"github.com/ava-labs/avalanchego/api/server"
	"github.com/ava-labs/avalanchego/chains"
	"github.com/ava-labs/avalanchego/ids"
	"github.com/ava-labs/avalanchego/snow/engine/common"
	"github.com/ava-labs/avalanchego/utils/constants"
	"github.com/ava-labs/avalanchego/utils/logging"
	"github.com/ava-labs/avalanchego/utils/perms"
	"github.com/ava-labs/avalanchego/utils/profiler"

	cjson "github.com/ava-labs/avalanchego/utils/json"
)

const (
	maxAliasLength = 512

	// Name of file that stacktraces are written to
	stacktraceFile = "stacktrace.txt"
)

var errAliasTooLong = errors.New("alias length is too long")

// Admin is the API service for node admin management
type Admin struct {
	log          logging.Logger
	profiler     profiler.Profiler
	chainManager chains.Manager
	httpServer   *server.Server
	logFactory   logging.Factory
}

// NewService returns a new admin API service
func NewService(log logging.Logger, chainManager chains.Manager, httpServer *server.Server, profileDir string, logFactory logging.Factory) (*common.HTTPHandler, error) {
	newServer := rpc.NewServer()
	codec := cjson.NewCodec()
	newServer.RegisterCodec(codec, "application/json")
	newServer.RegisterCodec(codec, "application/json;charset=UTF-8")
	if err := newServer.RegisterService(&Admin{
		log:          log,
		chainManager: chainManager,
		httpServer:   httpServer,
		profiler:     profiler.New(profileDir),
		logFactory:   logFactory,
	}, "admin"); err != nil {
		return nil, err
	}
	return &common.HTTPHandler{Handler: newServer}, nil
}

// StartCPUProfiler starts a cpu profile writing to the specified file
func (service *Admin) StartCPUProfiler(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: StartCPUProfiler called")
	reply.Success = true
	return service.profiler.StartCPUProfiler()
}

// StopCPUProfiler stops the cpu profile
func (service *Admin) StopCPUProfiler(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: StopCPUProfiler called")

	reply.Success = true
	return service.profiler.StopCPUProfiler()
}

// MemoryProfile runs a memory profile writing to the specified file
func (service *Admin) MemoryProfile(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: MemoryProfile called")

	reply.Success = true
	return service.profiler.MemoryProfile()
}

// LockProfile runs a mutex profile writing to the specified file
func (service *Admin) LockProfile(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: LockProfile called")

	reply.Success = true
	return service.profiler.LockProfile()
}

// AliasArgs are the arguments for calling Alias
type AliasArgs struct {
	Endpoint string `json:"endpoint"`
	Alias    string `json:"alias"`
}

// Alias attempts to alias an HTTP endpoint to a new name
func (service *Admin) Alias(_ *http.Request, args *AliasArgs, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: Alias called with URL: %s, Alias: %s", args.Endpoint, args.Alias)

	if len(args.Alias) > maxAliasLength {
		return errAliasTooLong
	}

	reply.Success = true
	return service.httpServer.AddAliasesWithReadLock(args.Endpoint, args.Alias)
}

// AliasChainArgs are the arguments for calling AliasChain
type AliasChainArgs struct {
	Chain string `json:"chain"`
	Alias string `json:"alias"`
}

// AliasChain attempts to alias a chain to a new name
func (service *Admin) AliasChain(_ *http.Request, args *AliasChainArgs, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: AliasChain called with Chain: %s, Alias: %s", args.Chain, args.Alias)

	if len(args.Alias) > maxAliasLength {
		return errAliasTooLong
	}
	chainID, err := service.chainManager.Lookup(args.Chain)
	if err != nil {
		return err
	}

	if err := service.chainManager.Alias(chainID, args.Alias); err != nil {
		return err
	}

	reply.Success = true
	return service.httpServer.AddAliasesWithReadLock(constants.ChainAliasPrefix+chainID.String(), constants.ChainAliasPrefix+args.Alias)
}

// GetChainAliasesArgs are the arguments for calling GetChainAliases
type GetChainAliasesArgs struct {
	Chain string `json:"chain"`
}

// GetChainAliasesReply are the aliases of the given chain
type GetChainAliasesReply struct {
	Aliases []string `json:"aliases"`
}

// GetChainAliases returns the aliases of the chain
func (service *Admin) GetChainAliases(_ *http.Request, args *GetChainAliasesArgs, reply *GetChainAliasesReply) error {
	service.log.Debug("Admin: GetChainAliases called with Chain: %s", args.Chain)

	id, err := ids.FromString(args.Chain)
	if err != nil {
		return err
	}

	reply.Aliases = service.chainManager.Aliases(id)
	return nil
}

// Stacktrace returns the current global stacktrace
func (service *Admin) Stacktrace(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: Stacktrace called")

	reply.Success = true
	stacktrace := []byte(logging.Stacktrace{Global: true}.String())
	return perms.WriteFile(stacktraceFile, stacktrace, perms.ReadWrite)
}

// See SetLoggerLevel
type SetLoggerLevelArgs struct {
	LoggerName   string         `json:"loggerName"`
	LogLevel     *logging.Level `json:"logLevel"`
	DisplayLevel *logging.Level `json:"displayLevel"`
}

// SetLoggerLevel sets the log level and/or display level for loggers.
// If len([args.LoggerName]) == 0, sets the log/display level of all loggers.
// Otherwise, sets the log/display level of the loggers named in that argument.
// Sets the log level of these loggers to args.LogLevel.
// If args.LogLevel == nil, doesn't set the log level of these loggers.
// If args.LogLevel != nil, must be a valid string representation of a log level.
// Sets the display level of these loggers to args.LogLevel.
// If args.DisplayLevel == nil, doesn't set the display level of these loggers.
// If args.DisplayLevel != nil, must be a valid string representation of a log level.
func (service *Admin) SetLoggerLevel(_ *http.Request, args *SetLoggerLevelArgs, reply *api.SuccessResponse) error {
	service.log.Info("Admin: SetLogLevels called with LoggerName: %q, LogLevel: %q, DisplayLevel: %q", args.LoggerName, args.LogLevel, args.DisplayLevel)

	if args.LogLevel == nil && args.DisplayLevel == nil {
		return errors.New("need to specify either displayLevel or logLevel")
	}

	var loggerNames []string
	if len(args.LoggerName) > 0 {
		loggerNames = []string{args.LoggerName}
	} else {
		// Empty name means all loggers
		loggerNames = service.logFactory.GetLoggerNames()
	}

	for _, name := range loggerNames {
		if args.LogLevel != nil {
			if err := service.logFactory.SetLogLevel(name, *args.LogLevel); err != nil {
				return err
			}
		}
		if args.DisplayLevel != nil {
			if err := service.logFactory.SetDisplayLevel(name, *args.DisplayLevel); err != nil {
				return err
			}
		}
	}
	reply.Success = true
	return nil
}

type LogAndDisplayLevels struct {
	LogLevel     logging.Level `json:"logLevel"`
	DisplayLevel logging.Level `json:"displayLevel"`
}

// See GetLoggerLevel
type GetLoggerLevelArgs struct {
	LoggerName string `json:"loggerName"`
}

// See GetLoggerLevel
type GetLoggerLevelReply struct {
	LoggerLevels map[string]LogAndDisplayLevels `json:"loggerLevels"`
}

// GetLogLevel returns the log level and display level of all loggers.
func (service *Admin) GetLoggerLevel(_ *http.Request, args *GetLoggerLevelArgs, reply *GetLoggerLevelReply) error {
	service.log.Info("Admin: GetLoggerLevels called with LoggerName: %q", args.LoggerName)
	reply.LoggerLevels = make(map[string]LogAndDisplayLevels)
	var loggerNames []string
	// Empty name means all loggers
	if len(args.LoggerName) > 0 {
		loggerNames = []string{args.LoggerName}
	} else {
		loggerNames = service.logFactory.GetLoggerNames()
	}

	for _, name := range loggerNames {
		logLevel, err := service.logFactory.GetLogLevel(name)
		if err != nil {
			return err
		}
		displayLevel, err := service.logFactory.GetDisplayLevel(name)
		if err != nil {
			return err
		}
		reply.LoggerLevels[name] = LogAndDisplayLevels{
			LogLevel:     logLevel,
			DisplayLevel: displayLevel,
		}
	}
	return nil
}
<commit_msg>adjust log level from info to debug<commit_after>// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package admin

import (
	"errors"
	"net/http"

	"github.com/gorilla/rpc/v2"

	"github.com/ava-labs/avalanchego/api"
	"github.com/ava-labs/avalanchego/api/server"
	"github.com/ava-labs/avalanchego/chains"
	"github.com/ava-labs/avalanchego/ids"
	"github.com/ava-labs/avalanchego/snow/engine/common"
	"github.com/ava-labs/avalanchego/utils/constants"
	"github.com/ava-labs/avalanchego/utils/logging"
	"github.com/ava-labs/avalanchego/utils/perms"
	"github.com/ava-labs/avalanchego/utils/profiler"

	cjson "github.com/ava-labs/avalanchego/utils/json"
)

const (
	maxAliasLength = 512

	// Name of file that stacktraces are written to
	stacktraceFile = "stacktrace.txt"
)

var errAliasTooLong = errors.New("alias length is too long")

// Admin is the API service for node admin management
type Admin struct {
	log          logging.Logger
	profiler     profiler.Profiler
	chainManager chains.Manager
	httpServer   *server.Server
	logFactory   logging.Factory
}

// NewService returns a new admin API service
func NewService(log logging.Logger, chainManager chains.Manager, httpServer *server.Server, profileDir string, logFactory logging.Factory) (*common.HTTPHandler, error) {
	newServer := rpc.NewServer()
	codec := cjson.NewCodec()
	newServer.RegisterCodec(codec, "application/json")
	newServer.RegisterCodec(codec, "application/json;charset=UTF-8")
	if err := newServer.RegisterService(&Admin{
		log:          log,
		chainManager: chainManager,
		httpServer:   httpServer,
		profiler:     profiler.New(profileDir),
		logFactory:   logFactory,
	}, "admin"); err != nil {
		return nil, err
	}
	return &common.HTTPHandler{Handler: newServer}, nil
}

// StartCPUProfiler starts a cpu profile writing to the specified file
func (service *Admin) StartCPUProfiler(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: StartCPUProfiler called")
	reply.Success = true
	return service.profiler.StartCPUProfiler()
}

// StopCPUProfiler stops the cpu profile
func (service *Admin) StopCPUProfiler(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: StopCPUProfiler called")

	reply.Success = true
	return service.profiler.StopCPUProfiler()
}

// MemoryProfile runs a memory profile writing to the specified file
func (service *Admin) MemoryProfile(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: MemoryProfile called")

	reply.Success = true
	return service.profiler.MemoryProfile()
}

// LockProfile runs a mutex profile writing to the specified file
func (service *Admin) LockProfile(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: LockProfile called")

	reply.Success = true
	return service.profiler.LockProfile()
}

// AliasArgs are the arguments for calling Alias
type AliasArgs struct {
	Endpoint string `json:"endpoint"`
	Alias    string `json:"alias"`
}

// Alias attempts to alias an HTTP endpoint to a new name
func (service *Admin) Alias(_ *http.Request, args *AliasArgs, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: Alias called with URL: %s, Alias: %s", args.Endpoint, args.Alias)

	if len(args.Alias) > maxAliasLength {
		return errAliasTooLong
	}

	reply.Success = true
	return service.httpServer.AddAliasesWithReadLock(args.Endpoint, args.Alias)
}

// AliasChainArgs are the arguments for calling AliasChain
type AliasChainArgs struct {
	Chain string `json:"chain"`
	Alias string `json:"alias"`
}

// AliasChain attempts to alias a chain to a new name
func (service *Admin) AliasChain(_ *http.Request, args *AliasChainArgs, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: AliasChain called with Chain: %s, Alias: %s", args.Chain, args.Alias)

	if len(args.Alias) > maxAliasLength {
		return errAliasTooLong
	}
	chainID, err := service.chainManager.Lookup(args.Chain)
	if err != nil {
		return err
	}

	if err := service.chainManager.Alias(chainID, args.Alias); err != nil {
		return err
	}

	reply.Success = true
	return service.httpServer.AddAliasesWithReadLock(constants.ChainAliasPrefix+chainID.String(), constants.ChainAliasPrefix+args.Alias)
}

// GetChainAliasesArgs are the arguments for calling GetChainAliases
type GetChainAliasesArgs struct {
	Chain string `json:"chain"`
}

// GetChainAliasesReply are the aliases of the given chain
type GetChainAliasesReply struct {
	Aliases []string `json:"aliases"`
}

// GetChainAliases returns the aliases of the chain
func (service *Admin) GetChainAliases(_ *http.Request, args *GetChainAliasesArgs, reply *GetChainAliasesReply) error {
	service.log.Debug("Admin: GetChainAliases called with Chain: %s", args.Chain)

	id, err := ids.FromString(args.Chain)
	if err != nil {
		return err
	}

	reply.Aliases = service.chainManager.Aliases(id)
	return nil
}

// Stacktrace returns the current global stacktrace
func (service *Admin) Stacktrace(_ *http.Request, _ *struct{}, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: Stacktrace called")

	reply.Success = true
	stacktrace := []byte(logging.Stacktrace{Global: true}.String())
	return perms.WriteFile(stacktraceFile, stacktrace, perms.ReadWrite)
}

// See SetLoggerLevel
type SetLoggerLevelArgs struct {
	LoggerName   string         `json:"loggerName"`
	LogLevel     *logging.Level `json:"logLevel"`
	DisplayLevel *logging.Level `json:"displayLevel"`
}

// SetLoggerLevel sets the log level and/or display level for loggers.
// If len([args.LoggerName]) == 0, sets the log/display level of all loggers.
// Otherwise, sets the log/display level of the loggers named in that argument.
// Sets the log level of these loggers to args.LogLevel.
// If args.LogLevel == nil, doesn't set the log level of these loggers.
// If args.LogLevel != nil, must be a valid string representation of a log level.
// Sets the display level of these loggers to args.LogLevel.
// If args.DisplayLevel == nil, doesn't set the display level of these loggers.
// If args.DisplayLevel != nil, must be a valid string representation of a log level.
func (service *Admin) SetLoggerLevel(_ *http.Request, args *SetLoggerLevelArgs, reply *api.SuccessResponse) error {
	service.log.Debug("Admin: SetLogLevels called with LoggerName: %q, LogLevel: %q, DisplayLevel: %q", args.LoggerName, args.LogLevel, args.DisplayLevel)

	if args.LogLevel == nil && args.DisplayLevel == nil {
		return errors.New("need to specify either displayLevel or logLevel")
	}

	var loggerNames []string
	if len(args.LoggerName) > 0 {
		loggerNames = []string{args.LoggerName}
	} else {
		// Empty name means all loggers
		loggerNames = service.logFactory.GetLoggerNames()
	}

	for _, name := range loggerNames {
		if args.LogLevel != nil {
			if err := service.logFactory.SetLogLevel(name, *args.LogLevel); err != nil {
				return err
			}
		}
		if args.DisplayLevel != nil {
			if err := service.logFactory.SetDisplayLevel(name, *args.DisplayLevel); err != nil {
				return err
			}
		}
	}
	reply.Success = true
	return nil
}

type LogAndDisplayLevels struct {
	LogLevel     logging.Level `json:"logLevel"`
	DisplayLevel logging.Level `json:"displayLevel"`
}

// See GetLoggerLevel
type GetLoggerLevelArgs struct {
	LoggerName string `json:"loggerName"`
}

// See GetLoggerLevel
type GetLoggerLevelReply struct {
	LoggerLevels map[string]LogAndDisplayLevels `json:"loggerLevels"`
}

// GetLogLevel returns the log level and display level of all loggers.
func (service *Admin) GetLoggerLevel(_ *http.Request, args *GetLoggerLevelArgs, reply *GetLoggerLevelReply) error {
	service.log.Debug("Admin: GetLoggerLevels called with LoggerName: %q", args.LoggerName)
	reply.LoggerLevels = make(map[string]LogAndDisplayLevels)
	var loggerNames []string
	// Empty name means all loggers
	if len(args.LoggerName) > 0 {
		loggerNames = []string{args.LoggerName}
	} else {
		loggerNames = service.logFactory.GetLoggerNames()
	}

	for _, name := range loggerNames {
		logLevel, err := service.logFactory.GetLogLevel(name)
		if err != nil {
			return err
		}
		displayLevel, err := service.logFactory.GetDisplayLevel(name)
		if err != nil {
			return err
		}
		reply.LoggerLevels[name] = LogAndDisplayLevels{
			LogLevel:     logLevel,
			DisplayLevel: displayLevel,
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package notaryapi

import (
	"encoding/xml"
	"fmt"
	"github.com/FactomProject/dynrsrc"
	"github.com/FactomProject/gocoding"
	"github.com/FactomProject/gocoding/html"
	"github.com/FactomProject/gocoding/json"
	"io"
	"reflect"
	"text/template"
)

var htmlTmpl *template.Template

func StartStatic(path string) (err error) {
	htmlTmpl, err = template.ParseFiles(path);
	return
}

func StartDynamic(path string, readEH func(err error)) error {
	return dynrsrc.CreateDynamicResource(path, func(data []byte) {
		var err error
		htmlTmpl, err = template.New("html").Parse(string(data))
		if err != nil { readEH(err) }
	})
}

var M = struct {Main, Alt gocoding.Marshaller}{
	json.NewMarshaller(),
	json.NewMarshaller(),
}

var hashEncoder = M.Alt.FindEncoder(reflect.TypeOf(new(Hash)))

func init() {
	M.Alt.CacheEncoder(reflect.TypeOf(new(EBlock)), AltBlockEncoder)
	//M.Alt.CacheEncoder(reflect.TypeOf(new(Entry)), AltEntryEncoder)
}

func AltBlockEncoder(scratch [64]byte, renderer gocoding.Renderer, value reflect.Value) {
	value = value.Elem()

	renderer.StartStruct()

	renderer.StartElement("BlockID")
	M.Alt.MarshalValue(renderer, value.FieldByName("BlockID"))
	renderer.StopElement("BlockID")

	renderer.StartElement("PreviousHash")
	M.Alt.MarshalValue(renderer, value.FieldByName("PreviousHash"))
	renderer.StopElement("PreviousHash")

	renderer.StartElement("NumEntries")
	M.Alt.MarshalObject(renderer, value.FieldByName("Entries").Len())
	renderer.StopElement("NumEntries")

	renderer.StartElement("Salt")
	M.Alt.MarshalValue(renderer, value.FieldByName("Salt"))
	renderer.StopElement("Salt")

	renderer.StopStruct()
}

func Marshal(resource interface{}, accept string, writer io.Writer, alt bool) (r *Error) {
	var err error
	var marshaller gocoding.Marshaller
	var renderer gocoding.Renderer

	if alt {
		marshaller = M.Alt
	} else {
		marshaller = M.Main
	}

	switch accept {
	case "text":
		renderer = json.RenderIndented(writer, "", "  ")

	case "json":
		renderer = json.Render(writer)

	case "xml":
		data, err := xml.Marshal(resource)
		if err != nil {
			r = CreateError(ErrorXMLMarshal, err.Error())
			data, err = xml.Marshal(r)
			if err != nil {
				panic(err)
			}
		}
		writer.Write(data)
		return

	case "html":
		renderer = html.Render(writer)

	default:
		resource  = CreateError(ErrorUnsupportedMarshal, fmt.Sprintf(`"%s" is an unsupported marshalling format`, accept))
		renderer = json.Render(writer)
	}

	err = marshaller.Marshal(renderer, resource)
	if err != nil {
		r = CreateError(ErrorJSONMarshal, err.Error())
		err = marshaller.Marshal(renderer, r)
		if err != nil {
			panic(err)
		}
	}
	return
}
<commit_msg>cleanup for notaryapi/marshal.go<commit_after>package notaryapi

import (
	"encoding/xml"
	"fmt"
	"io"
	"reflect"
	"text/template"

	"github.com/FactomProject/dynrsrc"
	"github.com/FactomProject/gocoding"
	"github.com/FactomProject/gocoding/html"
	"github.com/FactomProject/gocoding/json"
)

var htmlTmpl *template.Template

func StartStatic(path string) (err error) {
	htmlTmpl, err = template.ParseFiles(path)
	return
}

func StartDynamic(path string, readEH func(err error)) error {
	return dynrsrc.CreateDynamicResource(path, func(data []byte) {
		var err error
		htmlTmpl, err = template.New("html").Parse(string(data))
		if err != nil {
			readEH(err)
		}
	})
}

var M = struct{ Main, Alt gocoding.Marshaller }{
	json.NewMarshaller(),
	json.NewMarshaller(),
}

var hashEncoder = M.Alt.FindEncoder(reflect.TypeOf(new(Hash)))

func init() {
	M.Alt.CacheEncoder(reflect.TypeOf(new(EBlock)), AltBlockEncoder)
	//M.Alt.CacheEncoder(reflect.TypeOf(new(Entry)), AltEntryEncoder)
}

func AltBlockEncoder(scratch [64]byte, r gocoding.Renderer, v reflect.Value) {
	v = v.Elem()

	r.StartStruct()

	r.StartElement("BlockID")
	M.Alt.MarshalValue(r, v.FieldByName("BlockID"))
	r.StopElement("BlockID")

	r.StartElement("PreviousHash")
	M.Alt.MarshalValue(r, v.FieldByName("PreviousHash"))
	r.StopElement("PreviousHash")

	r.StartElement("NumEntries")
	M.Alt.MarshalObject(r, v.FieldByName("Entries").Len())
	r.StopElement("NumEntries")

	r.StartElement("Salt")
	M.Alt.MarshalValue(r, v.FieldByName("Salt"))
	r.StopElement("Salt")

	r.StopStruct()
}

func Marshal(resource interface{}, accept string, writer io.Writer, alt bool) (r *Error) {
	var err error
	var marshaller gocoding.Marshaller
	var renderer gocoding.Renderer

	if alt {
		marshaller = M.Alt
	} else {
		marshaller = M.Main
	}

	switch accept {
	case "text":
		renderer = json.RenderIndented(writer, "", "  ")

	case "json":
		renderer = json.Render(writer)

	case "xml":
		data, err := xml.Marshal(resource)
		if err != nil {
			r = CreateError(ErrorXMLMarshal, err.Error())
			data, err = xml.Marshal(r)
			if err != nil {
				panic(err)
			}
		}
		writer.Write(data)
		return

	case "html":
		renderer = html.Render(writer)

	default:
		resource = CreateError(ErrorUnsupportedMarshal, fmt.Sprintf(`"%s" is an unsupported marshalling format`, accept))
		renderer = json.Render(writer)
	}

	err = marshaller.Marshal(renderer, resource)
	if err != nil {
		r = CreateError(ErrorJSONMarshal, err.Error())
		err = marshaller.Marshal(renderer, r)
		if err != nil {
			panic(err)
		}
	}
	return
}
<|endoftext|>


<commit_before>// Copyright 2015 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.

package runtime_test

import (
	"runtime"
	"syscall"
	"testing"
)

func TestFixedGOROOT(t *testing.T) {
	if runtime.GOOS == "plan9" {
		t.Skipf("skipping plan9, it is inconsistent by allowing GOROOT to be updated by Setenv")
	}

	envs := runtime.Envs()
	oldenvs := append([]string{}, envs...)
	defer runtime.SetEnvs(oldenvs)

	// attempt to reuse existing envs backing array.
	want := runtime.GOROOT()
	runtime.SetEnvs(append(envs[:0], "GOROOT="+want))

	if got := runtime.GOROOT(); got != want {
		t.Errorf(`initial runtime.GOROOT()=%q, want %q`, got, want)
	}
	if err := syscall.Setenv("GOROOT", "/os"); err != nil {
		t.Fatal(err)
	}
	if got := runtime.GOROOT(); got != want {
		t.Errorf(`after setenv runtime.GOROOT()=%q, want %q`, got, want)
	}
	if err := syscall.Unsetenv("GOROOT"); err != nil {
		t.Fatal(err)
	}
	if got := runtime.GOROOT(); got != want {
		t.Errorf(`after unsetenv runtime.GOROOT()=%q, want %q`, got, want)
	}
}
<commit_msg>runtime: fix TestFixedGOROOT to properly restore the GOROOT env var after test<commit_after>// Copyright 2015 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.

package runtime_test

import (
	"runtime"
	"syscall"
	"testing"
)

func TestFixedGOROOT(t *testing.T) {
	if runtime.GOOS == "plan9" {
		t.Skipf("skipping plan9, it is inconsistent by allowing GOROOT to be updated by Setenv")
	}

	// Restore both the real GOROOT environment variable, and runtime's copies:
	if orig, ok := syscall.Getenv("GOROOT"); ok {
		defer syscall.Setenv("GOROOT", orig)
	} else {
		defer syscall.Unsetenv("GOROOT")
	}
	envs := runtime.Envs()
	oldenvs := append([]string{}, envs...)
	defer runtime.SetEnvs(oldenvs)

	// attempt to reuse existing envs backing array.
	want := runtime.GOROOT()
	runtime.SetEnvs(append(envs[:0], "GOROOT="+want))

	if got := runtime.GOROOT(); got != want {
		t.Errorf(`initial runtime.GOROOT()=%q, want %q`, got, want)
	}
	if err := syscall.Setenv("GOROOT", "/os"); err != nil {
		t.Fatal(err)
	}
	if got := runtime.GOROOT(); got != want {
		t.Errorf(`after setenv runtime.GOROOT()=%q, want %q`, got, want)
	}
	if err := syscall.Unsetenv("GOROOT"); err != nil {
		t.Fatal(err)
	}
	if got := runtime.GOROOT(); got != want {
		t.Errorf(`after unsetenv runtime.GOROOT()=%q, want %q`, got, want)
	}
}
<|endoftext|>


<commit_before>// go test -run=BenchmarkRouter -bench=.
// go test -bench=.
// go test -bench=BenchmarkRouter

package violetear

import (
	"net/http"
	"testing"
)

func benchRequest(b *testing.B, router http.Handler, r *http.Request) {
	w := &ResponseWriter{}
	u := r.URL
	rq := u.RawQuery
	r.RequestURI = u.RequestURI()
	b.ReportAllocs()
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		u.RawQuery = rq
		router.ServeHTTP(w, r)
	}
}

// func BenchmarkRouterStatic(b *testing.B) {
func BenchmarkXX(b *testing.B) {
	router := New()
	router.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {}, "GET,HEAD")
	r, _ := http.NewRequest("GET", "/hello", nil)
	benchRequest(b, router, r)
}

func BenchmarkRouterDynamic(b *testing.B) {
	router := New()
	router.AddRegex(":word", `^\w+$`)
	router.HandleFunc("/test/:word", func(w http.ResponseWriter, r *http.Request) {}, "GET,HEAD")
	r, _ := http.NewRequest("GET", "/test/foo", nil)
	benchRequest(b, router, r)
}
<commit_msg>go test -bench BenchmarkRouterStatic -run=^$<commit_after>// go test -run=BenchmarkRouter -bench=.
// go test -bench=.
// go test -bench=BenchmarkRouter

package violetear

import (
	"net/http"
	"testing"
)

func benchRequest(b *testing.B, router http.Handler, r *http.Request) {
	w := &ResponseWriter{}
	u := r.URL
	rq := u.RawQuery
	r.RequestURI = u.RequestURI()
	b.ReportAllocs()
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		u.RawQuery = rq
		router.ServeHTTP(w, r)
	}
}

func BenchmarkRouterStatic(b *testing.B) {
	router := New()
	router.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {}, "GET,HEAD")
	r, _ := http.NewRequest("GET", "/hello", nil)
	benchRequest(b, router, r)
}

func BenchmarkRouterDynamic(b *testing.B) {
	router := New()
	router.AddRegex(":word", `^\w+$`)
	router.HandleFunc("/test/:word", func(w http.ResponseWriter, r *http.Request) {}, "GET,HEAD")
	r, _ := http.NewRequest("GET", "/test/foo", nil)
	benchRequest(b, router, r)
}
<|endoftext|>


<commit_before>package timeutil

import (
	"testing"
	"time"
)

var dt6ForDt14Tests = []struct {
	v    int64
	want int32
}{
	{int64(20060102150405), int32(20060102)}}

func TestDt6ForDt14(t *testing.T) {
	for _, tt := range dt6ForDt14Tests {
		got := Dt6ForDt14(tt.v)
		if got != tt.want {
			t.Errorf("Dt6ForDt14(%v): want %v, got %v", tt.v, tt.want, got)
		}
	}
}

var dt8ForStringTests = []struct {
	v    string
	want int32
}{
	{"2006-01-02T15:04:05Z", int32(20060102)}}

func TestDt8ForString(t *testing.T) {
	for _, tt := range dt8ForStringTests {
		got, err := Dt8ForString(time.RFC3339, tt.v)
		if err != nil {
			t.Errorf("Dt8ForString(%v): want %v, error ", tt.v, tt.want, err)
		}
		if got != tt.want {
			t.Errorf("Dt8ForString(%v): want %v, got %v", tt.v, tt.want, got)
		}
	}
}

/*
var fromToTests = []struct {
	v    string
	want string
}{
	{"Wed, 25 May 2016 11:07:20 +0000", "2016-05-25T11:07:20Z"}}

func FromToTest(t *testing.T) {
	for _, tt := range fromToTests {
		got, err := FromTo(tt.v, time.RFC1123Z, time.RFC3339)
		if err != nil {
			t.Errorf("FromTo(%v): want %v, error ", tt.v, tt.want, err)
		}
		if got != tt.want {
			t.Errorf("FromTo(%v): want %v, got %v", tt.v, tt.want, got)
		}
	}
}
*/
<commit_msg>update test<commit_after>package timeutil

import (
	"testing"
	"time"
)

var dt6ForDt14Tests = []struct {
	v    int64
	want int32
}{
	{int64(20060102150405), int32(20060102)}}

func TestDt6ForDt14(t *testing.T) {
	for _, tt := range dt6ForDt14Tests {
		got := Dt6ForDt14(tt.v)
		if got != tt.want {
			t.Errorf("Dt6ForDt14(%v): want %v, got %v", tt.v, tt.want, got)
		}
	}
}

var dt8ForStringTests = []struct {
	v    string
	want int32
}{
	{"2006-01-02T15:04:05Z", int32(20060102)}}

func TestDt8ForString(t *testing.T) {
	for _, tt := range dt8ForStringTests {
		got, err := Dt8ForString(time.RFC3339, tt.v)
		if err != nil {
			t.Errorf("Dt8ForString(%v): want %v, error %v", tt.v, tt.want, err)
		}
		if got != tt.want {
			t.Errorf("Dt8ForString(%v): want %v, got %v", tt.v, tt.want, got)
		}
	}
}

/*
var fromToTests = []struct {
	v    string
	want string
}{
	{"Wed, 25 May 2016 11:07:20 +0000", "2016-05-25T11:07:20Z"}}

func FromToTest(t *testing.T) {
	for _, tt := range fromToTests {
		got, err := FromTo(tt.v, time.RFC1123Z, time.RFC3339)
		if err != nil {
			t.Errorf("FromTo(%v): want %v, error ", tt.v, tt.want, err)
		}
		if got != tt.want {
			t.Errorf("FromTo(%v): want %v, got %v", tt.v, tt.want, got)
		}
	}
}
*/
<|endoftext|>