<commit_before>/*
Copyright 2019 Google Inc. All rights reserved.

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

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

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

// Package sessions implements proxy-side user session tracking for reverse proxies.
package sessions

import (
	"fmt"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"sync"
	"time"

	"github.com/golang/groupcache/lru"
	"github.com/google/uuid"
	"golang.org/x/net/publicsuffix"
)

type sessionResponseWriter struct {
	cj            *Cache
	sessionID     string
	urlForCookies *url.URL

	wrapped     http.ResponseWriter
	wroteHeader bool
}

func (w *sessionResponseWriter) Header() http.Header {
	return w.wrapped.Header()
}

func (w *sessionResponseWriter) Write(bs []byte) (int, error) {
	if !w.wroteHeader {
		w.WriteHeader(http.StatusOK)
	}
	return w.wrapped.Write(bs)
}

func (w *sessionResponseWriter) WriteHeader(statusCode int) {
	if w.wroteHeader {
		// Multiple calls ot WriteHeader are no-ops
		return
	}
	w.wroteHeader = true
	w.cj.interceptSession(w.sessionID, w, w.urlForCookies)
	w.wrapped.WriteHeader(statusCode)
}

type sessionHandler struct {
	cj      *Cache
	wrapped http.Handler
}

func (h *sessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	urlForCookies := *(r.URL)
	urlForCookies.Scheme = "https"
	urlForCookies.Host = r.Host
	sessionID := h.cj.extractAndRestoreSession(r, &urlForCookies)
	w = &sessionResponseWriter{
		cj:            h.cj,
		sessionID:     sessionID,
		urlForCookies: &urlForCookies,
		wrapped:       w,
	}
	h.wrapped.ServeHTTP(w, r)
}

// SessionHandler returns an instance of `http.Handler` that wraps the given handler and adds proxy-side session tracking.
func (cj *Cache) SessionHandler(wrapped http.Handler) http.Handler {
	return &sessionHandler{
		cj:      cj,
		wrapped: wrapped,
	}
}

// Cache represents a LRU cache to store sessions
type Cache struct {
	sessionCookieName    string
	sessionCookieTimeout time.Duration
	disableSSLForTest    bool

	cache *lru.Cache
	mu    sync.Mutex
}

// NewCache initializes an LRU session cache
func NewCache(sessionCookieName string, sessionCookieTimeout time.Duration, cookieCacheLimit int, disableSSLForTest bool) (*Cache, error) {
	return &Cache{
		sessionCookieName:    sessionCookieName,
		sessionCookieTimeout: sessionCookieTimeout,
		disableSSLForTest:    disableSSLForTest,
		cache:                lru.New(cookieCacheLimit),
	}, nil
}

// addJarToCache takes a Jar from http.Client and stores it in a cache
func (cj *Cache) addJarToCache(sessionID string, jar http.CookieJar) {
	cj.mu.Lock()
	cj.cache.Add(sessionID, jar)
	cj.mu.Unlock()
}

// cachedCookieJar returns the CookieJar mapped to the sessionID
func (cj *Cache) cachedCookieJar(sessionID string) (jar http.CookieJar, err error) {
	val, ok := cj.cache.Get(sessionID)
	if !ok {
		options := cookiejar.Options{
			PublicSuffixList: publicsuffix.List,
		}
		jar, err = cookiejar.New(&options)
		cj.addJarToCache(sessionID, jar)
		return jar, err
	}

	jar, ok = val.(http.CookieJar)
	if !ok {
		return nil, fmt.Errorf("Internal error; unexpected type for value (%+v) stored in the cookie jar cache", val)
	}
	return jar, nil
}

// interceptSession modifies the given ResponseWriter by removing any Set-Cookie headers
// and instead adding those cookies to the corresponding session.
//
// If there is not already a session, and we have new cookies to save in the session, then
// this method will create a new session, and set a session cookie for it.
//
// This is the inverse of extractAndRestoreSession.
func (cj *Cache) interceptSession(sessionID string, w http.ResponseWriter, u *url.URL) error {
	if cj == nil {
		return nil
	}

	header := w.Header()
	cookiesToAdd := (&http.Response{Header: header}).Cookies()
	if len(cookiesToAdd) == 0 {
		// There were no cookies to intercept
		return nil
	}

	header.Del("Set-Cookie")
	if sessionID == "" {
		// No session was previously defined, so we need to create a new one
		sessionID = uuid.New().String()
		sessionCookie := &http.Cookie{
			Name:     cj.sessionCookieName,
			Value:    sessionID,
			Path:     "/",
			Secure:   !cj.disableSSLForTest,
			HttpOnly: true,
			Expires:  time.Now().Add(cj.sessionCookieTimeout),
		}
		header.Add("Set-Cookie", sessionCookie.String())
	}

	cookieJar, err := cj.cachedCookieJar(sessionID)
	if err != nil {
		log.Printf("Failure reading a cached cookie jar: %v", err)
		return fmt.Errorf("Failure reading a cached cookie jar: %v", err)
	}
	cookieJar.SetCookies(u, cookiesToAdd)
	return nil
}

// extractAndRestoreSession pulls the session ID cookie (if any) out of the given request,
// finds the corresponding session, and then adds any saved cookies for that session to the request.
//
// The return value is the session ID, or an empty string if there is no session.
//
// This is the inverse of interceptSession.
func (cj *Cache) extractAndRestoreSession(r *http.Request, u *url.URL) (sessionID string) {
	if cj == nil {
		return ""
	}

	sessionCookie, err := r.Cookie(cj.sessionCookieName)
	if err != nil || sessionCookie == nil {
		// There is no session cookie, so we have nothing to do.
		return ""
	}

	sessionID = sessionCookie.Value
	cachedCookieJar, err := cj.cachedCookieJar(sessionID)
	if err != nil {
		log.Printf("Failure reading the cookie jar for session %q: %v", sessionID, err)
		// We are unable to fetch a cookie jar for the session, so we have no
		// existing, cached cookies to insert into the request.
		return ""
	}

	// Remove the session cookie
	existingCookies := r.Cookies()
	r.Header.Del("Cookie")
	for _, c := range existingCookies {
		if c.Name != cj.sessionCookieName {
			r.AddCookie(c)
		}
	}

	// Restore any cached cookies from the session
	cachedCookies := cachedCookieJar.Cookies(u)
	for _, c := range cachedCookies {
		r.AddCookie(c)
	}
	return sessionID
}
<commit_msg>Consolidate the handling of a nil cache into a single location<commit_after>/*
Copyright 2019 Google Inc. All rights reserved.

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

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

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

// Package sessions implements proxy-side user session tracking for reverse proxies.
package sessions

import (
	"fmt"
	"log"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"sync"
	"time"

	"github.com/golang/groupcache/lru"
	"github.com/google/uuid"
	"golang.org/x/net/publicsuffix"
)

type sessionResponseWriter struct {
	cj            *Cache
	sessionID     string
	urlForCookies *url.URL

	wrapped     http.ResponseWriter
	wroteHeader bool
}

func (w *sessionResponseWriter) Header() http.Header {
	return w.wrapped.Header()
}

func (w *sessionResponseWriter) Write(bs []byte) (int, error) {
	if !w.wroteHeader {
		w.WriteHeader(http.StatusOK)
	}
	return w.wrapped.Write(bs)
}

func (w *sessionResponseWriter) WriteHeader(statusCode int) {
	if w.wroteHeader {
		// Multiple calls ot WriteHeader are no-ops
		return
	}
	w.wroteHeader = true
	w.cj.interceptSession(w.sessionID, w, w.urlForCookies)
	w.wrapped.WriteHeader(statusCode)
}

type sessionHandler struct {
	cj      *Cache
	wrapped http.Handler
}

func (h *sessionHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	urlForCookies := *(r.URL)
	urlForCookies.Scheme = "https"
	urlForCookies.Host = r.Host
	sessionID := h.cj.extractAndRestoreSession(r, &urlForCookies)
	w = &sessionResponseWriter{
		cj:            h.cj,
		sessionID:     sessionID,
		urlForCookies: &urlForCookies,
		wrapped:       w,
	}
	h.wrapped.ServeHTTP(w, r)
}

// SessionHandler returns an instance of `http.Handler` that wraps the given handler and adds proxy-side session tracking.
func (cj *Cache) SessionHandler(wrapped http.Handler) http.Handler {
	if cj == nil {
		return wrapped
	}
	return &sessionHandler{
		cj:      cj,
		wrapped: wrapped,
	}
}

// Cache represents a LRU cache to store sessions
type Cache struct {
	sessionCookieName    string
	sessionCookieTimeout time.Duration
	disableSSLForTest    bool

	cache *lru.Cache
	mu    sync.Mutex
}

// NewCache initializes an LRU session cache
func NewCache(sessionCookieName string, sessionCookieTimeout time.Duration, cookieCacheLimit int, disableSSLForTest bool) (*Cache, error) {
	return &Cache{
		sessionCookieName:    sessionCookieName,
		sessionCookieTimeout: sessionCookieTimeout,
		disableSSLForTest:    disableSSLForTest,
		cache:                lru.New(cookieCacheLimit),
	}, nil
}

// addJarToCache takes a Jar from http.Client and stores it in a cache
func (cj *Cache) addJarToCache(sessionID string, jar http.CookieJar) {
	cj.mu.Lock()
	cj.cache.Add(sessionID, jar)
	cj.mu.Unlock()
}

// cachedCookieJar returns the CookieJar mapped to the sessionID
func (cj *Cache) cachedCookieJar(sessionID string) (jar http.CookieJar, err error) {
	val, ok := cj.cache.Get(sessionID)
	if !ok {
		options := cookiejar.Options{
			PublicSuffixList: publicsuffix.List,
		}
		jar, err = cookiejar.New(&options)
		cj.addJarToCache(sessionID, jar)
		return jar, err
	}

	jar, ok = val.(http.CookieJar)
	if !ok {
		return nil, fmt.Errorf("Internal error; unexpected type for value (%+v) stored in the cookie jar cache", val)
	}
	return jar, nil
}

// interceptSession modifies the given ResponseWriter by removing any Set-Cookie headers
// and instead adding those cookies to the corresponding session.
//
// If there is not already a session, and we have new cookies to save in the session, then
// this method will create a new session, and set a session cookie for it.
//
// This is the inverse of extractAndRestoreSession.
func (cj *Cache) interceptSession(sessionID string, w http.ResponseWriter, u *url.URL) error {
	header := w.Header()
	cookiesToAdd := (&http.Response{Header: header}).Cookies()
	if len(cookiesToAdd) == 0 {
		// There were no cookies to intercept
		return nil
	}

	header.Del("Set-Cookie")
	if sessionID == "" {
		// No session was previously defined, so we need to create a new one
		sessionID = uuid.New().String()
		sessionCookie := &http.Cookie{
			Name:     cj.sessionCookieName,
			Value:    sessionID,
			Path:     "/",
			Secure:   !cj.disableSSLForTest,
			HttpOnly: true,
			Expires:  time.Now().Add(cj.sessionCookieTimeout),
		}
		header.Add("Set-Cookie", sessionCookie.String())
	}

	cookieJar, err := cj.cachedCookieJar(sessionID)
	if err != nil {
		log.Printf("Failure reading a cached cookie jar: %v", err)
		return fmt.Errorf("Failure reading a cached cookie jar: %v", err)
	}
	cookieJar.SetCookies(u, cookiesToAdd)
	return nil
}

// extractAndRestoreSession pulls the session ID cookie (if any) out of the given request,
// finds the corresponding session, and then adds any saved cookies for that session to the request.
//
// The return value is the session ID, or an empty string if there is no session.
//
// This is the inverse of interceptSession.
func (cj *Cache) extractAndRestoreSession(r *http.Request, u *url.URL) (sessionID string) {
	sessionCookie, err := r.Cookie(cj.sessionCookieName)
	if err != nil || sessionCookie == nil {
		// There is no session cookie, so we have nothing to do.
		return ""
	}

	sessionID = sessionCookie.Value
	cachedCookieJar, err := cj.cachedCookieJar(sessionID)
	if err != nil {
		log.Printf("Failure reading the cookie jar for session %q: %v", sessionID, err)
		// We are unable to fetch a cookie jar for the session, so we have no
		// existing, cached cookies to insert into the request.
		return ""
	}

	// Remove the session cookie
	existingCookies := r.Cookies()
	r.Header.Del("Cookie")
	for _, c := range existingCookies {
		if c.Name != cj.sessionCookieName {
			r.AddCookie(c)
		}
	}

	// Restore any cached cookies from the session
	cachedCookies := cachedCookieJar.Cookies(u)
	for _, c := range cachedCookies {
		r.AddCookie(c)
	}
	return sessionID
}
<|endoftext|>


<commit_before>package config

import (
	"github.com/coreos/coreos-cloudinit/config"
	"github.com/docker/libcompose/project"
	"github.com/rancher/netconf"
)

const (
	DOCKER_BIN         = "/usr/bin/docker"
	ROS_BIN            = "/usr/bin/ros"
	SYSINIT_BIN        = "/usr/bin/ros-sysinit"
	DOCKER_SYSTEM_HOME = "/var/lib/system-docker"
	DOCKER_SYSTEM_HOST = "unix:///var/run/system-docker.sock"
	DOCKER_HOST        = "unix:///var/run/docker.sock"
	IMAGES_PATH        = "/usr/share/ros"
	IMAGES_PATTERN     = "images*.tar"
	MODULES_ARCHIVE    = "/modules.tar"
	DEBUG              = false
	SYSTEM_DOCKER_LOG  = "/var/log/system-docker.log"

	LABEL         = "label"
	HASH          = "io.rancher.os.hash"
	ID            = "io.rancher.os.id"
	DETACH        = "io.rancher.os.detach"
	CREATE_ONLY   = "io.rancher.os.createonly"
	RELOAD_CONFIG = "io.rancher.os.reloadconfig"
	SCOPE         = "io.rancher.os.scope"
	SYSTEM        = "system"

	OsConfigFile           = "/usr/share/ros/os-config.yml"
	CloudConfigDir         = "/var/lib/rancher/conf/cloud-config.d"
	CloudConfigBootFile    = "/var/lib/rancher/conf/cloud-config.d/boot.yml"
	CloudConfigPrivateFile = "/var/lib/rancher/conf/cloud-config.d/private.yml"
	CloudConfigScriptFile  = "/var/lib/rancher/conf/cloud-config-script"
	MetaDataFile           = "/var/lib/rancher/conf/metadata"
	CloudConfigFile        = "/var/lib/rancher/conf/cloud-config.yml"
)

var (
	VERSION string
)

func init() {
	if VERSION == "" {
		VERSION = "v0.0.0-dev"
	}
}

type ContainerConfig struct {
	Id             string                 `yaml:"id,omitempty"`
	Cmd            string                 `yaml:"run,omitempty"`
	MigrateVolumes bool                   `yaml:"migrate_volumes,omitempty"`
	ReloadConfig   bool                   `yaml:"reload_config,omitempty"`
	CreateOnly     bool                   `yaml:create_only,omitempty`
	Service        *project.ServiceConfig `yaml:service,omitempty`
}

type Repository struct {
	Url string `yaml:url,omitempty`
}

type Repositories map[string]Repository

type CloudConfig struct {
	SSHAuthorizedKeys []string      `yaml:"ssh_authorized_keys"`
	WriteFiles        []config.File `yaml:"write_files"`
	Hostname          string        `yaml:"hostname"`

	Rancher RancherConfig `yaml:"rancher,omitempty"`
}

type RancherConfig struct {
	Environment         map[string]string                 `yaml:"environment,omitempty"`
	Services            map[string]*project.ServiceConfig `yaml:"services,omitempty"`
	BootstrapContainers map[string]*project.ServiceConfig `yaml:"bootstrap,omitempty"`
	Autoformat          map[string]*project.ServiceConfig `yaml:"autoformat,omitempty"`
	BootstrapDocker     DockerConfig                      `yaml:"bootstrap_docker,omitempty"`
	CloudInit           CloudInit                         `yaml:"cloud_init,omitempty"`
	Debug               bool                              `yaml:"debug,omitempty"`
	RmUsr               bool                              `yaml:"rm_usr,omitempty"`
	Log                 bool                              `yaml:"log,omitempty"`
	Disable             []string                          `yaml:"disable,omitempty"`
	ServicesInclude     map[string]bool                   `yaml:"services_include,omitempty"`
	Modules             []string                          `yaml:"modules,omitempty"`
	Network             netconf.NetworkConfig             `yaml:"network,omitempty"`
	Repositories        Repositories                      `yaml:"repositories,omitempty"`
	Ssh                 SshConfig                         `yaml:"ssh,omitempty"`
	State               StateConfig                       `yaml:"state,omitempty"`
	SystemDocker        DockerConfig                      `yaml:"system_docker,omitempty"`
	Upgrade             UpgradeConfig                     `yaml:"upgrade,omitempty"`
	Docker              DockerConfig                      `yaml:"docker,omitempty"`
}

type UpgradeConfig struct {
	Url      string `yaml:"url,omitempty"`
	Image    string `yaml:"image,omitempty"`
	Rollback string `yaml:"rollback,omitempty"`
}

type DockerConfig struct {
	TLS            bool     `yaml:"tls,omitempty"`
	TLSArgs        []string `yaml:"tls_args,flow,omitempty"`
	Args           []string `yaml:"args,flow,omitempty"`
	ExtraArgs      []string `yaml:"extra_args,flow,omitempty"`
	ServerCert     string   `yaml:"server_cert,omitempty"`
	ServerKey      string   `yaml:"server_key,omitempty"`
	CACert         string   `yaml:"ca_cert,omitempty"`
	CAKey          string   `yaml:"ca_key,omitempty"`
	Environment    []string `yaml:"environment,omitempty"`
	StorageContext string   `yaml:"storage_context,omitempty"`
}

type SshConfig struct {
	Keys map[string]string `yaml:"keys,omitempty"`
}

type StateConfig struct {
	FsType     string   `yaml:"fstype,omitempty"`
	Dev        string   `yaml:"dev,omitempty"`
	Required   bool     `yaml:"required,omitempty"`
	Autoformat []string `yaml:"autoformat,omitempty"`
	FormatZero bool     `yaml:"formatzero,omitempty"`
}

type CloudInit struct {
	Datasources []string `yaml:"datasources,omitempty"`
}

func (r Repositories) ToArray() []string {
	result := make([]string, 0, len(r))
	for _, repo := range r {
		if repo.Url != "" {
			result = append(result, repo.Url)
		}
	}

	return result
}
<commit_msg>config/types.go: add "" to field tag<commit_after>package config

import (
	"github.com/coreos/coreos-cloudinit/config"
	"github.com/docker/libcompose/project"
	"github.com/rancher/netconf"
)

const (
	DOCKER_BIN         = "/usr/bin/docker"
	ROS_BIN            = "/usr/bin/ros"
	SYSINIT_BIN        = "/usr/bin/ros-sysinit"
	DOCKER_SYSTEM_HOME = "/var/lib/system-docker"
	DOCKER_SYSTEM_HOST = "unix:///var/run/system-docker.sock"
	DOCKER_HOST        = "unix:///var/run/docker.sock"
	IMAGES_PATH        = "/usr/share/ros"
	IMAGES_PATTERN     = "images*.tar"
	MODULES_ARCHIVE    = "/modules.tar"
	DEBUG              = false
	SYSTEM_DOCKER_LOG  = "/var/log/system-docker.log"

	LABEL         = "label"
	HASH          = "io.rancher.os.hash"
	ID            = "io.rancher.os.id"
	DETACH        = "io.rancher.os.detach"
	CREATE_ONLY   = "io.rancher.os.createonly"
	RELOAD_CONFIG = "io.rancher.os.reloadconfig"
	SCOPE         = "io.rancher.os.scope"
	SYSTEM        = "system"

	OsConfigFile           = "/usr/share/ros/os-config.yml"
	CloudConfigDir         = "/var/lib/rancher/conf/cloud-config.d"
	CloudConfigBootFile    = "/var/lib/rancher/conf/cloud-config.d/boot.yml"
	CloudConfigPrivateFile = "/var/lib/rancher/conf/cloud-config.d/private.yml"
	CloudConfigScriptFile  = "/var/lib/rancher/conf/cloud-config-script"
	MetaDataFile           = "/var/lib/rancher/conf/metadata"
	CloudConfigFile        = "/var/lib/rancher/conf/cloud-config.yml"
)

var (
	VERSION string
)

func init() {
	if VERSION == "" {
		VERSION = "v0.0.0-dev"
	}
}

type ContainerConfig struct {
	Id             string                 `yaml:"id,omitempty"`
	Cmd            string                 `yaml:"run,omitempty"`
	MigrateVolumes bool                   `yaml:"migrate_volumes,omitempty"`
	ReloadConfig   bool                   `yaml:"reload_config,omitempty"`
	CreateOnly     bool                   `yaml:"create_only,omitempty"`
	Service        *project.ServiceConfig `yaml:"service,omitempty"`
}

type Repository struct {
	Url string `yaml:"url,omitempty"`
}

type Repositories map[string]Repository

type CloudConfig struct {
	SSHAuthorizedKeys []string      `yaml:"ssh_authorized_keys"`
	WriteFiles        []config.File `yaml:"write_files"`
	Hostname          string        `yaml:"hostname"`

	Rancher RancherConfig `yaml:"rancher,omitempty"`
}

type RancherConfig struct {
	Environment         map[string]string                 `yaml:"environment,omitempty"`
	Services            map[string]*project.ServiceConfig `yaml:"services,omitempty"`
	BootstrapContainers map[string]*project.ServiceConfig `yaml:"bootstrap,omitempty"`
	Autoformat          map[string]*project.ServiceConfig `yaml:"autoformat,omitempty"`
	BootstrapDocker     DockerConfig                      `yaml:"bootstrap_docker,omitempty"`
	CloudInit           CloudInit                         `yaml:"cloud_init,omitempty"`
	Debug               bool                              `yaml:"debug,omitempty"`
	RmUsr               bool                              `yaml:"rm_usr,omitempty"`
	Log                 bool                              `yaml:"log,omitempty"`
	Disable             []string                          `yaml:"disable,omitempty"`
	ServicesInclude     map[string]bool                   `yaml:"services_include,omitempty"`
	Modules             []string                          `yaml:"modules,omitempty"`
	Network             netconf.NetworkConfig             `yaml:"network,omitempty"`
	Repositories        Repositories                      `yaml:"repositories,omitempty"`
	Ssh                 SshConfig                         `yaml:"ssh,omitempty"`
	State               StateConfig                       `yaml:"state,omitempty"`
	SystemDocker        DockerConfig                      `yaml:"system_docker,omitempty"`
	Upgrade             UpgradeConfig                     `yaml:"upgrade,omitempty"`
	Docker              DockerConfig                      `yaml:"docker,omitempty"`
}

type UpgradeConfig struct {
	Url      string `yaml:"url,omitempty"`
	Image    string `yaml:"image,omitempty"`
	Rollback string `yaml:"rollback,omitempty"`
}

type DockerConfig struct {
	TLS            bool     `yaml:"tls,omitempty"`
	TLSArgs        []string `yaml:"tls_args,flow,omitempty"`
	Args           []string `yaml:"args,flow,omitempty"`
	ExtraArgs      []string `yaml:"extra_args,flow,omitempty"`
	ServerCert     string   `yaml:"server_cert,omitempty"`
	ServerKey      string   `yaml:"server_key,omitempty"`
	CACert         string   `yaml:"ca_cert,omitempty"`
	CAKey          string   `yaml:"ca_key,omitempty"`
	Environment    []string `yaml:"environment,omitempty"`
	StorageContext string   `yaml:"storage_context,omitempty"`
}

type SshConfig struct {
	Keys map[string]string `yaml:"keys,omitempty"`
}

type StateConfig struct {
	FsType     string   `yaml:"fstype,omitempty"`
	Dev        string   `yaml:"dev,omitempty"`
	Required   bool     `yaml:"required,omitempty"`
	Autoformat []string `yaml:"autoformat,omitempty"`
	FormatZero bool     `yaml:"formatzero,omitempty"`
}

type CloudInit struct {
	Datasources []string `yaml:"datasources,omitempty"`
}

func (r Repositories) ToArray() []string {
	result := make([]string, 0, len(r))
	for _, repo := range r {
		if repo.Url != "" {
			result = append(result, repo.Url)
		}
	}

	return result
}
<|endoftext|>


<commit_before>package main

import "fmt"

//====================================

type OrangeObj interface {
	Print()
	Eval(Env) OrangeObj
}

/* primitive */
type OrangePrimitive func(OrangeObj) OrangeObj

func (obj OrangePrimitive) Print() {
	fmt.Printf("<#primitive>")
}

func (obj OrangePrimitive) Eval(env Env) OrangeObj {
	return Void
}

/* undefined */
type OrangeUndefined struct{}

func (obj OrangeUndefined) Print() {
	fmt.Printf("<#undefined>")
}

func (obj OrangeUndefined) Eval(env Env) OrangeObj {
	return Undefined
}

/* void */
type OrangeVoid struct{}

func (obj OrangeVoid) Print() {
	fmt.Printf("<#void>")
}

func (ovoid OrangeVoid) Eval(env Env) OrangeObj {
	return Void
}

/* boolean */
type OrangeBoolean bool

func (obj OrangeBoolean) Print() {
	var s string
	if obj {
		s = "#t"
	} else {
		s = "#f"
	}
	fmt.Printf("%s", s)
}
func (obj OrangeBoolean) Eval(env Env) OrangeObj {
	return obj
}

/* integer */
type OrangeInteger int

func (obj OrangeInteger) Print() {
	fmt.Printf("%d", obj)
}
func (obj OrangeInteger) Eval(env Env) OrangeObj {
	return obj
}

/* string */
type OrangeString string

func (obj OrangeString) Print() {
	fmt.Printf("%s", obj)
}
func (obj OrangeString) Eval(env Env) OrangeObj {
	return obj
}

/* symbol */
type OrangeSymbol string

func (obj OrangeSymbol) Print() {
	fmt.Printf("'%s", obj)
}
func (obj OrangeSymbol) Eval(env Env) OrangeObj {
	return Void
}

/* pair */
type OrangePair struct {
	car OrangeObj
	cdr OrangeObj
}

func (obj OrangePair) Print() {
	if obj == Nil {
		//fmt.Printf("'()")
		fmt.Printf("nil")
	} else {
		fmt.Printf("(")
		obj.car.Print()
		fmt.Printf("%c", ',')
		obj.cdr.Print()
		fmt.Printf(")")
	}
}

/* eval */
func (obj OrangePair) Eval(env Env) OrangeObj {
	if obj == Nil {
		return Nil
	} else {
		first := car(obj)
		if sym, ok := first.(OrangeSymbol); ok {
			switch sym {
			case "if":
				sym.Print()
			case "lambda":
				sym.Print()
			default:
				lookup_variable_value(sym, env)
			}
		} else if pair, ok := first.(OrangePair); ok {
			proc := car(pair).Eval(env)
			if proc, ok := proc.(OrangePair); ok {
				return apply(proc, list_of_values(pair, env))
			} else {
				panic("some thing error!")
			}
		} else {
			panic("not supported exp type")
		}
		return Void
	}
}

//====================================

type Env []map[OrangeSymbol]OrangeObj

/* get value for a variable */
func lookup_variable_value(sym OrangeSymbol, env Env) OrangeObj {
	return Void
}

/* eval parameters */
func list_of_values(pair OrangePair, env Env) OrangePair {
	return OrangePair{}
}

/*
('primitive <proc>)
('procedure params,body,env)
*/
func apply(procedure OrangePair, arguments OrangePair) OrangeObj {
	first := car(procedure)
	if sym, ok := first.(OrangeSymbol); ok {
		if sym == "primitive" {
		} else if sym == "procedure" {
		} else {
			panic("not supported procedure type")
		}
	} else {
		panic("error! first must be OrangeSymbol")
	}
	return Void
}

//====================================

/* global values */
var Nil OrangePair = OrangePair{}
var Undefined OrangeUndefined = OrangeUndefined{}
var Void OrangeVoid = OrangeVoid{}

//====================================

func cons(left OrangeObj, right OrangeObj) OrangePair {
	return OrangePair{left, right}
}

func car(obj OrangeObj) OrangeObj {
	if pair, ok := obj.(OrangePair); ok {
		return pair.car
	} else {
		panic("not pair object,can't get car")
	}
}
func cdr(obj OrangeObj) OrangeObj {
	if pair, ok := obj.(OrangePair); ok {
		return pair.cdr
	} else {
		panic("not pair object,can't get cdr")
	}
}

func cadr(pair OrangeObj) OrangeObj { return car(cdr(pair)) }
func cddr(pair OrangeObj) OrangeObj { return cdr(cdr(pair)) }

func caddr(pair OrangeObj) OrangeObj { return car(cdr(cdr(pair))) }
func caadr(pair OrangeObj) OrangeObj { return car(car(cdr(pair))) }
func cdadr(pair OrangeObj) OrangeObj { return cdr(car(cdr(pair))) }
func cdddr(pair OrangeObj) OrangeObj { return cdr(cdr(cdr(pair))) }

func cadddr(pair OrangeObj) OrangeObj { return car(cdr(cdr(cdr(pair)))) }

//====================================

func list(elements []OrangeObj) OrangePair {
	len := len(elements)
	if len == 0 {
		return Nil
	} else if len == 1 {
		return cons(elements[0], Nil)
	} else {
		var result_list OrangePair = Nil
		for i := len - 1; i > -1; i-- {
			result_list = cons(elements[i], result_list)
		}
		return result_list
	}
}

func test_list1() {
	nums := []int{1, 2, 3, 4, 5}
	var orange_nums []OrangeObj = []OrangeObj{}
	for i := 0; i < len(nums); i++ {
		orange_nums = append(orange_nums, OrangeInteger(nums[i]))
	}
	mylist := list(orange_nums)
	mylist.Print()
	fmt.Println()
}

//====================================

func main() {
	var left1 OrangeInteger = OrangeInteger(3)
	car(left1)
	var right1 OrangeInteger = 4
	//var n9 OrangeInteger = 4
	cell := cons(left1, cons(right1, Nil))
	cell.Print()
	fmt.Println()
	test_list1()
}
<commit_msg>implementing read<commit_after>package main

import "fmt"
import "io"
import "os"
import "bufio"
import "log"

//====================================

type OrangeObj interface {
	Print()
	Eval(Env) OrangeObj
}

/* primitive */
type OrangePrimitive func(OrangeObj) OrangeObj

func (obj OrangePrimitive) Print() {
	fmt.Printf("<#primitive>")
}

func (obj OrangePrimitive) Eval(env Env) OrangeObj {
	return Void
}

/* undefined */
type OrangeUndefined struct{}

func (obj OrangeUndefined) Print() {
	fmt.Printf("<#undefined>")
}

func (obj OrangeUndefined) Eval(env Env) OrangeObj {
	return Undefined
}

/* void */
type OrangeVoid struct{}

func (obj OrangeVoid) Print() {
	fmt.Printf("<#void>")
}

func (ovoid OrangeVoid) Eval(env Env) OrangeObj {
	return Void
}

/* boolean */
type OrangeBoolean bool

func (obj OrangeBoolean) Print() {
	var s string
	if obj {
		s = "#t"
	} else {
		s = "#f"
	}
	fmt.Printf("%s", s)
}
func (obj OrangeBoolean) Eval(env Env) OrangeObj {
	return obj
}

/* integer */
type OrangeInteger int

func (obj OrangeInteger) Print() {
	fmt.Printf("%d", obj)
}
func (obj OrangeInteger) Eval(env Env) OrangeObj {
	return obj
}

/* string */
type OrangeString string

func (obj OrangeString) Print() {
	fmt.Printf("%s", obj)
}
func (obj OrangeString) Eval(env Env) OrangeObj {
	return obj
}

/* symbol */
type OrangeSymbol string

func (obj OrangeSymbol) Print() {
	fmt.Printf("'%s", obj)
}
func (obj OrangeSymbol) Eval(env Env) OrangeObj {
	return Void
}

/* pair */
type OrangePair struct {
	car OrangeObj
	cdr OrangeObj
}

func (obj OrangePair) Print() {
	if obj == Nil {
		//fmt.Printf("'()")
		fmt.Printf("nil")
	} else {
		fmt.Printf("(")
		obj.car.Print()
		fmt.Printf("%c", ',')
		obj.cdr.Print()
		fmt.Printf(")")
	}
}

/* eval */
func (obj OrangePair) Eval(env Env) OrangeObj {
	if obj == Nil {
		return Nil
	} else {
		first := car(obj)
		if sym, ok := first.(OrangeSymbol); ok {
			switch sym {
			case "if":
				sym.Print()
			case "lambda":
				sym.Print()
			default:
				lookup_variable_value(sym, env)
			}
		} else if pair, ok := first.(OrangePair); ok {
			proc := car(pair).Eval(env)
			if proc, ok := proc.(OrangePair); ok {
				return apply(proc, list_of_values(pair, env))
			} else {
				panic("some thing error!")
			}
		} else {
			panic("not supported exp type")
		}
		return Void
	}
}

//====================================

type Env []map[OrangeSymbol]OrangeObj

/* get value for a variable */
func lookup_variable_value(sym OrangeSymbol, env Env) OrangeObj {
	return Void
}

/* eval parameters */
func list_of_values(pair OrangePair, env Env) OrangePair {
	return OrangePair{}
}

/*
('primitive <proc>)
('procedure params,body,env)
*/
func apply(procedure OrangePair, arguments OrangePair) OrangeObj {
	first := car(procedure)
	if sym, ok := first.(OrangeSymbol); ok {
		if sym == "primitive" {
		} else if sym == "procedure" {
		} else {
			panic("not supported procedure type")
		}
	} else {
		panic("error! first must be OrangeSymbol")
	}
	return Void
}

//====================================

var Nil OrangePair = OrangePair{}                 /* empty list */
var Undefined OrangeUndefined = OrangeUndefined{} /* unknow things */
var Void OrangeVoid = OrangeVoid{}                /* nothing */

//====================================

func cons(left OrangeObj, right OrangeObj) OrangePair {
	return OrangePair{left, right}
}

func car(obj OrangeObj) OrangeObj {
	if pair, ok := obj.(OrangePair); ok {
		return pair.car
	} else {
		panic("not pair object,can't get car")
	}
}
func cdr(obj OrangeObj) OrangeObj {
	if pair, ok := obj.(OrangePair); ok {
		return pair.cdr
	} else {
		panic("not pair object,can't get cdr")
	}
}

func cadr(pair OrangeObj) OrangeObj { return car(cdr(pair)) }
func cddr(pair OrangeObj) OrangeObj { return cdr(cdr(pair)) }

func caddr(pair OrangeObj) OrangeObj { return car(cdr(cdr(pair))) }
func caadr(pair OrangeObj) OrangeObj { return car(car(cdr(pair))) }
func cdadr(pair OrangeObj) OrangeObj { return cdr(car(cdr(pair))) }
func cdddr(pair OrangeObj) OrangeObj { return cdr(cdr(cdr(pair))) }

func cadddr(pair OrangeObj) OrangeObj { return car(cdr(cdr(cdr(pair)))) }

func list(elements []OrangeObj) OrangePair {
	len := len(elements)
	if len == 0 {
		return Nil
	} else if len == 1 {
		return cons(elements[0], Nil)
	} else {
		var result_list OrangePair = Nil
		for i := len - 1; i > -1; i-- {
			result_list = cons(elements[i], result_list)
		}
		return result_list
	}
}

func test_list1() {
	nums := []int{1, 2, 3, 4, 5}
	var orange_nums []OrangeObj = []OrangeObj{}
	for i := 0; i < len(nums); i++ {
		orange_nums = append(orange_nums, OrangeInteger(nums[i]))
	}
	mylist := list(orange_nums)
	mylist.Print()
	fmt.Println()
}

//====================================
func primitive_add(params OrangeObj) OrangeObj {
	return OrangeInteger(0)
}

//====================================
const (
	EOF     = -1
	L_PAREN = 0
	R_PAREN = 1
	SYMBOL  = 2
	QUOTE   = 3
	INTEGER = 4
)

func read_token(reader *bufio.Reader) (c string, flag int) {
	//sr := string.NewReader("(define myadd (lambda (a b) (+ a b)))")
	t, size, err := reader.ReadRune()
	if err == io.EOF {
		err = nil
		flag = -1
	} else if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("char=%c,size=%d\n", t, size)
	switch t {
	case '(':
		return string(t), L_PAREN
	case ')':
		return string(t), R_PAREN
	case '\'':
		return string(t), QUOTE
	}
	return string(t), 2
}

/* lparen,rparen,symbol,number */
func read(file_name string) {
	//sr := string.NewReader("(define myadd (lambda (a b) (+ a b)))")
	//symbol_first_1 := "a-zA-Z!$%&*/:<=>?^_~"
	//symbol_next_ := "a-zA-Z!$%&*/:<=>?^_~0-9+-@"
	//symbol := "+|-|..."
	log.Println("----read file----")
	fi, err := os.Open(file_name)
	if err != nil {
		log.Fatal("open file error!")
	}
	reader := bufio.NewReader(fi)
	read_token(reader)
	defer fi.Close()
}

//====================================

func main() {
	/*
		var myfunc OrangePrimitive = primitive_add
		var left1 OrangeInteger = OrangeInteger(3)
		var right1 OrangeInteger = 4
		//var n9 OrangeInteger = 4
		cell := cons(left1, cons(right1, Nil))
		cell.Print()
		fmt.Println()
		test_list1()
		myfunc(left1)
	*/
	read("example.scm")
}
<|endoftext|>


<commit_before>// Copyright (C) 2017, 2018 Damon Revoe. All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

package main

import (
	"fmt"
	"log"

	"github.com/spf13/cobra"
)

func configurePackage(_ string, pd *packageDefinition) error {
	fmt.Println("[configure] " + pd.PackageName)
	return nil
}

func configurePackages(workspaceDir string, pkgNames []string) error {
	wp, err := readWorkspaceParams(workspaceDir)
	if err != nil {
		return err
	}

	pi, err := readPackageDefinitions(workspaceDir, wp)
	if err != nil {
		return err
	}

	if len(pkgNames) > 0 {
		pd, err := pi.getPackageByName(pkgNames[0])
		if err != nil {
			return err
		}
		return configurePackage(workspaceDir, pd)
	}

	privateDir := getPrivateDir(workspaceDir)

	selection, err := readPackageSelection(pi, privateDir)
	if err != nil {
		return err
	}

	for _, pd := range selection {
		if err = configurePackage(workspaceDir, pd); err != nil {
			return err
		}
	}

	return nil
}

// configureCmd represents the configure command
var configureCmd = &cobra.Command{
	Use:   "configure",
	Short: "Configure all selected packages or the specified package",
	Args:  cobra.MaximumNArgs(1),
	Run: func(_ *cobra.Command, args []string) {
		err := configurePackages(getWorkspaceDir(), args)
		if err != nil {
			log.Fatal(err)
		}
	},
}

func init() {
	RootCmd.AddCommand(configureCmd)

	configureCmd.Flags().SortFlags = false
	addQuietFlag(configureCmd)
	addWorkspaceDirFlag(configureCmd)
}
<commit_msg>Implement first working version of configurecmd<commit_after>// Copyright (C) 2017, 2018 Damon Revoe. All rights reserved.
// Use of this source code is governed by the MIT
// license, which can be found in the LICENSE file.

package main

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

	"github.com/spf13/cobra"
)

func configurePackage(workspaceDir string, wp *workspaceParams,
	pd *packageDefinition) error {
	fmt.Println("[configure] " + pd.PackageName)

	privateDir := getPrivateDir(workspaceDir)

	pkgRootDir := getGeneratedPkgRootDir(privateDir)
	pkgDir := pkgRootDir + "/" + pd.PackageName

	buildDir := getBuildDir(privateDir, wp)
	pkgBuildDir := buildDir + "/" + pd.PackageName

	relPkgSrcDir, err := filepath.Rel(pkgBuildDir, pkgDir)
	if err != nil {
		relPkgSrcDir, err = filepath.Abs(pkgDir)
		if err != nil {
			return err
		}
	}

	err = os.MkdirAll(pkgBuildDir, os.FileMode(0775))
	if err != nil {
		return nil
	}

	configurePathname := relPkgSrcDir + "/configure"

	configureCmd := exec.Command(configurePathname, "--quiet")
	configureCmd.Dir = pkgBuildDir
	configureCmd.Stdout = os.Stdout
	configureCmd.Stderr = os.Stderr
	if err := configureCmd.Run(); err != nil {
		return errors.New(configurePathname + ": " + err.Error())
	}

	return nil
}

func configurePackages(pkgNames []string) error {
	workspaceDir := getWorkspaceDir()

	wp, err := readWorkspaceParams(workspaceDir)
	if err != nil {
		return err
	}

	pi, err := readPackageDefinitions(workspaceDir, wp)
	if err != nil {
		return err
	}

	if len(pkgNames) > 0 {
		pd, err := pi.getPackageByName(pkgNames[0])
		if err != nil {
			return err
		}
		return configurePackage(workspaceDir, wp, pd)
	}

	privateDir := getPrivateDir(workspaceDir)

	selection, err := readPackageSelection(pi, privateDir)
	if err != nil {
		return err
	}

	for _, pd := range selection {
		if err = configurePackage(workspaceDir, wp, pd); err != nil {
			return err
		}
	}

	return nil
}

// configureCmd represents the configure command
var configureCmd = &cobra.Command{
	Use:   "configure",
	Short: "Configure all selected packages or the specified package",
	Args:  cobra.MaximumNArgs(1),
	Run: func(_ *cobra.Command, args []string) {
		err := configurePackages(args)
		if err != nil {
			log.Fatal(err)
		}
	},
}

func init() {
	RootCmd.AddCommand(configureCmd)

	configureCmd.Flags().SortFlags = false
	addQuietFlag(configureCmd)
	addWorkspaceDirFlag(configureCmd)
}
<|endoftext|>


<commit_before>package webhook

import (
	"encoding/json"
	"strings"

	"github.com/google/go-github/github"
	"github.com/macports/mpbot-github/pr/db"
	"log"
	"strconv"
)

func (receiver *Receiver) handlePullRequest(body []byte) {
	defer func() {
		if r := recover(); r != nil {
			log.Println(r)
		}
	}()

	event := &github.PullRequestEvent{}
	err := json.Unmarshal(body, event)
	if err != nil {
		// TODO: log
		return
	}
	number := *event.Number
	owner := *event.Repo.Owner.Login
	repo := *event.Repo.Name

	ports, changes, err := receiver.githubClient.ListChangedPortsAndLines(number)
	if err != nil {
		return
	}

	handles := make(map[string][]string)
	isOpenmaintainer := true
	isNomaintainer := true
	isMaintainer := true
	isOneMaintainer := false
	for i, port := range ports {
		portMaintainer, err := db.GetPortMaintainer(port)
		if err != nil {
			continue
		}
		isNomaintainer = isNomaintainer && portMaintainer.NoMaintainer
		isOpenmaintainer = isOpenmaintainer && (portMaintainer.OpenMaintainer || portMaintainer.NoMaintainer)
		if portMaintainer.NoMaintainer {
			continue
		}
		allMaintainers := append(portMaintainer.Others, portMaintainer.Primary)
		isPortMaintainer := false
		for _, maintainer := range allMaintainers {
			if maintainer.GithubHandle != "" {
				handles[maintainer.GithubHandle] = append(handles[maintainer.GithubHandle], port)
				if maintainer.GithubHandle == *event.Sender.Login {
					isPortMaintainer = true
					isOneMaintainer = true
				}
			}
		}
		if changes[i] > 7 && !isPortMaintainer {
			isMaintainer = false
		}
	}
	isMaintainer = isOneMaintainer && isMaintainer

	switch *event.Action {
	case "opened":
		// Notify maintainers
		mentionSymbol := "@_"
		if receiver.production {
			mentionSymbol = "@"
		}
		if len(handles) > 0 {
			body := "Notifying maintainers:\n"
			for handle, ports := range handles {
				body += mentionSymbol + handle + " for port " + strings.Join(ports, ", ") + ".\n"
			}
			body += "\nBy a harmless bot."
			err = receiver.githubClient.CreateComment(owner, repo, number, &body)
			if err != nil {
				log.Println(err)
			}
		}
		fallthrough
	case "synchronize":
		// Modify labels
		labels, err := receiver.githubClient.ListLabels(owner, repo, number)
		newLabels := make([]string, len(labels))
		copy(newLabels, labels)
		if err != nil {
			return
		}
		maintainerLabels := make([]string, 0)
		if isMaintainer {
			maintainerLabels = append(maintainerLabels, "maintainer")
		}
		if isNomaintainer {
			maintainerLabels = append(maintainerLabels, "maintainer: none")
		} else if isOpenmaintainer {
			maintainerLabels = append(maintainerLabels, "maintainer: open")
		}
		for _, label := range labels {
			if !strings.HasPrefix(label, "maintainer") {
				newLabels = append(newLabels, label)
			}
		}
		newLabels = append(newLabels, maintainerLabels...)
		err = receiver.githubClient.ReplaceLabels(owner, repo, number, newLabels)
		if err != nil {
			log.Println(err)
		}
	}
	log.Println("PR #" + strconv.Itoa(number) + " processed")
}
<commit_msg>Add some logging<commit_after>package webhook

import (
	"encoding/json"
	"strings"

	"github.com/google/go-github/github"
	"github.com/macports/mpbot-github/pr/db"
	"log"
	"strconv"
)

func (receiver *Receiver) handlePullRequest(body []byte) {
	defer func() {
		if r := recover(); r != nil {
			log.Println(r)
		}
	}()

	event := &github.PullRequestEvent{}
	err := json.Unmarshal(body, event)
	if err != nil {
		// TODO: log
		log.Println(err)
		return
	}
	number := *event.Number
	owner := *event.Repo.Owner.Login
	repo := *event.Repo.Name

	ports, changes, err := receiver.githubClient.ListChangedPortsAndLines(number)
	if err != nil {
		log.Println(err)
		return
	}

	handles := make(map[string][]string)
	isOpenmaintainer := true
	isNomaintainer := true
	isMaintainer := true
	isOneMaintainer := false
	for i, port := range ports {
		portMaintainer, err := db.GetPortMaintainer(port)
		if err != nil {
			continue
		}
		isNomaintainer = isNomaintainer && portMaintainer.NoMaintainer
		isOpenmaintainer = isOpenmaintainer && (portMaintainer.OpenMaintainer || portMaintainer.NoMaintainer)
		if portMaintainer.NoMaintainer {
			continue
		}
		allMaintainers := append(portMaintainer.Others, portMaintainer.Primary)
		isPortMaintainer := false
		for _, maintainer := range allMaintainers {
			if maintainer.GithubHandle != "" {
				handles[maintainer.GithubHandle] = append(handles[maintainer.GithubHandle], port)
				if maintainer.GithubHandle == *event.Sender.Login {
					isPortMaintainer = true
					isOneMaintainer = true
				}
			}
		}
		if changes[i] > 7 && !isPortMaintainer {
			isMaintainer = false
		}
	}
	isMaintainer = isOneMaintainer && isMaintainer

	switch *event.Action {
	case "opened":
		// Notify maintainers
		mentionSymbol := "@_"
		if receiver.production {
			mentionSymbol = "@"
		}
		if len(handles) > 0 {
			body := "Notifying maintainers:\n"
			for handle, ports := range handles {
				body += mentionSymbol + handle + " for port " + strings.Join(ports, ", ") + ".\n"
			}
			body += "\nBy a harmless bot."
			err = receiver.githubClient.CreateComment(owner, repo, number, &body)
			if err != nil {
				log.Println(err)
			}
		}
		fallthrough
	case "synchronize":
		// Modify labels
		labels, err := receiver.githubClient.ListLabels(owner, repo, number)
		newLabels := make([]string, len(labels))
		copy(newLabels, labels)
		if err != nil {
			log.Println(err)
			return
		}
		maintainerLabels := make([]string, 0)
		if isMaintainer {
			maintainerLabels = append(maintainerLabels, "maintainer")
		}
		if isNomaintainer {
			maintainerLabels = append(maintainerLabels, "maintainer: none")
		} else if isOpenmaintainer {
			maintainerLabels = append(maintainerLabels, "maintainer: open")
		}
		for _, label := range labels {
			if !strings.HasPrefix(label, "maintainer") {
				newLabels = append(newLabels, label)
			}
		}
		newLabels = append(newLabels, maintainerLabels...)
		err = receiver.githubClient.ReplaceLabels(owner, repo, number, newLabels)
		if err != nil {
			log.Println(err)
		}
	}
	log.Println("PR #" + strconv.Itoa(number) + " processed")
}
<|endoftext|>


<commit_before>/*
agorn is a wrapper around gorename for use with Acme.
It renames the entity under the cursor.

Usage:
	agorn name

Example:
	agorn Foo
renames the entity under the cursor with 'Foo'.

gorename must be installed:
	% go get golang.org/x/tools/cmd/gorename
*/
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"code.google.com/p/goplan9/plan9/acme"
)

type bodyReader struct{ *acme.Win }

func (r bodyReader) Read(data []byte) (int, error) {
	return r.Win.Read("body", data)
}

func openWin() (*acme.Win, error) {
	id, err := strconv.Atoi(os.Getenv("winid"))
	if err != nil {
		return nil, err
	}
	return acme.Open(id, nil)
}

func readAddr(win *acme.Win) (q0, q1 int, err error) {
	if _, _, err := win.ReadAddr(); err != nil {
		return 0, 0, err
	}
	if err := win.Ctl("addr=dot"); err != nil {
		return 0, 0, err
	}
	return win.ReadAddr()
}

func readFilename(win *acme.Win) (string, error) {
	b, err := win.ReadAll("tag")
	if err != nil {
		return "", err
	}
	tag := string(b)
	i := strings.Index(tag, " ")
	if i == -1 {
		return "", fmt.Errorf("cannot get filename from tag")
	}
	return tag[0:i], nil
}

func selection(win *acme.Win) (filename string, off int, err error) {
	filename, err = readFilename(win)
	if err != nil {
		return "", 0, err
	}
	q0, _, err := readAddr(win)
	if err != nil {
		return "", 0, err
	}
	off, err = byteOffset(bufio.NewReader(&bodyReader{win}), q0)
	if err != nil {
		return "", 0, err
	}
	return
}

func byteOffset(r io.RuneReader, off int) (bo int, err error) {
	for i := 0; i != off; i++ {
		_, s, err := r.ReadRune()
		if err != nil {
			return 0, err
		}
		bo += s
	}
	return
}

func reloadShowAddr(win *acme.Win, off int) error {
	if err := win.Ctl("get"); err != nil {
		return err
	}
	if err := win.Addr("#%d", off); err != nil {
		return err
	}
	return win.Ctl("dot=addr\nshow")
}

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "usage: agorn name\n")
		os.Exit(1)
	}

	win, err := openWin()
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot open window: %v\n", err)
		os.Exit(1)
	}

	filename, off, err := selection(win)
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot get selection: %v\n", err)
		os.Exit(1)
	}

	c := exec.Command("gorename", "-offset", fmt.Sprintf("%s:#%d", filename, off), "-to", os.Args[1])
	c.Stderr = os.Stderr
	if err = c.Run(); err != nil {
		fmt.Fprintf(os.Stderr, "rename failed: %v\n", err)
		os.Exit(1)
	}
	if err := reloadShowAddr(win, off); err != nil {
		fmt.Fprintf(os.Stderr, "cannot restore selection: %s\n", err)
	}
}
<commit_msg>Exit with status 1 if an error occured.<commit_after>/*
agorn is a wrapper around gorename for use with Acme.
It renames the entity under the cursor.

Usage:
	agorn name

Example:
	agorn Foo
renames the entity under the cursor with 'Foo'.

gorename must be installed:
	% go get golang.org/x/tools/cmd/gorename
*/
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"code.google.com/p/goplan9/plan9/acme"
)

type bodyReader struct{ *acme.Win }

func (r bodyReader) Read(data []byte) (int, error) {
	return r.Win.Read("body", data)
}

func openWin() (*acme.Win, error) {
	id, err := strconv.Atoi(os.Getenv("winid"))
	if err != nil {
		return nil, err
	}
	return acme.Open(id, nil)
}

func readAddr(win *acme.Win) (q0, q1 int, err error) {
	if _, _, err := win.ReadAddr(); err != nil {
		return 0, 0, err
	}
	if err := win.Ctl("addr=dot"); err != nil {
		return 0, 0, err
	}
	return win.ReadAddr()
}

func readFilename(win *acme.Win) (string, error) {
	b, err := win.ReadAll("tag")
	if err != nil {
		return "", err
	}
	tag := string(b)
	i := strings.Index(tag, " ")
	if i == -1 {
		return "", fmt.Errorf("cannot get filename from tag")
	}
	return tag[0:i], nil
}

func selection(win *acme.Win) (filename string, off int, err error) {
	filename, err = readFilename(win)
	if err != nil {
		return "", 0, err
	}
	q0, _, err := readAddr(win)
	if err != nil {
		return "", 0, err
	}
	off, err = byteOffset(bufio.NewReader(&bodyReader{win}), q0)
	if err != nil {
		return "", 0, err
	}
	return
}

func byteOffset(r io.RuneReader, off int) (bo int, err error) {
	for i := 0; i != off; i++ {
		_, s, err := r.ReadRune()
		if err != nil {
			return 0, err
		}
		bo += s
	}
	return
}

func reloadShowAddr(win *acme.Win, off int) error {
	if err := win.Ctl("get"); err != nil {
		return err
	}
	if err := win.Addr("#%d", off); err != nil {
		return err
	}
	return win.Ctl("dot=addr\nshow")
}

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "usage: agorn name\n")
		os.Exit(1)
	}

	win, err := openWin()
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot open window: %v\n", err)
		os.Exit(1)
	}

	filename, off, err := selection(win)
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot get selection: %v\n", err)
		os.Exit(1)
	}

	c := exec.Command("gorename", "-offset", fmt.Sprintf("%s:#%d", filename, off), "-to", os.Args[1])
	c.Stderr = os.Stderr
	if err = c.Run(); err != nil {
		fmt.Fprintf(os.Stderr, "rename failed: %v\n", err)
		os.Exit(1)
	}
	if err := reloadShowAddr(win, off); err != nil {
		fmt.Fprintf(os.Stderr, "cannot restore selection: %s\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>/*
agorn is a wrapper around gorename for use with Acme.
It renames the entity under the cursor.

Usage:
	agorn <name>

Example:
	agorn Foo
renames the entity under the cursor with 'Foo'.

gorename must be installed:
	% go get golang.org/x/tools/cmd/gorename
*/
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"code.google.com/p/goplan9/plan9/acme"
)

type bodyReader struct{ *acme.Win }

func (r bodyReader) Read(data []byte) (int, error) {
	return r.Win.Read("body", data)
}

func openWin() (*acme.Win, error) {
	id, err := strconv.Atoi(os.Getenv("winid"))
	if err != nil {
		return nil, err
	}
	return acme.Open(id, nil)
}

func readAddr(win *acme.Win) (q0, q1 int, err error) {
	if _, _, err := win.ReadAddr(); err != nil {
		return 0, 0, err
	}
	if err := win.Ctl("addr=dot"); err != nil {
		return 0, 0, err
	}
	return win.ReadAddr()
}

func readFilename(win *acme.Win) (string, error) {
	b, err := win.ReadAll("tag")
	if err != nil {
		return "", err
	}
	tag := string(b)
	i := strings.Index(tag, " ")
	if i == -1 {
		return "", fmt.Errorf("cannot get filename from tag")
	}
	return tag[0:i], nil
}

func selection(win *acme.Win) (filename string, off int, err error) {
	filename, err = readFilename(win)
	if err != nil {
		return "", 0, err
	}
	q0, _, err := readAddr(win)
	if err != nil {
		return "", 0, err
	}
	off, err = byteOffset(bufio.NewReader(&bodyReader{win}), q0)
	if err != nil {
		return "", 0, err
	}
	return
}

func byteOffset(r io.RuneReader, off int) (bo int, err error) {
	for i := 0; i != off; i++ {
		_, s, err := r.ReadRune()
		if err != nil {
			return 0, err
		}
		bo += s
	}
	return
}

func reloadShowAddr(win *acme.Win, off int) error {
	if err := win.Ctl("get"); err != nil {
		return err
	}
	if err := win.Addr("#%d", off); err != nil {
		return err
	}
	return win.Ctl("dot=addr\nshow")
}

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "usage: agorn <name>\n")
		os.Exit(1)
	}

	win, err := openWin()
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot open window: %v\n", err)
		os.Exit(1)
	}

	filename, off, err := selection(win)
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot get selection: %v\n", err)
		os.Exit(1)
	}

	c := exec.Command("gorename", "-offset", fmt.Sprintf("%s:#%d", filename, off), "-to", os.Args[1])
	c.Stderr = os.Stderr
	if err = c.Run(); err != nil {
		fmt.Fprintf(os.Stderr, "rename failed: %v\n", err)
		os.Exit(1)
	}
	if err := reloadShowAddr(win, off); err != nil {
		fmt.Fprintf(os.Stderr, "cannot restore selection: %s\n", err)
		os.Exit(1)
	}
}
<commit_msg>Begin usage with a capital letter.<commit_after>/*
agorn is a wrapper around gorename for use with Acme.
It renames the entity under the cursor.

Usage:
	agorn <name>

Example:
	agorn Foo
renames the entity under the cursor with 'Foo'.

gorename must be installed:
	% go get golang.org/x/tools/cmd/gorename
*/
package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"os/exec"
	"strconv"
	"strings"

	"code.google.com/p/goplan9/plan9/acme"
)

type bodyReader struct{ *acme.Win }

func (r bodyReader) Read(data []byte) (int, error) {
	return r.Win.Read("body", data)
}

func openWin() (*acme.Win, error) {
	id, err := strconv.Atoi(os.Getenv("winid"))
	if err != nil {
		return nil, err
	}
	return acme.Open(id, nil)
}

func readAddr(win *acme.Win) (q0, q1 int, err error) {
	if _, _, err := win.ReadAddr(); err != nil {
		return 0, 0, err
	}
	if err := win.Ctl("addr=dot"); err != nil {
		return 0, 0, err
	}
	return win.ReadAddr()
}

func readFilename(win *acme.Win) (string, error) {
	b, err := win.ReadAll("tag")
	if err != nil {
		return "", err
	}
	tag := string(b)
	i := strings.Index(tag, " ")
	if i == -1 {
		return "", fmt.Errorf("cannot get filename from tag")
	}
	return tag[0:i], nil
}

func selection(win *acme.Win) (filename string, off int, err error) {
	filename, err = readFilename(win)
	if err != nil {
		return "", 0, err
	}
	q0, _, err := readAddr(win)
	if err != nil {
		return "", 0, err
	}
	off, err = byteOffset(bufio.NewReader(&bodyReader{win}), q0)
	if err != nil {
		return "", 0, err
	}
	return
}

func byteOffset(r io.RuneReader, off int) (bo int, err error) {
	for i := 0; i != off; i++ {
		_, s, err := r.ReadRune()
		if err != nil {
			return 0, err
		}
		bo += s
	}
	return
}

func reloadShowAddr(win *acme.Win, off int) error {
	if err := win.Ctl("get"); err != nil {
		return err
	}
	if err := win.Addr("#%d", off); err != nil {
		return err
	}
	return win.Ctl("dot=addr\nshow")
}

func main() {
	if len(os.Args) < 2 {
		fmt.Fprintf(os.Stderr, "Usage: agorn <name>\n")
		os.Exit(1)
	}

	win, err := openWin()
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot open window: %v\n", err)
		os.Exit(1)
	}

	filename, off, err := selection(win)
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot get selection: %v\n", err)
		os.Exit(1)
	}

	c := exec.Command("gorename", "-offset", fmt.Sprintf("%s:#%d", filename, off), "-to", os.Args[1])
	c.Stderr = os.Stderr
	if err = c.Run(); err != nil {
		fmt.Fprintf(os.Stderr, "rename failed: %v\n", err)
		os.Exit(1)
	}
	if err := reloadShowAddr(win, off); err != nil {
		fmt.Fprintf(os.Stderr, "cannot restore selection: %s\n", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package kubernetes

import (
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/cache"
	"k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"
)

// These constants are keys used in node metadata
const (
	Namespace = "kubernetes_namespace"
)

// Client keeps track of running kubernetes pods and services
type Client interface {
	Stop()
	WalkPods(f func(Pod) error) error
	WalkServices(f func(Service) error) error
}

type client struct {
	quit             chan struct{}
	client           cache.Getter
	podReflector     *cache.Reflector
	serviceReflector *cache.Reflector
	podStore         *cache.StoreToPodLister
	serviceStore     *cache.StoreToServiceLister
}

// NewClient returns a usable Client. Don't forget to Stop it.
func NewClient(addr string, resyncPeriod time.Duration) (Client, error) {
	var config *unversioned.Config
	if addr != "" {
		config = &unversioned.Config{Host: addr}
	} else {
		// If no API server address was provided, assume we are running
		// inside a pod. Try to connect to the API server through its
		// Service environment variables, using the default Service
		// Account Token.
		var err error
		if config, err = unversioned.InClusterConfig(); err != nil {
			return nil, err
		}
	}

	c, err := unversioned.New(config)
	if err != nil {
		return nil, err
	}

	podListWatch := cache.NewListWatchFromClient(c, "pods", api.NamespaceAll, fields.Everything())
	podStore := cache.NewStore(cache.MetaNamespaceKeyFunc)
	podReflector := cache.NewReflector(podListWatch, &api.Pod{}, podStore, resyncPeriod)

	serviceListWatch := cache.NewListWatchFromClient(c, "services", api.NamespaceAll, fields.Everything())
	serviceStore := cache.NewStore(cache.MetaNamespaceKeyFunc)
	serviceReflector := cache.NewReflector(serviceListWatch, &api.Service{}, serviceStore, resyncPeriod)

	quit := make(chan struct{})
	podReflector.RunUntil(quit)
	serviceReflector.RunUntil(quit)

	return &client{
		quit:             quit,
		client:           c,
		podReflector:     podReflector,
		podStore:         &cache.StoreToPodLister{Store: podStore},
		serviceReflector: serviceReflector,
		serviceStore:     &cache.StoreToServiceLister{Store: serviceStore},
	}, nil
}

func (c *client) WalkPods(f func(Pod) error) error {
	pods, err := c.podStore.List(labels.Everything())
	if err != nil {
		return err
	}
	for _, pod := range pods {
		if err := f(NewPod(pod)); err != nil {
			return err
		}
	}
	return nil
}

func (c *client) WalkServices(f func(Service) error) error {
	list, err := c.serviceStore.List()
	if err != nil {
		return err
	}
	for i := range list.Items {
		if err := f(NewService(&(list.Items[i]))); err != nil {
			return err
		}
	}
	return nil
}

func (c *client) Stop() {
	close(c.quit)
}
<commit_msg>k8s: Log errors when contacting the API server<commit_after>package kubernetes

import (
	"log"
	"time"

	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/client/cache"
	"k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/util"
)

// These constants are keys used in node metadata
const (
	Namespace = "kubernetes_namespace"
)

// Client keeps track of running kubernetes pods and services
type Client interface {
	Stop()
	WalkPods(f func(Pod) error) error
	WalkServices(f func(Service) error) error
}

type client struct {
	quit             chan struct{}
	client           cache.Getter
	podReflector     *cache.Reflector
	serviceReflector *cache.Reflector
	podStore         *cache.StoreToPodLister
	serviceStore     *cache.StoreToServiceLister
}

// runReflectorUntil is equivalent to cache.Reflector.RunUntil, but it also logs
// errors, which cache.Reflector.RunUntil simply ignores
func runReflectorUntil(r *cache.Reflector, resyncPeriod time.Duration, stopCh <-chan struct{}) {
	loggingListAndWatch := func() {
		if err := r.ListAndWatch(stopCh); err != nil {
			log.Printf("Kubernetes reflector error: %v", err)
		}
	}
	go util.Until(loggingListAndWatch, resyncPeriod, stopCh)
}

// NewClient returns a usable Client. Don't forget to Stop it.
func NewClient(addr string, resyncPeriod time.Duration) (Client, error) {
	var config *unversioned.Config
	if addr != "" {
		config = &unversioned.Config{Host: addr}
	} else {
		// If no API server address was provided, assume we are running
		// inside a pod. Try to connect to the API server through its
		// Service environment variables, using the default Service
		// Account Token.
		var err error
		if config, err = unversioned.InClusterConfig(); err != nil {
			return nil, err
		}
	}

	c, err := unversioned.New(config)
	if err != nil {
		return nil, err
	}

	podListWatch := cache.NewListWatchFromClient(c, "pods", api.NamespaceAll, fields.Everything())
	podStore := cache.NewStore(cache.MetaNamespaceKeyFunc)
	podReflector := cache.NewReflector(podListWatch, &api.Pod{}, podStore, resyncPeriod)

	serviceListWatch := cache.NewListWatchFromClient(c, "services", api.NamespaceAll, fields.Everything())
	serviceStore := cache.NewStore(cache.MetaNamespaceKeyFunc)
	serviceReflector := cache.NewReflector(serviceListWatch, &api.Service{}, serviceStore, resyncPeriod)

	quit := make(chan struct{})
	runReflectorUntil(podReflector, resyncPeriod, quit)
	runReflectorUntil(serviceReflector, resyncPeriod, quit)

	return &client{
		quit:             quit,
		client:           c,
		podReflector:     podReflector,
		podStore:         &cache.StoreToPodLister{Store: podStore},
		serviceReflector: serviceReflector,
		serviceStore:     &cache.StoreToServiceLister{Store: serviceStore},
	}, nil
}

func (c *client) WalkPods(f func(Pod) error) error {
	pods, err := c.podStore.List(labels.Everything())
	if err != nil {
		return err
	}
	for _, pod := range pods {
		if err := f(NewPod(pod)); err != nil {
			return err
		}
	}
	return nil
}

func (c *client) WalkServices(f func(Service) error) error {
	list, err := c.serviceStore.List()
	if err != nil {
		return err
	}
	for i := range list.Items {
		if err := f(NewService(&(list.Items[i]))); err != nil {
			return err
		}
	}
	return nil
}

func (c *client) Stop() {
	close(c.quit)
}
<|endoftext|>


<commit_before>package goose

import (
	"code.google.com/p/go.net/html"
	"github.com/PuerkitoBio/goquery"
)

type parser struct{}

func NewParser() *parser {
	return &parser{}
}

func (this *parser) dropTag(selection *goquery.Selection) {
	selection.Each(func(i int, s *goquery.Selection) {
		node := s.Get(0)
		node.Data = s.Text()
		node.Type = html.TextNode
	})
}

func (this *parser) indexOfAttribute(selection *goquery.Selection, attr string) int {
	node := selection.Get(0)
	for i, a := range node.Attr {
		if a.Key == attr {
			return i
		}
	}
	return -1
}

func (this *parser) delAttr(selection *goquery.Selection, attr string) {
	idx := this.indexOfAttribute(selection, attr)
	if idx > -1 {
		node := selection.Get(0)
		node.Attr = append(node.Attr[:idx], node.Attr[idx+1:]...)
	}
}

func (this *parser) getElementsByTags(div *goquery.Selection, tags []string) *goquery.Selection {
	selection := new(goquery.Selection)
	for _, tag := range tags {
		selections := div.Find(tag)
		if selections != nil {
			selection = selection.Union(selections)
		}
	}
	return selection
}

func (this *parser) clear(selection *goquery.Selection) {
	selection.Nodes = make([]*html.Node, 0)
}

func (this *parser) removeNode(selection *goquery.Selection) {
	if selection != nil {
		node := selection.Get(0)
		if node != nil && node.Parent != nil {
			node.Parent.RemoveChild(node)
		}
	}
}

func (this *parser) name(selector string, selection *goquery.Selection) string {
	value, exists := selection.Attr(selector)
	if exists {
		return value
	}
	return ""
}

func (this *parser) setAttr(selection *goquery.Selection, attr string, value string) {
	node := selection.Get(0)
	attrs := make([]html.Attribute, 0)
	for _, a := range node.Attr {
		if a.Key != attr {
			newAttr := new(html.Attribute)
			newAttr.Key = a.Key
			newAttr.Val = a.Val
			attrs = append(attrs, *newAttr)
		}
	}
	newAttr := new(html.Attribute)
	newAttr.Key = attr
	newAttr.Val = value
	attrs = append(attrs, *newAttr)
	node.Attr = attrs
}
<commit_msg>check if selection.Size > 0 in setAttr<commit_after>package goose

import (
	"code.google.com/p/go.net/html"
	"github.com/PuerkitoBio/goquery"
)

type parser struct{}

func NewParser() *parser {
	return &parser{}
}

func (this *parser) dropTag(selection *goquery.Selection) {
	selection.Each(func(i int, s *goquery.Selection) {
		node := s.Get(0)
		node.Data = s.Text()
		node.Type = html.TextNode
	})
}

func (this *parser) indexOfAttribute(selection *goquery.Selection, attr string) int {
	node := selection.Get(0)
	for i, a := range node.Attr {
		if a.Key == attr {
			return i
		}
	}
	return -1
}

func (this *parser) delAttr(selection *goquery.Selection, attr string) {
	idx := this.indexOfAttribute(selection, attr)
	if idx > -1 {
		node := selection.Get(0)
		node.Attr = append(node.Attr[:idx], node.Attr[idx+1:]...)
	}
}

func (this *parser) getElementsByTags(div *goquery.Selection, tags []string) *goquery.Selection {
	selection := new(goquery.Selection)
	for _, tag := range tags {
		selections := div.Find(tag)
		if selections != nil {
			selection = selection.Union(selections)
		}
	}
	return selection
}

func (this *parser) clear(selection *goquery.Selection) {
	selection.Nodes = make([]*html.Node, 0)
}

func (this *parser) removeNode(selection *goquery.Selection) {
	if selection != nil {
		node := selection.Get(0)
		if node != nil && node.Parent != nil {
			node.Parent.RemoveChild(node)
		}
	}
}

func (this *parser) name(selector string, selection *goquery.Selection) string {
	value, exists := selection.Attr(selector)
	if exists {
		return value
	}
	return ""
}

func (this *parser) setAttr(selection *goquery.Selection, attr string, value string) {
	if selection.Size() > 0 {
		node := selection.Get(0)
		attrs := make([]html.Attribute, 0)
		for _, a := range node.Attr {
			if a.Key != attr {
				newAttr := new(html.Attribute)
				newAttr.Key = a.Key
				newAttr.Val = a.Val
				attrs = append(attrs, *newAttr)
			}
		}
		newAttr := new(html.Attribute)
		newAttr.Key = attr
		newAttr.Val = value
		attrs = append(attrs, *newAttr)
		node.Attr = attrs
	}
}
<|endoftext|>


<commit_before>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package flags

import (
	"os"
	"path"
)

// A Parser provides command line option parsing. It can contain several
// option groups each with their own set of options.
type Parser struct {
	// Embedded, see Command for more information
	*Command

	// A usage string to be displayed in the help message.
	Usage string

	// Option flags changing the behavior of the parser.
	Options Options

	// NamespaceDelimiter separates group namespaces and option long names
	NamespaceDelimiter string

	// UnknownOptionsHandler is a function which, if non-nil, is called
	// when the parser encounters an option that is unmapped.
	// It takes the option name and remaining args to be parsed, and should
	// return the (modified, if necessary) args, and a non-nil error if the
	// handler fails.
	UnknownOptionHandler func(option string, args []string) ([]string, error)

	internalError error
}

// Options provides parser options that change the behavior of the option
// parser.
type Options uint

const (
	// None indicates no options.
	None Options = 0

	// HelpFlag adds a default Help Options group to the parser containing
	// -h and --help options. When either -h or --help is specified on the
	// command line, the parser will return the special error of type
	// ErrHelp. When PrintErrors is also specified, then the help message
	// will also be automatically printed to os.Stderr.
	HelpFlag = 1 << iota

	// PassDoubleDash passes all arguments after a double dash, --, as
	// remaining command line arguments (i.e. they will not be parsed for
	// flags).
	PassDoubleDash

	// IgnoreUnknown ignores any unknown options and passes them as
	// remaining command line arguments instead of generating an error.
	IgnoreUnknown

	// PrintErrors prints any errors which occurred during parsing to
	// os.Stderr.
	PrintErrors

	// PassAfterNonOption passes all arguments after the first non option
	// as remaining command line arguments. This is equivalent to strict
	// POSIX processing.
	PassAfterNonOption

	// Default is a convenient default set of options which should cover
	// most of the uses of the flags package.
	Default = HelpFlag | PrintErrors | PassDoubleDash
)

// Parse is a convenience function to parse command line options with default
// settings. The provided data is a pointer to a struct representing the
// default option group (named "Application Options"). For more control, use
// flags.NewParser.
func Parse(data interface{}) ([]string, error) {
	return NewParser(data, Default).Parse()
}

// ParseArgs is a convenience function to parse command line options with default
// settings. The provided data is a pointer to a struct representing the
// default option group (named "Application Options"). The args argument is
// the list of command line arguments to parse. If you just want to parse the
// default program command line arguments (i.e. os.Args), then use flags.Parse
// instead. For more control, use flags.NewParser.
func ParseArgs(data interface{}, args []string) ([]string, error) {
	return NewParser(data, Default).ParseArgs(args)
}

// NewParser creates a new parser. It uses os.Args[0] as the application
// name and then calls Parser.NewNamedParser (see Parser.NewNamedParser for
// more details). The provided data is a pointer to a struct representing the
// default option group (named "Application Options"), or nil if the default
// group should not be added. The options parameter specifies a set of options
// for the parser.
func NewParser(data interface{}, options Options) *Parser {
	p := NewNamedParser(path.Base(os.Args[0]), options)

	if data != nil {
		g, err := p.AddGroup("Application Options", "", data)

		if err == nil {
			g.parent = p
		}

		p.internalError = err
	}

	return p
}

// NewNamedParser creates a new parser. The appname is used to display the
// executable name in the built-in help message. Option groups and commands can
// be added to this parser by using AddGroup and AddCommand.
func NewNamedParser(appname string, options Options) *Parser {
	p := &Parser{
		Command:            newCommand(appname, "", "", nil),
		Options:            options,
		NamespaceDelimiter: ".",
	}

	p.Command.parent = p

	return p
}

// Parse parses the command line arguments from os.Args using Parser.ParseArgs.
// For more detailed information see ParseArgs.
func (p *Parser) Parse() ([]string, error) {
	return p.ParseArgs(os.Args[1:])
}

// ParseArgs parses the command line arguments according to the option groups that
// were added to the parser. On successful parsing of the arguments, the
// remaining, non-option, arguments (if any) are returned. The returned error
// indicates a parsing error and can be used with PrintError to display
// contextual information on where the error occurred exactly.
//
// When the common help group has been added (AddHelp) and either -h or --help
// was specified in the command line arguments, a help message will be
// automatically printed. Furthermore, the special error type ErrHelp is returned.
// It is up to the caller to exit the program if so desired.
func (p *Parser) ParseArgs(args []string) ([]string, error) {
	if p.internalError != nil {
		return nil, p.internalError
	}

	p.clearIsSet()

	// Add built-in help group to all commands if necessary
	if (p.Options & HelpFlag) != None {
		p.addHelpGroups(p.showBuiltinHelp)
	}

	compval := os.Getenv("GO_FLAGS_COMPLETION")

	if len(compval) != 0 {
		comp := &completion{parser: p}

		if compval == "verbose" {
			comp.ShowDescriptions = true
		}

		comp.execute(args)

		return nil, nil
	}

	s := &parseState{
		args:    args,
		retargs: make([]string, 0, len(args)),
	}

	p.fillParseState(s)

	for !s.eof() {
		arg := s.pop()

		// When PassDoubleDash is set and we encounter a --, then
		// simply append all the rest as arguments and break out
		if (p.Options&PassDoubleDash) != None && arg == "--" {
			s.addArgs(s.args...)
			break
		}

		if !argumentIsOption(arg) {
			// Note: this also sets s.err, so we can just check for
			// nil here and use s.err later
			if p.parseNonOption(s) != nil {
				break
			}

			continue
		}

		var err error

		prefix, optname, islong := stripOptionPrefix(arg)
		optname, _, argument := splitOption(prefix, optname, islong)

		if islong {
			err = p.parseLong(s, optname, argument)
		} else {
			err = p.parseShort(s, optname, argument)
		}

		if err != nil {
			ignoreUnknown := (p.Options & IgnoreUnknown) != None
			parseErr := wrapError(err)

			if parseErr.Type != ErrUnknownFlag ||
				(!ignoreUnknown && p.UnknownOptionHandler == nil) {
				s.err = parseErr
				break
			}

			if ignoreUnknown {
				s.addArgs(arg)
			} else if p.UnknownOptionHandler != nil {
				modifiedArgs, err := p.UnknownOptionHandler(optname, s.args)
				if err != nil {
					s.err = err
					break
				}
				s.args = modifiedArgs
			}
		}
	}

	if s.err == nil {
		p.eachCommand(func(c *Command) {
			c.eachGroup(func(g *Group) {
				for _, option := range g.options {
					if option.isSet {
						continue
					}

					option.clearDefault()
				}
			})
		}, true)

		s.checkRequired(p)
	}

	var reterr error

	if s.err != nil {
		reterr = s.err
	} else if len(s.command.commands) != 0 && !s.command.SubcommandsOptional {
		reterr = s.estimateCommand()
	} else if cmd, ok := s.command.data.(Commander); ok {
		reterr = cmd.Execute(s.retargs)
	}

	if reterr != nil {
		return append([]string{s.arg}, s.args...), p.printError(reterr)
	}

	return s.retargs, nil
}
<commit_msg>put if-condition on one line<commit_after>// Copyright 2012 Jesse van den Kieboom. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package flags

import (
	"os"
	"path"
)

// A Parser provides command line option parsing. It can contain several
// option groups each with their own set of options.
type Parser struct {
	// Embedded, see Command for more information
	*Command

	// A usage string to be displayed in the help message.
	Usage string

	// Option flags changing the behavior of the parser.
	Options Options

	// NamespaceDelimiter separates group namespaces and option long names
	NamespaceDelimiter string

	// UnknownOptionsHandler is a function which, if non-nil, is called
	// when the parser encounters an option that is unmapped.
	// It takes the option name and remaining args to be parsed, and should
	// return the (modified, if necessary) args, and a non-nil error if the
	// handler fails.
	UnknownOptionHandler func(option string, args []string) ([]string, error)

	internalError error
}

// Options provides parser options that change the behavior of the option
// parser.
type Options uint

const (
	// None indicates no options.
	None Options = 0

	// HelpFlag adds a default Help Options group to the parser containing
	// -h and --help options. When either -h or --help is specified on the
	// command line, the parser will return the special error of type
	// ErrHelp. When PrintErrors is also specified, then the help message
	// will also be automatically printed to os.Stderr.
	HelpFlag = 1 << iota

	// PassDoubleDash passes all arguments after a double dash, --, as
	// remaining command line arguments (i.e. they will not be parsed for
	// flags).
	PassDoubleDash

	// IgnoreUnknown ignores any unknown options and passes them as
	// remaining command line arguments instead of generating an error.
	IgnoreUnknown

	// PrintErrors prints any errors which occurred during parsing to
	// os.Stderr.
	PrintErrors

	// PassAfterNonOption passes all arguments after the first non option
	// as remaining command line arguments. This is equivalent to strict
	// POSIX processing.
	PassAfterNonOption

	// Default is a convenient default set of options which should cover
	// most of the uses of the flags package.
	Default = HelpFlag | PrintErrors | PassDoubleDash
)

// Parse is a convenience function to parse command line options with default
// settings. The provided data is a pointer to a struct representing the
// default option group (named "Application Options"). For more control, use
// flags.NewParser.
func Parse(data interface{}) ([]string, error) {
	return NewParser(data, Default).Parse()
}

// ParseArgs is a convenience function to parse command line options with default
// settings. The provided data is a pointer to a struct representing the
// default option group (named "Application Options"). The args argument is
// the list of command line arguments to parse. If you just want to parse the
// default program command line arguments (i.e. os.Args), then use flags.Parse
// instead. For more control, use flags.NewParser.
func ParseArgs(data interface{}, args []string) ([]string, error) {
	return NewParser(data, Default).ParseArgs(args)
}

// NewParser creates a new parser. It uses os.Args[0] as the application
// name and then calls Parser.NewNamedParser (see Parser.NewNamedParser for
// more details). The provided data is a pointer to a struct representing the
// default option group (named "Application Options"), or nil if the default
// group should not be added. The options parameter specifies a set of options
// for the parser.
func NewParser(data interface{}, options Options) *Parser {
	p := NewNamedParser(path.Base(os.Args[0]), options)

	if data != nil {
		g, err := p.AddGroup("Application Options", "", data)

		if err == nil {
			g.parent = p
		}

		p.internalError = err
	}

	return p
}

// NewNamedParser creates a new parser. The appname is used to display the
// executable name in the built-in help message. Option groups and commands can
// be added to this parser by using AddGroup and AddCommand.
func NewNamedParser(appname string, options Options) *Parser {
	p := &Parser{
		Command:            newCommand(appname, "", "", nil),
		Options:            options,
		NamespaceDelimiter: ".",
	}

	p.Command.parent = p

	return p
}

// Parse parses the command line arguments from os.Args using Parser.ParseArgs.
// For more detailed information see ParseArgs.
func (p *Parser) Parse() ([]string, error) {
	return p.ParseArgs(os.Args[1:])
}

// ParseArgs parses the command line arguments according to the option groups that
// were added to the parser. On successful parsing of the arguments, the
// remaining, non-option, arguments (if any) are returned. The returned error
// indicates a parsing error and can be used with PrintError to display
// contextual information on where the error occurred exactly.
//
// When the common help group has been added (AddHelp) and either -h or --help
// was specified in the command line arguments, a help message will be
// automatically printed. Furthermore, the special error type ErrHelp is returned.
// It is up to the caller to exit the program if so desired.
func (p *Parser) ParseArgs(args []string) ([]string, error) {
	if p.internalError != nil {
		return nil, p.internalError
	}

	p.clearIsSet()

	// Add built-in help group to all commands if necessary
	if (p.Options & HelpFlag) != None {
		p.addHelpGroups(p.showBuiltinHelp)
	}

	compval := os.Getenv("GO_FLAGS_COMPLETION")

	if len(compval) != 0 {
		comp := &completion{parser: p}

		if compval == "verbose" {
			comp.ShowDescriptions = true
		}

		comp.execute(args)

		return nil, nil
	}

	s := &parseState{
		args:    args,
		retargs: make([]string, 0, len(args)),
	}

	p.fillParseState(s)

	for !s.eof() {
		arg := s.pop()

		// When PassDoubleDash is set and we encounter a --, then
		// simply append all the rest as arguments and break out
		if (p.Options&PassDoubleDash) != None && arg == "--" {
			s.addArgs(s.args...)
			break
		}

		if !argumentIsOption(arg) {
			// Note: this also sets s.err, so we can just check for
			// nil here and use s.err later
			if p.parseNonOption(s) != nil {
				break
			}

			continue
		}

		var err error

		prefix, optname, islong := stripOptionPrefix(arg)
		optname, _, argument := splitOption(prefix, optname, islong)

		if islong {
			err = p.parseLong(s, optname, argument)
		} else {
			err = p.parseShort(s, optname, argument)
		}

		if err != nil {
			ignoreUnknown := (p.Options & IgnoreUnknown) != None
			parseErr := wrapError(err)

			if parseErr.Type != ErrUnknownFlag || (!ignoreUnknown && p.UnknownOptionHandler == nil) {
				s.err = parseErr
				break
			}

			if ignoreUnknown {
				s.addArgs(arg)
			} else if p.UnknownOptionHandler != nil {
				modifiedArgs, err := p.UnknownOptionHandler(optname, s.args)
				if err != nil {
					s.err = err
					break
				}
				s.args = modifiedArgs
			}
		}
	}

	if s.err == nil {
		p.eachCommand(func(c *Command) {
			c.eachGroup(func(g *Group) {
				for _, option := range g.options {
					if option.isSet {
						continue
					}

					option.clearDefault()
				}
			})
		}, true)

		s.checkRequired(p)
	}

	var reterr error

	if s.err != nil {
		reterr = s.err
	} else if len(s.command.commands) != 0 && !s.command.SubcommandsOptional {
		reterr = s.estimateCommand()
	} else if cmd, ok := s.command.data.(Commander); ok {
		reterr = cmd.Execute(s.retargs)
	}

	if reterr != nil {
		return append([]string{s.arg}, s.args...), p.printError(reterr)
	}

	return s.retargs, nil
}
<|endoftext|>


<commit_before>package toscalib

import (
	"io"
	"io/ioutil"
	"regexp"

	"github.com/gonum/matrix/mat64"
	"gopkg.in/yaml.v2"
)

// NodeGap is the gap between each node see @FillAdjacencyMatrix for explanation
const nodeGap int = 10

// GetInitialIndex return the index of the initial state of the node in the AdjacencyMatrix
func (nodeTemplate *NodeTemplate) GetInitialIndex() int { return nodeTemplate.Id }

// GetCreateIndex return the index of the Create state of the node in the AdjacencyMatrix
func (nodeTemplate *NodeTemplate) GetCreateIndex() int { return nodeTemplate.Id + 1 }

// GetPreConfigureSourceIndex return the index of the pre_configure_source state of the node in the AdjacencyMatrix
func (nodeTemplate *NodeTemplate) GetPreConfigureSourceIndex() int  { return nodeTemplate.Id + 2 }
func (nodeTemplate *NodeTemplate) GetPreConfigureTargetIndex() int  { return nodeTemplate.Id + 3 }
func (nodeTemplate *NodeTemplate) GetConfigureIndex() int           { return nodeTemplate.Id + 4 }
func (nodeTemplate *NodeTemplate) GetPostConfigureSourceIndex() int { return nodeTemplate.Id + 5 }
func (nodeTemplate *NodeTemplate) GetPostConfigureTargetIndex() int { return nodeTemplate.Id + 6 }
func (nodeTemplate *NodeTemplate) GetStartIndex() int               { return nodeTemplate.Id + 7 }
func (nodeTemplate *NodeTemplate) GetStopIndex() int                { return nodeTemplate.Id + 8 }
func (nodeTemplate *NodeTemplate) GetDeleteIndex() int              { return nodeTemplate.Id + 9 }

// GetNodeTemplate returns a pointer to a node template given its name
// its returns nil if not found
func (toscaStructure *ToscaDefinition) GetNodeTemplate(nodeName string) *NodeTemplate {
	for name, nodeTemplate := range toscaStructure.TopologyTemplate.NodeTemplates {
		if name == nodeName {
			return &nodeTemplate
		}
	}
	return nil
}

// GetNodeTemplate returns a pointer to a node template given its id
// the ID may be the initial index or whatever index of the lifecycle operation
// its returns nil if not found
func (toscaStructure *ToscaDefinition) GetNodeTemplateFromId(nodeId int) *NodeTemplate {
	modulo := 10
	for _, nodeTemplate := range toscaStructure.TopologyTemplate.NodeTemplates {
		if nodeTemplate.Id == nodeId-(nodeId%modulo)+1 {
			return &nodeTemplate
		}
	}
	return nil
}

// FillAdjacencyMatrix fills the adjacency matrix AdjacencyMatrix in the current ToscaDefinition structure
// for more information, see doc/node_instanciation_lifecycle.md
func (toscaStructure *ToscaDefinition) FillAdjacencyMatrix() error {
	// Get the number of nodes
	numberOfNodes := len(toscaStructure.TopologyTemplate.NodeTemplates)
	// Initialize the AdjacencyMatrix
	adjacencyMatrix := mat64.NewDense(numberOfNodes*nodeGap, numberOfNodes*nodeGap, nil)
	index := 1
	for i, nodeDetail := range toscaStructure.TopologyTemplate.NodeTemplates {
		// Set the Id of the node
		nodeDetail.Id = index
		toscaStructure.TopologyTemplate.NodeTemplates[i] = nodeDetail
		index = index + nodeGap
	}
	// Then set the matrix
	for nodeAName, nodeDetail := range toscaStructure.TopologyTemplate.NodeTemplates {
		// Check if the current node has at least one requirement with an interface of type tosca.interfaces.relationship.Configure
		var res1 bool
		var res2 bool
		if nodeDetail.Requirements != nil {
			for _, requirementAssignements := range nodeDetail.Requirements {
				for _, requirementAssignement := range requirementAssignements {
					nodeBName := requirementAssignement.Node
					// Check if we have a requirement type that is .*Configure of if we have an Interface key that is .*Configure
					res1, _ = regexp.MatchString(".*Configure", requirementAssignement.Relationship.Type)
					for inter := range requirementAssignement.Relationship.Interfaces {
						res2, _ = regexp.MatchString(".*Configure", inter)
						if res2 == true {
							break
						}
					}
					// We have a Configure relationship
					if res1 == true || res2 == true {
						//log.Printf("%v Special workflow with %v", nodeAName, nodeBName)
						nodeA := toscaStructure.GetNodeTemplate(nodeAName)
						nodeB := toscaStructure.GetNodeTemplate(nodeBName)
						//nodeB:Create() -> nodeA:Create()
						adjacencyMatrix.Set(nodeB.GetCreateIndex(), nodeA.GetCreateIndex(), 1)
						//nodeA:Create() -> nodeA:PreConfigureSource()
						adjacencyMatrix.Set(nodeA.GetCreateIndex(), nodeA.GetPreConfigureSourceIndex(), 1)
						//nodeA:PreConfigureSource -> nodeB:PreConfigureTarget()
						adjacencyMatrix.Set(nodeA.GetPreConfigureSourceIndex(), nodeB.GetPreConfigureTargetIndex(), 1)
						//nodeB:PreConfigureTarget -> nodeA:Configure()
						adjacencyMatrix.Set(nodeB.GetPreConfigureTargetIndex(), nodeA.GetConfigureIndex(), 1)
						//nodeB:PreConfigureTarget -> nodeB:Configure()
						adjacencyMatrix.Set(nodeB.GetPreConfigureTargetIndex(), nodeB.GetConfigureIndex(), 1)
						//nodeA:Configure() -> nodeA:PostConfigureSource()
						adjacencyMatrix.Set(nodeA.GetConfigureIndex(), nodeA.GetPostConfigureSourceIndex(), 1)
						//nodeB:Configure() -> nodeB:PostConfigureTarget()
						adjacencyMatrix.Set(nodeB.GetConfigureIndex(), nodeB.GetPostConfigureTargetIndex(), 1)
						//nodeA:PostConfigureSource() -> nodeA:Start()
						adjacencyMatrix.Set(nodeA.GetPostConfigureSourceIndex(), nodeA.GetStartIndex(), 1)
						//nodeB:PostConfigureTarget() -> nodeB:Start()
						adjacencyMatrix.Set(nodeB.GetPostConfigureTargetIndex(), nodeB.GetStartIndex(), 1)
						//nodeB:Start() -> nodeA:Start()
						adjacencyMatrix.Set(nodeA.GetStartIndex(), nodeA.GetStartIndex(), 1)
					} else {
						//log.Printf("%v normal workflow with %v", nodeAName, nodeBName)
						nodeA := toscaStructure.GetNodeTemplate(nodeAName)
						nodeB := toscaStructure.GetNodeTemplate(nodeBName)
						// nodeB:Create() -> nodeB:Configure() -> nodeB:Start() -> nodeA:Create() -> nodeA:Configure() -> nodeA:Start()
						adjacencyMatrix.Set(nodeB.GetCreateIndex(), nodeB.GetConfigureIndex(), 1)
						adjacencyMatrix.Set(nodeB.GetConfigureIndex(), nodeB.GetStartIndex(), 1)
						adjacencyMatrix.Set(nodeB.GetStartIndex(), nodeA.GetCreateIndex(), 1)
						adjacencyMatrix.Set(nodeA.GetCreateIndex(), nodeA.GetConfigureIndex(), 1)
						adjacencyMatrix.Set(nodeA.GetConfigureIndex(), nodeA.GetStartIndex(), 1)
					}
				}

			}
		}
		index = index + nodeGap
	}
	toscaStructure.AdjacencyMatrix = *adjacencyMatrix
	return nil
}

// Parse a TOSCA document and fill in the structure
func (toscaStructure *ToscaDefinition) Parse(r io.Reader) error {
	var tempStruct ToscaDefinition
	tempStruct.NodeTypes = make(map[string]NodeType)
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}

	// Unmarshal the data in an interface
	err = yaml.Unmarshal(data, &tempStruct)
	if err != nil {
		return err
	}
	// Sets the initial state
	for _, nodeTemplate := range tempStruct.TopologyTemplate.NodeTemplates {
		nodeTemplate.RunChan = make(chan int)
		nodeTemplate.State = StateInitial
	}
	/*
		// for each node, add its corresponding notetype definition to the structure
		// if not present yet

		// index is the node name and nodeTemplate is the corresponding NodeTemplate
		for _, nodeTemplate := range tempStruct.TopologyTemplate.NodeTemplates {
			// nodeType is he node type of the current NodeTemplate
			nodeType := nodeTemplate.Type
			if _, typeIsPresent := tempStruct.NodeTypes[nodeType]; typeIsPresent == false {
				// Get the corresponding asset and add it to the global structure
				data, err := Asset(nodeType)
				if err != nil {
					//  For debuging purpode
					log.Printf("Cannot find the NodeType definition for %v", nodeType)
				}
				var nt map[string]NodeType
				// Unmarshal the data in an interface
				err = yaml.Unmarshal(data, &nt)
				if err != nil {
					return errors.New(fmt.Sprintf("cannot unmarshal %v (%v)", nodeType, err))
				}
				tempStruct.NodeTypes[nodeType] = nt[nodeType]
			}
		}
	*/
	// TODO: deal with the import files
	*toscaStructure = tempStruct
	err = toscaStructure.FillAdjacencyMatrix()
	if err != nil {
		return err
	}
	return nil

}
<commit_msg>nodegap has been defined and is used instead of the local modulo variable<commit_after>package toscalib

import (
	"io"
	"io/ioutil"
	"regexp"

	"github.com/gonum/matrix/mat64"
	"gopkg.in/yaml.v2"
)

// NodeGap is the gap between each node see @FillAdjacencyMatrix for explanation
const nodeGap int = 10

// GetInitialIndex return the index of the initial state of the node in the AdjacencyMatrix
func (nodeTemplate *NodeTemplate) GetInitialIndex() int { return nodeTemplate.Id }

// GetCreateIndex return the index of the Create state of the node in the AdjacencyMatrix
func (nodeTemplate *NodeTemplate) GetCreateIndex() int { return nodeTemplate.Id + 1 }

// GetPreConfigureSourceIndex return the index of the pre_configure_source state of the node in the AdjacencyMatrix
func (nodeTemplate *NodeTemplate) GetPreConfigureSourceIndex() int  { return nodeTemplate.Id + 2 }
func (nodeTemplate *NodeTemplate) GetPreConfigureTargetIndex() int  { return nodeTemplate.Id + 3 }
func (nodeTemplate *NodeTemplate) GetConfigureIndex() int           { return nodeTemplate.Id + 4 }
func (nodeTemplate *NodeTemplate) GetPostConfigureSourceIndex() int { return nodeTemplate.Id + 5 }
func (nodeTemplate *NodeTemplate) GetPostConfigureTargetIndex() int { return nodeTemplate.Id + 6 }
func (nodeTemplate *NodeTemplate) GetStartIndex() int               { return nodeTemplate.Id + 7 }
func (nodeTemplate *NodeTemplate) GetStopIndex() int                { return nodeTemplate.Id + 8 }
func (nodeTemplate *NodeTemplate) GetDeleteIndex() int              { return nodeTemplate.Id + 9 }

// GetNodeTemplate returns a pointer to a node template given its name
// its returns nil if not found
func (toscaStructure *ToscaDefinition) GetNodeTemplate(nodeName string) *NodeTemplate {
	for name, nodeTemplate := range toscaStructure.TopologyTemplate.NodeTemplates {
		if name == nodeName {
			return &nodeTemplate
		}
	}
	return nil
}

// GetNodeTemplate returns a pointer to a node template given its id
// the ID may be the initial index or whatever index of the lifecycle operation
// its returns nil if not found
func (toscaStructure *ToscaDefinition) GetNodeTemplateFromId(nodeId int) *NodeTemplate {
	for _, nodeTemplate := range toscaStructure.TopologyTemplate.NodeTemplates {
		if nodeTemplate.Id == nodeId-(nodeId%nodeGap)+1 {
			return &nodeTemplate
		}
	}
	return nil
}

// FillAdjacencyMatrix fills the adjacency matrix AdjacencyMatrix in the current ToscaDefinition structure
// for more information, see doc/node_instanciation_lifecycle.md
func (toscaStructure *ToscaDefinition) FillAdjacencyMatrix() error {
	// Get the number of nodes
	numberOfNodes := len(toscaStructure.TopologyTemplate.NodeTemplates)
	// Initialize the AdjacencyMatrix
	adjacencyMatrix := mat64.NewDense(numberOfNodes*nodeGap, numberOfNodes*nodeGap, nil)
	index := 1
	for i, nodeDetail := range toscaStructure.TopologyTemplate.NodeTemplates {
		// Set the Id of the node
		nodeDetail.Id = index
		toscaStructure.TopologyTemplate.NodeTemplates[i] = nodeDetail
		index = index + nodeGap
	}
	// Then set the matrix
	for nodeAName, nodeDetail := range toscaStructure.TopologyTemplate.NodeTemplates {
		// Check if the current node has at least one requirement with an interface of type tosca.interfaces.relationship.Configure
		var res1 bool
		var res2 bool
		if nodeDetail.Requirements != nil {
			for _, requirementAssignements := range nodeDetail.Requirements {
				for _, requirementAssignement := range requirementAssignements {
					nodeBName := requirementAssignement.Node
					// Check if we have a requirement type that is .*Configure of if we have an Interface key that is .*Configure
					res1, _ = regexp.MatchString(".*Configure", requirementAssignement.Relationship.Type)
					for inter := range requirementAssignement.Relationship.Interfaces {
						res2, _ = regexp.MatchString(".*Configure", inter)
						if res2 == true {
							break
						}
					}
					// We have a Configure relationship
					if res1 == true || res2 == true {
						//log.Printf("%v Special workflow with %v", nodeAName, nodeBName)
						nodeA := toscaStructure.GetNodeTemplate(nodeAName)
						nodeB := toscaStructure.GetNodeTemplate(nodeBName)
						//nodeB:Create() -> nodeA:Create()
						adjacencyMatrix.Set(nodeB.GetCreateIndex(), nodeA.GetCreateIndex(), 1)
						//nodeA:Create() -> nodeA:PreConfigureSource()
						adjacencyMatrix.Set(nodeA.GetCreateIndex(), nodeA.GetPreConfigureSourceIndex(), 1)
						//nodeA:PreConfigureSource -> nodeB:PreConfigureTarget()
						adjacencyMatrix.Set(nodeA.GetPreConfigureSourceIndex(), nodeB.GetPreConfigureTargetIndex(), 1)
						//nodeB:PreConfigureTarget -> nodeA:Configure()
						adjacencyMatrix.Set(nodeB.GetPreConfigureTargetIndex(), nodeA.GetConfigureIndex(), 1)
						//nodeB:PreConfigureTarget -> nodeB:Configure()
						adjacencyMatrix.Set(nodeB.GetPreConfigureTargetIndex(), nodeB.GetConfigureIndex(), 1)
						//nodeA:Configure() -> nodeA:PostConfigureSource()
						adjacencyMatrix.Set(nodeA.GetConfigureIndex(), nodeA.GetPostConfigureSourceIndex(), 1)
						//nodeB:Configure() -> nodeB:PostConfigureTarget()
						adjacencyMatrix.Set(nodeB.GetConfigureIndex(), nodeB.GetPostConfigureTargetIndex(), 1)
						//nodeA:PostConfigureSource() -> nodeA:Start()
						adjacencyMatrix.Set(nodeA.GetPostConfigureSourceIndex(), nodeA.GetStartIndex(), 1)
						//nodeB:PostConfigureTarget() -> nodeB:Start()
						adjacencyMatrix.Set(nodeB.GetPostConfigureTargetIndex(), nodeB.GetStartIndex(), 1)
						//nodeB:Start() -> nodeA:Start()
						adjacencyMatrix.Set(nodeA.GetStartIndex(), nodeA.GetStartIndex(), 1)
					} else {
						//log.Printf("%v normal workflow with %v", nodeAName, nodeBName)
						nodeA := toscaStructure.GetNodeTemplate(nodeAName)
						nodeB := toscaStructure.GetNodeTemplate(nodeBName)
						// nodeB:Create() -> nodeB:Configure() -> nodeB:Start() -> nodeA:Create() -> nodeA:Configure() -> nodeA:Start()
						adjacencyMatrix.Set(nodeB.GetCreateIndex(), nodeB.GetConfigureIndex(), 1)
						adjacencyMatrix.Set(nodeB.GetConfigureIndex(), nodeB.GetStartIndex(), 1)
						adjacencyMatrix.Set(nodeB.GetStartIndex(), nodeA.GetCreateIndex(), 1)
						adjacencyMatrix.Set(nodeA.GetCreateIndex(), nodeA.GetConfigureIndex(), 1)
						adjacencyMatrix.Set(nodeA.GetConfigureIndex(), nodeA.GetStartIndex(), 1)
					}
				}

			}
		}
		index = index + nodeGap
	}
	toscaStructure.AdjacencyMatrix = *adjacencyMatrix
	return nil
}

// Parse a TOSCA document and fill in the structure
func (toscaStructure *ToscaDefinition) Parse(r io.Reader) error {
	var tempStruct ToscaDefinition
	tempStruct.NodeTypes = make(map[string]NodeType)
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return err
	}

	// Unmarshal the data in an interface
	err = yaml.Unmarshal(data, &tempStruct)
	if err != nil {
		return err
	}
	// Sets the initial state
	for _, nodeTemplate := range tempStruct.TopologyTemplate.NodeTemplates {
		nodeTemplate.RunChan = make(chan int)
		nodeTemplate.State = StateInitial
	}
	/*
		// for each node, add its corresponding notetype definition to the structure
		// if not present yet

		// index is the node name and nodeTemplate is the corresponding NodeTemplate
		for _, nodeTemplate := range tempStruct.TopologyTemplate.NodeTemplates {
			// nodeType is he node type of the current NodeTemplate
			nodeType := nodeTemplate.Type
			if _, typeIsPresent := tempStruct.NodeTypes[nodeType]; typeIsPresent == false {
				// Get the corresponding asset and add it to the global structure
				data, err := Asset(nodeType)
				if err != nil {
					//  For debuging purpode
					log.Printf("Cannot find the NodeType definition for %v", nodeType)
				}
				var nt map[string]NodeType
				// Unmarshal the data in an interface
				err = yaml.Unmarshal(data, &nt)
				if err != nil {
					return errors.New(fmt.Sprintf("cannot unmarshal %v (%v)", nodeType, err))
				}
				tempStruct.NodeTypes[nodeType] = nt[nodeType]
			}
		}
	*/
	// TODO: deal with the import files
	*toscaStructure = tempStruct
	err = toscaStructure.FillAdjacencyMatrix()
	if err != nil {
		return err
	}
	return nil

}
<|endoftext|>