<commit_before>package dockerhub

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/goharbor/harbor/src/common/utils"
	"github.com/goharbor/harbor/src/lib/log"
	adp "github.com/goharbor/harbor/src/replication/adapter"
	"github.com/goharbor/harbor/src/replication/adapter/native"
	"github.com/goharbor/harbor/src/replication/model"
	"github.com/goharbor/harbor/src/replication/util"
)

func init() {
	if err := adp.RegisterFactory(model.RegistryTypeDockerHub, new(factory)); err != nil {
		log.Errorf("Register adapter factory for %s error: %v", model.RegistryTypeDockerHub, err)
		return
	}
	log.Infof("Factory for adapter %s registered", model.RegistryTypeDockerHub)
}

func newAdapter(registry *model.Registry) (adp.Adapter, error) {
	client, err := NewClient(registry)
	if err != nil {
		return nil, err
	}

	return &adapter{
		client:   client,
		registry: registry,
		Adapter: native.NewAdapter(&model.Registry{
			URL:        registryURL,
			Credential: registry.Credential,
			Insecure:   registry.Insecure,
		}),
	}, nil
}

type factory struct {
}

// Create ...
func (f *factory) Create(r *model.Registry) (adp.Adapter, error) {
	return newAdapter(r)
}

// AdapterPattern ...
func (f *factory) AdapterPattern() *model.AdapterPattern {
	return getAdapterInfo()
}

var (
	_ adp.Adapter          = (*adapter)(nil)
	_ adp.ArtifactRegistry = (*adapter)(nil)
)

type adapter struct {
	*native.Adapter
	registry *model.Registry
	client   *Client
}

// Ensure '*adapter' implements interface 'Adapter'.
var _ adp.Adapter = (*adapter)(nil)

// Info returns information of the registry
func (a *adapter) Info() (*model.RegistryInfo, error) {
	return &model.RegistryInfo{
		Type: model.RegistryTypeDockerHub,
		SupportedResourceTypes: []model.ResourceType{
			model.ResourceTypeImage,
		},
		SupportedResourceFilters: []*model.FilterStyle{
			{
				Type:  model.FilterTypeName,
				Style: model.FilterStyleTypeText,
			},
			{
				Type:  model.FilterTypeTag,
				Style: model.FilterStyleTypeText,
			},
		},
		SupportedTriggers: []model.TriggerType{
			model.TriggerTypeManual,
			model.TriggerTypeScheduled,
		},
	}, nil
}

func getAdapterInfo() *model.AdapterPattern {
	info := &model.AdapterPattern{
		EndpointPattern: &model.EndpointPattern{
			EndpointType: model.EndpointPatternTypeFix,
			Endpoints: []*model.Endpoint{
				{
					Key:   "hub.docker.com",
					Value: "https://hub.docker.com",
				},
			},
		},
	}
	return info
}

// PrepareForPush does the prepare work that needed for pushing/uploading the resource
// eg: create the namespace or repository
func (a *adapter) PrepareForPush(resources []*model.Resource) error {
	namespaces := map[string]struct{}{}
	for _, resource := range resources {
		if resource == nil {
			return errors.New("the resource cannot be null")
		}
		if resource.Metadata == nil {
			return errors.New("the metadata of resource cannot be null")
		}
		if resource.Metadata.Repository == nil {
			return errors.New("the namespace of resource cannot be null")
		}
		if len(resource.Metadata.Repository.Name) == 0 {
			return errors.New("the name of the namespace cannot be null")
		}
		paths := strings.Split(resource.Metadata.Repository.Name, "/")
		namespace := paths[0]
		namespaces[namespace] = struct{}{}
	}

	for namespace := range namespaces {
		err := a.CreateNamespace(&model.Namespace{
			Name: namespace,
		})
		if err != nil {
			return fmt.Errorf("create namespace '%s' in DockerHub error: %v", namespace, err)
		}
		log.Debugf("namespace %s created", namespace)
	}
	return nil
}

func (a *adapter) listNamespaces() ([]string, error) {
	resp, err := a.client.Do(http.MethodGet, listNamespacePath, nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("list namespace error: %s", string(body))
		return nil, fmt.Errorf("%s", string(body))
	}

	namespaces := NamespacesResp{}
	err = json.Unmarshal(body, &namespaces)
	if err != nil {
		return nil, err
	}
	log.Debugf("got namespaces %v by calling the listing namespaces API", namespaces)
	return namespaces.Namespaces, nil
}

// CreateNamespace creates a new namespace in DockerHub
func (a *adapter) CreateNamespace(namespace *model.Namespace) error {
	ns, err := a.getNamespace(namespace.Name)
	if err != nil {
		return fmt.Errorf("check existence of namespace '%s' error: %v", namespace.Name, err)
	}

	// If the namespace already exist, return succeeded directly.
	if ns != nil {
		log.Infof("Namespace %s already exist in DockerHub, skip it.", namespace.Name)
		return nil
	}

	req := &NewOrgReq{
		Name:     namespace.Name,
		FullName: namespace.GetStringMetadata(metadataKeyFullName, namespace.Name),
		Company:  namespace.GetStringMetadata(metadataKeyCompany, namespace.Name),
	}
	b, err := json.Marshal(req)
	if err != nil {
		return err
	}

	resp, err := a.client.Do(http.MethodPost, createNamespacePath, bytes.NewReader(b))
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("create namespace error: %d -- %s", resp.StatusCode, string(body))
		return fmt.Errorf("%d -- %s", resp.StatusCode, body)
	}

	return nil
}

// getNamespace get namespace from DockerHub, if the namespace not found, two nil would be returned.
func (a *adapter) getNamespace(namespace string) (*model.Namespace, error) {
	resp, err := a.client.Do(http.MethodGet, getNamespacePath(namespace), nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("get namespace error: %d -- %s", resp.StatusCode, string(body))
		return nil, fmt.Errorf("%d -- %s", resp.StatusCode, body)
	}

	return &model.Namespace{
		Name: namespace,
	}, nil
}

// FetchArtifacts fetches images
func (a *adapter) FetchArtifacts(filters []*model.Filter) ([]*model.Resource, error) {
	var repos []Repo
	nameFilter, err := a.getStringFilterValue(model.FilterTypeName, filters)
	if err != nil {
		return nil, err
	}
	tagFilter, err := a.getStringFilterValue(model.FilterTypeTag, filters)
	if err != nil {
		return nil, err
	}

	namespaces, err := a.listCandidateNamespaces(nameFilter)
	if err != nil {
		return nil, err
	}
	log.Debugf("got %d namespaces", len(namespaces))
	for _, ns := range namespaces {
		page := 1
		pageSize := 100
		n := 0
		for {
			pageRepos, err := a.getRepos(ns, "", page, pageSize)
			if err != nil {
				return nil, fmt.Errorf("get repos for namespace '%s' from DockerHub error: %v", ns, err)
			}
			repos = append(repos, pageRepos.Repos...)

			n += len(pageRepos.Repos)
			if len(pageRepos.Next) == 0 {
				break
			}

			page++
		}
		log.Debugf("got %d repositories for namespace %s", n, ns)
	}

	var rawResources = make([]*model.Resource, len(repos))
	runner := utils.NewLimitedConcurrentRunner(adp.MaxConcurrency)
	for i, r := range repos {
		index := i
		repo := r
		runner.AddTask(func() error {
			name := fmt.Sprintf("%s/%s", repo.Namespace, repo.Name)
			log.Infof("Routine started to collect tags for repo: %s", name)

			// If name filter set, skip repos that don't match the filter pattern.
			if len(nameFilter) != 0 {
				m, err := util.Match(nameFilter, name)
				if err != nil {
					return fmt.Errorf("match repo name '%s' against pattern '%s' error: %v", name, nameFilter, err)
				}
				if !m {
					return nil
				}
			}

			var tags []string
			page := 1
			pageSize := 100
			for {
				pageTags, err := a.getTags(repo.Namespace, repo.Name, page, pageSize)
				if err != nil {
					return fmt.Errorf("get tags for repo '%s/%s' from DockerHub error: %v", repo.Namespace, repo.Name, err)
				}
				for _, t := range pageTags.Tags {
					// If tag filter set, skip tags that don't match the filter pattern.
					if len(tagFilter) != 0 {
						m, err := util.Match(tagFilter, t.Name)
						if err != nil {
							return fmt.Errorf("match tag name '%s' against pattern '%s' error: %v", t.Name, tagFilter, err)
						}

						if !m {
							continue
						}
					}
					tags = append(tags, t.Name)
				}

				if len(pageTags.Next) == 0 {
					break
				}
				page++
			}

			if len(tags) > 0 {
				rawResources[index] = &model.Resource{
					Type:     model.ResourceTypeImage,
					Registry: a.registry,
					Metadata: &model.ResourceMetadata{
						Repository: &model.Repository{
							Name: name,
						},
						Vtags: tags,
					},
				}
			}

			return nil
		})
	}
	if err = runner.Wait(); err != nil {
		return nil, fmt.Errorf("failed to fetch artifacts: %v", err)
	}
	var resources []*model.Resource
	for _, r := range rawResources {
		if r != nil {
			resources = append(resources, r)
		}
	}

	return resources, nil
}

func (a *adapter) listCandidateNamespaces(pattern string) ([]string, error) {
	namespaces := []string{}
	if len(pattern) > 0 {
		substrings := strings.Split(pattern, "/")
		namespacePattern := substrings[0]
		if nms, ok := util.IsSpecificPathComponent(namespacePattern); ok {
			namespaces = append(namespaces, nms...)
		}
	}
	if len(namespaces) > 0 {
		log.Debugf("parsed the namespaces %v from pattern %s", namespaces, pattern)
		return namespaces, nil
	}
	return a.listNamespaces()
}

// DeleteManifest ...
// Note: DockerHub only supports delete by tag
func (a *adapter) DeleteManifest(repository, reference string) error {
	parts := strings.Split(repository, "/")
	if len(parts) != 2 {
		return fmt.Errorf("dockerhub only support repo in format <namespace>/<name>, but got: %s", repository)
	}

	resp, err := a.client.Do(http.MethodDelete, deleteTagPath(parts[0], parts[1], reference), nil)
	if err != nil {
		return err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("Delete tag error: %d -- %s", resp.StatusCode, string(body))
		return fmt.Errorf("%d -- %s", resp.StatusCode, string(body))
	}

	return nil
}

// getRepos gets a page of repos from DockerHub
func (a *adapter) getRepos(namespace, name string, page, pageSize int) (*ReposResp, error) {
	resp, err := a.client.Do(http.MethodGet, listReposPath(namespace, name, page, pageSize), nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("list repos error: %d -- %s", resp.StatusCode, string(body))
		return nil, fmt.Errorf("%d -- %s", resp.StatusCode, string(body))
	}

	repos := &ReposResp{}
	err = json.Unmarshal(body, repos)
	if err != nil {
		return nil, fmt.Errorf("unmarshal repos list %s error: %v", string(body), err)
	}

	return repos, nil
}

// getTags gets a page of tags for a repo from DockerHub
func (a *adapter) getTags(namespace, repo string, page, pageSize int) (*TagsResp, error) {
	resp, err := a.client.Do(http.MethodGet, listTagsPath(namespace, repo, page, pageSize), nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("list tags error: %d -- %s", resp.StatusCode, string(body))
		return nil, fmt.Errorf("%d -- %s", resp.StatusCode, body)
	}

	tags := &TagsResp{}
	err = json.Unmarshal(body, tags)
	if err != nil {
		return nil, fmt.Errorf("unmarshal tags list %s error: %v", string(body), err)
	}

	return tags, nil
}

// getFilter gets specific type filter value from filters list.
func (a *adapter) getStringFilterValue(filterType model.FilterType, filters []*model.Filter) (string, error) {
	for _, f := range filters {
		if f.Type == filterType {
			v, ok := f.Value.(string)
			if !ok {
				msg := fmt.Sprintf("expect filter value to be string, but got: %v", f.Value)
				log.Error(msg)
				return "", errors.New(msg)
			}
			return v, nil
		}
	}
	return "", nil
}
<commit_msg>update adapter log level to debug<commit_after>package dockerhub

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"

	"github.com/goharbor/harbor/src/common/utils"
	"github.com/goharbor/harbor/src/lib/log"
	adp "github.com/goharbor/harbor/src/replication/adapter"
	"github.com/goharbor/harbor/src/replication/adapter/native"
	"github.com/goharbor/harbor/src/replication/model"
	"github.com/goharbor/harbor/src/replication/util"
)

func init() {
	if err := adp.RegisterFactory(model.RegistryTypeDockerHub, new(factory)); err != nil {
		log.Errorf("Register adapter factory for %s error: %v", model.RegistryTypeDockerHub, err)
		return
	}
	log.Infof("Factory for adapter %s registered", model.RegistryTypeDockerHub)
}

func newAdapter(registry *model.Registry) (adp.Adapter, error) {
	client, err := NewClient(registry)
	if err != nil {
		return nil, err
	}

	return &adapter{
		client:   client,
		registry: registry,
		Adapter: native.NewAdapter(&model.Registry{
			URL:        registryURL,
			Credential: registry.Credential,
			Insecure:   registry.Insecure,
		}),
	}, nil
}

type factory struct {
}

// Create ...
func (f *factory) Create(r *model.Registry) (adp.Adapter, error) {
	return newAdapter(r)
}

// AdapterPattern ...
func (f *factory) AdapterPattern() *model.AdapterPattern {
	return getAdapterInfo()
}

var (
	_ adp.Adapter          = (*adapter)(nil)
	_ adp.ArtifactRegistry = (*adapter)(nil)
)

type adapter struct {
	*native.Adapter
	registry *model.Registry
	client   *Client
}

// Ensure '*adapter' implements interface 'Adapter'.
var _ adp.Adapter = (*adapter)(nil)

// Info returns information of the registry
func (a *adapter) Info() (*model.RegistryInfo, error) {
	return &model.RegistryInfo{
		Type: model.RegistryTypeDockerHub,
		SupportedResourceTypes: []model.ResourceType{
			model.ResourceTypeImage,
		},
		SupportedResourceFilters: []*model.FilterStyle{
			{
				Type:  model.FilterTypeName,
				Style: model.FilterStyleTypeText,
			},
			{
				Type:  model.FilterTypeTag,
				Style: model.FilterStyleTypeText,
			},
		},
		SupportedTriggers: []model.TriggerType{
			model.TriggerTypeManual,
			model.TriggerTypeScheduled,
		},
	}, nil
}

func getAdapterInfo() *model.AdapterPattern {
	info := &model.AdapterPattern{
		EndpointPattern: &model.EndpointPattern{
			EndpointType: model.EndpointPatternTypeFix,
			Endpoints: []*model.Endpoint{
				{
					Key:   "hub.docker.com",
					Value: "https://hub.docker.com",
				},
			},
		},
	}
	return info
}

// PrepareForPush does the prepare work that needed for pushing/uploading the resource
// eg: create the namespace or repository
func (a *adapter) PrepareForPush(resources []*model.Resource) error {
	namespaces := map[string]struct{}{}
	for _, resource := range resources {
		if resource == nil {
			return errors.New("the resource cannot be null")
		}
		if resource.Metadata == nil {
			return errors.New("the metadata of resource cannot be null")
		}
		if resource.Metadata.Repository == nil {
			return errors.New("the namespace of resource cannot be null")
		}
		if len(resource.Metadata.Repository.Name) == 0 {
			return errors.New("the name of the namespace cannot be null")
		}
		paths := strings.Split(resource.Metadata.Repository.Name, "/")
		namespace := paths[0]
		namespaces[namespace] = struct{}{}
	}

	for namespace := range namespaces {
		err := a.CreateNamespace(&model.Namespace{
			Name: namespace,
		})
		if err != nil {
			return fmt.Errorf("create namespace '%s' in DockerHub error: %v", namespace, err)
		}
		log.Debugf("namespace %s created", namespace)
	}
	return nil
}

func (a *adapter) listNamespaces() ([]string, error) {
	resp, err := a.client.Do(http.MethodGet, listNamespacePath, nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("list namespace error: %s", string(body))
		return nil, fmt.Errorf("%s", string(body))
	}

	namespaces := NamespacesResp{}
	err = json.Unmarshal(body, &namespaces)
	if err != nil {
		return nil, err
	}
	log.Debugf("got namespaces %v by calling the listing namespaces API", namespaces)
	return namespaces.Namespaces, nil
}

// CreateNamespace creates a new namespace in DockerHub
func (a *adapter) CreateNamespace(namespace *model.Namespace) error {
	ns, err := a.getNamespace(namespace.Name)
	if err != nil {
		return fmt.Errorf("check existence of namespace '%s' error: %v", namespace.Name, err)
	}

	// If the namespace already exist, return succeeded directly.
	if ns != nil {
		log.Infof("Namespace %s already exist in DockerHub, skip it.", namespace.Name)
		return nil
	}

	req := &NewOrgReq{
		Name:     namespace.Name,
		FullName: namespace.GetStringMetadata(metadataKeyFullName, namespace.Name),
		Company:  namespace.GetStringMetadata(metadataKeyCompany, namespace.Name),
	}
	b, err := json.Marshal(req)
	if err != nil {
		return err
	}

	resp, err := a.client.Do(http.MethodPost, createNamespacePath, bytes.NewReader(b))
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("create namespace error: %d -- %s", resp.StatusCode, string(body))
		return fmt.Errorf("%d -- %s", resp.StatusCode, body)
	}

	return nil
}

// getNamespace get namespace from DockerHub, if the namespace not found, two nil would be returned.
func (a *adapter) getNamespace(namespace string) (*model.Namespace, error) {
	resp, err := a.client.Do(http.MethodGet, getNamespacePath(namespace), nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode == http.StatusNotFound {
		return nil, nil
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("get namespace error: %d -- %s", resp.StatusCode, string(body))
		return nil, fmt.Errorf("%d -- %s", resp.StatusCode, body)
	}

	return &model.Namespace{
		Name: namespace,
	}, nil
}

// FetchArtifacts fetches images
func (a *adapter) FetchArtifacts(filters []*model.Filter) ([]*model.Resource, error) {
	var repos []Repo
	nameFilter, err := a.getStringFilterValue(model.FilterTypeName, filters)
	if err != nil {
		return nil, err
	}
	tagFilter, err := a.getStringFilterValue(model.FilterTypeTag, filters)
	if err != nil {
		return nil, err
	}

	namespaces, err := a.listCandidateNamespaces(nameFilter)
	if err != nil {
		return nil, err
	}
	log.Debugf("got %d namespaces", len(namespaces))
	for _, ns := range namespaces {
		page := 1
		pageSize := 100
		n := 0
		for {
			pageRepos, err := a.getRepos(ns, "", page, pageSize)
			if err != nil {
				return nil, fmt.Errorf("get repos for namespace '%s' from DockerHub error: %v", ns, err)
			}
			repos = append(repos, pageRepos.Repos...)

			n += len(pageRepos.Repos)
			if len(pageRepos.Next) == 0 {
				break
			}

			page++
		}
		log.Debugf("got %d repositories for namespace %s", n, ns)
	}

	var rawResources = make([]*model.Resource, len(repos))
	runner := utils.NewLimitedConcurrentRunner(adp.MaxConcurrency)
	for i, r := range repos {
		index := i
		repo := r
		runner.AddTask(func() error {
			name := fmt.Sprintf("%s/%s", repo.Namespace, repo.Name)
			log.Debugf("Routine started to collect tags for repo: %s", name)

			// If name filter set, skip repos that don't match the filter pattern.
			if len(nameFilter) != 0 {
				m, err := util.Match(nameFilter, name)
				if err != nil {
					return fmt.Errorf("match repo name '%s' against pattern '%s' error: %v", name, nameFilter, err)
				}
				if !m {
					return nil
				}
			}

			var tags []string
			page := 1
			pageSize := 100
			for {
				pageTags, err := a.getTags(repo.Namespace, repo.Name, page, pageSize)
				if err != nil {
					return fmt.Errorf("get tags for repo '%s/%s' from DockerHub error: %v", repo.Namespace, repo.Name, err)
				}
				for _, t := range pageTags.Tags {
					// If tag filter set, skip tags that don't match the filter pattern.
					if len(tagFilter) != 0 {
						m, err := util.Match(tagFilter, t.Name)
						if err != nil {
							return fmt.Errorf("match tag name '%s' against pattern '%s' error: %v", t.Name, tagFilter, err)
						}

						if !m {
							continue
						}
					}
					tags = append(tags, t.Name)
				}

				if len(pageTags.Next) == 0 {
					break
				}
				page++
			}

			if len(tags) > 0 {
				rawResources[index] = &model.Resource{
					Type:     model.ResourceTypeImage,
					Registry: a.registry,
					Metadata: &model.ResourceMetadata{
						Repository: &model.Repository{
							Name: name,
						},
						Vtags: tags,
					},
				}
			}

			return nil
		})
	}
	if err = runner.Wait(); err != nil {
		return nil, fmt.Errorf("failed to fetch artifacts: %v", err)
	}
	var resources []*model.Resource
	for _, r := range rawResources {
		if r != nil {
			resources = append(resources, r)
		}
	}

	return resources, nil
}

func (a *adapter) listCandidateNamespaces(pattern string) ([]string, error) {
	namespaces := []string{}
	if len(pattern) > 0 {
		substrings := strings.Split(pattern, "/")
		namespacePattern := substrings[0]
		if nms, ok := util.IsSpecificPathComponent(namespacePattern); ok {
			namespaces = append(namespaces, nms...)
		}
	}
	if len(namespaces) > 0 {
		log.Debugf("parsed the namespaces %v from pattern %s", namespaces, pattern)
		return namespaces, nil
	}
	return a.listNamespaces()
}

// DeleteManifest ...
// Note: DockerHub only supports delete by tag
func (a *adapter) DeleteManifest(repository, reference string) error {
	parts := strings.Split(repository, "/")
	if len(parts) != 2 {
		return fmt.Errorf("dockerhub only support repo in format <namespace>/<name>, but got: %s", repository)
	}

	resp, err := a.client.Do(http.MethodDelete, deleteTagPath(parts[0], parts[1], reference), nil)
	if err != nil {
		return err
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("Delete tag error: %d -- %s", resp.StatusCode, string(body))
		return fmt.Errorf("%d -- %s", resp.StatusCode, string(body))
	}

	return nil
}

// getRepos gets a page of repos from DockerHub
func (a *adapter) getRepos(namespace, name string, page, pageSize int) (*ReposResp, error) {
	resp, err := a.client.Do(http.MethodGet, listReposPath(namespace, name, page, pageSize), nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("list repos error: %d -- %s", resp.StatusCode, string(body))
		return nil, fmt.Errorf("%d -- %s", resp.StatusCode, string(body))
	}

	repos := &ReposResp{}
	err = json.Unmarshal(body, repos)
	if err != nil {
		return nil, fmt.Errorf("unmarshal repos list %s error: %v", string(body), err)
	}

	return repos, nil
}

// getTags gets a page of tags for a repo from DockerHub
func (a *adapter) getTags(namespace, repo string, page, pageSize int) (*TagsResp, error) {
	resp, err := a.client.Do(http.MethodGet, listTagsPath(namespace, repo, page, pageSize), nil)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode/100 != 2 {
		log.Errorf("list tags error: %d -- %s", resp.StatusCode, string(body))
		return nil, fmt.Errorf("%d -- %s", resp.StatusCode, body)
	}

	tags := &TagsResp{}
	err = json.Unmarshal(body, tags)
	if err != nil {
		return nil, fmt.Errorf("unmarshal tags list %s error: %v", string(body), err)
	}

	return tags, nil
}

// getFilter gets specific type filter value from filters list.
func (a *adapter) getStringFilterValue(filterType model.FilterType, filters []*model.Filter) (string, error) {
	for _, f := range filters {
		if f.Type == filterType {
			v, ok := f.Value.(string)
			if !ok {
				msg := fmt.Sprintf("expect filter value to be string, but got: %v", f.Value)
				log.Error(msg)
				return "", errors.New(msg)
			}
			return v, nil
		}
	}
	return "", nil
}
<|endoftext|>


<commit_before>// Library for all handler functions used by the Yieldbot Infrastructure
// teams in sensu.
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

// Package sensuhandler implements common data structures and functions for Yieldbot monitoring alerts and dashboards
package sensuhandler

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"github.com/yieldbot/sensuplugin/sensuutil"
)

// AcquireUchiwa returns an uchiwa url for the node alerting
// func (e SensuEvent) AcquireMonitoredInstance() string {
func (e EnvDetails) AcquireUchiwa(h string, c string) string {
	var tags string
	var dc string

	tags = e.Sensu.Consul.Tags
	dc = e.Sensu.Consul.Datacenter

	url := "https://" + tags + ".uchiwa.service" + "." + dc + ".consul/#/client/" + dc + "/" + h + "?check=" + c
	return url
}

// CleanOutput will shorten the output to a more manageable length
func CleanOutput(output string) string {
	return strings.Split(output, ":")[0]
}

// EventName generates a simple string for use by elasticsearch and internal logging of all monitoring alerts.
func EventName(client string, check string) string {
	return client + "_" + check
}

// AcquireMonitoredInstance sets the correct device that is being monitored. In the case of snmp trap collection, containers,
// or appliance monitoring the device running the sensu-client may not be the device actually being monitored.
func (e SensuEvent) AcquireMonitoredInstance() string {
	if e.Check.Source != "" {
		return e.Check.Source
	}
	return e.Client.Name
}

// AcquireThreshold will get the current threshold for the alert state.
func (e SensuEvent) AcquireThreshold() string {
	var w string
	var c string

	if e.Check.Thresholds.Warning != -1 {
		w = strconv.Itoa(e.Check.Thresholds.Warning)
	}
	if e.Check.Thresholds.Critical != -1 {
		c = strconv.Itoa(e.Check.Thresholds.Critical)
	}

	// YELLOW
	// refactor this so the case is dynamic

	// for k, v := range sensuutil.MonitoringErrorCodes {
	// 	if status == v {
	// 		eCode = k
	// 	}
	// }
	//
	for _, v := range sensuutil.MonitoringErrorCodes {
		switch e.Check.Status {
		case v: // this is stupid and ugly, fix it
			if w != "" {
				if c != "" {
					return "Warning Threshold: " + w + " Critical Threshold: " + c
				}
			}
			return "No " + DefineStatus(v) + " threshold set"
		// case 1:
		// 	if w != "" {
		// 		return "Warning Threshold: " + w
		// 	}
		// 	return "No " + DefineStatus(2) + " threshold set"
		// case 2:
		// 	if c != "" {
		// 		return "Critical Threshold: " + c
		// 	}
		// 	return "No " + DefineStatus(2) + " threshold set"
		// case 3:
		// 	return "No " + DefineStatus(2) + " threshold set"
		default:
			return "No threshold information"
		}
	}
	return "Unknown Error Code"
}

// SetColor is used to set the correct notification color for a given status. By setting it in a single place for all alerts
// we ensure a measure of cohesiveness across various notification channels.
func SetColor(status int) string {
	switch status {
	case 0:
		return NotificationColor["green"]
	case 1:
		return NotificationColor["yellow"]
	case 2:
		return NotificationColor["red"]
	case 3:
		return NotificationColor["orange"]
	default:
		return NotificationColor["orange"]
	}
}

// DefineSensuEnv sets the environment that the machine is running in based upon values
// dropped via Oahi during the Chef run.
func DefineSensuEnv(env string) string {
	switch env {
	case "prd":
		return "Prod "
	case "dev":
		return "Dev "
	case "stg":
		return "Stg "
	case "vagrant":
		return "Vagrant "
	default:
		return "Test "
	}
}

// DefineStatus converts the check result status from an integer to a string.
func DefineStatus(status int) string {
	eCode := "UNDEFINED_STATUS"

	for k, v := range sensuutil.MonitoringErrorCodes {
		if status == v {
			eCode = k
		}
	}
	return eCode
}

// CreateCheckName creates a monitor name that is easily searchable in ES using different
// levels of granularity.
func CreateCheckName(check string) string {
	return strings.Replace(check, "-", ".", -1)
}

// DefineCheckStateDuration calculates how long a monitor has been in a given state.
func DefineCheckStateDuration() int {
	return 0
}

// SetSensuEnv reads in the environment details provided by Oahi and drops them into a statically defined struct.
func (e EnvDetails) SetSensuEnv() *EnvDetails {
	envFile, err := ioutil.ReadFile(sensuutil.EnvironmentFile)
	if err != nil {
		panic(err)
	}

	// var envDetails EnvDetails
	err = json.Unmarshal(envFile, &e)
	if err != nil {
		panic(err)
	}
	return &e
}

// AcquireSensuEvent reads in the check result generated by Sensu via stdin and drop it into a statically defined struct.
func (e SensuEvent) AcquireSensuEvent() *SensuEvent {
	results, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		panic(err)
	}
	err = json.Unmarshal(results, &e)
	if err != nil {
		panic(err)
	}
	return &e
}
<commit_msg>refactor threshold switch to be normal..poop<commit_after>// Library for all handler functions used by the Yieldbot Infrastructure
// teams in sensu.
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

// Package sensuhandler implements common data structures and functions for Yieldbot monitoring alerts and dashboards
package sensuhandler

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"strconv"
	"strings"

	"github.com/yieldbot/sensuplugin/sensuutil"
)

// AcquireUchiwa returns an uchiwa url for the node alerting
// func (e SensuEvent) AcquireMonitoredInstance() string {
func (e EnvDetails) AcquireUchiwa(h string, c string) string {
	var tags string
	var dc string

	tags = e.Sensu.Consul.Tags
	dc = e.Sensu.Consul.Datacenter

	url := "https://" + tags + ".uchiwa.service" + "." + dc + ".consul/#/client/" + dc + "/" + h + "?check=" + c
	return url
}

// CleanOutput will shorten the output to a more manageable length
func CleanOutput(output string) string {
	return strings.Split(output, ":")[0]
}

// EventName generates a simple string for use by elasticsearch and internal logging of all monitoring alerts.
func EventName(client string, check string) string {
	return client + "_" + check
}

// AcquireMonitoredInstance sets the correct device that is being monitored. In the case of snmp trap collection, containers,
// or appliance monitoring the device running the sensu-client may not be the device actually being monitored.
func (e SensuEvent) AcquireMonitoredInstance() string {
	if e.Check.Source != "" {
		return e.Check.Source
	}
	return e.Client.Name
}

// AcquireThreshold will get the current threshold for the alert state.
func (e SensuEvent) AcquireThreshold() string {
	var w string
	var c string

	if e.Check.Thresholds.Warning != -1 {
		w = strconv.Itoa(e.Check.Thresholds.Warning)
	}
	if e.Check.Thresholds.Critical != -1 {
		c = strconv.Itoa(e.Check.Thresholds.Critical)
	}

	// YELLOW
	// refactor this so the case is dynamic
	switch e.Check.Status {
	case 0: // this is stupid and ugly, fix it
		if w != "" {
			if c != "" {
				return "Warning Threshold: " + w + " Critical Threshold: " + c
			}
		}
		return "No thresholds set"
	case 1:
		if w != "" {
			return "Warning Threshold: " + w
		}
		return "No " + DefineStatus(1) + " threshold set"
	case 2:
		if c != "" {
			return "Critical Threshold: " + c
		}
		return "No " + DefineStatus(2) + " threshold set"
	case 3:
		return "No " + DefineStatus(3) + " threshold set"
	default:
		return "No threshold information"
	}
}

// SetColor is used to set the correct notification color for a given status. By setting it in a single place for all alerts
// we ensure a measure of cohesiveness across various notification channels.
func SetColor(status int) string {
	switch status {
	case 0:
		return NotificationColor["green"]
	case 1:
		return NotificationColor["yellow"]
	case 2:
		return NotificationColor["red"]
	case 3:
		return NotificationColor["orange"]
	default:
		return NotificationColor["orange"]
	}
}

// DefineSensuEnv sets the environment that the machine is running in based upon values
// dropped via Oahi during the Chef run.
func DefineSensuEnv(env string) string {
	switch env {
	case "prd":
		return "Prod "
	case "dev":
		return "Dev "
	case "stg":
		return "Stg "
	case "vagrant":
		return "Vagrant "
	default:
		return "Test "
	}
}

// DefineStatus converts the check result status from an integer to a string.
func DefineStatus(status int) string {
	eCode := "UNDEFINED_STATUS"

	for k, v := range sensuutil.MonitoringErrorCodes {
		if status == v {
			eCode = k
		}
	}
	return eCode
}

// CreateCheckName creates a monitor name that is easily searchable in ES using different
// levels of granularity.
func CreateCheckName(check string) string {
	return strings.Replace(check, "-", ".", -1)
}

// DefineCheckStateDuration calculates how long a monitor has been in a given state.
func DefineCheckStateDuration() int {
	return 0
}

// SetSensuEnv reads in the environment details provided by Oahi and drops them into a statically defined struct.
func (e EnvDetails) SetSensuEnv() *EnvDetails {
	envFile, err := ioutil.ReadFile(sensuutil.EnvironmentFile)
	if err != nil {
		panic(err)
	}

	// var envDetails EnvDetails
	err = json.Unmarshal(envFile, &e)
	if err != nil {
		panic(err)
	}
	return &e
}

// AcquireSensuEvent reads in the check result generated by Sensu via stdin and drop it into a statically defined struct.
func (e SensuEvent) AcquireSensuEvent() *SensuEvent {
	results, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		panic(err)
	}
	err = json.Unmarshal(results, &e)
	if err != nil {
		panic(err)
	}
	return &e
}
<|endoftext|>


<commit_before>// Copyright 2021 Google LLC
//
// 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
//
//     https://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.

// Command genrobots generates a robots.txt file for the given buckets.
package main

import (
	"context"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
	"sort"
	"strings"

	"cloud.google.com/go/storage"
	"google.golang.org/api/iterator"
)

// versionRE matches versions of libraries. Examples:
//    rev1234-2.3.4
//    v1.0.0
//    0.1.2
//    HEAD
var versionRE = regexp.MustCompile(`(rev\d+-)?v?(\d+\.\d+\.\d+|HEAD)`)

func main() {
	googleapisBucketName := flag.String("gbucket", "", "googleapis.dev bucket name")
	cgcBucketName := flag.String("cgcbucket", "", "c.g.c. bucket name")
	robotsFilename := "robots.txt"

	flag.Parse()

	if *googleapisBucketName == "" {
		log.Fatal("must set -gbucket")
	}
	if *cgcBucketName == "" {
		log.Fatal("must set -cgcbucket")
	}

	ctx := context.Background()

	client, err := storage.NewClient(ctx)
	if err != nil {
		log.Fatalf("failed to create storage client: %v", err)
	}
	defer client.Close()

	googleapisBucket := client.Bucket(*googleapisBucketName)
	googleapisPkgs, err := names(ctx, googleapisBucket)
	if err != nil {
		log.Fatal(err)
	}

	cgcBucket := client.Bucket(*cgcBucketName)
	cgcPkgs, err := names(ctx, cgcBucket)
	if err != nil {
		log.Fatal(err)
	}

	excludeInRobots := []string{}
	for name := range googleapisPkgs {
		if _, ok := cgcPkgs[name]; ok {
			excludeInRobots = append(excludeInRobots, name)
		}
	}
	f, err := os.OpenFile(robotsFilename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	if err := writeRobots(f, excludeInRobots); err != nil {
		log.Fatal(err)
	}
}

func names(ctx context.Context, bucket *storage.BucketHandle) (map[string]struct{}, error) {
	names := map[string]struct{}{}
	it := bucket.Objects(ctx, nil)
	for {
		obj, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}
		if strings.HasPrefix(obj.Name, "docfx") || strings.HasPrefix(obj.Name, "xrefs") {
			continue
		}
		if !strings.HasPrefix(obj.Name, "dotnet") &&
			!strings.HasPrefix(obj.Name, "go") &&
			!strings.HasPrefix(obj.Name, "java") &&
			!strings.HasPrefix(obj.Name, "nodejs") &&
			!strings.HasPrefix(obj.Name, "python") {
			continue
		}
		name, err := trimVersion(obj.Name)
		if err != nil {
			return nil, err
		}
		names[name] = struct{}{}
	}
	return names, nil
}

func writeRobots(w io.Writer, excludes []string) error {
	fmt.Fprintf(w, "User-agent: *\n")

	sort.Strings(excludes)

	for _, exclude := range excludes {
		parts := strings.SplitN(exclude, "-", 2)
		lang := parts[0]
		pkg := parts[1]
		fmt.Fprintf(w, "Disallow: /%s/%s/\n", lang, pkg)
	}
	return nil
}

func trimVersion(name string) (string, error) {
	match := versionRE.FindStringIndex(name)
	if match == nil {
		return "", fmt.Errorf("invalid name: %q", name)
	}

	return name[:match[0]-1], nil
}
<commit_msg>feat: Add Ruby entries to generated robots file (#170)<commit_after>// Copyright 2021 Google LLC
//
// 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
//
//     https://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.

// Command genrobots generates a robots.txt file for the given buckets.
package main

import (
	"context"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"regexp"
	"sort"
	"strings"

	"cloud.google.com/go/storage"
	"google.golang.org/api/iterator"
)

// versionRE matches versions of libraries. Examples:
//    rev1234-2.3.4
//    v1.0.0
//    0.1.2
//    HEAD
var versionRE = regexp.MustCompile(`(rev\d+-)?v?(\d+\.\d+\.\d+|HEAD)`)

func main() {
	googleapisBucketName := flag.String("gbucket", "", "googleapis.dev bucket name")
	cgcBucketName := flag.String("cgcbucket", "", "c.g.c. bucket name")
	robotsFilename := "robots.txt"

	flag.Parse()

	if *googleapisBucketName == "" {
		log.Fatal("must set -gbucket")
	}
	if *cgcBucketName == "" {
		log.Fatal("must set -cgcbucket")
	}

	ctx := context.Background()

	client, err := storage.NewClient(ctx)
	if err != nil {
		log.Fatalf("failed to create storage client: %v", err)
	}
	defer client.Close()

	googleapisBucket := client.Bucket(*googleapisBucketName)
	googleapisPkgs, err := names(ctx, googleapisBucket)
	if err != nil {
		log.Fatal(err)
	}

	cgcBucket := client.Bucket(*cgcBucketName)
	cgcPkgs, err := names(ctx, cgcBucket)
	if err != nil {
		log.Fatal(err)
	}

	excludeInRobots := []string{}
	for name := range googleapisPkgs {
		if _, ok := cgcPkgs[name]; ok {
			excludeInRobots = append(excludeInRobots, name)
		}
	}
	f, err := os.OpenFile(robotsFilename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0664)
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	if err := writeRobots(f, excludeInRobots); err != nil {
		log.Fatal(err)
	}
}

func names(ctx context.Context, bucket *storage.BucketHandle) (map[string]struct{}, error) {
	names := map[string]struct{}{}
	it := bucket.Objects(ctx, nil)
	for {
		obj, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return nil, err
		}
		if strings.HasPrefix(obj.Name, "docfx") || strings.HasPrefix(obj.Name, "xrefs") {
			continue
		}
		if !strings.HasPrefix(obj.Name, "dotnet") &&
			!strings.HasPrefix(obj.Name, "go") &&
			!strings.HasPrefix(obj.Name, "java") &&
			!strings.HasPrefix(obj.Name, "nodejs") &&
			!strings.HasPrefix(obj.Name, "python") &&
			!strings.HasPrefix(obj.Name, "ruby") {
			continue
		}
		name, err := trimVersion(obj.Name)
		if err != nil {
			return nil, err
		}
		names[name] = struct{}{}
	}
	return names, nil
}

func writeRobots(w io.Writer, excludes []string) error {
	fmt.Fprintf(w, "User-agent: *\n")

	sort.Strings(excludes)

	for _, exclude := range excludes {
		parts := strings.SplitN(exclude, "-", 2)
		lang := parts[0]
		pkg := parts[1]
		fmt.Fprintf(w, "Disallow: /%s/%s/\n", lang, pkg)
	}
	return nil
}

func trimVersion(name string) (string, error) {
	match := versionRE.FindStringIndex(name)
	if match == nil {
		return "", fmt.Errorf("invalid name: %q", name)
	}

	return name[:match[0]-1], nil
}
<|endoftext|>


<commit_before>package ssh

import (
	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/terminal"
	"log"
	"os"
)

func KeyboardInteractive() ssh.KeyboardInteractiveChallenge {
	return func(user, instruction string, questions []string, echos []bool) ([]string, error) {
		if len(questions) == 0 {
			return []string{}, nil
		}

		log.Printf("[INFO] -- User: %s", user)
		log.Printf("[INFO] -- Instructions: %s", instruction)
		for i, question := range questions {
			log.Printf("[INFO] -- Question %d: %s", i+1, question)
		}
		answers := make([]string, len(questions))
		for i := range questions {
			var fd int
			if terminal.IsTerminal(int(os.Stdin.Fd())) {
				fd = int(os.Stdin.Fd())
			} else {
				tty, err := os.Open("/dev/tty")
				if err != nil {
					return nil, err
				}
				defer tty.Close()
				fd = int(tty.Fd())
			}
			s, err := terminal.ReadPassword(fd)
			if err != nil {
				return nil, err
			}
			answers[i] = string(s)
		}
		return answers, nil
	}
}
<commit_msg>fix lint<commit_after>package ssh

import (
	"log"
	"os"

	"golang.org/x/crypto/ssh"
	"golang.org/x/crypto/ssh/terminal"
)

func KeyboardInteractive() ssh.KeyboardInteractiveChallenge {
	return func(user, instruction string, questions []string, echos []bool) ([]string, error) {
		if len(questions) == 0 {
			return []string{}, nil
		}

		log.Printf("[INFO] -- User: %s", user)
		log.Printf("[INFO] -- Instructions: %s", instruction)
		for i, question := range questions {
			log.Printf("[INFO] -- Question %d: %s", i+1, question)
		}
		answers := make([]string, len(questions))
		for i := range questions {
			var fd int
			if terminal.IsTerminal(int(os.Stdin.Fd())) {
				fd = int(os.Stdin.Fd())
			} else {
				tty, err := os.Open("/dev/tty")
				if err != nil {
					return nil, err
				}
				defer tty.Close()
				fd = int(tty.Fd())
			}
			s, err := terminal.ReadPassword(fd)
			if err != nil {
				return nil, err
			}
			answers[i] = string(s)
		}
		return answers, nil
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Copyright 2015 Cloudbase Solutions SRL
// Licensed under the AGPLv3, see LICENCE file for details.

package commands

const (
	// AptConfFilePath is the full file path for the proxy settings that are
	// written by cloud-init and the machine environ worker.
	AptConfFilePath = "/etc/apt/apt.conf.d/42-juju-proxy-settings"

	// the basic command for all dpkg calls:
	dpkg = "dpkg"

	// the basic command for all apt-get calls:
	//		--force-confold is passed to dpkg to never overwrite config files
	//		--force-unsafe-io makes dpkg less sync-happy
	//		--assume-yes to never prompt for confirmation
	aptget = "apt-get --option=Dpkg::Options::=--force-confold --option=Dpkg::options::=--force-unsafe-io --assume-yes --quiet"

	// the basic command for all apt-cache calls:
	aptcache = "apt-cache"

	// the basic command for all add-apt-repository calls:
	//		--yes to never prompt for confirmation
	addaptrepo = "add-apt-repository --yes"

	// the basic command for all apt-config calls:
	aptconfig = "apt-config dump"

	// the basic format for specifying a proxy option for apt:
	aptProxySettingFormat = "Acquire::%s::Proxy %q;"
)

// aptCmder is the packageCommander instantiation for apt-based systems.
var aptCmder = packageCommander{
	prereq:              buildCommand(aptget, "install python-software-properties"),
	update:              buildCommand(aptget, "update"),
	upgrade:             buildCommand(aptget, "upgrade"),
	install:             buildCommand(aptget, "install"),
	remove:              buildCommand(aptget, "remove"),
	purge:               buildCommand(aptget, "purge"),
	search:              buildCommand(aptcache, "search --names-only ^%s$"),
	isInstalled:         buildCommand(dpkg, "-s %s"),
	listAvailable:       buildCommand(aptcache, "pkgnames"),
	listInstalled:       buildCommand(dpkg, "--get-selections"),
	addRepository:       buildCommand(addaptrepo, "%s"),
	listRepositories:    buildCommand(`sed -r -n "s|^deb(-src)? (.*)|\2|p"`, "/etc/apt/sources.list"),
	removeRepository:    buildCommand(addaptrepo, "--remove ppa:%s"),
	cleanup:             buildCommand(aptget, "autoremove"),
	getProxy:            buildCommand(aptconfig, "Acquire::http::Proxy Acquire::https::Proxy Acquire::ftp::Proxy"),
	proxySettingsFormat: aptProxySettingFormat,
	setProxy:            buildCommand("echo %s >> ", AptConfFilePath),
}
<commit_msg>Fixed add-apt-repository quoting.<commit_after>// Copyright 2015 Canonical Ltd.
// Copyright 2015 Cloudbase Solutions SRL
// Licensed under the AGPLv3, see LICENCE file for details.

package commands

const (
	// AptConfFilePath is the full file path for the proxy settings that are
	// written by cloud-init and the machine environ worker.
	AptConfFilePath = "/etc/apt/apt.conf.d/42-juju-proxy-settings"

	// the basic command for all dpkg calls:
	dpkg = "dpkg"

	// the basic command for all apt-get calls:
	//		--force-confold is passed to dpkg to never overwrite config files
	//		--force-unsafe-io makes dpkg less sync-happy
	//		--assume-yes to never prompt for confirmation
	aptget = "apt-get --option=Dpkg::Options::=--force-confold --option=Dpkg::options::=--force-unsafe-io --assume-yes --quiet"

	// the basic command for all apt-cache calls:
	aptcache = "apt-cache"

	// the basic command for all add-apt-repository calls:
	//		--yes to never prompt for confirmation
	addaptrepo = "add-apt-repository --yes"

	// the basic command for all apt-config calls:
	aptconfig = "apt-config dump"

	// the basic format for specifying a proxy option for apt:
	aptProxySettingFormat = "Acquire::%s::Proxy %q;"
)

// aptCmder is the packageCommander instantiation for apt-based systems.
var aptCmder = packageCommander{
	prereq:              buildCommand(aptget, "install python-software-properties"),
	update:              buildCommand(aptget, "update"),
	upgrade:             buildCommand(aptget, "upgrade"),
	install:             buildCommand(aptget, "install"),
	remove:              buildCommand(aptget, "remove"),
	purge:               buildCommand(aptget, "purge"),
	search:              buildCommand(aptcache, "search --names-only ^%s$"),
	isInstalled:         buildCommand(dpkg, "-s %s"),
	listAvailable:       buildCommand(aptcache, "pkgnames"),
	listInstalled:       buildCommand(dpkg, "--get-selections"),
	addRepository:       buildCommand(addaptrepo, "%q"),
	listRepositories:    buildCommand(`sed -r -n "s|^deb(-src)? (.*)|\2|p"`, "/etc/apt/sources.list"),
	removeRepository:    buildCommand(addaptrepo, "--remove ppa:%s"),
	cleanup:             buildCommand(aptget, "autoremove"),
	getProxy:            buildCommand(aptconfig, "Acquire::http::Proxy Acquire::https::Proxy Acquire::ftp::Proxy"),
	proxySettingsFormat: aptProxySettingFormat,
	setProxy:            buildCommand("echo %s >> ", AptConfFilePath),
}
<|endoftext|>


<commit_before>package backend

import (
	"github.com/golang/glog"
	"github.com/nelhage/livegrep/client"
	"github.com/nelhage/livegrep/config"
	"sync"
	"time"
)

const (
	PoolSize = 4
)

type Repo struct {
	Name   string
	Github string
}

type I struct {
	Name  string
	Repos []Repo
	sync.Mutex
}

type Backend struct {
	Addr    string
	Id      string
	I       *I
	Clients chan client.Client
	pending chan struct{}
}

func New(cfg *config.Backend) *Backend {
	bk := &Backend{
		Addr:    cfg.Addr,
		Id:      cfg.Id,
		I:       &I{Name: cfg.Name},
		Clients: make(chan client.Client, PoolSize),
		pending: make(chan struct{}, PoolSize),
	}
	for _, r := range cfg.Repos {
		bk.I.Repos = append(bk.I.Repos, Repo{Name: r.Name, Github: r.Github})
	}
	for i := 0; i < PoolSize; i++ {
		bk.pending <- struct{}{}
	}
	go bk.connectLoop()
	return bk
}

func (bk *Backend) CheckIn(c client.Client) {
	if c.Err() != nil {
		c.Close()
		bk.pending <- struct{}{}
		return
	}

	bk.Clients <- c
}

func (bk *Backend) connectLoop() {
	for _ = range bk.pending {
		for {
			cl, err := client.Dial("tcp", bk.Addr)
			if err != nil {
				glog.Infof("Connection error: %s", err.Error())
				time.Sleep(5 * time.Second)
				continue
			}
			glog.Infof("Connected, backend=%s addr=%s",
				bk.Id, bk.Addr)

			if info := cl.Info(); info != nil {
				bk.refresh(info)
			}
			bk.Clients <- cl
			break
		}
	}
}

func (bk *Backend) refresh(info *client.ServerInfo) {
	bk.I.Lock()
	defer bk.I.Unlock()

	if info.Name != "" {
		bk.I.Name = info.Name
	}
	if len(info.Repos) > 0 {
		bk.I.Repos = nil
		for _, r := range info.Repos {
			gh := ""
			v, ok := r.Metadata["github"]
			if ok {
				gh = v.(string)
			}
			bk.I.Repos = append(bk.I.Repos,
				Repo{r.Name, gh})
		}
	}
}

/*
		&backend{
		config:  &bk,
		clients: make(chan client.Client, ClientPoolSize),
	}
*/
<commit_msg>Bump the backend connection pool size.<commit_after>package backend

import (
	"github.com/golang/glog"
	"github.com/nelhage/livegrep/client"
	"github.com/nelhage/livegrep/config"
	"sync"
	"time"
)

const (
	PoolSize = 8
)

type Repo struct {
	Name   string
	Github string
}

type I struct {
	Name  string
	Repos []Repo
	sync.Mutex
}

type Backend struct {
	Addr    string
	Id      string
	I       *I
	Clients chan client.Client
	pending chan struct{}
}

func New(cfg *config.Backend) *Backend {
	bk := &Backend{
		Addr:    cfg.Addr,
		Id:      cfg.Id,
		I:       &I{Name: cfg.Name},
		Clients: make(chan client.Client, PoolSize),
		pending: make(chan struct{}, PoolSize),
	}
	for _, r := range cfg.Repos {
		bk.I.Repos = append(bk.I.Repos, Repo{Name: r.Name, Github: r.Github})
	}
	for i := 0; i < PoolSize; i++ {
		bk.pending <- struct{}{}
	}
	go bk.connectLoop()
	return bk
}

func (bk *Backend) CheckIn(c client.Client) {
	if c.Err() != nil {
		c.Close()
		bk.pending <- struct{}{}
		return
	}

	bk.Clients <- c
}

func (bk *Backend) connectLoop() {
	for _ = range bk.pending {
		for {
			cl, err := client.Dial("tcp", bk.Addr)
			if err != nil {
				glog.Infof("Connection error: %s", err.Error())
				time.Sleep(5 * time.Second)
				continue
			}
			glog.Infof("Connected, backend=%s addr=%s",
				bk.Id, bk.Addr)

			if info := cl.Info(); info != nil {
				bk.refresh(info)
			}
			bk.Clients <- cl
			break
		}
	}
}

func (bk *Backend) refresh(info *client.ServerInfo) {
	bk.I.Lock()
	defer bk.I.Unlock()

	if info.Name != "" {
		bk.I.Name = info.Name
	}
	if len(info.Repos) > 0 {
		bk.I.Repos = nil
		for _, r := range info.Repos {
			gh := ""
			v, ok := r.Metadata["github"]
			if ok {
				gh = v.(string)
			}
			bk.I.Repos = append(bk.I.Repos,
				Repo{r.Name, gh})
		}
	}
}

/*
		&backend{
		config:  &bk,
		clients: make(chan client.Client, ClientPoolSize),
	}
*/
<|endoftext|>


<commit_before>package main

import (
	"io/ioutil"

	yaml "gopkg.in/yaml.v1"
)

func LoadYAML(path string, v interface{}) error {
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return nil
	}

	err = yaml.Unmarshal(b, v)
	return err
}
<commit_msg>Fiddled with the YAML parser a bit more<commit_after>package main

import (
	"io/ioutil"

	yaml "gopkg.in/yaml.v1"
)

type (
	RawYAML map[string]interface{}
)

func LoadYAML(path string) (RawYAML, error) {
	var y RawYAML
	b, err := ioutil.ReadFile(path)
	if err != nil {
		return y, err
	}

	err = yaml.Unmarshal(b, &y)
	return y, err
}

func (y RawYAML) ToString(key string) string {
	if v, found := y[key]; found {
		if s, ok := v.(string); ok {
			delete(y, key)
			return s
		}
	}
	return ""
}

func (y RawYAML) ToStringSlice(key string) []string {
	if v, found := y[key]; found {
		if s, ok := v.([]string); ok {
			delete(y, key)
			return s
		}
	}
	return nil
}

func (y RawYAML) Length() int {
	return len(y)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"testing"
)

func TestInitMap(t *testing.T) {
	m := make(map[int]int)
	n := 10
	initMap(m, n)
	got := len(m)
	if got != n {
		t.Errorf("initMap: len = %d; want %d", got, n)
	}
}

var result map[int]int

var benchs = []int{100} //, 1000, 10000}

func BenchmarkMaps(b *testing.B) {
	var name string
	for _, bb := range benchs {

		name = fmt.Sprintf("baseMap(%d)", bb)
		b.Run(name, func(b *testing.B) {
			m := make(map[int]int)
			b.ResetTimer()
			for n := 0; n < b.N; n++ {
				initMap(m, bb)
			}
			result = m
		})

	}
}
<commit_msg>mapcap: clean benchmarks<commit_after>package main

import (
	"fmt"
	"testing"
)

func TestInitMap(t *testing.T) {
	m := make(map[int]int)
	n := 10
	initMap(m, n)
	got := len(m)
	if got != n {
		t.Errorf("initMap: len = %d; want %d", got, n)
	}
}

var result map[int]int

var benchs = []int{30000, 100000} //, 1000, 10000}

func BenchmarkMaps(b *testing.B) {
	var name string
	for _, bb := range benchs {

		name = fmt.Sprintf("base(%d)", bb)
		b.Run(name, func(b *testing.B) {
			m := make(map[int]int)
			b.ResetTimer()
			for n := 0; n < b.N; n++ {
				initMap(m, bb)
			}
			result = m
		})

		name = fmt.Sprintf("cap(%d)", bb)
		b.Run(name, func(b *testing.B) {
			m := make(map[int]int, bb)
			b.ResetTimer()
			for n := 0; n < b.N; n++ {
				initMap(m, bb)
			}
			result = m
		})

	}
}
<|endoftext|>


<commit_before>package main

import (
	"sync"

	"github.com/flynn/flynn/router/types"
)

type Watcher interface {
	Watch(chan *strowger.Event)
	Unwatch(chan *strowger.Event)
}

func NewWatchManager() *WatchManager {
	return &WatchManager{watchers: make(map[chan *strowger.Event]struct{})}
}

type WatchManager struct {
	mtx      sync.RWMutex
	watchers map[chan *strowger.Event]struct{}
}

func (m *WatchManager) Watch(ch chan *strowger.Event) {
	m.mtx.Lock()
	m.watchers[ch] = struct{}{}
	m.mtx.Unlock()
}

func (m *WatchManager) Unwatch(ch chan *strowger.Event) {
	go func() {
		// drain channel so that we don't deadlock
		for _ = range ch {
		}
	}()
	m.mtx.Lock()
	delete(m.watchers, ch)
	m.mtx.Unlock()
}

func (m *WatchManager) Send(event *strowger.Event) {
	m.mtx.RLock()
	defer m.mtx.RUnlock()
	for ch := range m.watchers {
		ch <- event
	}
}
<commit_msg>router: Fix goroutine leak<commit_after>package main

import (
	"sync"

	"github.com/flynn/flynn/router/types"
)

type Watcher interface {
	Watch(chan *strowger.Event)
	Unwatch(chan *strowger.Event)
}

func NewWatchManager() *WatchManager {
	return &WatchManager{watchers: make(map[chan *strowger.Event]struct{})}
}

type WatchManager struct {
	mtx      sync.RWMutex
	watchers map[chan *strowger.Event]struct{}
}

func (m *WatchManager) Watch(ch chan *strowger.Event) {
	m.mtx.Lock()
	m.watchers[ch] = struct{}{}
	m.mtx.Unlock()
}

func (m *WatchManager) Unwatch(ch chan *strowger.Event) {
	go func() {
		// drain channel so that we don't deadlock
		for _ = range ch {
		}
	}()
	m.mtx.Lock()
	delete(m.watchers, ch)
	m.mtx.Unlock()
	close(ch)
}

func (m *WatchManager) Send(event *strowger.Event) {
	m.mtx.RLock()
	defer m.mtx.RUnlock()
	for ch := range m.watchers {
		ch <- event
	}
}
<|endoftext|>


<commit_before>package routers

import (
	"xcfg-server/controllers"
	"xcfg-server/models"

	"github.com/astaxie/beego/context"

	"strings"

	"github.com/astaxie/beego"
)

func init() {
	beego.Router("/", &controllers.MainController{})

	beego.Router("/auth/login", &controllers.AuthController{}, "post:Login")
	beego.Router("/auth/checkpwd", &controllers.AuthController{}, "post:CheckPwd")
	beego.Router("/auth/mod", &controllers.AuthController{}, "post:ModPwd")
	beego.Router("/auth/menus", &controllers.AuthController{}, "get:GetMenus")

	beego.Router("/user/list", &controllers.UserController{}, "post:GetUsers")
	beego.Router("/user/disable", &controllers.UserController{}, "post:DisableUser")
	beego.Router("/user/enable", &controllers.UserController{}, "post:EnableUser")
	beego.Router("/user/add", &controllers.UserController{}, "post:AddUser")
	beego.Router("/user/exists", &controllers.UserController{}, "post:IsExists")
	beego.Router("/user/get", &controllers.UserController{}, "get:GetUser")
	beego.Router("/user/roles", &controllers.UserController{}, "get:GetUserRoles")
	beego.Router("/user/update", &controllers.UserController{}, "post:UpdateUser")

	beego.Router("/role/list", &controllers.RoleController{}, "post:GetRoles")
	beego.Router("/role/add", &controllers.RoleController{}, "post:AddRole")
	beego.Router("/role/exists", &controllers.RoleController{}, "post:IsExists")
	beego.Router("/role/get", &controllers.RoleController{}, "get:GetRole")
	beego.Router("/role/update", &controllers.RoleController{}, "post:UpdateRole")
	beego.Router("/role/resources", &controllers.RoleController{}, "get:GetRoleMenus")

	beego.Router("/menu/list", &controllers.RoleController{}, "post:GetMenus")

	beego.Router("/ConfigVersionHandler.ashx", &controllers.CfgController{}, "post:Post")
	beego.Router("/cfg/list", &controllers.CfgController{}, "post:GetCfgs")
	beego.Router("/cfghistory/list", &controllers.CfgHistroyController{}, "post:GetCfgHistorys")
	beego.Router("/cfghistory/rollback", &controllers.CfgHistroyController{}, "post:RollBack")
	beego.Router("/cfghistory/get", &controllers.CfgHistroyController{}, "get:Get")
	beego.Router("/cfghistory/getTemplate", &controllers.CfgHistroyController{}, "get:GetTemplate")
	beego.Router("/cfg/add", &controllers.CfgController{}, "post:AddCfg")
	beego.Router("/cfg/exists", &controllers.CfgController{}, "post:Exists")
	beego.Router("/cfg/get", &controllers.CfgController{}, "get:GetCfg")
	beego.Router("/xcfg/get", &controllers.CfgController{}, "get:Get")
	beego.Router("/xcfg/getTemplate", &controllers.CfgController{}, "get:GetTemplate")
	beego.Router("/cfg/update", &controllers.CfgController{}, "post:UpdateCfg")

	var FilterUser = func(ctx *context.Context) {
		ctx.Output.Header("Access-Control-Allow-Origin","*")
		return
		requestURI := ctx.Request.RequestURI
		if requestURI == "/notfound" || requestURI == "/" || requestURI == "/ConfigVersionHandler.ashx" || strings.HasPrefix(requestURI, "/xcfg/get") {
			return
		}
		isPass := false
		//白名单
		menus := models.GetWhiteListByMenuIds()
		for _, v := range menus {
			if strings.HasPrefix(requestURI, v.Url) {
				isPass = true
			}
		}

		if isPass {
			return
		}
		//需要登录
		adAuthCookie := ctx.Input.Cookie("adAuthCookie")
		if adAuthCookie != "true" && requestURI != "/" {
			ctx.Redirect(302, "/")
		}
		//用户权限
		un := ctx.GetCookie("loginUser")
		if un != "admin" && ctx.Input.Session("userId") != nil {

			id := ctx.Input.Session("userId").(int)
			roles := models.GetRolesByUserId(id)
			menuIds := []int{0}
			for _, v := range roles {
				rms := models.GetMenusByRoleId(v.RoleId)
				for _, rm := range rms {
					menuIds = append(menuIds, rm.MenuId)
				}
			}
			menus := models.GetResourcesByMenuIds(menuIds)
			for _, v := range menus {
				if strings.HasPrefix(requestURI, v.Url) {
					isPass = true
				}
			}
			if !isPass {
				ctx.Redirect(302, "/notfound")
			}
		}

	}

	beego.InsertFilter("/*", beego.BeforeRouter, FilterUser)
}
<commit_msg>form support<commit_after>package routers

import (
	"xcfg-server/controllers"
	"xcfg-server/models"

	"github.com/astaxie/beego/context"

	"strings"

	"github.com/astaxie/beego"
)

func init() {
	beego.Router("/", &controllers.MainController{})

	beego.Router("/auth/login", &controllers.AuthController{}, "post:Login")
	beego.Router("/auth/checkpwd", &controllers.AuthController{}, "post:CheckPwd")
	beego.Router("/auth/mod", &controllers.AuthController{}, "post:ModPwd")
	beego.Router("/auth/menus", &controllers.AuthController{}, "get:GetMenus")

	beego.Router("/user/list", &controllers.UserController{}, "post:GetUsers")
	beego.Router("/user/disable", &controllers.UserController{}, "post:DisableUser")
	beego.Router("/user/enable", &controllers.UserController{}, "post:EnableUser")
	beego.Router("/user/add", &controllers.UserController{}, "post:AddUser")
	beego.Router("/user/exists", &controllers.UserController{}, "post:IsExists")
	beego.Router("/user/get", &controllers.UserController{}, "get:GetUser")
	beego.Router("/user/roles", &controllers.UserController{}, "get:GetUserRoles")
	beego.Router("/user/update", &controllers.UserController{}, "post:UpdateUser")

	beego.Router("/role/list", &controllers.RoleController{}, "post:GetRoles")
	beego.Router("/role/add", &controllers.RoleController{}, "post:AddRole")
	beego.Router("/role/exists", &controllers.RoleController{}, "post:IsExists")
	beego.Router("/role/get", &controllers.RoleController{}, "get:GetRole")
	beego.Router("/role/update", &controllers.RoleController{}, "post:UpdateRole")
	beego.Router("/role/resources", &controllers.RoleController{}, "get:GetRoleMenus")

	beego.Router("/menu/list", &controllers.RoleController{}, "post:GetMenus")

	beego.Router("/ConfigVersionHandler.ashx", &controllers.CfgController{}, "post:Post")
	beego.Router("/cfg/list", &controllers.CfgController{}, "post:GetCfgs")
	beego.Router("/cfghistory/list", &controllers.CfgHistroyController{}, "post:GetCfgHistorys")
	beego.Router("/cfghistory/rollback", &controllers.CfgHistroyController{}, "post:RollBack")
	beego.Router("/cfghistory/get", &controllers.CfgHistroyController{}, "get:Get")
	beego.Router("/cfghistory/getTemplate", &controllers.CfgHistroyController{}, "get:GetTemplate")
	beego.Router("/cfg/add", &controllers.CfgController{}, "post:AddCfg")
	beego.Router("/cfg/exists", &controllers.CfgController{}, "post:Exists")
	beego.Router("/cfg/get", &controllers.CfgController{}, "get:GetCfg")
	beego.Router("/xcfg/get", &controllers.CfgController{}, "get:Get")
	beego.Router("/xcfg/getTemplate", &controllers.CfgController{}, "get:GetTemplate")
	beego.Router("/cfg/update", &controllers.CfgController{}, "post:UpdateCfg")

	var FilterUser = func(ctx *context.Context) {
		//ctx.Output.Header("Access-Control-Allow-Origin","*")
		//return
		requestURI := ctx.Request.RequestURI
		if requestURI == "/notfound" || requestURI == "/" || requestURI == "/ConfigVersionHandler.ashx" || strings.HasPrefix(requestURI, "/xcfg/get") {
			return
		}
		isPass := false
		//白名单
		menus := models.GetWhiteListByMenuIds()
		for _, v := range menus {
			if strings.HasPrefix(requestURI, v.Url) {
				isPass = true
			}
		}

		if isPass {
			return
		}
		//需要登录
		adAuthCookie := ctx.Input.Cookie("adAuthCookie")
		if adAuthCookie != "true" && requestURI != "/" {
			ctx.Redirect(302, "/")
		}
		//用户权限
		un := ctx.GetCookie("loginUser")
		if un != "admin" && ctx.Input.Session("userId") != nil {

			id := ctx.Input.Session("userId").(int)
			roles := models.GetRolesByUserId(id)
			menuIds := []int{0}
			for _, v := range roles {
				rms := models.GetMenusByRoleId(v.RoleId)
				for _, rm := range rms {
					menuIds = append(menuIds, rm.MenuId)
				}
			}
			menus := models.GetResourcesByMenuIds(menuIds)
			for _, v := range menus {
				if strings.HasPrefix(requestURI, v.Url) {
					isPass = true
				}
			}
			if !isPass {
				ctx.Redirect(302, "/notfound")
			}
		}

	}

	beego.InsertFilter("/*", beego.BeforeRouter, FilterUser)
}
<|endoftext|>


<commit_before>package zest

import (
	"fmt"
	"net/http"
	"os"

	"github.com/codegangsta/negroni"
	"github.com/dimfeld/httptreemux"
	"github.com/rs/cors"
	"github.com/solher/zest/infrastructure"
	"github.com/solher/zest/middlewares"
	"github.com/solher/zest/resources"
	"github.com/solher/zest/usecases"
)

type Zest struct {
	Port, Environment, DatabaseURL string

	App      *negroni.Negroni
	Injector *infrastructure.Injector
	Swagger  *infrastructure.Swagger

	HandleOsArgs     func(z *Zest) (bool, error)
	Build            func(z *Zest) error
	AfterBuild       func(z *Zest) error
	Init             func(z *Zest) error
	AfterInit        func(z *Zest) error
	Close            func(z *Zest) error
	ReinitDatabase   func(z *Zest) error
	SeedDatabase     func(z *Zest) error
	UserSeedDatabase func(z *Zest) error
	UpdateDatabase   func(z *Zest) error
}

func New() *Zest {
	return &Zest{
		Environment: "development",
		Port:        ":3000",
		App:         negroni.New(),
		Swagger:     infrastructure.NewSwagger(),
		Injector:    infrastructure.NewInjector(),
	}
}

func Classic() *Zest {
	zest := &Zest{
		Environment:      "development",
		Port:             ":3000",
		App:              negroni.New(),
		Swagger:          infrastructure.NewSwagger(),
		Injector:         infrastructure.NewInjector(),
		HandleOsArgs:     handleOsArgs,
		Build:            buildApp,
		AfterBuild:       func(z *Zest) error { return nil },
		Init:             initApp,
		AfterInit:        func(z *Zest) error { return nil },
		Close:            closeApp,
		ReinitDatabase:   reinitDatabase,
		SeedDatabase:     seedDatabase,
		UserSeedDatabase: userSeedDatabase,
		UpdateDatabase:   updateDatabase,
	}

	env := os.Getenv("GOENV")
	if env == "development" || env == "production" {
		zest.Environment = env
	}

	port := os.Getenv("PORT")
	if port != "" {
		zest.Port = ":" + os.Getenv("PORT")
	}

	zest.DatabaseURL = os.Getenv("DATABASE_URL")

	return zest
}

func (z *Zest) Run() {
	err := z.Build(z)
	if err != nil {
		panic(err)
	}

	mustExit, err := z.HandleOsArgs(z)
	if err != nil {
		panic(err)
	}

	if mustExit {
		return
	}

	err = z.AfterBuild(z)
	if err != nil {
		panic(err)
	}

	err = z.Init(z)
	if err != nil {
		panic(err)
	}
	defer z.Close(z)

	err = z.AfterInit(z)
	if err != nil {
		panic(err)
	}

	z.App.Run(z.Port)
}

func handleOsArgs(z *Zest) (bool, error) {
	var err error

	if len(os.Args) > 1 {
		switch os.Args[1] {
		case "resetDB":
			err = z.ReinitDatabase(z)
			if err != nil {
				return true, err
			}
			err = z.SeedDatabase(z)
			if err != nil {
				return true, err
			}
			return true, nil
		case "updateDB":
			err = z.UpdateDatabase(z)
			if err != nil {
				return true, err
			}
			return true, nil
		case "generateDoc":
			err = z.Swagger.Generate()
			if err != nil {
				return true, err
			}
			return true, nil
		default:
			fmt.Printf("Unknown command. Available: resetDB, updateDB, generateDoc")
			return true, nil
		}
	}

	return false, nil
}

func buildApp(z *Zest) error {
	deps := usecases.DependencyDirectory.Get()

	store := infrastructure.NewGormStore()
	accountRepo := resources.NewAccountRepo(store)
	aclRepo := resources.NewAclRepo(store)
	sessionRepo := resources.NewSessionRepo(store)

	deps = append(
		deps,

		store,
		accountRepo,
		aclRepo,
		sessionRepo,
		httptreemux.New(),
		infrastructure.NewRender(),
		infrastructure.NewCacheStore(),
		usecases.NewPermissionCacheInter(accountRepo, aclRepo, infrastructure.NewCacheStore(), infrastructure.NewCacheStore()),
		usecases.NewSessionCacheInter(sessionRepo, infrastructure.NewLRUCacheStore(1024)),
		usecases.NewRouteDirectory,
		usecases.NewPermissionInter,
	)

	z.Injector.RegisterMultiple(deps)

	err := z.Injector.Populate()
	if err != nil {
		return err
	}

	type dependencies struct {
		RouteDir *usecases.RouteDirectory
		Render   *infrastructure.Render
	}

	d := &dependencies{}
	err = z.Injector.Get(d)
	if err != nil {
		return err
	}

	z.Swagger.AddRoutes(d.RouteDir)

	handler := func(w http.ResponseWriter, r *http.Request, _ map[string]string) {
		http.ServeFile(w, r, "./swagger-ui/images/favicon.ico")
	}
	d.RouteDir.Add(usecases.NewDirectoryKey("static").For("Favicon"), &usecases.Route{Method: "GET", Path: "/favicon.ico", Handler: handler, Visible: true, CheckPermissions: false})

	return nil
}

func initApp(z *Zest) error {
	type dependencies struct {
		Router *httptreemux.TreeMux

		Store *infrastructure.GormStore

		SessionCacheInter    *usecases.SessionCacheInter
		PermissionCacheInter *usecases.PermissionCacheInter
		AccountGuestInter    *resources.AccountGuestInter

		RouteDir *usecases.RouteDirectory
		Render   *infrastructure.Render
	}

	d := &dependencies{}
	err := z.Injector.Get(d)
	if err != nil {
		return err
	}

	if z.DatabaseURL != "" {
		err = d.Store.Connect("postgres", z.DatabaseURL)
	} else {
		err = d.Store.Connect("sqlite3", "database.db")
	}
	if err != nil {
		return err
	}

	d.SessionCacheInter.Refresh()
	d.PermissionCacheInter.Refresh()

	d.RouteDir.Register(d.Router)

	z.App.Use(middlewares.NewLogger())
	z.App.Use(middlewares.NewRecovery(d.Render))
	z.App.Use(cors.Default())
	z.App.Use(middlewares.NewSessions(d.AccountGuestInter))

	d.Router.RedirectBehavior = httptreemux.UseHandler

	z.App.UseHandler(d.Router)

	return nil
}

func closeApp(z *Zest) error {
	type dependencies struct {
		Store *infrastructure.GormStore
	}

	d := &dependencies{}
	err := z.Injector.Get(d)
	if err != nil {
		return err
	}

	d.Store.Close()

	return nil
}
<commit_msg>Printf fixed.<commit_after>package zest

import (
	"fmt"
	"net/http"
	"os"

	"github.com/codegangsta/negroni"
	"github.com/dimfeld/httptreemux"
	"github.com/rs/cors"
	"github.com/solher/zest/infrastructure"
	"github.com/solher/zest/middlewares"
	"github.com/solher/zest/resources"
	"github.com/solher/zest/usecases"
)

type Zest struct {
	Port, Environment, DatabaseURL string

	App      *negroni.Negroni
	Injector *infrastructure.Injector
	Swagger  *infrastructure.Swagger

	HandleOsArgs     func(z *Zest) (bool, error)
	Build            func(z *Zest) error
	AfterBuild       func(z *Zest) error
	Init             func(z *Zest) error
	AfterInit        func(z *Zest) error
	Close            func(z *Zest) error
	ReinitDatabase   func(z *Zest) error
	SeedDatabase     func(z *Zest) error
	UserSeedDatabase func(z *Zest) error
	UpdateDatabase   func(z *Zest) error
}

func New() *Zest {
	return &Zest{
		Environment: "development",
		Port:        ":3000",
		App:         negroni.New(),
		Swagger:     infrastructure.NewSwagger(),
		Injector:    infrastructure.NewInjector(),
	}
}

func Classic() *Zest {
	zest := &Zest{
		Environment:      "development",
		Port:             ":3000",
		App:              negroni.New(),
		Swagger:          infrastructure.NewSwagger(),
		Injector:         infrastructure.NewInjector(),
		HandleOsArgs:     handleOsArgs,
		Build:            buildApp,
		AfterBuild:       func(z *Zest) error { return nil },
		Init:             initApp,
		AfterInit:        func(z *Zest) error { return nil },
		Close:            closeApp,
		ReinitDatabase:   reinitDatabase,
		SeedDatabase:     seedDatabase,
		UserSeedDatabase: userSeedDatabase,
		UpdateDatabase:   updateDatabase,
	}

	env := os.Getenv("GOENV")
	if env == "development" || env == "production" {
		zest.Environment = env
	}

	port := os.Getenv("PORT")
	if port != "" {
		zest.Port = ":" + os.Getenv("PORT")
	}

	zest.DatabaseURL = os.Getenv("DATABASE_URL")

	return zest
}

func (z *Zest) Run() {
	err := z.Build(z)
	if err != nil {
		panic(err)
	}

	mustExit, err := z.HandleOsArgs(z)
	if err != nil {
		panic(err)
	}

	if mustExit {
		return
	}

	err = z.AfterBuild(z)
	if err != nil {
		panic(err)
	}

	err = z.Init(z)
	if err != nil {
		panic(err)
	}
	defer z.Close(z)

	err = z.AfterInit(z)
	if err != nil {
		panic(err)
	}

	z.App.Run(z.Port)
}

func handleOsArgs(z *Zest) (bool, error) {
	var err error

	if len(os.Args) > 1 {
		switch os.Args[1] {
		case "resetDB":
			err = z.ReinitDatabase(z)
			if err != nil {
				return true, err
			}
			err = z.SeedDatabase(z)
			if err != nil {
				return true, err
			}
			return true, nil
		case "updateDB":
			err = z.UpdateDatabase(z)
			if err != nil {
				return true, err
			}
			return true, nil
		case "generateDoc":
			err = z.Swagger.Generate()
			if err != nil {
				return true, err
			}
			return true, nil
		default:
			fmt.Println("Unknown command. Available: resetDB, updateDB, generateDoc")
			return true, nil
		}
	}

	return false, nil
}

func buildApp(z *Zest) error {
	deps := usecases.DependencyDirectory.Get()

	store := infrastructure.NewGormStore()
	accountRepo := resources.NewAccountRepo(store)
	aclRepo := resources.NewAclRepo(store)
	sessionRepo := resources.NewSessionRepo(store)

	deps = append(
		deps,

		store,
		accountRepo,
		aclRepo,
		sessionRepo,
		httptreemux.New(),
		infrastructure.NewRender(),
		infrastructure.NewCacheStore(),
		usecases.NewPermissionCacheInter(accountRepo, aclRepo, infrastructure.NewCacheStore(), infrastructure.NewCacheStore()),
		usecases.NewSessionCacheInter(sessionRepo, infrastructure.NewLRUCacheStore(1024)),
		usecases.NewRouteDirectory,
		usecases.NewPermissionInter,
	)

	z.Injector.RegisterMultiple(deps)

	err := z.Injector.Populate()
	if err != nil {
		return err
	}

	type dependencies struct {
		RouteDir *usecases.RouteDirectory
		Render   *infrastructure.Render
	}

	d := &dependencies{}
	err = z.Injector.Get(d)
	if err != nil {
		return err
	}

	z.Swagger.AddRoutes(d.RouteDir)

	handler := func(w http.ResponseWriter, r *http.Request, _ map[string]string) {
		http.ServeFile(w, r, "./swagger-ui/images/favicon.ico")
	}
	d.RouteDir.Add(usecases.NewDirectoryKey("static").For("Favicon"), &usecases.Route{Method: "GET", Path: "/favicon.ico", Handler: handler, Visible: true, CheckPermissions: false})

	return nil
}

func initApp(z *Zest) error {
	type dependencies struct {
		Router *httptreemux.TreeMux

		Store *infrastructure.GormStore

		SessionCacheInter    *usecases.SessionCacheInter
		PermissionCacheInter *usecases.PermissionCacheInter
		AccountGuestInter    *resources.AccountGuestInter

		RouteDir *usecases.RouteDirectory
		Render   *infrastructure.Render
	}

	d := &dependencies{}
	err := z.Injector.Get(d)
	if err != nil {
		return err
	}

	if z.DatabaseURL != "" {
		err = d.Store.Connect("postgres", z.DatabaseURL)
	} else {
		err = d.Store.Connect("sqlite3", "database.db")
	}
	if err != nil {
		return err
	}

	d.SessionCacheInter.Refresh()
	d.PermissionCacheInter.Refresh()

	d.RouteDir.Register(d.Router)

	z.App.Use(middlewares.NewLogger())
	z.App.Use(middlewares.NewRecovery(d.Render))
	z.App.Use(cors.Default())
	z.App.Use(middlewares.NewSessions(d.AccountGuestInter))

	d.Router.RedirectBehavior = httptreemux.UseHandler

	z.App.UseHandler(d.Router)

	return nil
}

func closeApp(z *Zest) error {
	type dependencies struct {
		Store *infrastructure.GormStore
	}

	d := &dependencies{}
	err := z.Injector.Get(d)
	if err != nil {
		return err
	}

	d.Store.Close()

	return nil
}
<|endoftext|>


<commit_before>// Package zest contains a lightweight framework based on the codegangsta/cli package allowing
// clean and easy command line interfaces, the codegangsta/negroni middleware
// handler, and the solher/syringe injector.
//
// Zest encourages the use of small, well chosen individual dependencies
// instead of high productivity, full-stack frameworks.
package zest

import (
	"fmt"
	"os"
	"time"

	"gopkg.in/tylerb/graceful.v1"

	"github.com/codegangsta/cli"
	"github.com/codegangsta/negroni"
	"github.com/dimfeld/httptreemux"
	"github.com/rs/cors"
	"github.com/solher/syringe"
)

// Injector provide a quick access to an instanciated injector.
var Injector = syringe.New()

// SeqFunc is the prototype of the functions present in the exit/init sequences.
type SeqFunc func(z *Zest) error

// Zest is an aggregation of well known and efficient package, also providing
// a simple init/exit process to the user.
//
// Init and exit sequences are run following the order of the array, at each
// start/stop of the app, thanks to Cli and the tylerb/graceful module.
type Zest struct {
	cli     *cli.App
	Context *cli.Context

	Server   *negroni.Negroni
	Injector *syringe.Syringe

	InitSequence []SeqFunc
	ExitSequence []SeqFunc
}

// Cli returns a copy of the embedded Cli app.
func (z *Zest) Cli() cli.App {
	return *z.cli
}

// SetCli sets a copy of the embedded Cli app.
func (z *Zest) SetCli(cli cli.App) {
	*z.cli = cli
}

// Run starts the Cli app.
func (z *Zest) Run() {
	z.cli.Run(os.Args)
}

// Classic returns a new instance of Zest, with some default init steps, in this order :
// "classicRegister" which registers the default dependencies (Render, Httptreemux) in the injector.
// "classicBuild" which triggers the dependency injection of the app.
// "classicInit" which initialize the Httptreemux router and the default middlewares in Negroni.
func Classic() *Zest {
	z := New()

	z.InitSequence = append([]SeqFunc{classicRegister}, z.InitSequence...)
	z.InitSequence = append(z.InitSequence, classicInit)

	return z
}

// New returns a new instance of Zest.
func New() *Zest {
	z := &Zest{
		cli:      cli.NewApp(),
		Server:   negroni.New(),
		Injector: Injector,
	}

	z.InitSequence = append(z.InitSequence, classicBuild)

	z.cli.Usage = "A Zest powered service."
	z.cli.Before = z.init
	z.cli.After = z.exit
	z.cli.Action = z.run
	z.cli.Flags = []cli.Flag{
		cli.IntFlag{
			Name:  "port,p",
			Value: 3000,
			Usage: "listening port",
		},
		cli.IntFlag{
			Name:  "exitTimeout,t",
			Value: 10,
			Usage: "graceful shutdown timeout in seconds (0 for infinite)",
		},
	}

	return z
}

func (z *Zest) init(c *cli.Context) error {
	z.Context = c

	for _, f := range z.InitSequence {
		if err := f(z); err != nil {
			return err
		}
	}

	return nil
}

func (z *Zest) run(c *cli.Context) {
	z.Context = c

	port := fmt.Sprintf(":%d", z.Context.GlobalInt("port"))
	exitTimeout := time.Duration(z.Context.GlobalInt("exitTimeout")) * time.Second

	fmt.Println("\n[Zest] Running on " + port)

	graceful.Run(port, exitTimeout, z.Server)
}

func (z *Zest) exit(c *cli.Context) error {
	z.Context = c

	for _, f := range z.ExitSequence {
		if err := f(z); err != nil {
			return err
		}
	}

	return nil
}

func classicRegister(z *Zest) error {
	z.Injector.Register(NewRender(), httptreemux.New())

	return nil
}

func classicBuild(z *Zest) error {
	return z.Injector.Inject()
}

func classicInit(z *Zest) error {
	d := &struct{ Router *httptreemux.TreeMux }{}

	if err := z.Injector.Get(d); err != nil {
		return err
	}

	z.Server.UseHandler(d.Router)

	z.Server.Use(NewLogger())
	z.Server.Use(NewRecovery())
	z.Server.Use(cors.Default())

	return nil
}
<commit_msg>Middleware sequence fixed.<commit_after>// Package zest contains a lightweight framework based on the codegangsta/cli package allowing
// clean and easy command line interfaces, the codegangsta/negroni middleware
// handler, and the solher/syringe injector.
//
// Zest encourages the use of small, well chosen individual dependencies
// instead of high productivity, full-stack frameworks.
package zest

import (
	"fmt"
	"os"
	"time"

	"gopkg.in/tylerb/graceful.v1"

	"github.com/codegangsta/cli"
	"github.com/codegangsta/negroni"
	"github.com/dimfeld/httptreemux"
	"github.com/rs/cors"
	"github.com/solher/syringe"
)

// Injector provide a quick access to an instanciated injector.
var Injector = syringe.New()

// SeqFunc is the prototype of the functions present in the exit/init sequences.
type SeqFunc func(z *Zest) error

// Zest is an aggregation of well known and efficient package, also providing
// a simple init/exit process to the user.
//
// Init and exit sequences are run following the order of the array, at each
// start/stop of the app, thanks to Cli and the tylerb/graceful module.
type Zest struct {
	cli     *cli.App
	Context *cli.Context

	Server   *negroni.Negroni
	Injector *syringe.Syringe

	InitSequence []SeqFunc
	ExitSequence []SeqFunc
}

// Cli returns a copy of the embedded Cli app.
func (z *Zest) Cli() cli.App {
	return *z.cli
}

// SetCli sets a copy of the embedded Cli app.
func (z *Zest) SetCli(cli cli.App) {
	*z.cli = cli
}

// Run starts the Cli app.
func (z *Zest) Run() {
	z.cli.Run(os.Args)
}

// Classic returns a new instance of Zest, with some default init steps, in this order :
// "classicRegister" which registers the default dependencies (Render, Httptreemux) in the injector.
// "classicBuild" which triggers the dependency injection of the app.
// "classicInit" which initialize the Httptreemux router and the default middlewares in Negroni.
func Classic() *Zest {
	z := New()

	z.InitSequence = append([]SeqFunc{classicRegister}, z.InitSequence...)
	z.InitSequence = append(z.InitSequence, classicInit)

	return z
}

// New returns a new instance of Zest.
func New() *Zest {
	z := &Zest{
		cli:      cli.NewApp(),
		Server:   negroni.New(),
		Injector: Injector,
	}

	z.InitSequence = append(z.InitSequence, classicBuild)

	z.cli.Usage = "A Zest powered service."
	z.cli.Before = z.init
	z.cli.After = z.exit
	z.cli.Action = z.run
	z.cli.Flags = []cli.Flag{
		cli.IntFlag{
			Name:  "port,p",
			Value: 3000,
			Usage: "listening port",
		},
		cli.IntFlag{
			Name:  "exitTimeout,t",
			Value: 10,
			Usage: "graceful shutdown timeout in seconds (0 for infinite)",
		},
	}

	return z
}

func (z *Zest) init(c *cli.Context) error {
	z.Context = c

	for _, f := range z.InitSequence {
		if err := f(z); err != nil {
			return err
		}
	}

	return nil
}

func (z *Zest) run(c *cli.Context) {
	z.Context = c

	port := fmt.Sprintf(":%d", z.Context.GlobalInt("port"))
	exitTimeout := time.Duration(z.Context.GlobalInt("exitTimeout")) * time.Second

	fmt.Println("\n[Zest] Listening on " + port)

	graceful.Run(port, exitTimeout, z.Server)
}

func (z *Zest) exit(c *cli.Context) error {
	z.Context = c

	for _, f := range z.ExitSequence {
		if err := f(z); err != nil {
			return err
		}
	}

	return nil
}

func classicRegister(z *Zest) error {
	z.Injector.Register(NewRender(), httptreemux.New())

	return nil
}

func classicBuild(z *Zest) error {
	return z.Injector.Inject()
}

func classicInit(z *Zest) error {
	d := &struct{ Router *httptreemux.TreeMux }{}

	if err := z.Injector.Get(d); err != nil {
		return err
	}

	z.Server.Use(NewRecovery())
	z.Server.Use(NewLogger())
	z.Server.Use(cors.Default())

	z.Server.UseHandler(d.Router)

	return nil
}
<|endoftext|>


<commit_before><commit_msg>Connect ANF resize logic<commit_after><|endoftext|>


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

package dns

import (
	"os"
	"sort"
	"strings"
)

const _CLASS = 2 << 16

// ZRRset is a structure that keeps several items from
// a zone file together.
type ZRRset struct {
	RRs    RRset // the RRset for this type and name
	RRsigs RRset // the RRSIGs belonging to this RRset (if any)
	Nxt    RR    // the NSEC or NSEC3 for this name
	Glue   bool  // when this RRset is glue, set to true
}

// NewZRRset returns a pointer to a new ZRRset.
func NewZRRset() *ZRRset {
	s := new(ZRRset)
	s.RRs = NewRRset()
	s.RRsigs = NewRRset()
	return s
}

// Zone implements the concept of RFC 1035 master zone files.
// We store the zone contents in a map where the ownername is
// the key. In that map we have another map with integers
// (class * _CLASS + type) that has the ZRRset:
// map[<ownername>] -> map[<int>] -> ZRRset
type Zone struct {
	Zone map[string]map[int]*ZRRset // the contents of the zone
	Nxt  *QnameString               // sorted list of owernames in the zone
}

// NewZone returns a new *Zone
func NewZone() *Zone {
	z := new(Zone)
	z.Zone = make(map[string]map[int]*ZRRset)
	z.Nxt = NewQnameString()
	return z
}

// Pop returns the last pushed ZRRset from z.
// Get the first value
func (z *Zone) Pop() *ZRRset {
	for _, v := range z.Zone {
		for _, v1 := range v {
			return v1
		}
	}
	return nil
}

// PopRR returns the last RR pushed from z.
func (z *Zone) PopRR() RR {
	s := z.Pop()
	if s == nil {
		return nil
	}
	switch {
	case len(s.RRs) != 0:
		return s.RRs.Pop()
	case len(s.RRsigs) != 0:
		return s.RRsigs.Pop()
	case s.Nxt != nil:
		return s.Nxt
	}
	panic("not reached")
	return nil
}

// Len returns the number of RRs in z.
func (z *Zone) Len() int {
	i := 0
	for _, im := range z.Zone {
		for _, s := range im {
			i += len(s.RRs) + len(s.RRsigs)
			if s.Nxt != nil {
				i++
			}
		}
	}
	return i
}

func (z *Zone) String() string {
	s := ""
	for _, im := range z.Zone {
		for _, s1 := range im {
			s += s1.RRs.String()
			s += s1.RRsigs.String()
			if s1.Nxt != nil {
				s += s1.Nxt.String() + "\n"
			}
		}
	}
	return s
}

// PushRR adds a new RR to the zone.
func (z *Zone) PushRR(r RR) {
	s, _ := z.LookupRR(r)
	if s == nil {
		s = NewZRRset()
	}
	// Add to the sorted ownernames list
	SortInsert(z.Nxt, r.Header().Name)

	switch r.Header().Rrtype {
	case TypeRRSIG:
		s.RRsigs.Push(r)
	case TypeNSEC, TypeNSEC3:
		s.Nxt = r
	default:
		s.RRs.Push(r)
	}
	z.Push(s)
}

// Push adds a new ZRRset to the zone.
func (z *Zone) Push(s *ZRRset) {
	// s can hold RRs, RRsigs or a Nxt
	name := ""
	i := 0
	switch {
	case len(s.RRs) != 0:
		name = s.RRs[0].Header().Name
		i = intval(s.RRs[0].Header().Class, s.RRs[0].Header().Rrtype)
	case len(s.RRsigs) != 0:
		name = s.RRsigs[0].Header().Name
		i = intval(s.RRsigs[0].Header().Class, s.RRsigs[0].(*RR_RRSIG).TypeCovered)
	case s.Nxt != nil:
		name = s.Nxt.Header().Name
		i = intval(s.Nxt.Header().Class, s.Nxt.Header().Rrtype)
	}
	if z.Zone[name] == nil {
		im := make(map[int]*ZRRset) // intmap
		im[i] = s
		z.Zone[name] = im
		return
	}
	im := z.Zone[name]
	im[i] = s
	return
}

// Lookup the RR in the zone, we are only looking at
// qname, qtype and qclass of the RR
// Considerations for wildcards
// Return NXDomain, Name error, wildcard?
// Casing!
func (z *Zone) LookupRR(r RR) (*ZRRset, os.Error) {
	if r.Header().Rrtype == TypeRRSIG {
		return z.LookupName(r.Header().Name, r.Header().Class, r.(*RR_RRSIG).TypeCovered)
	}
	return z.LookupName(r.Header().Name, r.Header().Class, r.Header().Rrtype)
}

func (z *Zone) LookupQuestion(q Question) (*ZRRset, os.Error) {
	// Impossible to look for an typecovered in a question, because the rdata is
	// not there.
	return z.LookupName(q.Name, q.Qclass, q.Qtype)
}

func (z *Zone) LookupName(qname string, qclass, qtype uint16) (*ZRRset, os.Error) {
	i := intval(qclass, qtype)
	if im, ok := z.Zone[strings.ToLower(qname)]; ok {
		// Have an im, intmap
		if s, ok := im[i]; ok {
			return s, nil
		}
		// Wildcard 'n stuff
		return nil, ErrName
	}
	return nil, nil
}

// Number in the second map denotes the class + type.
func intval(c, t uint16) int {
	return int(c)*_CLASS + int(t)
}

// SortInsert insert the string s in the already sorted
// vector p. If s is already present it is not inserted again.
func SortInsert(p *QnameString, s string) {
	i := sort.Search(len(*p), func(i int) bool { return (*p)[i] >= s })
	if i < len(*p) && (*p)[i] == s {
		// element already there
		return
	}
	p.Insert(i, s)
}

// Search searches the sorted vector p using binary search. If
// the element s can not be found, the previous element is returned.
func SortSearch(p *QnameString, s string) string {
	i := sort.Search(len(*p), func(i int) bool { return (*p)[i] >= s })
	// with zones there must always be one before
	if (*p)[i] == s {
		return s
	}
	if i > 0 {
		i--
	}
	return (*p)[i]
}
<commit_msg>Extra nil checks<commit_after>// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dns

import (
	"os"
	"sort"
	"strings"
)

const _CLASS = 2 << 16

// ZRRset is a structure that keeps several items from
// a zone file together.
type ZRRset struct {
	RRs    RRset // the RRset for this type and name
	RRsigs RRset // the RRSIGs belonging to this RRset (if any)
	Nxt    RR    // the NSEC or NSEC3 for this name
	Glue   bool  // when this RRset is glue, set to true
}

// NewZRRset returns a pointer to a new ZRRset.
func NewZRRset() *ZRRset {
	s := new(ZRRset)
	s.RRs = NewRRset()
	s.RRsigs = NewRRset()
	return s
}

// Zone implements the concept of RFC 1035 master zone files.
// We store the zone contents in a map where the ownername is
// the key. In that map we have another map with integers
// (class * _CLASS + type) that has the ZRRset:
// map[<ownername>] -> map[<int>] -> ZRRset
type Zone struct {
	Zone map[string]map[int]*ZRRset // the contents of the zone
	Nxt  *QnameString               // sorted list of owernames in the zone
}

// NewZone returns a new *Zone
func NewZone() *Zone {
	z := new(Zone)
	z.Zone = make(map[string]map[int]*ZRRset)
	z.Nxt = NewQnameString()
	return z
}

// Pop returns the last pushed ZRRset from z.
// Get the first value
func (z *Zone) Pop() *ZRRset {
        if z == nil {
                return nil
        }
	for _, v := range z.Zone {
		for _, v1 := range v {
			return v1
		}
	}
	return nil
}

// PopRR returns the last RR pushed from z.
func (z *Zone) PopRR() RR {
        if z == nil {
                return nil
        }
	s := z.Pop()
	if s == nil {
		return nil
	}
	switch {
	case len(s.RRs) != 0:
		return s.RRs.Pop()
	case len(s.RRsigs) != 0:
		return s.RRsigs.Pop()
	case s.Nxt != nil:
		return s.Nxt
	}
	panic("not reached")
	return nil
}

// Len returns the number of RRs in z.
func (z *Zone) Len() int {
	i := 0
	for _, im := range z.Zone {
		for _, s := range im {
			i += len(s.RRs) + len(s.RRsigs)
			if s.Nxt != nil {
				i++
			}
		}
	}
	return i
}

func (z *Zone) String() string {
        if z == nil {
                return "<nil> zone"
        }
	s := ""
	for _, im := range z.Zone {
		for _, s1 := range im {
			s += s1.RRs.String()
			s += s1.RRsigs.String()
			if s1.Nxt != nil {
				s += s1.Nxt.String() + "\n"
			}
		}
	}
	return s
}

// PushRR adds a new RR to the zone.
func (z *Zone) PushRR(r RR) {
	s, _ := z.LookupRR(r)
	if s == nil {
		s = NewZRRset()
	}
	// Add to the sorted ownernames list
	SortInsert(z.Nxt, r.Header().Name)

	switch r.Header().Rrtype {
	case TypeRRSIG:
		s.RRsigs.Push(r)
	case TypeNSEC, TypeNSEC3:
		s.Nxt = r
	default:
		s.RRs.Push(r)
	}
	z.Push(s)
}

// Push adds a new ZRRset to the zone.
func (z *Zone) Push(s *ZRRset) {
	// s can hold RRs, RRsigs or a Nxt
	name := ""
	i := 0
	switch {
	case len(s.RRs) != 0:
		name = s.RRs[0].Header().Name
		i = intval(s.RRs[0].Header().Class, s.RRs[0].Header().Rrtype)
	case len(s.RRsigs) != 0:
		name = s.RRsigs[0].Header().Name
		i = intval(s.RRsigs[0].Header().Class, s.RRsigs[0].(*RR_RRSIG).TypeCovered)
	case s.Nxt != nil:
		name = s.Nxt.Header().Name
		i = intval(s.Nxt.Header().Class, s.Nxt.Header().Rrtype)
	}
	if z.Zone[name] == nil {
		im := make(map[int]*ZRRset) // intmap
		im[i] = s
		z.Zone[name] = im
		return
	}
	im := z.Zone[name]
	im[i] = s
	return
}

// Lookup the RR in the zone, we are only looking at
// qname, qtype and qclass of the RR
// Considerations for wildcards
// Return NXDomain, Name error, wildcard?
// Casing!
func (z *Zone) LookupRR(r RR) (*ZRRset, os.Error) {
	if r.Header().Rrtype == TypeRRSIG {
		return z.LookupName(r.Header().Name, r.Header().Class, r.(*RR_RRSIG).TypeCovered)
	}
	return z.LookupName(r.Header().Name, r.Header().Class, r.Header().Rrtype)
}

func (z *Zone) LookupQuestion(q Question) (*ZRRset, os.Error) {
	// Impossible to look for an typecovered in a question, because the rdata is
	// not there.
	return z.LookupName(q.Name, q.Qclass, q.Qtype)
}

func (z *Zone) LookupName(qname string, qclass, qtype uint16) (*ZRRset, os.Error) {
	i := intval(qclass, qtype)
	if im, ok := z.Zone[strings.ToLower(qname)]; ok {
		// Have an im, intmap
		if s, ok := im[i]; ok {
			return s, nil
		}
		// Wildcard 'n stuff
		return nil, ErrName
	}
	return nil, nil
}

// Number in the second map denotes the class + type.
func intval(c, t uint16) int {
	return int(c)*_CLASS + int(t)
}

// SortInsert insert the string s in the already sorted
// vector p. If s is already present it is not inserted again.
func SortInsert(p *QnameString, s string) {
	i := sort.Search(len(*p), func(i int) bool { return (*p)[i] >= s })
	if i < len(*p) && (*p)[i] == s {
		// element already there
		return
	}
	p.Insert(i, s)
}

// Search searches the sorted vector p using binary search. If
// the element s can not be found, the previous element is returned.
func SortSearch(p *QnameString, s string) string {
	i := sort.Search(len(*p), func(i int) bool { return (*p)[i] >= s })
	// with zones there must always be one before
	if (*p)[i] == s {
		return s
	}
	if i > 0 {
		i--
	}
	return (*p)[i]
}
<|endoftext|>


<commit_before>package fix

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"time"
)

var entryFixes []EntryFix

func init() {
	entryFixes = []EntryFix{
		AddClosedAtTimestamp{},
	}
}

type EntryFix interface {
	// Parses io.Reader for the error that can be fixed
	CanFix(io.Reader) (bool, error)

	// Returns byte slice that has been fixed
	Execute(io.Reader) ([]byte, error)
}

// Parse the opened at timestamp and add 2 mins
// then append it to the end
type AddClosedAtTimestamp struct{}

func (AddClosedAtTimestamp) CanFix(r io.Reader) (bool, error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return false, err
	}

	return !lastLineIsTimestamp(data), nil
}

func lastLineIsTimestamp(data []byte) bool {
	scanner := bufio.NewScanner(bytes.NewReader(data))
	// Scan to the last line
	for scanner.Scan() {
	}
	_, err := time.Parse(time.UnixDate, scanner.Text())

	return err == nil
}

func (AddClosedAtTimestamp) Execute(r io.Reader) ([]byte, error) {
	// For adding 2 mins and making the closed at timestamp
	var openedAt time.Time

	// For storing the fixed output
	b := bytes.NewBuffer(make([]byte, 0, 1024))

	scanner := bufio.NewScanner(r)

	// Scan in the opened at timestamp
	if scanner.Scan() {
		if time, err := time.Parse(time.UnixDate, scanner.Text()); err != nil {
			// First line wasn't a timestamp
			return nil, err
		} else {
			openedAt = time
			// Print the timestamp to the fixed buffer
			if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
				return nil, err
			}
		}
	} else {
		return nil, errors.New("error parsing opened at timestamp")
	}

	// Scan and copy lines into the fixed buffer
	for scanner.Scan() {
		if scanner.Err() != nil {
			return nil, scanner.Err()
		}

		if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
			return nil, err
		}
	}

	// Append the closed at timestamp to the end of the buffer
	closedAt := openedAt.Add(time.Minute * 2)
	if _, err := fmt.Fprintf(b, "\n%s\n", closedAt.Format(time.UnixDate)); err != nil {
		return nil, err
	}

	return b.Bytes(), nil
}
<commit_msg>Prefixed the Fix implementation type with Fix<commit_after>package fix

import (
	"bufio"
	"bytes"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"time"
)

var entryFixes []EntryFix

func init() {
	entryFixes = []EntryFix{
		FixAddClosedAtTimestamp{},
	}
}

type EntryFix interface {
	// Parses io.Reader for the error that can be fixed
	CanFix(io.Reader) (bool, error)

	// Returns byte slice that has been fixed
	Execute(io.Reader) ([]byte, error)
}

// Parse the opened at timestamp and add 2 mins
// then append it to the end
type FixAddClosedAtTimestamp struct{}

func (FixAddClosedAtTimestamp) CanFix(r io.Reader) (bool, error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return false, err
	}

	return !lastLineIsTimestamp(data), nil
}

func lastLineIsTimestamp(data []byte) bool {
	scanner := bufio.NewScanner(bytes.NewReader(data))
	// Scan to the last line
	for scanner.Scan() {
	}
	_, err := time.Parse(time.UnixDate, scanner.Text())

	return err == nil
}

func (FixAddClosedAtTimestamp) Execute(r io.Reader) ([]byte, error) {
	// For adding 2 mins and making the closed at timestamp
	var openedAt time.Time

	// For storing the fixed output
	b := bytes.NewBuffer(make([]byte, 0, 1024))

	scanner := bufio.NewScanner(r)

	// Scan in the opened at timestamp
	if scanner.Scan() {
		if time, err := time.Parse(time.UnixDate, scanner.Text()); err != nil {
			// First line wasn't a timestamp
			return nil, err
		} else {
			openedAt = time
			// Print the timestamp to the fixed buffer
			if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
				return nil, err
			}
		}
	} else {
		return nil, errors.New("error parsing opened at timestamp")
	}

	// Scan and copy lines into the fixed buffer
	for scanner.Scan() {
		if scanner.Err() != nil {
			return nil, scanner.Err()
		}

		if _, err := fmt.Fprintln(b, scanner.Text()); err != nil {
			return nil, err
		}
	}

	// Append the closed at timestamp to the end of the buffer
	closedAt := openedAt.Add(time.Minute * 2)
	if _, err := fmt.Fprintf(b, "\n%s\n", closedAt.Format(time.UnixDate)); err != nil {
		return nil, err
	}

	return b.Bytes(), nil
}
<|endoftext|>