<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package servicebackend

import (
	"context"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/onsi/ginkgo"
	"github.com/stretchr/testify/assert"
	core "k8s.io/api/core/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"

	"k8s.io/ingress-nginx/internal/nginx"
	"k8s.io/ingress-nginx/test/e2e/framework"
)

var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
	f := framework.NewDefaultFramework("type-externalname")

	ginkgo.It("works with external name set to incomplete fdqn", func() {
		f.NewEchoDeployment()

		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: framework.EchoService,
				Type:         corev1.ServiceTypeExternalName,
			},
		}

		f.EnsureService(svc)

		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK)
	})

	ginkgo.It("should return 200 for service type=ExternalName without a port defined", func() {
		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: "httpbin.org",
				Type:         corev1.ServiceTypeExternalName,
			},
		}

		f.EnsureService(svc)

		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK)
	})

	ginkgo.It("should return 200 for service type=ExternalName with a port defined", func() {
		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: "httpbin.org",
				Type:         corev1.ServiceTypeExternalName,
				Ports: []corev1.ServicePort{
					{
						Name:       host,
						Port:       80,
						TargetPort: intstr.FromInt(80),
						Protocol:   "TCP",
					},
				},
			},
		}
		f.EnsureService(svc)

		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK)
	})

	ginkgo.It("should return status 502 for service type=ExternalName with an invalid host", func() {
		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: "invalid.hostname",
				Type:         corev1.ServiceTypeExternalName,
			},
		}

		f.EnsureService(svc)

		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusBadGateway)
	})

	ginkgo.It("should return 200 for service type=ExternalName using a port name", func() {
		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: "httpbin.org",
				Type:         corev1.ServiceTypeExternalName,
				Ports: []corev1.ServicePort{
					{
						Name:       host,
						Port:       80,
						TargetPort: intstr.FromInt(80),
						Protocol:   "TCP",
					},
				},
			},
		}
		f.EnsureService(svc)

		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
		ing.Spec.Rules[0].HTTP.Paths[0].Backend.ServicePort = intstr.FromString(host)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK)
	})

	ginkgo.It("should update the external name after a service update", func() {
		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: "httpbin.org",
				Type:         corev1.ServiceTypeExternalName,
				Ports: []corev1.ServicePort{
					{
						Name:       host,
						Port:       80,
						TargetPort: intstr.FromInt(80),
						Protocol:   "TCP",
					},
				},
			},
		}
		f.EnsureService(svc)

		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
		ing.Spec.Rules[0].HTTP.Paths[0].Backend.ServicePort = intstr.FromString(host)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		body := f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK).
			Body().
			Raw()

		assert.Contains(ginkgo.GinkgoT(), body, `"X-Forwarded-Host": "echo"`)

		svc, err := f.KubeClientSet.CoreV1().Services(f.Namespace).Get(context.TODO(), framework.HTTPBinService, metav1.GetOptions{})
		assert.Nil(ginkgo.GinkgoT(), err, "unexpected error obtaining httpbin service")

		svc.Spec.ExternalName = "eu.httpbin.org"

		_, err = f.KubeClientSet.CoreV1().Services(f.Namespace).Update(context.Background(), svc, metav1.UpdateOptions{})
		assert.Nil(ginkgo.GinkgoT(), err, "unexpected error updating httpbin service")

		time.Sleep(5 * time.Second)

		body = f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK).
			Body().
			Raw()

		assert.Contains(ginkgo.GinkgoT(), body, `"X-Forwarded-Host": "echo"`)

		ginkgo.By("checking the service is updated to use eu.httpbin.org")
		curlCmd := fmt.Sprintf("curl --fail --silent http://localhost:%v/configuration/backends", nginx.StatusPort)
		output, err := f.ExecIngressPod(curlCmd)
		assert.Nil(ginkgo.GinkgoT(), err)
		assert.Contains(ginkgo.GinkgoT(), output, `{"address":"eu.httpbin.org"`)
	})
})
<commit_msg>Fix e2e externalName test<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package servicebackend

import (
	"context"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/onsi/ginkgo"
	"github.com/stretchr/testify/assert"
	core "k8s.io/api/core/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/util/intstr"

	"k8s.io/ingress-nginx/internal/nginx"
	"k8s.io/ingress-nginx/test/e2e/framework"
)

var _ = framework.IngressNginxDescribe("[Service] Type ExternalName", func() {
	f := framework.NewDefaultFramework("type-externalname")

	ginkgo.It("works with external name set to incomplete fdqn", func() {
		f.NewEchoDeployment()

		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: framework.EchoService,
				Type:         corev1.ServiceTypeExternalName,
			},
		}

		f.EnsureService(svc)

		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK)
	})

	ginkgo.It("should return 200 for service type=ExternalName without a port defined", func() {
		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: "httpbin.org",
				Type:         corev1.ServiceTypeExternalName,
			},
		}

		f.EnsureService(svc)

		annotations := map[string]string{
			"nginx.ingress.kubernetes.io/upstream-vhost": "httpbin.org",
		}
		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, annotations)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK)
	})

	ginkgo.It("should return 200 for service type=ExternalName with a port defined", func() {
		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: "httpbin.org",
				Type:         corev1.ServiceTypeExternalName,
				Ports: []corev1.ServicePort{
					{
						Name:       host,
						Port:       80,
						TargetPort: intstr.FromInt(80),
						Protocol:   "TCP",
					},
				},
			},
		}
		f.EnsureService(svc)

		annotations := map[string]string{
			"nginx.ingress.kubernetes.io/upstream-vhost": "httpbin.org",
		}
		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, annotations)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK)
	})

	ginkgo.It("should return status 502 for service type=ExternalName with an invalid host", func() {
		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: "invalid.hostname",
				Type:         corev1.ServiceTypeExternalName,
			},
		}

		f.EnsureService(svc)

		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, nil)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusBadGateway)
	})

	ginkgo.It("should return 200 for service type=ExternalName using a port name", func() {
		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: "httpbin.org",
				Type:         corev1.ServiceTypeExternalName,
				Ports: []corev1.ServicePort{
					{
						Name:       host,
						Port:       80,
						TargetPort: intstr.FromInt(80),
						Protocol:   "TCP",
					},
				},
			},
		}
		f.EnsureService(svc)

		annotations := map[string]string{
			"nginx.ingress.kubernetes.io/upstream-vhost": "httpbin.org",
		}
		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, annotations)
		ing.Spec.Rules[0].HTTP.Paths[0].Backend.ServicePort = intstr.FromString(host)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK)
	})

	ginkgo.It("should update the external name after a service update", func() {
		host := "echo"

		svc := &core.Service{
			ObjectMeta: metav1.ObjectMeta{
				Name:      framework.HTTPBinService,
				Namespace: f.Namespace,
			},
			Spec: corev1.ServiceSpec{
				ExternalName: "httpbin.org",
				Type:         corev1.ServiceTypeExternalName,
				Ports: []corev1.ServicePort{
					{
						Name:       host,
						Port:       80,
						TargetPort: intstr.FromInt(80),
						Protocol:   "TCP",
					},
				},
			},
		}
		f.EnsureService(svc)

		annotations := map[string]string{
			"nginx.ingress.kubernetes.io/upstream-vhost": "httpbin.org",
		}
		ing := framework.NewSingleIngress(host, "/", host, f.Namespace, framework.HTTPBinService, 80, annotations)
		ing.Spec.Rules[0].HTTP.Paths[0].Backend.ServicePort = intstr.FromString(host)
		f.EnsureIngress(ing)

		f.WaitForNginxServer(host,
			func(server string) bool {
				return strings.Contains(server, "proxy_pass http://upstream_balancer;")
			})

		body := f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK).
			Body().
			Raw()

		assert.Contains(ginkgo.GinkgoT(), body, `"X-Forwarded-Host": "echo"`)

		svc, err := f.KubeClientSet.CoreV1().Services(f.Namespace).Get(context.TODO(), framework.HTTPBinService, metav1.GetOptions{})
		assert.Nil(ginkgo.GinkgoT(), err, "unexpected error obtaining httpbin service")

		svc.Spec.ExternalName = "eu.httpbin.org"

		_, err = f.KubeClientSet.CoreV1().Services(f.Namespace).Update(context.Background(), svc, metav1.UpdateOptions{})
		assert.Nil(ginkgo.GinkgoT(), err, "unexpected error updating httpbin service")

		time.Sleep(5 * time.Second)

		body = f.HTTPTestClient().
			GET("/get").
			WithHeader("Host", host).
			Expect().
			Status(http.StatusOK).
			Body().
			Raw()

		assert.Contains(ginkgo.GinkgoT(), body, `"X-Forwarded-Host": "echo"`)

		ginkgo.By("checking the service is updated to use eu.httpbin.org")
		curlCmd := fmt.Sprintf("curl --fail --silent http://localhost:%v/configuration/backends", nginx.StatusPort)
		output, err := f.ExecIngressPod(curlCmd)
		assert.Nil(ginkgo.GinkgoT(), err)
		assert.Contains(ginkgo.GinkgoT(), output, `{"address":"eu.httpbin.org"`)
	})
})
<|endoftext|>


<commit_before>package docs

import (
	"fmt"
	"pygmentize"
	"strings"
	"time"

	"github.com/blang/semver"
	"github.com/vito/booklit"
)

var flyBinariesVersion = semver.MustParse("2.2.0")

func init() {
	booklit.RegisterPlugin("concourse-docs", booklit.PluginFactoryFunc(NewPlugin))
}

type Plugin struct {
	section *booklit.Section
}

func NewPlugin(section *booklit.Section) booklit.Plugin {
	return Plugin{
		section: section,
	}
}

func (p Plugin) FontAwesome(class string) booklit.Content {
	return booklit.Element{
		Class:   "fa " + class,
		Content: booklit.Empty,
	}
}

func (p Plugin) Codeblock(language string, code booklit.Content) (booklit.Content, error) {
	code, err := pygmentize.Block(language, code.String())
	if err != nil {
		return nil, err
	}

	return booklit.Block{
		Class:   "code",
		Content: code,
	}, nil
}

func (p Plugin) TitledCodeblock(title booklit.Content, language string, code booklit.Content) (booklit.Content, error) {
	codeblock, err := p.Codeblock(language, code)
	if err != nil {
		return nil, err
	}

	return booklit.Block{
		Class: "titled-codeblock",
		Content: booklit.Sequence{
			booklit.Block{
				Class: "codeblock-title",
				Content: booklit.Styled{
					Style:   booklit.StyleVerbatim,
					Content: title,
				},
			},
			codeblock,
		},
	}, nil
}

func (p Plugin) Warn(content booklit.Content) booklit.Content {
	return booklit.Block{
		Class:   "warning",
		Content: content,
	}
}

func (p Plugin) DefineAttribute(attribute string, content booklit.Content, tags ...string) (booklit.Content, error) {
	attrSplit := strings.SplitN(attribute, ":", 2)

	attrName := attrSplit[0]
	if len(tags) == 0 {
		tags = []string{attrName}
	}

	display := booklit.Styled{
		Style: booklit.StyleVerbatim,
		Content: booklit.Styled{
			Style:   booklit.StyleBold,
			Content: booklit.String(attrName),
		},
	}

	targets := booklit.Sequence{}
	for _, t := range tags {
		targets = append(targets, booklit.Target{
			TagName: t,
			Display: display,
		})
	}

	return booklit.Block{
		Class: "definition",
		Content: booklit.Sequence{
			booklit.Block{
				Class: "thumb",
				Content: booklit.Sequence{
					targets,
					booklit.Styled{
						Style: booklit.StyleVerbatim,
						Content: booklit.Preformatted{
							booklit.Sequence{
								&booklit.Reference{
									TagName: tags[0],
									Content: booklit.Styled{
										Style:   booklit.StyleBold,
										Content: booklit.String(attrName),
									},
								},
								booklit.String(":" + attrSplit[1]),
							},
						},
					},
				},
			},
			content,
		},
	}, nil
}

func (p Plugin) DefineMetric(metric string, content booklit.Content) booklit.Content {
	return booklit.Block{
		Class: "definition",
		Content: booklit.Sequence{
			booklit.Block{
				Class: "thumb",
				Content: booklit.Sequence{
					booklit.Target{
						TagName: metric,
						Display: booklit.String(metric),
					},
					booklit.Styled{
						Style: booklit.StyleVerbatim,
						Content: booklit.Block{
							Content: booklit.String(metric),
						},
					},
				},
			},
			content,
		},
	}
}

func (p Plugin) Boshprop(job string, target string) booklit.Content {
	return booklit.Link{
		Target: fmt.Sprintf("http://bosh.io/jobs/%s?source=github.com/concourse/concourse#p=%s", job, target),
		Content: booklit.Styled{
			Style:   booklit.StyleVerbatim,
			Content: booklit.String(target),
		},
	}
}

func (p Plugin) Ghuser(user string) booklit.Content {
	return booklit.Link{
		Target: fmt.Sprintf("http://github.com/%s", user),
		Content: booklit.Styled{
			Style:   booklit.StyleBold,
			Content: booklit.String(user),
		},
	}
}

func (p Plugin) Ghissue(number string, optionalRepo ...string) booklit.Content {
	repo := "concourse"
	if len(optionalRepo) > 0 {
		repo = optionalRepo[0]
	}

	return booklit.Link{
		Target: fmt.Sprintf("http://github.com/concourse/%s/issues/%s", repo, number),
		Content: booklit.Styled{
			Style:   booklit.StyleBold,
			Content: booklit.String("#" + number),
		},
	}
}

func (p Plugin) Resource(resource string, optionalName ...string) booklit.Content {
	name := ""
	if len(optionalName) > 0 {
		name = optionalName[0]
	} else {
		for _, word := range strings.Split(resource, "-") {
			if name != "" {
				name += " "
			}

			name += strings.Title(word)
		}
	}

	return booklit.Link{
		Target:  fmt.Sprintf("http://github.com/concourse/%s-resource", resource),
		Content: booklit.String(fmt.Sprintf("%s resource", name)),
	}
}

func (p Plugin) TutorialImage(path string) booklit.Content {
	return booklit.Block{
		Class: "tutorial-image",
		Content: booklit.Image{
			Path:        path,
			Description: "tutorial image",
		},
	}
}

func (p Plugin) LiterateSegment(parasAndFinalCode ...booklit.Content) (booklit.Content, error) {
	if len(parasAndFinalCode) == 0 {
		return nil, fmt.Errorf("no paragraphs or code given")
	}

	paras := parasAndFinalCode[0 : len(parasAndFinalCode)-1]
	code := parasAndFinalCode[len(parasAndFinalCode)-1]

	if len(paras) == 0 {
		paras = []booklit.Content{code}
		code = booklit.Empty
	}

	return booklit.Block{
		Class: "literate-segment",
		Content: booklit.Block{
			Class: "literate-entry",
			Content: booklit.Sequence{
				booklit.Block{
					Class:   "prose",
					Content: booklit.Sequence(paras),
				},
				code,
			},
		},
	}, nil
}

func (p Plugin) PipelineImage(path string) booklit.Content {
	return booklit.Styled{
		Style: "pipeline-image",
		Content: booklit.Image{
			Path:        path,
			Description: "pipeline",
		},
	}
}

func (p Plugin) ReleaseWithGardenLinux(date string, concourseVersion string, gardenLinuxVersion string, content booklit.Content) (booklit.Content, error) {
	p.section.SetPartial("GardenReleaseFilename", booklit.String("garden-linux"))
	p.section.SetPartial("GardenReleaseName", booklit.String("Garden Linux"))
	return p.release(date, concourseVersion, gardenLinuxVersion, content)
}

func (p Plugin) Release(date string, concourseVersion string, gardenRunCVersion string, content booklit.Content) (booklit.Content, error) {
	p.section.SetPartial("GardenReleaseFilename", booklit.String("garden-runc"))
	p.section.SetPartial("GardenReleaseName", booklit.String("Garden runC"))
	return p.release(date, concourseVersion, gardenRunCVersion, content)
}

func (p Plugin) release(
	date string,
	concourseVersion string,
	gardenVersion string,
	content booklit.Content,
) (booklit.Content, error) {
	t, err := time.Parse("2006-1-2", date)
	if err != nil {
		return nil, err
	}

	p.section.SetTitle(booklit.String("v" + concourseVersion))

	p.section.SetPartial("Version", booklit.String(concourseVersion))
	p.section.SetPartial("VersionLabel", booklit.Element{
		Class:   "version-number",
		Content: booklit.String("v" + concourseVersion),
	})

	p.section.SetPartial("GardenVersion", booklit.String(gardenVersion))
	p.section.SetPartial("GardenVersionLabel", booklit.Element{
		Class:   "version-number",
		Content: booklit.String("v" + gardenVersion),
	})

	p.section.SetPartial("ReleaseDate", booklit.Element{
		Class:   "release-date",
		Content: booklit.String(t.Format("January 1, 2006")),
	})

	cv, err := semver.Parse(concourseVersion)
	if err != nil {
		return nil, err
	}

	if cv.GTE(flyBinariesVersion) {
		p.section.SetPartial("HasFlyBinaries", booklit.Empty)
	}

	return content, nil
}

func (p Plugin) Note(commaSeparatedTags string, content booklit.Content) booklit.Content {
	tags := strings.Split(commaSeparatedTags, ",")

	tagNotes := []booklit.Content{}
	for _, t := range tags {
		tagNotes = append(tagNotes, booklit.Block{
			Class:   "note-tag " + t,
			Content: booklit.String(t),
		})
	}

	return booklit.Block{
		Class: "release-note",
		Content: booklit.Sequence{
			booklit.Block{
				Class: "tags",
				Content: booklit.List{
					Items: tagNotes,
				},
			},
			content,
		},
	}
}
<commit_msg>fix booklit date formatting<commit_after>package docs

import (
	"fmt"
	"pygmentize"
	"strings"
	"time"

	"github.com/blang/semver"
	"github.com/vito/booklit"
)

var flyBinariesVersion = semver.MustParse("2.2.0")

func init() {
	booklit.RegisterPlugin("concourse-docs", booklit.PluginFactoryFunc(NewPlugin))
}

type Plugin struct {
	section *booklit.Section
}

func NewPlugin(section *booklit.Section) booklit.Plugin {
	return Plugin{
		section: section,
	}
}

func (p Plugin) FontAwesome(class string) booklit.Content {
	return booklit.Element{
		Class:   "fa " + class,
		Content: booklit.Empty,
	}
}

func (p Plugin) Codeblock(language string, code booklit.Content) (booklit.Content, error) {
	code, err := pygmentize.Block(language, code.String())
	if err != nil {
		return nil, err
	}

	return booklit.Block{
		Class:   "code",
		Content: code,
	}, nil
}

func (p Plugin) TitledCodeblock(title booklit.Content, language string, code booklit.Content) (booklit.Content, error) {
	codeblock, err := p.Codeblock(language, code)
	if err != nil {
		return nil, err
	}

	return booklit.Block{
		Class: "titled-codeblock",
		Content: booklit.Sequence{
			booklit.Block{
				Class: "codeblock-title",
				Content: booklit.Styled{
					Style:   booklit.StyleVerbatim,
					Content: title,
				},
			},
			codeblock,
		},
	}, nil
}

func (p Plugin) Warn(content booklit.Content) booklit.Content {
	return booklit.Block{
		Class:   "warning",
		Content: content,
	}
}

func (p Plugin) DefineAttribute(attribute string, content booklit.Content, tags ...string) (booklit.Content, error) {
	attrSplit := strings.SplitN(attribute, ":", 2)

	attrName := attrSplit[0]
	if len(tags) == 0 {
		tags = []string{attrName}
	}

	display := booklit.Styled{
		Style: booklit.StyleVerbatim,
		Content: booklit.Styled{
			Style:   booklit.StyleBold,
			Content: booklit.String(attrName),
		},
	}

	targets := booklit.Sequence{}
	for _, t := range tags {
		targets = append(targets, booklit.Target{
			TagName: t,
			Display: display,
		})
	}

	return booklit.Block{
		Class: "definition",
		Content: booklit.Sequence{
			booklit.Block{
				Class: "thumb",
				Content: booklit.Sequence{
					targets,
					booklit.Styled{
						Style: booklit.StyleVerbatim,
						Content: booklit.Preformatted{
							booklit.Sequence{
								&booklit.Reference{
									TagName: tags[0],
									Content: booklit.Styled{
										Style:   booklit.StyleBold,
										Content: booklit.String(attrName),
									},
								},
								booklit.String(":" + attrSplit[1]),
							},
						},
					},
				},
			},
			content,
		},
	}, nil
}

func (p Plugin) DefineMetric(metric string, content booklit.Content) booklit.Content {
	return booklit.Block{
		Class: "definition",
		Content: booklit.Sequence{
			booklit.Block{
				Class: "thumb",
				Content: booklit.Sequence{
					booklit.Target{
						TagName: metric,
						Display: booklit.String(metric),
					},
					booklit.Styled{
						Style: booklit.StyleVerbatim,
						Content: booklit.Block{
							Content: booklit.String(metric),
						},
					},
				},
			},
			content,
		},
	}
}

func (p Plugin) Boshprop(job string, target string) booklit.Content {
	return booklit.Link{
		Target: fmt.Sprintf("http://bosh.io/jobs/%s?source=github.com/concourse/concourse#p=%s", job, target),
		Content: booklit.Styled{
			Style:   booklit.StyleVerbatim,
			Content: booklit.String(target),
		},
	}
}

func (p Plugin) Ghuser(user string) booklit.Content {
	return booklit.Link{
		Target: fmt.Sprintf("http://github.com/%s", user),
		Content: booklit.Styled{
			Style:   booklit.StyleBold,
			Content: booklit.String(user),
		},
	}
}

func (p Plugin) Ghissue(number string, optionalRepo ...string) booklit.Content {
	repo := "concourse"
	if len(optionalRepo) > 0 {
		repo = optionalRepo[0]
	}

	return booklit.Link{
		Target: fmt.Sprintf("http://github.com/concourse/%s/issues/%s", repo, number),
		Content: booklit.Styled{
			Style:   booklit.StyleBold,
			Content: booklit.String("#" + number),
		},
	}
}

func (p Plugin) Resource(resource string, optionalName ...string) booklit.Content {
	name := ""
	if len(optionalName) > 0 {
		name = optionalName[0]
	} else {
		for _, word := range strings.Split(resource, "-") {
			if name != "" {
				name += " "
			}

			name += strings.Title(word)
		}
	}

	return booklit.Link{
		Target:  fmt.Sprintf("http://github.com/concourse/%s-resource", resource),
		Content: booklit.String(fmt.Sprintf("%s resource", name)),
	}
}

func (p Plugin) TutorialImage(path string) booklit.Content {
	return booklit.Block{
		Class: "tutorial-image",
		Content: booklit.Image{
			Path:        path,
			Description: "tutorial image",
		},
	}
}

func (p Plugin) LiterateSegment(parasAndFinalCode ...booklit.Content) (booklit.Content, error) {
	if len(parasAndFinalCode) == 0 {
		return nil, fmt.Errorf("no paragraphs or code given")
	}

	paras := parasAndFinalCode[0 : len(parasAndFinalCode)-1]
	code := parasAndFinalCode[len(parasAndFinalCode)-1]

	if len(paras) == 0 {
		paras = []booklit.Content{code}
		code = booklit.Empty
	}

	return booklit.Block{
		Class: "literate-segment",
		Content: booklit.Block{
			Class: "literate-entry",
			Content: booklit.Sequence{
				booklit.Block{
					Class:   "prose",
					Content: booklit.Sequence(paras),
				},
				code,
			},
		},
	}, nil
}

func (p Plugin) PipelineImage(path string) booklit.Content {
	return booklit.Styled{
		Style: "pipeline-image",
		Content: booklit.Image{
			Path:        path,
			Description: "pipeline",
		},
	}
}

func (p Plugin) ReleaseWithGardenLinux(date string, concourseVersion string, gardenLinuxVersion string, content booklit.Content) (booklit.Content, error) {
	p.section.SetPartial("GardenReleaseFilename", booklit.String("garden-linux"))
	p.section.SetPartial("GardenReleaseName", booklit.String("Garden Linux"))
	return p.release(date, concourseVersion, gardenLinuxVersion, content)
}

func (p Plugin) Release(date string, concourseVersion string, gardenRunCVersion string, content booklit.Content) (booklit.Content, error) {
	p.section.SetPartial("GardenReleaseFilename", booklit.String("garden-runc"))
	p.section.SetPartial("GardenReleaseName", booklit.String("Garden runC"))
	return p.release(date, concourseVersion, gardenRunCVersion, content)
}

func (p Plugin) release(
	date string,
	concourseVersion string,
	gardenVersion string,
	content booklit.Content,
) (booklit.Content, error) {
	t, err := time.Parse("2006-Jan-02", date)
	if err != nil {
		return nil, err
	}

	p.section.SetTitle(booklit.String("v" + concourseVersion))

	p.section.SetPartial("Version", booklit.String(concourseVersion))
	p.section.SetPartial("VersionLabel", booklit.Element{
		Class:   "version-number",
		Content: booklit.String("v" + concourseVersion),
	})

	p.section.SetPartial("GardenVersion", booklit.String(gardenVersion))
	p.section.SetPartial("GardenVersionLabel", booklit.Element{
		Class:   "version-number",
		Content: booklit.String("v" + gardenVersion),
	})

	p.section.SetPartial("ReleaseDate", booklit.Element{
		Class:   "release-date",
		Content: booklit.String(t.Format("January 2, 2006")),
	})

	cv, err := semver.Parse(concourseVersion)
	if err != nil {
		return nil, err
	}

	if cv.GTE(flyBinariesVersion) {
		p.section.SetPartial("HasFlyBinaries", booklit.Empty)
	}

	return content, nil
}

func (p Plugin) Note(commaSeparatedTags string, content booklit.Content) booklit.Content {
	tags := strings.Split(commaSeparatedTags, ",")

	tagNotes := []booklit.Content{}
	for _, t := range tags {
		tagNotes = append(tagNotes, booklit.Block{
			Class:   "note-tag " + t,
			Content: booklit.String(t),
		})
	}

	return booklit.Block{
		Class: "release-note",
		Content: booklit.Sequence{
			booklit.Block{
				Class: "tags",
				Content: booklit.List{
					Items: tagNotes,
				},
			},
			content,
		},
	}
}
<|endoftext|>


<commit_before>package chance

import (
	"math/rand"
	"time"
)

type Chance struct {
	seed int64
	r    *rand.Rand
}

func New() *Chance {
	seed := time.Now().UTC().UnixNano()
	return &Chance{
		seed,
		rand.New(rand.NewSource(seed)),
	}
}

func NewS(seed int64) *Chance {
	return &Chance{
		seed,
		rand.New(rand.NewSource(seed)),
	}
}
<commit_msg>Chance struct documented<commit_after>// Chance is a minimalist generator of random strings, numbers, etc. written in Go. Based on Chance.js
package chance

import (
	"math/rand"
	"time"
)

// Chance struct keeps own seed and random number generator
type Chance struct {
	seed int64
	r    *rand.Rand
}

// New creates new instance of Chance with seed based on current time
func New() *Chance {
	seed := time.Now().UTC().UnixNano()
	return &Chance{
		seed,
		rand.New(rand.NewSource(seed)),
	}
}

// NewS creates new instance of Chance with specified seed
func NewS(seed int64) *Chance {
	return &Chance{
		seed,
		rand.New(rand.NewSource(seed)),
	}
}
<|endoftext|>


<commit_before>// Package core provides convenient access to foundational, central go-libp2p primitives via type aliases.
package core

import (
	"github.com/libp2p/go-libp2p-core/host"
	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/protocol"
	"github.com/multiformats/go-multiaddr"
)

// Multiaddr aliases the Multiaddr type from github.com/multiformats/go-multiaddr.
//
// Refer to the docs on that type for more info.
type Multiaddr = multiaddr.Multiaddr

// PeerID aliases peer.ID.
//
// Refer to the docs on that type for more info.
type PeerID = peer.ID

// PeerID aliases protocol.ID.
//
// Refer to the docs on that type for more info.
type ProtocolID = protocol.ID

// PeerAddrInfo aliases peer.AddrInfo.
//
// Refer to the docs on that type for more info.
type PeerAddrInfo = peer.AddrInfo

// Host aliases host.Host.
//
// Refer to the docs on that type for more info.
type Host = host.Host

// Network aliases network.Network.
//
// Refer to the docs on that type for more info.
type Network = network.Network

// Conn aliases network.Conn.
//
// Refer to the docs on that type for more info.
type Conn = network.Conn

// Stream aliases network.Stream.
//
// Refer to the docs on that type for more info.
type Stream = network.Stream
<commit_msg>Fix typo in docs (#163)<commit_after>// Package core provides convenient access to foundational, central go-libp2p primitives via type aliases.
package core

import (
	"github.com/libp2p/go-libp2p-core/host"
	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/protocol"
	"github.com/multiformats/go-multiaddr"
)

// Multiaddr aliases the Multiaddr type from github.com/multiformats/go-multiaddr.
//
// Refer to the docs on that type for more info.
type Multiaddr = multiaddr.Multiaddr

// PeerID aliases peer.ID.
//
// Refer to the docs on that type for more info.
type PeerID = peer.ID

// ProtocolID aliases protocol.ID.
//
// Refer to the docs on that type for more info.
type ProtocolID = protocol.ID

// PeerAddrInfo aliases peer.AddrInfo.
//
// Refer to the docs on that type for more info.
type PeerAddrInfo = peer.AddrInfo

// Host aliases host.Host.
//
// Refer to the docs on that type for more info.
type Host = host.Host

// Network aliases network.Network.
//
// Refer to the docs on that type for more info.
type Network = network.Network

// Conn aliases network.Conn.
//
// Refer to the docs on that type for more info.
type Conn = network.Conn

// Stream aliases network.Stream.
//
// Refer to the docs on that type for more info.
type Stream = network.Stream
<|endoftext|>


<commit_before>package core

// WorkQueue Block policy implementation
// Copyright (c) 2017 - Valentin Kuznetsov <vkuznet@gmail.com>

import (
	log "github.com/sirupsen/logrus"
	"github.com/vkuznet/WorkQueue/services"
	"github.com/vkuznet/WorkQueue/utils"
	"github.com/zemirco/couchdb"
)

// BlockPolicy defines block policy
type BlockPolicy struct {
	Name   string
	Record utils.Record
}

// Split method satisfy Policy interface
func (b *BlockPolicy) Split() []couchdb.CouchDoc {
	var out []couchdb.CouchDoc
	var inputBlocks, parentData, pileupData map[string][]string
	var numberOfLumis, numberOfFiles, numberOfEvents, jobs, blowupFactor, priority, filesProcessed int
	var parentFlag, openForNewData, noInputUpdate, noPileupUpdate bool
	var mask map[string]int
	var acdc, task, requestName, taskName, dbs, wmSpec, parentQueueUrl, childQueueUrl, wmbsUrl string
	var siteWhiteList, siteBlackList []string
	var percentSuccess, percentComplete float32
	for rname, spec := range b.Record { // reqMgr2 record is {request_name: request_spec}
		switch rec := spec.(type) {
		case map[string]interface{}:
			requestName, _ = rec["RequestName"].(string)
			if rname != requestName {
				log.Warn("ReqMgr2 rname=%s != RequestName=%s", rname, requestName)
			}
			taskName = requestName
			dbs, _ = rec["DbsUrl"].(string)
			siteWhiteList, _ = rec["siteWhitelist"].([]string)
			siteBlackList, _ = rec["whiteBlacklist"].([]string)
			priority, _ = rec["RequestPriority"].(int)
			inputDataset, _ := rec["InputDataset"].(string)
			blocks := services.Blocks(inputDataset)
			maskedBlocks := services.MaskedBlocks(blocks)
			var mblocks []string
			for _, mb := range maskedBlocks {
				numberOfLumis += mb.NumberOfLumis()
				numberOfFiles += mb.NumberOfFiles()
				numberOfEvents += mb.NumberOfEvents()
				mblocks = append(mblocks, mb.Block)
			}
			inputBlocks = services.Blocks2Sites(mblocks)
			parentData = services.Blocks2Sites(services.ParentBlocks(mblocks))

			wqe := &WorkQueueElement{
				Inputs:          inputBlocks,
				ParentFlag:      parentFlag,
				ParentData:      parentData,
				PileupData:      pileupData,
				NumberOfLumis:   numberOfLumis,
				NumberOfFiles:   numberOfFiles,
				NumberOfEvents:  numberOfEvents,
				Jobs:            jobs,
				OpenForNewData:  openForNewData,
				NoInputUpdate:   noInputUpdate,
				NoPileupUpdate:  noPileupUpdate,
				WMSpec:          wmSpec,
				Mask:            mask,
				BlowupFactor:    blowupFactor,
				ACDC:            acdc,
				Dbs:             dbs,
				TaskName:        taskName,
				Task:            task,
				RequestName:     requestName,
				SiteWhiteList:   siteWhiteList,
				SiteBlackList:   siteBlackList,
				Priority:        priority,
				ParentQueueUrl:  parentQueueUrl,
				ChildQueueUrl:   childQueueUrl,
				PercentSuccess:  percentSuccess,
				PercentComplete: percentComplete,
				WMBSUrl:         wmbsUrl,
				FilesProcessed:  filesProcessed,
			}
			out = append(out, wqe)
		}
	}
	return out
}

// Split method satisfy Policy interface
func (b *BlockPolicy) Validate() bool {
	return true
}
<commit_msg>Add config to block policy; remove task<commit_after>package core

// WorkQueue Block policy implementation
// Copyright (c) 2017 - Valentin Kuznetsov <vkuznet@gmail.com>

import (
	log "github.com/sirupsen/logrus"
	"github.com/vkuznet/WorkQueue/services"
	"github.com/vkuznet/WorkQueue/utils"
	"github.com/zemirco/couchdb"
)

// BlockPolicy defines block policy
type BlockPolicy struct {
	Name   string
	Record utils.Record
	Config utils.Record
}

// Split method satisfy Policy interface
func (b *BlockPolicy) Split() []couchdb.CouchDoc {
	var out []couchdb.CouchDoc
	var inputBlocks, parentData, pileupData map[string][]string
	var numberOfLumis, numberOfFiles, numberOfEvents, jobs, blowupFactor, priority, filesProcessed int
	var parentFlag, openForNewData, noInputUpdate, noPileupUpdate bool
	var mask map[string]int
	var acdc, requestName, taskName, dbs, wmSpec, parentQueueUrl, childQueueUrl, wmbsUrl string
	var siteWhiteList, siteBlackList []string
	var percentSuccess, percentComplete float32
	for rname, spec := range b.Record { // reqMgr2 record is {request_name: request_spec}
		switch rec := spec.(type) {
		case map[string]interface{}:
			requestName, _ = rec["RequestName"].(string)
			if rname != requestName {
				log.Warn("ReqMgr2 rname=%s != RequestName=%s", rname, requestName)
			}
			taskName = requestName
			dbs, _ = rec["DbsUrl"].(string)
			siteWhiteList, _ = rec["siteWhitelist"].([]string)
			siteBlackList, _ = rec["whiteBlacklist"].([]string)
			priority, _ = rec["RequestPriority"].(int)
			wmSpec, _ = rec["RequestWorkflow"].(string)
			inputDataset, _ := rec["InputDataset"].(string)
			blocks := services.Blocks(inputDataset)
			maskedBlocks := services.MaskedBlocks(blocks)
			var mblocks []string
			for _, mb := range maskedBlocks {
				numberOfLumis += mb.NumberOfLumis()
				numberOfFiles += mb.NumberOfFiles()
				numberOfEvents += mb.NumberOfEvents()
				mblocks = append(mblocks, mb.Block)
			}
			inputBlocks = services.Blocks2Sites(mblocks)
			parentData = services.Blocks2Sites(services.ParentBlocks(mblocks))

			wqe := &WorkQueueElement{
				Inputs:          inputBlocks,
				ParentFlag:      parentFlag,
				ParentData:      parentData,
				PileupData:      pileupData,
				NumberOfLumis:   numberOfLumis,
				NumberOfFiles:   numberOfFiles,
				NumberOfEvents:  numberOfEvents,
				Jobs:            jobs,
				OpenForNewData:  openForNewData,
				NoInputUpdate:   noInputUpdate,
				NoPileupUpdate:  noPileupUpdate,
				WMSpec:          wmSpec,
				Mask:            mask,
				BlowupFactor:    blowupFactor,
				ACDC:            acdc,
				Dbs:             dbs,
				TaskName:        taskName,
				RequestName:     requestName,
				SiteWhiteList:   siteWhiteList,
				SiteBlackList:   siteBlackList,
				Priority:        priority,
				ParentQueueUrl:  parentQueueUrl,
				ChildQueueUrl:   childQueueUrl,
				PercentSuccess:  percentSuccess,
				PercentComplete: percentComplete,
				WMBSUrl:         wmbsUrl,
				FilesProcessed:  filesProcessed,
			}
			out = append(out, wqe)
		}
	}
	return out
}

// Split method satisfy Policy interface
func (b *BlockPolicy) Validate() bool {
	return true
}
<|endoftext|>


<commit_before>package afero

import (
	"os"
	"path/filepath"
	"runtime"
	"testing"
	"fmt"
)

func TestBasePath(t *testing.T) {
	baseFs := &MemMapFs{}
	baseFs.MkdirAll("/base/path/tmp", 0777)
	bp := NewBasePathFs(baseFs, "/base/path")

	if _, err := bp.Create("/tmp/foo"); err != nil {
		t.Errorf("Failed to set real path")
	}

	if fh, err := bp.Create("../tmp/bar"); err == nil {
		t.Errorf("succeeded in creating %s ...", fh.Name())
	}
}

func TestBasePathRoot(t *testing.T) {
	baseFs := &MemMapFs{}
	baseFs.MkdirAll("/base/path/foo/baz", 0777)
	baseFs.MkdirAll("/base/path/boo/", 0777)
	bp := NewBasePathFs(baseFs, "/base/path")

	rd, err := ReadDir(bp, string(os.PathSeparator))

	if len(rd) != 2 {
		t.Errorf("base path doesn't respect root")
	}

	if err != nil {
		t.Error(err)
	}
}

func TestRealPath(t *testing.T) {
	fs := NewOsFs()
	baseDir, err := TempDir(fs, "", "base")
	if err != nil {
		t.Fatal("error creating tempDir", err)
	}
	defer fs.RemoveAll(baseDir)
	anotherDir, err := TempDir(fs, "", "another")
	if err != nil {
		t.Fatal("error creating tempDir", err)
	}
	defer fs.RemoveAll(anotherDir)

	bp := NewBasePathFs(fs, baseDir).(*BasePathFs)

	subDir := filepath.Join(baseDir, "s1")

	realPath, err := bp.RealPath("/s1")

	if err != nil {
		t.Errorf("Got error %s", err)
	}

	if realPath != subDir {
		t.Errorf("Expected \n%s got \n%s", subDir, realPath)
	}

	if runtime.GOOS == "windows" {
		_, err = bp.RealPath(anotherDir)

		if err == nil {
			t.Errorf("Expected error")
		}

	} else {
		// on *nix we have no way of just looking at the path and tell that anotherDir
		// is not inside the base file system.
		// The user will receive an os.ErrNotExist later.
		surrealPath, err := bp.RealPath(anotherDir)

		if err != nil {
			t.Errorf("Got error %s", err)
		}

		excpected := filepath.Join(baseDir, anotherDir)

		if surrealPath != excpected {
			t.Errorf("Expected \n%s got \n%s", excpected, surrealPath)
		}
	}

}

func TestNestedBasePaths(t *testing.T) {
	type dirSpec struct {
		Dir1, Dir2, Dir3 string
	}
	dirSpecs := []dirSpec{
		dirSpec{Dir1: "/", Dir2: "/", Dir3: "/"},
		dirSpec{Dir1: "/", Dir2: "/path2", Dir3: "/"},
		dirSpec{Dir1: "/path1/dir", Dir2: "/path2/dir/", Dir3: "/path3/dir"},
		dirSpec{Dir1: "C:/path1", Dir2: "path2/dir", Dir3: "/path3/dir/"},
	}

	for _, ds := range dirSpecs {
		memFs := NewMemMapFs()
		level1Fs := NewBasePathFs(memFs, ds.Dir1)
		level2Fs := NewBasePathFs(level1Fs, ds.Dir2)
		level3Fs := NewBasePathFs(level2Fs, ds.Dir3)

		type spec struct {
			BaseFs   Fs
			FileName string
		}
		specs := []spec{
			spec{BaseFs: level3Fs, FileName: "f.txt"},
			spec{BaseFs: level2Fs, FileName: "f.txt"},
			spec{BaseFs: level1Fs, FileName: "f.txt"},
		}

		for _, s := range specs {
			if err := s.BaseFs.MkdirAll(s.FileName, 0755); err != nil {
				t.Errorf("Got error %s", err.Error())
			}
			if _, err := s.BaseFs.Stat(s.FileName); err != nil {
				t.Errorf("Got error %s", err.Error())
			}

			if s.BaseFs == level3Fs {
				pathToExist := filepath.Join(ds.Dir3, s.FileName)
				if _, err := level2Fs.Stat(pathToExist); err != nil {
					t.Errorf("Got error %s (path %s)", err.Error(), pathToExist)
				}
			} else if s.BaseFs == level2Fs {
				pathToExist := filepath.Join(ds.Dir2, ds.Dir3, s.FileName)
				if _, err := level1Fs.Stat(pathToExist); err != nil {
					t.Errorf("Got error %s (path %s)", err.Error(), pathToExist)
				}
			}
		}
	}
}

func TestBasePathOpenFile(t *testing.T) {
	baseFs := &MemMapFs{}
	baseFs.MkdirAll("/base/path/tmp", 0777)
	bp := NewBasePathFs(baseFs, "/base/path")
	f, err := bp.OpenFile("/tmp/file.txt", os.O_CREATE, 0600)
	if err != nil {
		t.Fatalf("failed to open file: %v", err)
	}
	if filepath.Dir(f.Name()) != filepath.Clean("/tmp") {
		t.Fatalf("realpath leaked: %s", f.Name())
	}
}

func TestBasePathCreate(t *testing.T) {
	baseFs := &MemMapFs{}
	baseFs.MkdirAll("/base/path/tmp", 0777)
	bp := NewBasePathFs(baseFs, "/base/path")
	f, err := bp.Create("/tmp/file.txt")
	if err != nil {
		t.Fatalf("failed to create file: %v", err)
	}
	if filepath.Dir(f.Name()) != filepath.Clean("/tmp") {
		t.Fatalf("realpath leaked: %s", f.Name())
	}
}

func TestBasePathTempFile(t *testing.T) {
	baseFs := &MemMapFs{}
	baseFs.MkdirAll("/base/path/tmp", 0777)
	bp := NewBasePathFs(baseFs, "/base/path")

	tDir, err := TempDir(bp, "/tmp", "")
	if err != nil {
		t.Fatalf("Failed to TempDir: %v", err)
	}
	fmt.Println(tDir)
	if filepath.Dir(tDir) != filepath.Clean("/tmp") {
		t.Fatalf("Tempdir realpath leaked: %s", tDir)
	}
	tempFile, err := TempFile(bp, tDir, "")
	if err != nil {
		t.Fatalf("Failed to TempFile: %v", err)
	}
	defer tempFile.Close()
	if expected, actual := tDir, filepath.Dir(tempFile.Name()); expected != actual {
		t.Fatalf("TempFile realpath leaked: expected %s, got %s", expected, actual)
	}
}<commit_msg>remove debug output<commit_after>package afero

import (
	"os"
	"path/filepath"
	"runtime"
	"testing"
)

func TestBasePath(t *testing.T) {
	baseFs := &MemMapFs{}
	baseFs.MkdirAll("/base/path/tmp", 0777)
	bp := NewBasePathFs(baseFs, "/base/path")

	if _, err := bp.Create("/tmp/foo"); err != nil {
		t.Errorf("Failed to set real path")
	}

	if fh, err := bp.Create("../tmp/bar"); err == nil {
		t.Errorf("succeeded in creating %s ...", fh.Name())
	}
}

func TestBasePathRoot(t *testing.T) {
	baseFs := &MemMapFs{}
	baseFs.MkdirAll("/base/path/foo/baz", 0777)
	baseFs.MkdirAll("/base/path/boo/", 0777)
	bp := NewBasePathFs(baseFs, "/base/path")

	rd, err := ReadDir(bp, string(os.PathSeparator))

	if len(rd) != 2 {
		t.Errorf("base path doesn't respect root")
	}

	if err != nil {
		t.Error(err)
	}
}

func TestRealPath(t *testing.T) {
	fs := NewOsFs()
	baseDir, err := TempDir(fs, "", "base")
	if err != nil {
		t.Fatal("error creating tempDir", err)
	}
	defer fs.RemoveAll(baseDir)
	anotherDir, err := TempDir(fs, "", "another")
	if err != nil {
		t.Fatal("error creating tempDir", err)
	}
	defer fs.RemoveAll(anotherDir)

	bp := NewBasePathFs(fs, baseDir).(*BasePathFs)

	subDir := filepath.Join(baseDir, "s1")

	realPath, err := bp.RealPath("/s1")

	if err != nil {
		t.Errorf("Got error %s", err)
	}

	if realPath != subDir {
		t.Errorf("Expected \n%s got \n%s", subDir, realPath)
	}

	if runtime.GOOS == "windows" {
		_, err = bp.RealPath(anotherDir)

		if err == nil {
			t.Errorf("Expected error")
		}

	} else {
		// on *nix we have no way of just looking at the path and tell that anotherDir
		// is not inside the base file system.
		// The user will receive an os.ErrNotExist later.
		surrealPath, err := bp.RealPath(anotherDir)

		if err != nil {
			t.Errorf("Got error %s", err)
		}

		excpected := filepath.Join(baseDir, anotherDir)

		if surrealPath != excpected {
			t.Errorf("Expected \n%s got \n%s", excpected, surrealPath)
		}
	}

}

func TestNestedBasePaths(t *testing.T) {
	type dirSpec struct {
		Dir1, Dir2, Dir3 string
	}
	dirSpecs := []dirSpec{
		dirSpec{Dir1: "/", Dir2: "/", Dir3: "/"},
		dirSpec{Dir1: "/", Dir2: "/path2", Dir3: "/"},
		dirSpec{Dir1: "/path1/dir", Dir2: "/path2/dir/", Dir3: "/path3/dir"},
		dirSpec{Dir1: "C:/path1", Dir2: "path2/dir", Dir3: "/path3/dir/"},
	}

	for _, ds := range dirSpecs {
		memFs := NewMemMapFs()
		level1Fs := NewBasePathFs(memFs, ds.Dir1)
		level2Fs := NewBasePathFs(level1Fs, ds.Dir2)
		level3Fs := NewBasePathFs(level2Fs, ds.Dir3)

		type spec struct {
			BaseFs   Fs
			FileName string
		}
		specs := []spec{
			spec{BaseFs: level3Fs, FileName: "f.txt"},
			spec{BaseFs: level2Fs, FileName: "f.txt"},
			spec{BaseFs: level1Fs, FileName: "f.txt"},
		}

		for _, s := range specs {
			if err := s.BaseFs.MkdirAll(s.FileName, 0755); err != nil {
				t.Errorf("Got error %s", err.Error())
			}
			if _, err := s.BaseFs.Stat(s.FileName); err != nil {
				t.Errorf("Got error %s", err.Error())
			}

			if s.BaseFs == level3Fs {
				pathToExist := filepath.Join(ds.Dir3, s.FileName)
				if _, err := level2Fs.Stat(pathToExist); err != nil {
					t.Errorf("Got error %s (path %s)", err.Error(), pathToExist)
				}
			} else if s.BaseFs == level2Fs {
				pathToExist := filepath.Join(ds.Dir2, ds.Dir3, s.FileName)
				if _, err := level1Fs.Stat(pathToExist); err != nil {
					t.Errorf("Got error %s (path %s)", err.Error(), pathToExist)
				}
			}
		}
	}
}

func TestBasePathOpenFile(t *testing.T) {
	baseFs := &MemMapFs{}
	baseFs.MkdirAll("/base/path/tmp", 0777)
	bp := NewBasePathFs(baseFs, "/base/path")
	f, err := bp.OpenFile("/tmp/file.txt", os.O_CREATE, 0600)
	if err != nil {
		t.Fatalf("failed to open file: %v", err)
	}
	if filepath.Dir(f.Name()) != filepath.Clean("/tmp") {
		t.Fatalf("realpath leaked: %s", f.Name())
	}
}

func TestBasePathCreate(t *testing.T) {
	baseFs := &MemMapFs{}
	baseFs.MkdirAll("/base/path/tmp", 0777)
	bp := NewBasePathFs(baseFs, "/base/path")
	f, err := bp.Create("/tmp/file.txt")
	if err != nil {
		t.Fatalf("failed to create file: %v", err)
	}
	if filepath.Dir(f.Name()) != filepath.Clean("/tmp") {
		t.Fatalf("realpath leaked: %s", f.Name())
	}
}

func TestBasePathTempFile(t *testing.T) {
	baseFs := &MemMapFs{}
	baseFs.MkdirAll("/base/path/tmp", 0777)
	bp := NewBasePathFs(baseFs, "/base/path")

	tDir, err := TempDir(bp, "/tmp", "")
	if err != nil {
		t.Fatalf("Failed to TempDir: %v", err)
	}
	if filepath.Dir(tDir) != filepath.Clean("/tmp") {
		t.Fatalf("Tempdir realpath leaked: %s", tDir)
	}
	tempFile, err := TempFile(bp, tDir, "")
	if err != nil {
		t.Fatalf("Failed to TempFile: %v", err)
	}
	defer tempFile.Close()
	if expected, actual := tDir, filepath.Dir(tempFile.Name()); expected != actual {
		t.Fatalf("TempFile realpath leaked: expected %s, got %s", expected, actual)
	}
}
<|endoftext|>


<commit_before>/*

The analysis package defines the interface between a modular static
analysis and an analysis driver program.

Background

A static analysis is a function that inspects a package of Go code and
reports a set of diagnostics (typically mistakes in the code), and
perhaps produces other results as well, such as suggested refactorings
or other facts. An analysis that reports mistakes is informally called a
"checker". For example, the printf checker reports mistakes in
fmt.Printf format strings.

A "modular" analysis is one that inspects one package at a time but can
save information from a lower-level package and use it when inspecting a
higher-level package, analogous to separate compilation in a toolchain.
The printf checker is modular: when it discovers that a function such as
log.Fatalf delegates to fmt.Printf, it records this fact, and checks
calls to that function too, including calls made from another package.

By implementing a common interface, checkers from a variety of sources
can be easily selected, incorporated, and reused in a wide range of
driver programs including command-line tools (such as vet), text editors and
IDEs, build and test systems (such as go build, Bazel, or Buck), test
frameworks, code review tools, code-base indexers (such as SourceGraph),
documentation viewers (such as godoc), batch pipelines for large code
bases, and so on.

Analyzer

The primary type in the API is Analyzer. An Analyzer statically
describes an analysis function: its name, documentation, flags,
relationship to other analyzers, and of course, its logic.

To define an analysis, a user declares a (logically constant) variable
of type Analyzer. Here is a typical example from one of the analyzers in
the go/analysis/passes/ subdirectory:

	package unusedresult

	var Analyzer = &analysis.Analyzer{
		Name: "unusedresult",
		Doc:  "check for unused results of calls to some functions",
		Run:  run,
		...
	}

	func run(pass *analysis.Pass) (interface{}, error) {
		...
	}

An analysis driver is a program such as vet that runs a set of
analyses and prints the diagnostics that they report.
The driver program must import the list of Analyzers it needs.
Typically each Analyzer resides in a separate package.
To add a new Analyzer to an existing driver, add another item to the list:

	import ( "unusedresult"; "nilness"; "printf" )

	var analyses = []*analysis.Analyzer{
		unusedresult.Analyzer,
		nilness.Analyzer,
		printf.Analyzer,
	}

A driver may use the name, flags, and documentation to provide on-line
help that describes the analyses it performs.
The doc comment contains a brief one-line summary,
optionally followed by paragraphs of explanation.
The vet command, shown below, is an example of a driver that runs
multiple analyzers. It is based on the multichecker package
(see the "Standalone commands" section for details).

	$ go build golang.org/x/tools/go/analysis/cmd/vet
	$ ./vet help
	vet is a tool for static analysis of Go programs.

	Usage: vet [-flag] [package]

	Registered analyzers:

	    asmdecl      report mismatches between assembly files and Go declarations
	    assign       check for useless assignments
	    atomic       check for common mistakes using the sync/atomic package
	    ...
	    unusedresult check for unused results of calls to some functions

	$ ./vet help unusedresult
	unusedresult: check for unused results of calls to some functions

	Analyzer flags:

	  -unusedresult.funcs value
	        comma-separated list of functions whose results must be used (default Error,String)
	  -unusedresult.stringmethods value
	        comma-separated list of names of methods of type func() string whose results must be used

	Some functions like fmt.Errorf return a result and have no side effects,
	so it is always a mistake to discard the result. This analyzer reports
	calls to certain functions in which the result of the call is ignored.

	The set of functions may be controlled using flags.

The Analyzer type has more fields besides those shown above:

	type Analyzer struct {
		Name             string
		Doc              string
		Flags            flag.FlagSet
		Run              func(*Pass) (interface{}, error)
		RunDespiteErrors bool
		ResultType       reflect.Type
		Requires         []*Analyzer
		FactTypes        []Fact
	}

The Flags field declares a set of named (global) flag variables that
control analysis behavior. Unlike vet, analysis flags are not declared
directly in the command line FlagSet; it is up to the driver to set the
flag variables. A driver for a single analysis, a, might expose its flag
f directly on the command line as -f, whereas a driver for multiple
analyses might prefix the flag name by the analysis name (-a.f) to avoid
ambiguity. An IDE might expose the flags through a graphical interface,
and a batch pipeline might configure them from a config file.
See the "findcall" analyzer for an example of flags in action.

The RunDespiteErrors flag indicates whether the analysis is equipped to
handle ill-typed code. If not, the driver will skip the analysis if
there were parse or type errors.
The optional ResultType field specifies the type of the result value
computed by this analysis and made available to other analyses.
The Requires field specifies a list of analyses upon which
this one depends and whose results it may access, and it constrains the
order in which a driver may run analyses.
The FactTypes field is discussed in the section on Modularity.
The analysis package provides a Validate function to perform basic
sanity checks on an Analyzer, such as that its Requires graph is
acyclic, its fact and result types are unique, and so on.

Finally, the Run field contains a function to be called by the driver to
execute the analysis on a single package. The driver passes it an
instance of the Pass type.

Pass

A Pass describes a single unit of work: the application of a particular
Analyzer to a particular package of Go code.
The Pass provides information to the Analyzer's Run function about the
package being analyzed, and provides operations to the Run function for
reporting diagnostics and other information back to the driver.

	type Pass struct {
		Fset       *token.FileSet
		Files      []*ast.File
		OtherFiles []string
		Pkg        *types.Package
		TypesInfo  *types.Info
		ResultOf   map[*Analyzer]interface{}
		Report     func(Diagnostic)
		...
	}

The Fset, Files, Pkg, and TypesInfo fields provide the syntax trees,
type information, and source positions for a single package of Go code.

The OtherFiles field provides the names, but not the contents, of non-Go
files such as assembly that are part of this package. See the "asmdecl"
or "buildtags" analyzers for examples of loading non-Go files and reporting
diagnostics against them.

The ResultOf field provides the results computed by the analyzers
required by this one, as expressed in its Analyzer.Requires field. The
driver runs the required analyzers first and makes their results
available in this map. Each Analyzer must return a value of the type
described in its Analyzer.ResultType field.
For example, the "ctrlflow" analyzer returns a *ctrlflow.CFGs, which
provides a control-flow graph for each function in the package (see
golang.org/x/tools/go/cfg); the "inspect" analyzer returns a value that
enables other Analyzers to traverse the syntax trees of the package more
efficiently; and the "buildssa" analyzer constructs an SSA-form
intermediate representation.
Each of these Analyzers extends the capabilities of later Analyzers
without adding a dependency to the core API, so an analysis tool pays
only for the extensions it needs.

The Report function emits a diagnostic, a message associated with a
source position. For most analyses, diagnostics are their primary
result.
For convenience, Pass provides a helper method, Reportf, to report a new
diagnostic by formatting a string.
Diagnostic is defined as:

	type Diagnostic struct {
		Pos      token.Pos
		Category string // optional
		Message  string
	}

The optional Category field is a short identifier that classifies the
kind of message when an analysis produces several kinds of diagnostic.

Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
and buildtag, inspect the raw text of Go source files or even non-Go
files such as assembly. To report a diagnostic against a line of a
raw text file, use the following sequence:

	content, err := ioutil.ReadFile(filename)
	if err != nil { ... }
	tf := fset.AddFile(filename, -1, len(content))
	tf.SetLinesForContent(content)
	...
	pass.Reportf(tf.LineStart(line), "oops")

Modular analysis with Facts

To improve efficiency and scalability, large programs are routinely
built using separate compilation: units of the program are compiled
separately, and recompiled only when one of their dependencies changes;
independent modules may be compiled in parallel. The same technique may
be applied to static analyses, for the same benefits. Such analyses are
described as "modular".

A compiler’s type checker is an example of a modular static analysis.
Many other checkers we would like to apply to Go programs can be
understood as alternative or non-standard type systems. For example,
vet's printf checker infers whether a function has the "printf wrapper"
type, and it applies stricter checks to calls of such functions. In
addition, it records which functions are printf wrappers for use by
later analysis passes to identify other printf wrappers by induction.
A result such as “f is a printf wrapper” that is not interesting by
itself but serves as a stepping stone to an interesting result (such as
a diagnostic) is called a "fact".

The analysis API allows an analysis to define new types of facts, to
associate facts of these types with objects (named entities) declared
within the current package, or with the package as a whole, and to query
for an existing fact of a given type associated with an object or
package.

An Analyzer that uses facts must declare their types:

	var Analyzer = &analysis.Analyzer{
		Name:      "printf",
		FactTypes: []analysis.Fact{new(isWrapper)},
		...
	}

	type isWrapper struct{} // => *types.Func f “is a printf wrapper”

The driver program ensures that facts for a pass’s dependencies are
generated before analyzing the package and is responsible for propagating
facts from one package to another, possibly across address spaces.
Consequently, Facts must be serializable. The API requires that drivers
use the gob encoding, an efficient, robust, self-describing binary
protocol. A fact type may implement the GobEncoder/GobDecoder interfaces
if the default encoding is unsuitable. Facts should be stateless.

The Pass type has functions to import and export facts,
associated either with an object or with a package:

	type Pass struct {
		...
		ExportObjectFact func(types.Object, Fact)
		ImportObjectFact func(types.Object, Fact) bool

		ExportPackageFact func(fact Fact)
		ImportPackageFact func(*types.Package, Fact) bool
	}

An Analyzer may only export facts associated with the current package or
its objects, though it may import facts from any package or object that
is an import dependency of the current package.

Conceptually, ExportObjectFact(obj, fact) inserts fact into a hidden map keyed by
the pair (obj, TypeOf(fact)), and the ImportObjectFact function
retrieves the entry from this map and copies its value into the variable
pointed to by fact. This scheme assumes that the concrete type of fact
is a pointer; this assumption is checked by the Validate function.
See the "printf" analyzer for an example of object facts in action.

Some driver implementations (such as those based on Bazel and Blaze) do
not currently apply analyzers to packages of the standard library.
Therefore, for best results, analyzer authors should not rely on
analysis facts being available for standard packages.
For example, although the printf checker is capable of deducing during
analysis of the log package that log.Printf is a printf wrapper,
this fact is built in to the analyzer so that it correctly checks
calls to log.Printf even when run in a driver that does not apply
it to standard packages. We would like to remove this limitation in future.

Testing an Analyzer

The analysistest subpackage provides utilities for testing an Analyzer.
In a few lines of code, it is possible to run an analyzer on a package
of testdata files and check that it reported all the expected
diagnostics and facts (and no more). Expectations are expressed using
"// want ..." comments in the input code.

Standalone commands

Analyzers are provided in the form of packages that a driver program is
expected to import. The vet command imports a set of several analyzers,
but users may wish to define their own analysis commands that perform
additional checks. To simplify the task of creating an analysis command,
either for a single analyzer or for a whole suite, we provide the
singlechecker and multichecker subpackages.

The singlechecker package provides the main function for a command that
runs one analyzer. By convention, each analyzer such as
go/passes/findcall should be accompanied by a singlechecker-based
command such as go/analysis/passes/findcall/cmd/findcall, defined in its
entirety as:

	package main

	import (
		"golang.org/x/tools/go/analysis/passes/findcall"
		"golang.org/x/tools/go/analysis/singlechecker"
	)

	func main() { singlechecker.Main(findcall.Analyzer) }

A tool that provides multiple analyzers can use multichecker in a
similar way, giving it the list of Analyzers.

*/
package analysis
<commit_msg>go/analysis: remove stale documentation citing vet<commit_after>/*

The analysis package defines the interface between a modular static
analysis and an analysis driver program.

Background

A static analysis is a function that inspects a package of Go code and
reports a set of diagnostics (typically mistakes in the code), and
perhaps produces other results as well, such as suggested refactorings
or other facts. An analysis that reports mistakes is informally called a
"checker". For example, the printf checker reports mistakes in
fmt.Printf format strings.

A "modular" analysis is one that inspects one package at a time but can
save information from a lower-level package and use it when inspecting a
higher-level package, analogous to separate compilation in a toolchain.
The printf checker is modular: when it discovers that a function such as
log.Fatalf delegates to fmt.Printf, it records this fact, and checks
calls to that function too, including calls made from another package.

By implementing a common interface, checkers from a variety of sources
can be easily selected, incorporated, and reused in a wide range of
driver programs including command-line tools (such as vet), text editors and
IDEs, build and test systems (such as go build, Bazel, or Buck), test
frameworks, code review tools, code-base indexers (such as SourceGraph),
documentation viewers (such as godoc), batch pipelines for large code
bases, and so on.

Analyzer

The primary type in the API is Analyzer. An Analyzer statically
describes an analysis function: its name, documentation, flags,
relationship to other analyzers, and of course, its logic.

To define an analysis, a user declares a (logically constant) variable
of type Analyzer. Here is a typical example from one of the analyzers in
the go/analysis/passes/ subdirectory:

	package unusedresult

	var Analyzer = &analysis.Analyzer{
		Name: "unusedresult",
		Doc:  "check for unused results of calls to some functions",
		Run:  run,
		...
	}

	func run(pass *analysis.Pass) (interface{}, error) {
		...
	}

An analysis driver is a program such as vet that runs a set of
analyses and prints the diagnostics that they report.
The driver program must import the list of Analyzers it needs.
Typically each Analyzer resides in a separate package.
To add a new Analyzer to an existing driver, add another item to the list:

	import ( "unusedresult"; "nilness"; "printf" )

	var analyses = []*analysis.Analyzer{
		unusedresult.Analyzer,
		nilness.Analyzer,
		printf.Analyzer,
	}

A driver may use the name, flags, and documentation to provide on-line
help that describes the analyses it performs.
The doc comment contains a brief one-line summary,
optionally followed by paragraphs of explanation.

The Analyzer type has more fields besides those shown above:

	type Analyzer struct {
		Name             string
		Doc              string
		Flags            flag.FlagSet
		Run              func(*Pass) (interface{}, error)
		RunDespiteErrors bool
		ResultType       reflect.Type
		Requires         []*Analyzer
		FactTypes        []Fact
	}

The Flags field declares a set of named (global) flag variables that
control analysis behavior. Unlike vet, analysis flags are not declared
directly in the command line FlagSet; it is up to the driver to set the
flag variables. A driver for a single analysis, a, might expose its flag
f directly on the command line as -f, whereas a driver for multiple
analyses might prefix the flag name by the analysis name (-a.f) to avoid
ambiguity. An IDE might expose the flags through a graphical interface,
and a batch pipeline might configure them from a config file.
See the "findcall" analyzer for an example of flags in action.

The RunDespiteErrors flag indicates whether the analysis is equipped to
handle ill-typed code. If not, the driver will skip the analysis if
there were parse or type errors.
The optional ResultType field specifies the type of the result value
computed by this analysis and made available to other analyses.
The Requires field specifies a list of analyses upon which
this one depends and whose results it may access, and it constrains the
order in which a driver may run analyses.
The FactTypes field is discussed in the section on Modularity.
The analysis package provides a Validate function to perform basic
sanity checks on an Analyzer, such as that its Requires graph is
acyclic, its fact and result types are unique, and so on.

Finally, the Run field contains a function to be called by the driver to
execute the analysis on a single package. The driver passes it an
instance of the Pass type.

Pass

A Pass describes a single unit of work: the application of a particular
Analyzer to a particular package of Go code.
The Pass provides information to the Analyzer's Run function about the
package being analyzed, and provides operations to the Run function for
reporting diagnostics and other information back to the driver.

	type Pass struct {
		Fset       *token.FileSet
		Files      []*ast.File
		OtherFiles []string
		Pkg        *types.Package
		TypesInfo  *types.Info
		ResultOf   map[*Analyzer]interface{}
		Report     func(Diagnostic)
		...
	}

The Fset, Files, Pkg, and TypesInfo fields provide the syntax trees,
type information, and source positions for a single package of Go code.

The OtherFiles field provides the names, but not the contents, of non-Go
files such as assembly that are part of this package. See the "asmdecl"
or "buildtags" analyzers for examples of loading non-Go files and reporting
diagnostics against them.

The ResultOf field provides the results computed by the analyzers
required by this one, as expressed in its Analyzer.Requires field. The
driver runs the required analyzers first and makes their results
available in this map. Each Analyzer must return a value of the type
described in its Analyzer.ResultType field.
For example, the "ctrlflow" analyzer returns a *ctrlflow.CFGs, which
provides a control-flow graph for each function in the package (see
golang.org/x/tools/go/cfg); the "inspect" analyzer returns a value that
enables other Analyzers to traverse the syntax trees of the package more
efficiently; and the "buildssa" analyzer constructs an SSA-form
intermediate representation.
Each of these Analyzers extends the capabilities of later Analyzers
without adding a dependency to the core API, so an analysis tool pays
only for the extensions it needs.

The Report function emits a diagnostic, a message associated with a
source position. For most analyses, diagnostics are their primary
result.
For convenience, Pass provides a helper method, Reportf, to report a new
diagnostic by formatting a string.
Diagnostic is defined as:

	type Diagnostic struct {
		Pos      token.Pos
		Category string // optional
		Message  string
	}

The optional Category field is a short identifier that classifies the
kind of message when an analysis produces several kinds of diagnostic.

Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
and buildtag, inspect the raw text of Go source files or even non-Go
files such as assembly. To report a diagnostic against a line of a
raw text file, use the following sequence:

	content, err := ioutil.ReadFile(filename)
	if err != nil { ... }
	tf := fset.AddFile(filename, -1, len(content))
	tf.SetLinesForContent(content)
	...
	pass.Reportf(tf.LineStart(line), "oops")

Modular analysis with Facts

To improve efficiency and scalability, large programs are routinely
built using separate compilation: units of the program are compiled
separately, and recompiled only when one of their dependencies changes;
independent modules may be compiled in parallel. The same technique may
be applied to static analyses, for the same benefits. Such analyses are
described as "modular".

A compiler’s type checker is an example of a modular static analysis.
Many other checkers we would like to apply to Go programs can be
understood as alternative or non-standard type systems. For example,
vet's printf checker infers whether a function has the "printf wrapper"
type, and it applies stricter checks to calls of such functions. In
addition, it records which functions are printf wrappers for use by
later analysis passes to identify other printf wrappers by induction.
A result such as “f is a printf wrapper” that is not interesting by
itself but serves as a stepping stone to an interesting result (such as
a diagnostic) is called a "fact".

The analysis API allows an analysis to define new types of facts, to
associate facts of these types with objects (named entities) declared
within the current package, or with the package as a whole, and to query
for an existing fact of a given type associated with an object or
package.

An Analyzer that uses facts must declare their types:

	var Analyzer = &analysis.Analyzer{
		Name:      "printf",
		FactTypes: []analysis.Fact{new(isWrapper)},
		...
	}

	type isWrapper struct{} // => *types.Func f “is a printf wrapper”

The driver program ensures that facts for a pass’s dependencies are
generated before analyzing the package and is responsible for propagating
facts from one package to another, possibly across address spaces.
Consequently, Facts must be serializable. The API requires that drivers
use the gob encoding, an efficient, robust, self-describing binary
protocol. A fact type may implement the GobEncoder/GobDecoder interfaces
if the default encoding is unsuitable. Facts should be stateless.

The Pass type has functions to import and export facts,
associated either with an object or with a package:

	type Pass struct {
		...
		ExportObjectFact func(types.Object, Fact)
		ImportObjectFact func(types.Object, Fact) bool

		ExportPackageFact func(fact Fact)
		ImportPackageFact func(*types.Package, Fact) bool
	}

An Analyzer may only export facts associated with the current package or
its objects, though it may import facts from any package or object that
is an import dependency of the current package.

Conceptually, ExportObjectFact(obj, fact) inserts fact into a hidden map keyed by
the pair (obj, TypeOf(fact)), and the ImportObjectFact function
retrieves the entry from this map and copies its value into the variable
pointed to by fact. This scheme assumes that the concrete type of fact
is a pointer; this assumption is checked by the Validate function.
See the "printf" analyzer for an example of object facts in action.

Some driver implementations (such as those based on Bazel and Blaze) do
not currently apply analyzers to packages of the standard library.
Therefore, for best results, analyzer authors should not rely on
analysis facts being available for standard packages.
For example, although the printf checker is capable of deducing during
analysis of the log package that log.Printf is a printf wrapper,
this fact is built in to the analyzer so that it correctly checks
calls to log.Printf even when run in a driver that does not apply
it to standard packages. We would like to remove this limitation in future.

Testing an Analyzer

The analysistest subpackage provides utilities for testing an Analyzer.
In a few lines of code, it is possible to run an analyzer on a package
of testdata files and check that it reported all the expected
diagnostics and facts (and no more). Expectations are expressed using
"// want ..." comments in the input code.

Standalone commands

Analyzers are provided in the form of packages that a driver program is
expected to import. The vet command imports a set of several analyzers,
but users may wish to define their own analysis commands that perform
additional checks. To simplify the task of creating an analysis command,
either for a single analyzer or for a whole suite, we provide the
singlechecker and multichecker subpackages.

The singlechecker package provides the main function for a command that
runs one analyzer. By convention, each analyzer such as
go/passes/findcall should be accompanied by a singlechecker-based
command such as go/analysis/passes/findcall/cmd/findcall, defined in its
entirety as:

	package main

	import (
		"golang.org/x/tools/go/analysis/passes/findcall"
		"golang.org/x/tools/go/analysis/singlechecker"
	)

	func main() { singlechecker.Main(findcall.Analyzer) }

A tool that provides multiple analyzers can use multichecker in a
similar way, giving it the list of Analyzers.

*/
package analysis
<|endoftext|>


<commit_before>package engine

import (
	libkb "github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/protocol/go"
	jsonw "github.com/keybase/go-jsonw"
)

// Prove is an engine used for proving ownership of remote accounts,
// like Twitter, GitHub, etc.
type Prove struct {
	arg        *keybase1.ProveArg
	me         *libkb.User
	st         libkb.ServiceType
	supersede  bool
	proof      *jsonw.Wrapper
	sig        string
	sigID      *libkb.SigId
	postRes    *libkb.PostProofRes
	signingKey libkb.GenericKey

	username           string
	usernameNormalized string
	libkb.Contextified
}

// NewProve makes a new Prove Engine given an RPC-friendly ProveArg.
func NewProve(arg *keybase1.ProveArg, g *libkb.GlobalContext) *Prove {
	return &Prove{
		arg:          arg,
		Contextified: libkb.NewContextified(g),
	}
}

// Name provides the name of this engine for the engine interface contract
func (p *Prove) Name() string {
	return "Prove"
}

// GetPrereqs returns the engine prereqs.
func (p *Prove) GetPrereqs() EnginePrereqs {
	return EnginePrereqs{Session: true}
}

// RequiredUIs returns the required UIs.
func (p *Prove) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{
		libkb.LogUIKind,
		libkb.ProveUIKind,
		libkb.SecretUIKind,
	}
}

// SubConsumers returns the other UI consumers for this engine.
func (p *Prove) SubConsumers() []libkb.UIConsumer {
	return nil
}

func (p *Prove) loadMe() (err error) {
	p.me, err = libkb.LoadMe(libkb.LoadUserArg{AllKeys: false, ForceReload: true})
	return
}

func (p *Prove) checkExists1(ctx *Context) (err error) {
	proofs := p.me.IdTable().GetActiveProofsFor(p.st)
	if len(proofs) != 0 && !p.arg.Force && p.st.LastWriterWins() {
		lst := proofs[len(proofs)-1]
		var redo bool
		redo, err = ctx.ProveUI.PromptOverwrite(keybase1.PromptOverwriteArg{
			Account: lst.ToDisplayString(),
			Typ:     keybase1.PromptOverwriteType_SOCIAL,
		})
		if err != nil {
		} else if !redo {
			err = libkb.NotConfirmedError{}
		} else {
			p.supersede = true
		}
	}
	return
}

func (p *Prove) promptRemoteName(ctx *Context) (err error) {
	p.username = p.arg.Username
	if len(p.username) == 0 {
		var prevErr error
		for len(p.username) == 0 && err == nil {
			var un string
			un, err = ctx.ProveUI.PromptUsername(keybase1.PromptUsernameArg{
				Prompt:    p.st.GetPrompt(),
				PrevError: libkb.ExportErrorAsStatus(prevErr),
			})
			if err == nil {
				prevErr = p.st.CheckUsername(un)
				if prevErr == nil {
					p.username = un
				}
			}
		}
	} else {
		err = p.st.CheckUsername(p.username)
	}
	return
}

func (p *Prove) normalizeRemoteName() (err error) {
	p.usernameNormalized, err = p.st.NormalizeUsername(p.username)
	return
}

func (p *Prove) checkExists2(ctx *Context) (err error) {
	p.G().Log.Debug("+ CheckExists2")
	defer func() { p.G().Log.Debug("- CheckExists2 -> %s", libkb.ErrToOk(err)) }()
	if !p.st.LastWriterWins() {
		var found libkb.RemoteProofChainLink
		for _, proof := range p.me.IdTable().GetActiveProofsFor(p.st) {
			_, name := proof.ToKeyValuePair()
			if libkb.Cicmp(name, p.usernameNormalized) {
				found = proof
				break
			}
		}
		if found != nil {
			var redo bool
			redo, err = ctx.ProveUI.PromptOverwrite(keybase1.PromptOverwriteArg{
				Account: found.ToDisplayString(),
				Typ:     keybase1.PromptOverwriteType_SITE,
			})
			if err != nil {
			} else if !redo {
				err = libkb.NotConfirmedError{}
			} else {
				p.supersede = true
			}
		}
	}
	return
}

func (p *Prove) doPrechecks(ctx *Context) (err error) {
	var w *libkb.Markup
	w, err = p.st.PreProofCheck(p.usernameNormalized)
	if w != nil {
		ctx.ProveUI.OutputPrechecks(keybase1.OutputPrechecksArg{Text: w.Export()})
	}
	return
}

func (p *Prove) doWarnings(ctx *Context) (err error) {
	if mu := p.st.PreProofWarning(p.usernameNormalized); mu != nil {
		var ok bool
		arg := keybase1.PreProofWarningArg{Text: mu.Export()}
		if ok, err = ctx.ProveUI.PreProofWarning(arg); err == nil && !ok {
			err = libkb.NotConfirmedError{}
		}
	}
	return
}

func (p *Prove) generateProof(ctx *Context) (err error) {
	var locked *libkb.SKB
	var which string
	var seckey libkb.GenericKey

	if locked, which, err = p.G().Keyrings.GetSecretKeyLocked(libkb.SecretKeyArg{
		Me:      p.me,
		KeyType: libkb.AnySecretKeyType,
	}); err != nil {
		return
	}
	if p.signingKey, err = locked.GetPubKey(); err != nil {
		return
	}
	if p.proof, err = p.me.ServiceProof(p.signingKey, p.st, p.usernameNormalized); err != nil {
		return
	}
	if seckey, err = locked.PromptAndUnlock("proof signature", which, nil, ctx.SecretUI); err != nil {
		return
	}
	if p.sig, p.sigID, _, err = libkb.SignJson(p.proof, seckey); err != nil {
		return
	}
	return
}

func (p *Prove) postProofToServer() (err error) {
	arg := libkb.PostProofArg{
		Sig:            p.sig,
		ProofType:      p.st.GetProofType(),
		Id:             *p.sigID,
		Supersede:      p.supersede,
		RemoteUsername: p.usernameNormalized,
		RemoteKey:      p.st.GetApiArgKey(),
		SigningKey:     p.signingKey,
	}
	p.postRes, err = libkb.PostProof(arg)
	return
}

func (p *Prove) instructAction(ctx *Context) (err error) {
	mkp := p.st.PostInstructions(p.usernameNormalized)
	var txt string
	if txt, err = p.st.FormatProofText(p.postRes); err != nil {
		return
	}
	err = ctx.ProveUI.OutputInstructions(keybase1.OutputInstructionsArg{
		Instructions: mkp.Export(),
		Proof:        txt,
	})
	return
}

func (p *Prove) promptPostedLoop(ctx *Context) (err error) {
	found := false
	for i := 0; ; i++ {
		var retry bool
		var status int
		var warn *libkb.Markup
		retry, err = ctx.ProveUI.OkToCheck(keybase1.OkToCheckArg{
			Name:    p.st.DisplayName(p.usernameNormalized),
			Attempt: i,
		})
		if !retry || err != nil {
			break
		}
		found, status, err = libkb.CheckPosted(p.postRes.Id)
		if found || err != nil {
			break
		}
		warn, err = p.st.RecheckProofPosting(status, i)
		if warn != nil {
			ctx.ProveUI.DisplayRecheckWarning(keybase1.DisplayRecheckWarningArg{
				Text: warn.Export(),
			})
		}
		if err != nil {
			break
		}
	}
	if !found && err == nil {
		err = libkb.ProofNotYetAvailableError{}
	}

	return
}

func (p *Prove) checkProofText() error {
	return p.st.CheckProofText(p.postRes.Text, *p.sigID, p.sig)
}

func (p *Prove) getServiceType() (err error) {
	if p.st = libkb.GetServiceType(p.arg.Service); p.st == nil {
		err = libkb.BadServiceError{Service: p.arg.Service}
	}
	return
}

// Run is runs the Prove engine, performing all steps of the proof process.
func (p *Prove) Run(ctx *Context) (err error) {

	p.G().Log.Debug("+ ProofEngine.Run")
	defer func() {
		p.G().Log.Debug("- ProofEngine.Run -> %s", libkb.ErrToOk(err))
	}()

	stage := func(s string) {
		p.G().Log.Debug("| ProofEngine.Run() %s", s)
	}

	stage("GetServiceType")
	if err = p.getServiceType(); err != nil {
		return
	}
	stage("LoadMe")
	if err = p.loadMe(); err != nil {
		return
	}
	stage("CheckExists1")
	if err = p.checkExists1(ctx); err != nil {
		return
	}
	stage("PromptRemoteName")
	if err = p.promptRemoteName(ctx); err != nil {
		return
	}
	stage("NormalizeRemoteName")
	if err = p.normalizeRemoteName(); err != nil {
		return
	}
	stage("CheckExists2")
	if err = p.checkExists2(ctx); err != nil {
		return
	}
	stage("DoPrechecks")
	if err = p.doPrechecks(ctx); err != nil {
		return
	}
	stage("DoWarnings")
	if err = p.doWarnings(ctx); err != nil {
		return
	}
	stage("GenerateProof")
	if err = p.generateProof(ctx); err != nil {
		return
	}
	stage("PostProofToServer")
	if err = p.postProofToServer(); err != nil {
		return
	}
	stage("CheckProofText")
	if err = p.checkProofText(); err != nil {
		return
	}
	stage("InstructAction")
	if err = p.instructAction(ctx); err != nil {
		return
	}
	stage("PromptPostedLoop")
	if err = p.promptPostedLoop(ctx); err != nil {
		return
	}
	ctx.LogUI.Notice("Success!")
	return nil
}
<commit_msg>fixed build<commit_after>package engine

import (
	libkb "github.com/keybase/client/go/libkb"
	keybase1 "github.com/keybase/client/protocol/go"
	jsonw "github.com/keybase/go-jsonw"
)

// Prove is an engine used for proving ownership of remote accounts,
// like Twitter, GitHub, etc.
type Prove struct {
	arg        *keybase1.ProveArg
	me         *libkb.User
	st         libkb.ServiceType
	supersede  bool
	proof      *jsonw.Wrapper
	sig        string
	sigID      *libkb.SigId
	postRes    *libkb.PostProofRes
	signingKey libkb.GenericKey

	username           string
	usernameNormalized string
	libkb.Contextified
}

// NewProve makes a new Prove Engine given an RPC-friendly ProveArg.
func NewProve(arg *keybase1.ProveArg, g *libkb.GlobalContext) *Prove {
	return &Prove{
		arg:          arg,
		Contextified: libkb.NewContextified(g),
	}
}

// Name provides the name of this engine for the engine interface contract
func (p *Prove) Name() string {
	return "Prove"
}

// GetPrereqs returns the engine prereqs.
func (p *Prove) GetPrereqs() EnginePrereqs {
	return EnginePrereqs{Session: true}
}

// RequiredUIs returns the required UIs.
func (p *Prove) RequiredUIs() []libkb.UIKind {
	return []libkb.UIKind{
		libkb.LogUIKind,
		libkb.ProveUIKind,
		libkb.SecretUIKind,
	}
}

// SubConsumers returns the other UI consumers for this engine.
func (p *Prove) SubConsumers() []libkb.UIConsumer {
	return nil
}

func (p *Prove) loadMe() (err error) {
	p.me, err = libkb.LoadMe(libkb.LoadUserArg{AllKeys: false, ForceReload: true})
	return
}

func (p *Prove) checkExists1(ctx *Context) (err error) {
	proofs := p.me.IdTable().GetActiveProofsFor(p.st)
	if len(proofs) != 0 && !p.arg.Force && p.st.LastWriterWins() {
		lst := proofs[len(proofs)-1]
		var redo bool
		redo, err = ctx.ProveUI.PromptOverwrite(keybase1.PromptOverwriteArg{
			Account: lst.ToDisplayString(),
			Typ:     keybase1.PromptOverwriteType_SOCIAL,
		})
		if err != nil {
		} else if !redo {
			err = libkb.NotConfirmedError{}
		} else {
			p.supersede = true
		}
	}
	return
}

func (p *Prove) promptRemoteName(ctx *Context) (err error) {
	p.username = p.arg.Username
	if len(p.username) == 0 {
		var prevErr error
		for len(p.username) == 0 && err == nil {
			var un string
			un, err = ctx.ProveUI.PromptUsername(keybase1.PromptUsernameArg{
				Prompt:    p.st.GetPrompt(),
				PrevError: libkb.ExportErrorAsStatus(prevErr),
			})
			if err == nil {
				prevErr = p.st.CheckUsername(un)
				if prevErr == nil {
					p.username = un
				}
			}
		}
	} else {
		err = p.st.CheckUsername(p.username)
	}
	return
}

func (p *Prove) normalizeRemoteName() (err error) {
	p.usernameNormalized, err = p.st.NormalizeUsername(p.username)
	return
}

func (p *Prove) checkExists2(ctx *Context) (err error) {
	p.G().Log.Debug("+ CheckExists2")
	defer func() { p.G().Log.Debug("- CheckExists2 -> %s", libkb.ErrToOk(err)) }()
	if !p.st.LastWriterWins() {
		var found libkb.RemoteProofChainLink
		for _, proof := range p.me.IdTable().GetActiveProofsFor(p.st) {
			_, name := proof.ToKeyValuePair()
			if libkb.Cicmp(name, p.usernameNormalized) {
				found = proof
				break
			}
		}
		if found != nil {
			var redo bool
			redo, err = ctx.ProveUI.PromptOverwrite(keybase1.PromptOverwriteArg{
				Account: found.ToDisplayString(),
				Typ:     keybase1.PromptOverwriteType_SITE,
			})
			if err != nil {
			} else if !redo {
				err = libkb.NotConfirmedError{}
			} else {
				p.supersede = true
			}
		}
	}
	return
}

func (p *Prove) doPrechecks(ctx *Context) (err error) {
	var w *libkb.Markup
	w, err = p.st.PreProofCheck(p.usernameNormalized)
	if w != nil {
		ctx.ProveUI.OutputPrechecks(keybase1.OutputPrechecksArg{Text: w.Export()})
	}
	return
}

func (p *Prove) doWarnings(ctx *Context) (err error) {
	if mu := p.st.PreProofWarning(p.usernameNormalized); mu != nil {
		var ok bool
		arg := keybase1.PreProofWarningArg{Text: mu.Export()}
		if ok, err = ctx.ProveUI.PreProofWarning(arg); err == nil && !ok {
			err = libkb.NotConfirmedError{}
		}
	}
	return
}

func (p *Prove) generateProof(ctx *Context) (err error) {
	var locked *libkb.SKB
	var which string
	var seckey libkb.GenericKey

	if locked, which, err = p.G().Keyrings.GetSecretKeyLocked(libkb.SecretKeyArg{
		Me:      p.me,
		KeyType: libkb.AnySecretKeyType,
	}); err != nil {
		return
	}
	if p.signingKey, err = locked.GetPubKey(); err != nil {
		return
	}
	if p.proof, err = p.me.ServiceProof(p.signingKey, p.st, p.usernameNormalized); err != nil {
		return
	}
	if seckey, err = locked.PromptAndUnlock(ctx.LoginContext, "proof signature", which, nil, ctx.SecretUI, nil); err != nil {
		return
	}
	if p.sig, p.sigID, _, err = libkb.SignJson(p.proof, seckey); err != nil {
		return
	}
	return
}

func (p *Prove) postProofToServer() (err error) {
	arg := libkb.PostProofArg{
		Sig:            p.sig,
		ProofType:      p.st.GetProofType(),
		Id:             *p.sigID,
		Supersede:      p.supersede,
		RemoteUsername: p.usernameNormalized,
		RemoteKey:      p.st.GetApiArgKey(),
		SigningKey:     p.signingKey,
	}
	p.postRes, err = libkb.PostProof(arg)
	return
}

func (p *Prove) instructAction(ctx *Context) (err error) {
	mkp := p.st.PostInstructions(p.usernameNormalized)
	var txt string
	if txt, err = p.st.FormatProofText(p.postRes); err != nil {
		return
	}
	err = ctx.ProveUI.OutputInstructions(keybase1.OutputInstructionsArg{
		Instructions: mkp.Export(),
		Proof:        txt,
	})
	return
}

func (p *Prove) promptPostedLoop(ctx *Context) (err error) {
	found := false
	for i := 0; ; i++ {
		var retry bool
		var status int
		var warn *libkb.Markup
		retry, err = ctx.ProveUI.OkToCheck(keybase1.OkToCheckArg{
			Name:    p.st.DisplayName(p.usernameNormalized),
			Attempt: i,
		})
		if !retry || err != nil {
			break
		}
		found, status, err = libkb.CheckPosted(p.postRes.Id)
		if found || err != nil {
			break
		}
		warn, err = p.st.RecheckProofPosting(status, i)
		if warn != nil {
			ctx.ProveUI.DisplayRecheckWarning(keybase1.DisplayRecheckWarningArg{
				Text: warn.Export(),
			})
		}
		if err != nil {
			break
		}
	}
	if !found && err == nil {
		err = libkb.ProofNotYetAvailableError{}
	}

	return
}

func (p *Prove) checkProofText() error {
	return p.st.CheckProofText(p.postRes.Text, *p.sigID, p.sig)
}

func (p *Prove) getServiceType() (err error) {
	if p.st = libkb.GetServiceType(p.arg.Service); p.st == nil {
		err = libkb.BadServiceError{Service: p.arg.Service}
	}
	return
}

// Run is runs the Prove engine, performing all steps of the proof process.
func (p *Prove) Run(ctx *Context) (err error) {

	p.G().Log.Debug("+ ProofEngine.Run")
	defer func() {
		p.G().Log.Debug("- ProofEngine.Run -> %s", libkb.ErrToOk(err))
	}()

	stage := func(s string) {
		p.G().Log.Debug("| ProofEngine.Run() %s", s)
	}

	stage("GetServiceType")
	if err = p.getServiceType(); err != nil {
		return
	}
	stage("LoadMe")
	if err = p.loadMe(); err != nil {
		return
	}
	stage("CheckExists1")
	if err = p.checkExists1(ctx); err != nil {
		return
	}
	stage("PromptRemoteName")
	if err = p.promptRemoteName(ctx); err != nil {
		return
	}
	stage("NormalizeRemoteName")
	if err = p.normalizeRemoteName(); err != nil {
		return
	}
	stage("CheckExists2")
	if err = p.checkExists2(ctx); err != nil {
		return
	}
	stage("DoPrechecks")
	if err = p.doPrechecks(ctx); err != nil {
		return
	}
	stage("DoWarnings")
	if err = p.doWarnings(ctx); err != nil {
		return
	}
	stage("GenerateProof")
	if err = p.generateProof(ctx); err != nil {
		return
	}
	stage("PostProofToServer")
	if err = p.postProofToServer(); err != nil {
		return
	}
	stage("CheckProofText")
	if err = p.checkProofText(); err != nil {
		return
	}
	stage("InstructAction")
	if err = p.instructAction(ctx); err != nil {
		return
	}
	stage("PromptPostedLoop")
	if err = p.promptPostedLoop(ctx); err != nil {
		return
	}
	ctx.LogUI.Notice("Success!")
	return nil
}
<|endoftext|>


<commit_before>package googleauth

import (
	"encoding/json"
	"fmt"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

//sign() GCE signature it give URL to get Autorization code on which we it generate auth token and pass in each request in request header
func Sign() (token *oauth2.Token) {

	conf := &oauth2.Config{

		ClientID: os.Getenv("GoogleClientID"),

		ClientSecret:os.Getenv("GoogleClientSecret") ,

		RedirectURL: "urn:ietf:wg:oauth:2.0:oob",

		Scopes: []string{
			"https://www.googleapis.com/auth/compute",
			"https://www.googleapis.com/auth/devstorage.full_control",
			"https://www.googleapis.com/auth/ndev.clouddns.readwrite",
			"https://www.googleapis.com/auth/cloud-platform",
			"https://www.googleapis.com/auth/ndev.clouddns.readonly",
		},

		Endpoint: google.Endpoint,
	}

	url := conf.AuthCodeURL("state", oauth2.AccessTypeOffline)
	fmt.Printf("\nVisit the URL for autorization: \n %v", url)
	fmt.Printf("\nEnter autorization code: \n")

	var code string
	if _, err := fmt.Scan(&code); err != nil {
		log.Fatal(err)
	}

	token, err := conf.Exchange(oauth2.NoContext, code)
	if err != nil {
		log.Fatal(err)
	}

	return token
}

//JWT struct reperesnts JWT json.
type JWT struct {
	Type                    string `json:"type"`
	ProjectID               string `json:"project_id"`
	PrivateKeyID            string `json:"private_key_id"`
	PrivateKey              string `json:"private_key"`
	ClientEmail             string `json:"client_email"`
	ClientID                string `json:"client_id"`
	AuthURI                 string `json:"auth_uri"`
	TokenURI                string `json:"token_uri"`
	AuthProviderX509CertURL string `json:"auth_provider_x509_cert_url"`
	ClientX509CertURL       string `json:"client_x509_cert_url"`
}

//SignJWT reperesnts google service account authentication.
func SignJWT() (client *http.Client) {

	var home string = os.Getenv("HOME")

	data, err := ioutil.ReadFile(home + "/googlecloudconfig.json")

	if err != nil {
		jwt := JWT{}

		jwt.PrivateKey = os.Getenv("PrivateKey")

		jwt.Type = os.Getenv("Type")

		jwt.ProjectID = os.Getenv("ProjectID")

		jwt.PrivateKeyID = os.Getenv("PrivateKeyID")

		jwt.ClientID = os.Getenv("ClientID")

		jwt.ClientEmail = os.Getenv("ClientEmail")

		jwt.AuthURI = os.Getenv("AuthURI")

		jwt.TokenURI = os.Getenv("TokenURI")

		jwt.AuthProviderX509CertURL = os.Getenv("AuthProviderX509CertURL")

		jwt.ClientX509CertURL = os.Getenv("ClientX509CertURL")

		jwtjson, _ := json.Marshal(jwt)

		jwtjsonstring := string(jwtjson)

		datastr := strings.NewReader(jwtjsonstring)

		data, err = ioutil.ReadAll(datastr)
		if err != nil {
			log.Fatal(err)
		}
	}

	conf, err := google.JWTConfigFromJSON(data, "https://www.googleapis.com/auth/compute",
		"https://www.googleapis.com/auth/devstorage.full_control",
		"https://www.googleapis.com/auth/ndev.clouddns.readwrite",
		"https://www.googleapis.com/auth/cloud-platform",
		"https://www.googleapis.com/auth/ndev.clouddns.readonly",
	)
	if err != nil {
		log.Fatal(err)
	}

	client = conf.Client(oauth2.NoContext)
	return client
}
<commit_msg>google service account will be used in production<commit_after>package googleauth

import (
	"encoding/json"
	"golang.org/x/oauth2"
	"golang.org/x/oauth2/google"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

//JWT struct reperesnts JWT json.
type JWT struct {
	Type                    string `json:"type"`
	ProjectID               string `json:"project_id"`
	PrivateKeyID            string `json:"private_key_id"`
	PrivateKey              string `json:"private_key"`
	ClientEmail             string `json:"client_email"`
	ClientID                string `json:"client_id"`
	AuthURI                 string `json:"auth_uri"`
	TokenURI                string `json:"token_uri"`
	AuthProviderX509CertURL string `json:"auth_provider_x509_cert_url"`
	ClientX509CertURL       string `json:"client_x509_cert_url"`
}

//SignJWT reperesnts google service account authentication.
func SignJWT() (client *http.Client) {

	var home string = os.Getenv("HOME")

	data, err := ioutil.ReadFile(home + "/googlecloudconfig.json")

	if err != nil {
		jwt := JWT{}

		jwt.PrivateKey = os.Getenv("PrivateKey")

		jwt.Type = os.Getenv("Type")

		jwt.ProjectID = os.Getenv("ProjectID")

		jwt.PrivateKeyID = os.Getenv("PrivateKeyID")

		jwt.ClientID = os.Getenv("ClientID")

		jwt.ClientEmail = os.Getenv("ClientEmail")

		jwt.AuthURI = os.Getenv("AuthURI")

		jwt.TokenURI = os.Getenv("TokenURI")

		jwt.AuthProviderX509CertURL = os.Getenv("AuthProviderX509CertURL")

		jwt.ClientX509CertURL = os.Getenv("ClientX509CertURL")

		jwtjson, _ := json.Marshal(jwt)

		jwtjsonstring := string(jwtjson)

		datastr := strings.NewReader(jwtjsonstring)

		data, err = ioutil.ReadAll(datastr)
		if err != nil {
			log.Fatal(err)
		}
	}

	conf, err := google.JWTConfigFromJSON(data, "https://www.googleapis.com/auth/compute",
		"https://www.googleapis.com/auth/devstorage.full_control",
		"https://www.googleapis.com/auth/ndev.clouddns.readwrite",
		"https://www.googleapis.com/auth/cloud-platform",
		"https://www.googleapis.com/auth/ndev.clouddns.readonly",
	)
	if err != nil {
		log.Fatal(err)
	}

	client = conf.Client(oauth2.NoContext)
	return client
}
<|endoftext|>