<commit_before>package db

import (
	"fmt"
	"net/url"
	"strings"

	"github.com/lxc/lxd/lxd/db/generate/lex"
	"github.com/lxc/lxd/shared"
)

// Mapping holds information for mapping database tables to a Go structure.
type Mapping struct {
	Package string   // Package of the Go struct
	Name    string   // Name of the Go struct.
	Fields  []*Field // Metadata about the Go struct.
}

// NaturalKey returns the struct fields that can be used as natural key for
// uniquely identifying a row in the underlying table (==.
//
// By convention the natural key field is the one called "Name", unless
// specified otherwise with the `db:natural_key` tags.
func (m *Mapping) NaturalKey() []*Field {
	key := []*Field{}

	for _, field := range m.Fields {
		if field.Config.Get("primary") != "" {
			key = append(key, field)
		}
	}

	if len(key) == 0 {
		// Default primary key.
		key = append(key, m.FieldByName("Name"))
	}

	return key
}

// ContainsFields checks that the mapping contains fields with the same type
// and name of given ones.
func (m *Mapping) ContainsFields(fields []*Field) bool {
	matches := map[*Field]bool{}

	for _, field := range m.Fields {
		for _, other := range fields {
			if field.Name == other.Name && field.Type.Name == other.Type.Name {
				matches[field] = true
			}
		}
	}

	return len(matches) == len(fields)
}

// FieldByName returns the field with the given name, if any.
func (m *Mapping) FieldByName(name string) *Field {
	for _, field := range m.Fields {
		if field.Name == name {
			return field
		}
	}

	return nil
}

// FieldColumnName returns the column name of the field with the given name,
// prefixed with the entity's table name.
func (m *Mapping) FieldColumnName(name string) string {
	field := m.FieldByName(name)
	return fmt.Sprintf("%s.%s", entityTable(m.Name), field.Column())
}

// FilterFieldByName returns the field with the given name if that field can be
// used as query filter, an error otherwise.
func (m *Mapping) FilterFieldByName(name string) (*Field, error) {
	field := m.FieldByName(name)
	if field == nil {
		return nil, fmt.Errorf("Unknown filter %q", name)
	}

	if field.Type.Code != TypeColumn {
		return nil, fmt.Errorf("Unknown filter %q not a column", name)
	}

	return field, nil
}

// ColumnFields returns the fields that map directly to a database column,
// either on this table or on a joined one.
func (m *Mapping) ColumnFields(exclude ...string) []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if shared.StringInSlice(field.Name, exclude) {
			continue
		}
		if field.Type.Code == TypeColumn {
			fields = append(fields, field)
		}
	}

	return fields
}

// ScalarFields returns the fields that map directly to a single database
// column on another table that can be joined to this one.
func (m *Mapping) ScalarFields() []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if field.Config.Get("join") != "" {
			fields = append(fields, field)
		}
	}

	return fields
}

// RefFields returns the fields that are one-to-many references to other
// tables.
func (m *Mapping) RefFields() []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if field.Type.Code == TypeSlice || field.Type.Code == TypeMap {
			fields = append(fields, field)
		}
	}

	return fields
}

// Field holds all information about a field in a Go struct that is relevant
// for database code generation.
type Field struct {
	Name    string
	Type    Type
	Primary bool // Whether this field is part of the natural primary key.
	Config  url.Values
}

// Stmt must be used only on a non-columnar field. It returns the name of
// statement that should be used to fetch this field. A statement with that
// name must have been generated for the entity at hand.
func (f *Field) Stmt() string {
	switch f.Name {
	case "UsedBy":
		return "used_by"
	default:
		return ""
	}
}

// IsScalar returns true if the field is a scalar column value from a joined table.
func (f *Field) IsScalar() bool {
	return f.Config.Get("join") != ""
}

// IsIndirect returns true if the field is a scalar column value from a joined
// table that in turn requires another join.
func (f *Field) IsIndirect() bool {
	return f.IsScalar() && f.Config.Get("via") != ""
}

// IsPrimary returns true if the field part of the natural key.
func (f *Field) IsPrimary() bool {
	return f.Config.Get("primary") != "" || f.Name == "Name"
}

// Column returns the name of the database column the field maps to. The type
// code of the field must be TypeColumn.
func (f *Field) Column() string {
	if f.Type.Code != TypeColumn {
		panic("attempt to get column name of non-column field")
	}

	column := lex.Snake(f.Name)

	join := f.Config.Get("join")
	if join != "" {
		column = fmt.Sprintf("%s AS %s", join, column)

	}

	return column
}

// ZeroValue returns the literal representing the zero value for this field. The type
// code of the field must be TypeColumn.
func (f *Field) ZeroValue() string {
	if f.Type.Code != TypeColumn {
		panic("attempt to get zero value of non-column field")
	}

	switch f.Type.Name {
	case "string":
		return `""`
	case "int", "instancetype.Type", "int64", "OperationType":
		// FIXME: we use -1 since at the moment integer criteria are
		// required to be positive.
		return "-1"
	case "bool":
		return "false"
	default:
		panic("unsupported zero value")
	}
}

// FieldColumns converts thegiven fields to list of column names separated
// by a comma.
func FieldColumns(fields []*Field) string {
	columns := make([]string, len(fields))

	for i, field := range fields {
		columns[i] = field.Column()
	}

	return strings.Join(columns, ", ")
}

// FieldArgs converts the given fields to function arguments, rendering their
// name and type.
func FieldArgs(fields []*Field) string {
	args := make([]string, len(fields))
	for i, field := range fields {
		args[i] = fmt.Sprintf("%s %s", lex.Minuscule(field.Name), field.Type.Name)
	}

	return strings.Join(args, ", ")
}

// FieldParams converts the given fields to function parameters, rendering their
// name.
func FieldParams(fields []*Field) string {
	args := make([]string, len(fields))
	for i, field := range fields {
		args[i] = lex.Minuscule(field.Name)
	}

	return strings.Join(args, ", ")
}

// FieldCriteria converts the given fields to AND-separated WHERE criteria.
func FieldCriteria(fields []*Field) string {
	criteria := make([]string, len(fields))

	for i, field := range fields {
		criteria[i] = fmt.Sprintf("%s = ?", field.Column())
	}

	return strings.Join(criteria, " AND ")
}

// Type holds all information about a field in a field type that is relevant
// for database code generation.
type Type struct {
	Name string
	Code int
}

// Possible type code.
const (
	TypeColumn = iota
	TypeSlice
	TypeMap
)

// IsColumnType returns true if the given type name is one mapping directly to
// a database column.
func IsColumnType(name string) bool {
	return shared.StringInSlice(name, columnarTypeNames)
}

var columnarTypeNames = []string{
	"bool",
	"instancetype.Type",
	"int",
	"int64",
	"OperationType",
	"string",
	"time.Time",
}
<commit_msg>lxd/db/generate/db/mapping: check Filter field in FilterFieldByName<commit_after>package db

import (
	"fmt"
	"net/url"
	"strings"

	"github.com/lxc/lxd/lxd/db/generate/lex"
	"github.com/lxc/lxd/shared"
)

// Mapping holds information for mapping database tables to a Go structure.
type Mapping struct {
	Package string   // Package of the Go struct
	Name    string   // Name of the Go struct.
	Fields  []*Field // Metadata about the Go struct.
	Filters []*Field // Metadata about the Go struct used for filter fields.
}

// NaturalKey returns the struct fields that can be used as natural key for
// uniquely identifying a row in the underlying table (==.
//
// By convention the natural key field is the one called "Name", unless
// specified otherwise with the `db:natural_key` tags.
func (m *Mapping) NaturalKey() []*Field {
	key := []*Field{}

	for _, field := range m.Fields {
		if field.Config.Get("primary") != "" {
			key = append(key, field)
		}
	}

	if len(key) == 0 {
		// Default primary key.
		key = append(key, m.FieldByName("Name"))
	}

	return key
}

// ContainsFields checks that the mapping contains fields with the same type
// and name of given ones.
func (m *Mapping) ContainsFields(fields []*Field) bool {
	matches := map[*Field]bool{}

	for _, field := range m.Fields {
		for _, other := range fields {
			if field.Name == other.Name && field.Type.Name == other.Type.Name {
				matches[field] = true
			}
		}
	}

	return len(matches) == len(fields)
}

// FieldByName returns the field with the given name, if any.
func (m *Mapping) FieldByName(name string) *Field {
	for _, field := range m.Fields {
		if field.Name == name {
			return field
		}
	}

	return nil
}

// FieldColumnName returns the column name of the field with the given name,
// prefixed with the entity's table name.
func (m *Mapping) FieldColumnName(name string) string {
	field := m.FieldByName(name)
	return fmt.Sprintf("%s.%s", entityTable(m.Name), field.Column())
}

// FilterFieldByName returns the field with the given name if that field can be
// used as query filter, an error otherwise.
func (m *Mapping) FilterFieldByName(name string) (*Field, error) {
	for _, filter := range m.Filters {
		if name == filter.Name {
			if filter.Type.Code != TypeColumn {
				return nil, fmt.Errorf("Unknown filter %q not a column", name)
			}
			return filter, nil
		}
	}

	return nil, fmt.Errorf("Unknown filter %q", name)
}

// ColumnFields returns the fields that map directly to a database column,
// either on this table or on a joined one.
func (m *Mapping) ColumnFields(exclude ...string) []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if shared.StringInSlice(field.Name, exclude) {
			continue
		}
		if field.Type.Code == TypeColumn {
			fields = append(fields, field)
		}
	}

	return fields
}

// ScalarFields returns the fields that map directly to a single database
// column on another table that can be joined to this one.
func (m *Mapping) ScalarFields() []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if field.Config.Get("join") != "" {
			fields = append(fields, field)
		}
	}

	return fields
}

// RefFields returns the fields that are one-to-many references to other
// tables.
func (m *Mapping) RefFields() []*Field {
	fields := []*Field{}

	for _, field := range m.Fields {
		if field.Type.Code == TypeSlice || field.Type.Code == TypeMap {
			fields = append(fields, field)
		}
	}

	return fields
}

// Field holds all information about a field in a Go struct that is relevant
// for database code generation.
type Field struct {
	Name    string
	Type    Type
	Primary bool // Whether this field is part of the natural primary key.
	Config  url.Values
}

// Stmt must be used only on a non-columnar field. It returns the name of
// statement that should be used to fetch this field. A statement with that
// name must have been generated for the entity at hand.
func (f *Field) Stmt() string {
	switch f.Name {
	case "UsedBy":
		return "used_by"
	default:
		return ""
	}
}

// IsScalar returns true if the field is a scalar column value from a joined table.
func (f *Field) IsScalar() bool {
	return f.Config.Get("join") != ""
}

// IsIndirect returns true if the field is a scalar column value from a joined
// table that in turn requires another join.
func (f *Field) IsIndirect() bool {
	return f.IsScalar() && f.Config.Get("via") != ""
}

// IsPrimary returns true if the field part of the natural key.
func (f *Field) IsPrimary() bool {
	return f.Config.Get("primary") != "" || f.Name == "Name"
}

// Column returns the name of the database column the field maps to. The type
// code of the field must be TypeColumn.
func (f *Field) Column() string {
	if f.Type.Code != TypeColumn {
		panic("attempt to get column name of non-column field")
	}

	column := lex.Snake(f.Name)

	join := f.Config.Get("join")
	if join != "" {
		column = fmt.Sprintf("%s AS %s", join, column)

	}

	return column
}

// ZeroValue returns the literal representing the zero value for this field. The type
// code of the field must be TypeColumn.
func (f *Field) ZeroValue() string {
	if f.Type.Code != TypeColumn {
		panic("attempt to get zero value of non-column field")
	}

	switch f.Type.Name {
	case "string":
		return `""`
	case "int", "instancetype.Type", "int64", "OperationType":
		// FIXME: we use -1 since at the moment integer criteria are
		// required to be positive.
		return "-1"
	case "bool":
		return "false"
	default:
		panic("unsupported zero value")
	}
}

// FieldColumns converts thegiven fields to list of column names separated
// by a comma.
func FieldColumns(fields []*Field) string {
	columns := make([]string, len(fields))

	for i, field := range fields {
		columns[i] = field.Column()
	}

	return strings.Join(columns, ", ")
}

// FieldArgs converts the given fields to function arguments, rendering their
// name and type.
func FieldArgs(fields []*Field) string {
	args := make([]string, len(fields))
	for i, field := range fields {
		args[i] = fmt.Sprintf("%s %s", lex.Minuscule(field.Name), field.Type.Name)
	}

	return strings.Join(args, ", ")
}

// FieldParams converts the given fields to function parameters, rendering their
// name.
func FieldParams(fields []*Field) string {
	args := make([]string, len(fields))
	for i, field := range fields {
		args[i] = lex.Minuscule(field.Name)
	}

	return strings.Join(args, ", ")
}

// FieldCriteria converts the given fields to AND-separated WHERE criteria.
func FieldCriteria(fields []*Field) string {
	criteria := make([]string, len(fields))

	for i, field := range fields {
		criteria[i] = fmt.Sprintf("%s = ?", field.Column())
	}

	return strings.Join(criteria, " AND ")
}

// Type holds all information about a field in a field type that is relevant
// for database code generation.
type Type struct {
	Name string
	Code int
}

// Possible type code.
const (
	TypeColumn = iota
	TypeSlice
	TypeMap
)

// IsColumnType returns true if the given type name is one mapping directly to
// a database column.
func IsColumnType(name string) bool {
	return shared.StringInSlice(name, columnarTypeNames)
}

var columnarTypeNames = []string{
	"bool",
	"instancetype.Type",
	"int",
	"int64",
	"OperationType",
	"string",
	"time.Time",
}
<|endoftext|>


<commit_before>// Copyright 2017 Google Inc.
//
// 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 main

import (
	"context"
	"flag"
	"strconv"
	"strings"

	"golang.org/x/oauth2"

	"github.com/google/code-review-bot/config"
	"github.com/google/code-review-bot/ghutil"
	"github.com/google/code-review-bot/logging"
)

func main() {
	configFileFlag := flag.String("config", "config.json", "Path to cfg file; required")
	claSignersFileFlag := flag.String("cla-signers", "cla.json", "Path to CLA signers, required")
	orgFlag := flag.String("org", "", "Name of organization or username; required if not set via cfg")
	repoFlag := flag.String("repo", "", "Name of repo; if empty, implies all repos in org")
	prFlag := flag.String("pr", "", "Comma-separated list of PRs to process")
	updateRepoFlag := flag.Bool("update-repo", false, "Update labels on the repo")
	flag.Parse()

	// Read and parse the general cfg file.
	cfg := config.ParseConfig(*configFileFlag)

	// Read and parse the CLA signers file.
	claSigners := config.ParseClaSigners(*claSignersFileFlag)

	// Get the org name from command-line flags or config file.
	var orgName string
	if *orgFlag != "" {
		orgName = *orgFlag
	} else if cfg.Org != "" {
		orgName = cfg.Org
	} else {
		logging.Fatalf("-org must be non-empty or `org` must be specified in cfg file")
	}

	prNumbers := make([]uint64, 0)
	if *prFlag != "" {
		prElements := strings.Split(*prFlag, ",")
		prNumbers := make([]uint64, len(prElements))
		for idx, elt := range prElements {
			num, err := strconv.ParseUint(elt, 10, 32)
			if err != nil {
				logging.Fatalf("Invalid value for flag -pr: %s", *prFlag)
			}
			prNumbers[idx] = num
		}
	}

	ctx := context.Background()

	// Configure authentication and connet to GitHub.
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: cfg.Auth},
	)
	tc := oauth2.NewClient(ctx, ts)

	// Process org and repo(s) specified on the command-line.
	ghc := ghutil.NewClient(tc)
	repoSpec := ghutil.GitHubProcessSpec{
		Org:        orgName,
		Repo:       *repoFlag,
		Pulls:      prNumbers,
		UpdateRepo: *updateRepoFlag,
	}
	ghc.ProcessOrgRepo(ctx, repoSpec, claSigners)
}
<commit_msg>Fix typo<commit_after>// Copyright 2017 Google Inc.
//
// 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 main

import (
	"context"
	"flag"
	"strconv"
	"strings"

	"golang.org/x/oauth2"

	"github.com/google/code-review-bot/config"
	"github.com/google/code-review-bot/ghutil"
	"github.com/google/code-review-bot/logging"
)

func main() {
	configFileFlag := flag.String("config", "config.json", "Path to cfg file; required")
	claSignersFileFlag := flag.String("cla-signers", "cla.json", "Path to CLA signers, required")
	orgFlag := flag.String("org", "", "Name of organization or username; required if not set via cfg")
	repoFlag := flag.String("repo", "", "Name of repo; if empty, implies all repos in org")
	prFlag := flag.String("pr", "", "Comma-separated list of PRs to process")
	updateRepoFlag := flag.Bool("update-repo", false, "Update labels on the repo")
	flag.Parse()

	// Read and parse the general cfg file.
	cfg := config.ParseConfig(*configFileFlag)

	// Read and parse the CLA signers file.
	claSigners := config.ParseClaSigners(*claSignersFileFlag)

	// Get the org name from command-line flags or config file.
	var orgName string
	if *orgFlag != "" {
		orgName = *orgFlag
	} else if cfg.Org != "" {
		orgName = cfg.Org
	} else {
		logging.Fatalf("-org must be non-empty or `org` must be specified in cfg file")
	}

	prNumbers := make([]uint64, 0)
	if *prFlag != "" {
		prElements := strings.Split(*prFlag, ",")
		prNumbers := make([]uint64, len(prElements))
		for idx, elt := range prElements {
			num, err := strconv.ParseUint(elt, 10, 32)
			if err != nil {
				logging.Fatalf("Invalid value for flag -pr: %s", *prFlag)
			}
			prNumbers[idx] = num
		}
	}

	ctx := context.Background()

	// Configure authentication and connect to GitHub.
	ts := oauth2.StaticTokenSource(
		&oauth2.Token{AccessToken: cfg.Auth},
	)
	tc := oauth2.NewClient(ctx, ts)

	// Process org and repo(s) specified on the command-line.
	ghc := ghutil.NewClient(tc)
	repoSpec := ghutil.GitHubProcessSpec{
		Org:        orgName,
		Repo:       *repoFlag,
		Pulls:      prNumbers,
		UpdateRepo: *updateRepoFlag,
	}
	ghc.ProcessOrgRepo(ctx, repoSpec, claSigners)
}
<|endoftext|>


<commit_before>// Command docgen is an experimental development command for generating static
// documentation for lua modules.
package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"strings"

	"github.com/bmatsuo/lark/internal/textutil"
	"github.com/bmatsuo/lark/lib"
	"github.com/bmatsuo/lark/lib/doc"
	"github.com/bmatsuo/lark/project"
	"github.com/yuin/gopher-lua"
)

func main() {
	l := lua.NewState()
	defer l.Close()

	err := dump(l)
	if err != nil {
		log.Fatal(err)
	}
}

func dump(l *lua.LState) error {
	err := project.InitLib(l, nil)
	if err != nil {
		return err
	}

	var modules []string
	if len(os.Args[1:]) > 0 {
		modules = os.Args[1:]
	} else {
	mloop:
		for _, m := range lib.Modules {
			name := m.Name()
			for _, hidden := range lib.InternalModules {
				if name == hidden.Name() {
					continue mloop
				}
			}
			modules = append(modules, name)
		}
	}

	return dumpDocs(l, modules)
}

func dumpDocs(l *lua.LState, names []string) error {
	gen := &bufferedTextGenerator{}
	out := os.Stdout
	for _, m := range names {
		l.Push(l.GetGlobal("require"))
		l.Push(lua.LString(m))
		err := l.PCall(1, 1, nil)
		if err != nil {
			return fmt.Errorf("%s: %s", m, err)
		}

		mod := l.Get(-1)
		l.Pop(1)

		mdocs, err := doc.Get(l, mod, m)
		if err != nil {
			return fmt.Errorf("module %s: documentation error: %v", m, err)
		}

		header := &DocsHeader{
			DocsType: "Module",
			Name:     m,
			Usage:    fmt.Sprintf("local %s = require(%q)", m, m),
		}
		gen.GenerateDocs(out, header, mdocs)
	}
	return nil
}

// DocsHeader describes a page of documentation
type DocsHeader struct {
	DocsType string
	Name     string
	Usage    string
}

// Generator formats doc.Docs objects and writes them to an output stream.
type Generator interface {
	GenerateDocs(out io.Writer, h *DocsHeader, d *doc.Docs) error
}

type bufferedTextGenerator textGenerator

func (g *bufferedTextGenerator) GenerateDocs(out io.Writer, h *DocsHeader, d *doc.Docs) (err error) {
	_out := bufio.NewWriter(out)
	defer func() {
		if err != nil {
			err = _out.Flush()
		}
	}()
	return (*textGenerator)(g).GenerateDocs(out, h, d)
}

type textGenerator struct {
}

func (g *textGenerator) GenerateDocs(out io.Writer, h *DocsHeader, d *doc.Docs) error {
	var err error
	printf := func(format string, v ...interface{}) {
		if err != nil {
			return
		}
		_, err = fmt.Fprintf(out, format, v...)
	}

	printf("%s %s\n\n", h.DocsType, h.Name)
	if d.Sig != "" {
		text := d.Sig
		text = textutil.Unindent(text)
		text = strings.TrimSpace(text)
		text = textutil.Indent(text, "  ")
		printf("Signature:\n\n%s\n\n", d.Sig)
	}
	if h.Usage != "" {
		printf("  %s\n\n", h.Usage)
	}
	if d.Desc != "" {
		text := textutil.Unindent(d.Desc)
		text = textutil.Wrap(text, 72)
		text = strings.TrimSpace(text)
		printf("%s\n\n", text)
	}
	numvar := d.NumVar()
	if numvar > 0 {
		printf("Variables:\n\n")
		for i := 0; i < numvar; i++ {
			printf("  %s", d.Var(i))
			typ := d.VarType(i)
			if typ != "" {
				printf("  %s\n", typ)
			} else {
				printf("\n")
			}
			text := d.VarDesc(i)
			text = textutil.Unindent(text)
			text = textutil.Wrap(text, 66)
			text = strings.TrimSpace(text)
			if text != "" {
				text = textutil.Indent(text, "      ")
				printf("%s\n\n", text)
			} else {
				printf("\n")
			}
		}
	}
	numparam := d.NumParam()
	if numparam > 0 {
		printf("Parameters:\n\n")
		for i := 0; i < numparam; i++ {
			printf("  %s", d.Param(i))
			typ := d.ParamType(i)
			if typ != "" {
				printf("  %s\n", typ)
			} else {
				printf("\n")
			}
			text := d.ParamDesc(i)
			text = textutil.Unindent(text)
			text = textutil.Wrap(text, 66)
			text = strings.TrimSpace(text)
			if text != "" {
				text = textutil.Indent(text, "      ")
				printf("%s\n\n", text)
			} else {
				printf("\n")
			}
		}
	}

	funcs := d.Funcs()
	if len(funcs) > 0 {
		printf("Functions:\n\n")
		for _, sub := range funcs {
			if sub.Name == "" {
				continue
			}
			printf("  %s\n", sub.Name)
			text := sub.Desc
			text = textutil.Unindent(text)
			text = strings.TrimSpace(text)
			text = textutil.Synopsis(text)
			text = textutil.Wrap(text, 66)
			if text != "" {
				text = textutil.Indent(text, "      ")
				printf("%s\n\n", text)
			} else {
				printf("\n")
			}
		}
	}

	others := d.Others()
	if len(others) > 0 {
		printf("Subtopics:\n\n")
		for _, sub := range others {
			if sub.Name == "" {
				continue
			}
			printf("  %s\n", sub.Name)
			text := sub.Desc
			text = textutil.Unindent(text)
			text = strings.TrimSpace(text)
			text = textutil.Synopsis(text)
			text = textutil.Wrap(text, 66)
			if text != "" {
				text = textutil.Indent(text, "      ")
				printf("%s\n\n", text)
			} else {
				printf("\n")
			}
		}
	}

	return err
}
<commit_msg>docgen: fix panic when subtopic docs do not exist<commit_after>// Command docgen is an experimental development command for generating static
// documentation for lua modules.
package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"os"
	"strings"

	"github.com/bmatsuo/lark/internal/textutil"
	"github.com/bmatsuo/lark/lib"
	"github.com/bmatsuo/lark/lib/doc"
	"github.com/bmatsuo/lark/project"
	"github.com/yuin/gopher-lua"
)

func main() {
	l := lua.NewState()
	defer l.Close()

	err := dump(l)
	if err != nil {
		log.Fatal(err)
	}
}

func dump(l *lua.LState) error {
	err := project.InitLib(l, nil)
	if err != nil {
		return err
	}

	var modules []string
	if len(os.Args[1:]) > 0 {
		modules = os.Args[1:]
	} else {
	mloop:
		for _, m := range lib.Modules {
			name := m.Name()
			for _, hidden := range lib.InternalModules {
				if name == hidden.Name() {
					continue mloop
				}
			}
			modules = append(modules, name)
		}
	}

	return dumpDocs(l, modules)
}

func dumpDocs(l *lua.LState, names []string) error {
	gen := &bufferedTextGenerator{}
	out := os.Stdout
	for _, m := range names {
		l.Push(l.GetGlobal("require"))
		l.Push(lua.LString(m))
		err := l.PCall(1, 1, nil)
		if err != nil {
			return fmt.Errorf("%s: %s", m, err)
		}

		mod := l.Get(-1)
		l.Pop(1)

		mdocs, err := doc.Get(l, mod, m)
		if err != nil {
			return fmt.Errorf("module %s: documentation error: %v", m, err)
		}

		header := &DocsHeader{
			DocsType: "Module",
			Name:     m,
			Usage:    fmt.Sprintf("local %s = require(%q)", m, m),
		}
		gen.GenerateDocs(out, header, mdocs)
	}
	return nil
}

// DocsHeader describes a page of documentation
type DocsHeader struct {
	DocsType string
	Name     string
	Usage    string
}

// Generator formats doc.Docs objects and writes them to an output stream.
type Generator interface {
	GenerateDocs(out io.Writer, h *DocsHeader, d *doc.Docs) error
}

type bufferedTextGenerator textGenerator

func (g *bufferedTextGenerator) GenerateDocs(out io.Writer, h *DocsHeader, d *doc.Docs) (err error) {
	_out := bufio.NewWriter(out)
	defer func() {
		if err != nil {
			err = _out.Flush()
		}
	}()
	return (*textGenerator)(g).GenerateDocs(out, h, d)
}

type textGenerator struct {
}

func (g *textGenerator) GenerateDocs(out io.Writer, h *DocsHeader, d *doc.Docs) error {
	var err error
	printf := func(format string, v ...interface{}) {
		if err != nil {
			return
		}
		_, err = fmt.Fprintf(out, format, v...)
	}

	printf("%s %s\n\n", h.DocsType, h.Name)
	if d.Sig != "" {
		text := d.Sig
		text = textutil.Unindent(text)
		text = strings.TrimSpace(text)
		text = textutil.Indent(text, "  ")
		printf("Signature:\n\n%s\n\n", d.Sig)
	}
	if h.Usage != "" {
		printf("  %s\n\n", h.Usage)
	}
	if d.Desc != "" {
		text := textutil.Unindent(d.Desc)
		text = textutil.Wrap(text, 72)
		text = strings.TrimSpace(text)
		printf("%s\n\n", text)
	}
	numvar := d.NumVar()
	if numvar > 0 {
		printf("Variables:\n\n")
		for i := 0; i < numvar; i++ {
			printf("  %s", d.Var(i))
			typ := d.VarType(i)
			if typ != "" {
				printf("  %s\n", typ)
			} else {
				printf("\n")
			}
			text := d.VarDesc(i)
			text = textutil.Unindent(text)
			text = textutil.Wrap(text, 66)
			text = strings.TrimSpace(text)
			if text != "" {
				text = textutil.Indent(text, "      ")
				printf("%s\n\n", text)
			} else {
				printf("\n")
			}
		}
	}
	numparam := d.NumParam()
	if numparam > 0 {
		printf("Parameters:\n\n")
		for i := 0; i < numparam; i++ {
			printf("  %s", d.Param(i))
			typ := d.ParamType(i)
			if typ != "" {
				printf("  %s\n", typ)
			} else {
				printf("\n")
			}
			text := d.ParamDesc(i)
			text = textutil.Unindent(text)
			text = textutil.Wrap(text, 66)
			text = strings.TrimSpace(text)
			if text != "" {
				text = textutil.Indent(text, "      ")
				printf("%s\n\n", text)
			} else {
				printf("\n")
			}
		}
	}

	funcs := d.Funcs()
	if len(funcs) > 0 {
		printf("Functions:\n\n")
		for _, sub := range funcs {
			if sub.Name == "" {
				continue
			}
			printf("  %s\n", sub.Name)
			if sub.Docs == nil {
				printf("\n")
				continue
			}
			text := sub.Desc
			text = textutil.Unindent(text)
			text = strings.TrimSpace(text)
			text = textutil.Synopsis(text)
			text = textutil.Wrap(text, 66)
			if text != "" {
				text = textutil.Indent(text, "      ")
				printf("%s\n\n", text)
			} else {
				printf("\n")
			}
		}
	}

	others := d.Others()
	if len(others) > 0 {
		printf("Subtopics:\n\n")
		for _, sub := range others {
			if sub.Name == "" {
				continue
			}
			printf("  %s\n", sub.Name)
			if sub.Docs == nil {
				printf("\n")
				continue
			}
			text := sub.Desc
			text = textutil.Unindent(text)
			text = strings.TrimSpace(text)
			text = textutil.Synopsis(text)
			text = textutil.Wrap(text, 66)
			if text != "" {
				text = textutil.Indent(text, "      ")
				printf("%s\n\n", text)
			} else {
				printf("\n")
			}
		}
	}

	return err
}
<|endoftext|>


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

// This file implements access to gccgo-generated export data.

package main

import (
	"debug/elf"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"code.google.com/p/go.tools/go/gccgoimporter"
	"code.google.com/p/go.tools/go/importer"
	"code.google.com/p/go.tools/go/types"
)

func init() {
	// importer for default gccgo
	var inst gccgoimporter.GccgoInstallation
	inst.InitFromDriver("gccgo")
	register("gccgo", inst.GetImporter(nil))

	// importer for gccgo using condensed export format (experimental)
	register("gccgo-new", getNewImporter(append(inst.SearchPaths(), ".")))
}

// This function is an adjusted variant of gccgoimporter.GccgoInstallation.GetImporter.
func getNewImporter(searchpaths []string) types.Importer {
	return func(imports map[string]*types.Package, pkgpath string) (pkg *types.Package, err error) {
		if pkgpath == "unsafe" {
			return types.Unsafe, nil
		}

		fpath, err := findExportFile(searchpaths, pkgpath)
		if err != nil {
			return
		}

		reader, closer, err := openExportFile(fpath)
		if err != nil {
			return nil, err
		}
		defer closer.Close()

		// TODO(gri) At the moment we just read the entire file.
		// We should change importer.ImportData to take an io.Reader instead.
		data, err := ioutil.ReadAll(reader)
		if err != nil && err != io.EOF {
			return nil, err
		}

		return importer.ImportData(packages, data)
	}
}

// This function is an exact copy of gccgoimporter.findExportFile.
func findExportFile(searchpaths []string, pkgpath string) (string, error) {
	for _, spath := range searchpaths {
		pkgfullpath := filepath.Join(spath, pkgpath)
		pkgdir, name := filepath.Split(pkgfullpath)

		for _, filepath := range [...]string{
			pkgfullpath,
			pkgfullpath + ".gox",
			pkgdir + "lib" + name + ".so",
			pkgdir + "lib" + name + ".a",
			pkgfullpath + ".o",
		} {
			fi, err := os.Stat(filepath)
			if err == nil && !fi.IsDir() {
				return filepath, nil
			}
		}
	}

	return "", fmt.Errorf("%s: could not find export data (tried %s)", pkgpath, strings.Join(searchpaths, ":"))
}

// This function is an exact copy of gccgoimporter.openExportFile.
func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) {
	f, err := os.Open(fpath)
	if err != nil {
		return
	}
	defer func() {
		if err != nil {
			f.Close()
		}
	}()
	closer = f

	var magic [4]byte
	_, err = f.ReadAt(magic[:], 0)
	if err != nil {
		return
	}

	if string(magic[:]) == "v1;\n" {
		// Raw export data.
		reader = f
		return
	}

	ef, err := elf.NewFile(f)
	if err != nil {
		return
	}

	sec := ef.Section(".go_export")
	if sec == nil {
		err = fmt.Errorf("%s: .go_export section not found", fpath)
		return
	}

	reader = sec.Open()
	return
}
<commit_msg>go.tools/cmd/godex: permit absolute paths for gccgo-generated package (export) files<commit_after>// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements access to gccgo-generated export data.

package main

import (
	"debug/elf"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"code.google.com/p/go.tools/go/gccgoimporter"
	"code.google.com/p/go.tools/go/importer"
	"code.google.com/p/go.tools/go/types"
)

func init() {
	incpaths := []string{"/"}

	// importer for default gccgo
	var inst gccgoimporter.GccgoInstallation
	inst.InitFromDriver("gccgo")
	register("gccgo", inst.GetImporter(incpaths))

	// importer for gccgo using condensed export format (experimental)
	register("gccgo-new", getNewImporter(append(append(incpaths, inst.SearchPaths()...), ".")))
}

// This function is an adjusted variant of gccgoimporter.GccgoInstallation.GetImporter.
func getNewImporter(searchpaths []string) types.Importer {
	return func(imports map[string]*types.Package, pkgpath string) (pkg *types.Package, err error) {
		if pkgpath == "unsafe" {
			return types.Unsafe, nil
		}

		fpath, err := findExportFile(searchpaths, pkgpath)
		if err != nil {
			return
		}

		reader, closer, err := openExportFile(fpath)
		if err != nil {
			return nil, err
		}
		defer closer.Close()

		// TODO(gri) At the moment we just read the entire file.
		// We should change importer.ImportData to take an io.Reader instead.
		data, err := ioutil.ReadAll(reader)
		if err != nil && err != io.EOF {
			return nil, err
		}

		return importer.ImportData(packages, data)
	}
}

// This function is an exact copy of gccgoimporter.findExportFile.
func findExportFile(searchpaths []string, pkgpath string) (string, error) {
	for _, spath := range searchpaths {
		pkgfullpath := filepath.Join(spath, pkgpath)
		pkgdir, name := filepath.Split(pkgfullpath)

		for _, filepath := range [...]string{
			pkgfullpath,
			pkgfullpath + ".gox",
			pkgdir + "lib" + name + ".so",
			pkgdir + "lib" + name + ".a",
			pkgfullpath + ".o",
		} {
			println("trying", filepath)
			fi, err := os.Stat(filepath)
			if err == nil && !fi.IsDir() {
				return filepath, nil
			}
		}
	}

	return "", fmt.Errorf("%s: could not find export data (tried %s)", pkgpath, strings.Join(searchpaths, ":"))
}

// This function is an exact copy of gccgoimporter.openExportFile.
func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) {
	f, err := os.Open(fpath)
	if err != nil {
		return
	}
	defer func() {
		if err != nil {
			f.Close()
		}
	}()
	closer = f

	var magic [4]byte
	_, err = f.ReadAt(magic[:], 0)
	if err != nil {
		return
	}

	if string(magic[:]) == "v1;\n" {
		// Raw export data.
		reader = f
		return
	}

	ef, err := elf.NewFile(f)
	if err != nil {
		return
	}

	sec := ef.Section(".go_export")
	if sec == nil {
		err = fmt.Errorf("%s: .go_export section not found", fpath)
		return
	}

	reader = sec.Open()
	return
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/ecnahc515/goplayutils/gist"
	"github.com/ecnahc515/goplayutils/server"
	"github.com/google/go-github/github"
	"github.com/gregjones/httpcache/diskcache"
)

const cacheDir = "gist_playground_cache"

var (
	token  string
	daemon = flag.Bool("d", false, "Enable to daemonize and run as a web app.")
	addr   = flag.String("addr", "localhost:8080", "Address and port to listen on.")
)

func init() {
	token = os.Getenv("GISTPLAYGROUND_TOKEN")
	flag.Usage = Usage
}

func NewDiskCache() *diskcache.Cache {
	tmpDir := os.TempDir()
	path := filepath.Join(tmpDir, cacheDir)
	return diskcache.New(path)
}

func main() {
	flag.Parse()
	args := flag.Args()

	fi, err := os.Stdin.Stat()
	if err == nil && fi.Mode()&os.ModeNamedPipe != 0 {
		data, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		content := string(data)
		printPlayUrl(&content)
		os.Exit(0)
	}

	if *daemon {
		if len(args) > 0 {
			fmt.Println("-d flag requires no arguments.")
			os.Exit(1)
		}
		httpClient := gist.NewCachingHttpClient(token, nil, nil)
		client := github.NewClient(httpClient)
		server := &server.Server{Client: client}
		server.Start(*addr)
	}

	if len(args) < 1 {
		fmt.Printf("Error: Specify a gist ID to use.\n\n")
		fmt.Printf("example: run '%s 952190cba18de244b472'\n", os.Args[0])
		os.Exit(1)
	}

	gistToPlay(args[0])
}
<commit_msg>Rename github env variable<commit_after>package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/ecnahc515/goplayutils/gist"
	"github.com/ecnahc515/goplayutils/server"
	"github.com/google/go-github/github"
	"github.com/gregjones/httpcache/diskcache"
)

const cacheDir = "gist_playground_cache"

var (
	token  string
	daemon = flag.Bool("d", false, "Enable to daemonize and run as a web app.")
	addr   = flag.String("addr", "localhost:8080", "Address and port to listen on.")
)

func init() {
	token = os.Getenv("GOPLAY_GITHUB_TOKEN")
	flag.Usage = Usage
}

func NewDiskCache() *diskcache.Cache {
	tmpDir := os.TempDir()
	path := filepath.Join(tmpDir, cacheDir)
	return diskcache.New(path)
}

func main() {
	flag.Parse()
	args := flag.Args()

	fi, err := os.Stdin.Stat()
	if err == nil && fi.Mode()&os.ModeNamedPipe != 0 {
		data, err := ioutil.ReadAll(os.Stdin)
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		content := string(data)
		printPlayUrl(&content)
		os.Exit(0)
	}

	if *daemon {
		if len(args) > 0 {
			fmt.Println("-d flag requires no arguments.")
			os.Exit(1)
		}
		httpClient := gist.NewCachingHttpClient(token, nil, nil)
		client := github.NewClient(httpClient)
		server := &server.Server{Client: client}
		server.Start(*addr)
	}

	if len(args) < 1 {
		fmt.Printf("Error: Specify a gist ID to use.\n\n")
		fmt.Printf("example: run '%s 952190cba18de244b472'\n", os.Args[0])
		os.Exit(1)
	}

	gistToPlay(args[0])
}
<|endoftext|>


<commit_before>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"encoding/json"
	"fmt"

	"launchpad.net/gnuflag"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/cmd/envcmd"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/state/api/params"
	"launchpad.net/juju-core/state/apiserver/client"
)

type StatusCommand struct {
	envcmd.EnvCommandBase
	out      cmd.Output
	patterns []string
}

var statusDoc = `
This command will report on the runtime state of various system entities.

Service or unit names may be specified to filter the status to only those
services and units that match, along with the related machines, services
and units. If a subordinate unit is matched, then its principal unit will
be displayed. If a principal unit is matched, then all of its subordinates
will be displayed.

Wildcards ('*') may be specified in service/unit names to match any sequence
of characters. For example, 'nova-*' will match any service whose name begins
with 'nova-': 'nova-compute', 'nova-volume', etc.
`

func (c *StatusCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "status",
		Args:    "[pattern ...]",
		Purpose: "output status information about an environment",
		Doc:     statusDoc,
		Aliases: []string{"stat"},
	}
}

func (c *StatusCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)
	c.out.AddFlags(f, "yaml", map[string]cmd.Formatter{
		"yaml": cmd.FormatYaml,
		"json": cmd.FormatJson,
	})
}

func (c *StatusCommand) Init(args []string) error {
	c.patterns = args
	return c.EnvCommandBase.Init()
}

var connectionError = `Unable to connect to environment %q.
Please check your credentials or use 'juju bootstrap' to create a new environment.

Error details:
%v
`

func (c *StatusCommand) Run(ctx *cmd.Context) error {
	// Just verify the pattern validity client side, do not use the matcher
	_, err := client.NewUnitMatcher(c.patterns)
	if err != nil {
		return err
	}
	apiclient, err := juju.NewAPIClientFromName(c.EnvName)
	if err != nil {
		return fmt.Errorf(connectionError, c.EnvName, err)
	}
	defer apiclient.Close()

	status, err := apiclient.Status(c.patterns)
	// Display any error, but continue to print status if some was returned
	if err != nil {
		fmt.Fprintf(ctx.Stderr, "%v\n", err)
	}
	result := formatStatus(status)
	return c.out.Write(ctx, result)
}

type formattedStatus struct {
	Environment string                   `json:"environment"`
	Machines    map[string]machineStatus `json:"machines"`
	Services    map[string]serviceStatus `json:"services"`
}

type errorStatus struct {
	StatusError string `json:"status-error" yaml:"status-error"`
}

type machineStatus struct {
	Err            error                    `json:"-" yaml:",omitempty"`
	AgentState     params.Status            `json:"agent-state,omitempty" yaml:"agent-state,omitempty"`
	AgentStateInfo string                   `json:"agent-state-info,omitempty" yaml:"agent-state-info,omitempty"`
	AgentVersion   string                   `json:"agent-version,omitempty" yaml:"agent-version,omitempty"`
	DNSName        string                   `json:"dns-name,omitempty" yaml:"dns-name,omitempty"`
	InstanceId     instance.Id              `json:"instance-id,omitempty" yaml:"instance-id,omitempty"`
	InstanceState  string                   `json:"instance-state,omitempty" yaml:"instance-state,omitempty"`
	Life           string                   `json:"life,omitempty" yaml:"life,omitempty"`
	Series         string                   `json:"series,omitempty" yaml:"series,omitempty"`
	Id             string                   `json:"-" yaml:"-"`
	Containers     map[string]machineStatus `json:"containers,omitempty" yaml:"containers,omitempty"`
	Hardware       string                   `json:"hardware,omitempty" yaml:"hardware,omitempty"`
	Jobs []params.MachineJob
	HasVote bool
	WantsVote bool
}

// A goyaml bug means we can't declare these types
// locally to the GetYAML methods.
type machineStatusNoMarshal machineStatus

func (s machineStatus) MarshalJSON() ([]byte, error) {
	if s.Err != nil {
		return json.Marshal(errorStatus{s.Err.Error()})
	}
	return json.Marshal(machineStatusNoMarshal(s))
}

func (s machineStatus) GetYAML() (tag string, value interface{}) {
	if s.Err != nil {
		return "", errorStatus{s.Err.Error()}
	}
	// TODO(rog) rename mNoMethods to noMethods (and also in
	// the other GetYAML methods) when people are using the non-buggy
	// goyaml version.
	type mNoMethods machineStatus
	return "", mNoMethods(s)
}

type serviceStatus struct {
	Err           error                 `json:"-" yaml:",omitempty"`
	Charm         string                `json:"charm" yaml:"charm"`
	CanUpgradeTo  string                `json:"can-upgrade-to,omitempty" yaml:"can-upgrade-to,omitempty"`
	Exposed       bool                  `json:"exposed" yaml:"exposed"`
	Life          string                `json:"life,omitempty" yaml:"life,omitempty"`
	Relations     map[string][]string   `json:"relations,omitempty" yaml:"relations,omitempty"`
	Networks      map[string][]string   `json:"networks,omitempty" yaml:"networks,omitempty"`
	SubordinateTo []string              `json:"subordinate-to,omitempty" yaml:"subordinate-to,omitempty"`
	Units         map[string]unitStatus `json:"units,omitempty" yaml:"units,omitempty"`
}

type serviceStatusNoMarshal serviceStatus

func (s serviceStatus) MarshalJSON() ([]byte, error) {
	if s.Err != nil {
		return json.Marshal(errorStatus{s.Err.Error()})
	}
	type sNoMethods serviceStatus
	return json.Marshal(sNoMethods(s))
}

func (s serviceStatus) GetYAML() (tag string, value interface{}) {
	if s.Err != nil {
		return "", errorStatus{s.Err.Error()}
	}
	type sNoMethods serviceStatus
	return "", sNoMethods(s)
}

type unitStatus struct {
	Err            error                 `json:"-" yaml:",omitempty"`
	Charm          string                `json:"upgrading-from,omitempty" yaml:"upgrading-from,omitempty"`
	AgentState     params.Status         `json:"agent-state,omitempty" yaml:"agent-state,omitempty"`
	AgentStateInfo string                `json:"agent-state-info,omitempty" yaml:"agent-state-info,omitempty"`
	AgentVersion   string                `json:"agent-version,omitempty" yaml:"agent-version,omitempty"`
	Life           string                `json:"life,omitempty" yaml:"life,omitempty"`
	Machine        string                `json:"machine,omitempty" yaml:"machine,omitempty"`
	OpenedPorts    []string              `json:"open-ports,omitempty" yaml:"open-ports,omitempty"`
	PublicAddress  string                `json:"public-address,omitempty" yaml:"public-address,omitempty"`
	Subordinates   map[string]unitStatus `json:"subordinates,omitempty" yaml:"subordinates,omitempty"`
}

type unitStatusNoMarshal unitStatus

func (s unitStatus) MarshalJSON() ([]byte, error) {
	if s.Err != nil {
		return json.Marshal(errorStatus{s.Err.Error()})
	}
	return json.Marshal(unitStatusNoMarshal(s))
}

func (s unitStatus) GetYAML() (tag string, value interface{}) {
	if s.Err != nil {
		return "", errorStatus{s.Err.Error()}
	}
	type uNoMethods unitStatus
	return "", unitStatusNoMarshal(s)
}

func formatStatus(status *api.Status) formattedStatus {
	if status == nil {
		return formattedStatus{}
	}
	out := formattedStatus{
		Environment: status.EnvironmentName,
		Machines:    make(map[string]machineStatus),
		Services:    make(map[string]serviceStatus),
	}
	for k, m := range status.Machines {
		out.Machines[k] = formatMachine(m)
	}
	for k, s := range status.Services {
		out.Services[k] = formatService(s)
	}
	return out
}

func formatMachine(machine api.MachineStatus) machineStatus {
	out := machineStatus{
		Err:            machine.Err,
		AgentState:     machine.AgentState,
		AgentStateInfo: machine.AgentStateInfo,
		AgentVersion:   machine.AgentVersion,
		DNSName:        machine.DNSName,
		InstanceId:     machine.InstanceId,
		InstanceState:  machine.InstanceState,
		Life:           machine.Life,
		Series:         machine.Series,
		Id:             machine.Id,
		Containers:     make(map[string]machineStatus),
		Hardware:       machine.Hardware,
		HasVote: machine.HasVote,
		WantsVote: machine.WantsVote,
		Jobs: machine.Jobs,
	}
	for k, m := range machine.Containers {
		out.Containers[k] = formatMachine(m)
	}
	return out
}

func formatService(service api.ServiceStatus) serviceStatus {
	out := serviceStatus{
		Err:           service.Err,
		Charm:         service.Charm,
		Exposed:       service.Exposed,
		Life:          service.Life,
		Relations:     service.Relations,
		Networks:      make(map[string][]string),
		CanUpgradeTo:  service.CanUpgradeTo,
		SubordinateTo: service.SubordinateTo,
		Units:         make(map[string]unitStatus),
	}
	if len(service.Networks.Enabled) > 0 {
		out.Networks["enabled"] = service.Networks.Enabled
	}
	if len(service.Networks.Disabled) > 0 {
		out.Networks["disabled"] = service.Networks.Disabled
	}
	for k, m := range service.Units {
		out.Units[k] = formatUnit(m)
	}
	return out
}

func formatUnit(unit api.UnitStatus) unitStatus {
	out := unitStatus{
		Err:            unit.Err,
		AgentState:     unit.AgentState,
		AgentStateInfo: unit.AgentStateInfo,
		AgentVersion:   unit.AgentVersion,
		Life:           unit.Life,
		Machine:        unit.Machine,
		OpenedPorts:    unit.OpenedPorts,
		PublicAddress:  unit.PublicAddress,
		Charm:          unit.Charm,
		Subordinates:   make(map[string]unitStatus),
	}
	for k, m := range unit.Subordinates {
		out.Subordinates[k] = formatUnit(m)
	}
	return out
}
<commit_msg>use english instead of hasvote/wantsvote<commit_after>// Copyright 2012, 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package main

import (
	"encoding/json"
	"fmt"

	"launchpad.net/gnuflag"

	"launchpad.net/juju-core/cmd"
	"launchpad.net/juju-core/cmd/envcmd"
	"launchpad.net/juju-core/instance"
	"launchpad.net/juju-core/juju"
	"launchpad.net/juju-core/state/api"
	"launchpad.net/juju-core/state/api/params"
	"launchpad.net/juju-core/state/apiserver/client"
)

type StatusCommand struct {
	envcmd.EnvCommandBase
	out      cmd.Output
	patterns []string
}

var statusDoc = `
This command will report on the runtime state of various system entities.

Service or unit names may be specified to filter the status to only those
services and units that match, along with the related machines, services
and units. If a subordinate unit is matched, then its principal unit will
be displayed. If a principal unit is matched, then all of its subordinates
will be displayed.

Wildcards ('*') may be specified in service/unit names to match any sequence
of characters. For example, 'nova-*' will match any service whose name begins
with 'nova-': 'nova-compute', 'nova-volume', etc.
`

func (c *StatusCommand) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "status",
		Args:    "[pattern ...]",
		Purpose: "output status information about an environment",
		Doc:     statusDoc,
		Aliases: []string{"stat"},
	}
}

func (c *StatusCommand) SetFlags(f *gnuflag.FlagSet) {
	c.EnvCommandBase.SetFlags(f)
	c.out.AddFlags(f, "yaml", map[string]cmd.Formatter{
		"yaml": cmd.FormatYaml,
		"json": cmd.FormatJson,
	})
}

func (c *StatusCommand) Init(args []string) error {
	c.patterns = args
	return c.EnvCommandBase.Init()
}

var connectionError = `Unable to connect to environment %q.
Please check your credentials or use 'juju bootstrap' to create a new environment.

Error details:
%v
`

func (c *StatusCommand) Run(ctx *cmd.Context) error {
	// Just verify the pattern validity client side, do not use the matcher
	_, err := client.NewUnitMatcher(c.patterns)
	if err != nil {
		return err
	}
	apiclient, err := juju.NewAPIClientFromName(c.EnvName)
	if err != nil {
		return fmt.Errorf(connectionError, c.EnvName, err)
	}
	defer apiclient.Close()

	status, err := apiclient.Status(c.patterns)
	// Display any error, but continue to print status if some was returned
	if err != nil {
		fmt.Fprintf(ctx.Stderr, "%v\n", err)
	}
	result := formatStatus(status)
	return c.out.Write(ctx, result)
}

type formattedStatus struct {
	Environment string                   `json:"environment"`
	Machines    map[string]machineStatus `json:"machines"`
	Services    map[string]serviceStatus `json:"services"`
}

type errorStatus struct {
	StatusError string `json:"status-error" yaml:"status-error"`
}

type machineStatus struct {
	Err            error                    `json:"-" yaml:",omitempty"`
	AgentState     params.Status            `json:"agent-state,omitempty" yaml:"agent-state,omitempty"`
	AgentStateInfo string                   `json:"agent-state-info,omitempty" yaml:"agent-state-info,omitempty"`
	AgentVersion   string                   `json:"agent-version,omitempty" yaml:"agent-version,omitempty"`
	DNSName        string                   `json:"dns-name,omitempty" yaml:"dns-name,omitempty"`
	InstanceId     instance.Id              `json:"instance-id,omitempty" yaml:"instance-id,omitempty"`
	InstanceState  string                   `json:"instance-state,omitempty" yaml:"instance-state,omitempty"`
	Life           string                   `json:"life,omitempty" yaml:"life,omitempty"`
	Series         string                   `json:"series,omitempty" yaml:"series,omitempty"`
	Id             string                   `json:"-" yaml:"-"`
	Containers     map[string]machineStatus `json:"containers,omitempty" yaml:"containers,omitempty"`
	Hardware       string                   `json:"hardware,omitempty" yaml:"hardware,omitempty"`
	HAStatus       string                   `json:"member-status,omitempty" yaml:"member-status,omitempty"`
	Jobs           []params.MachineJob
}

// A goyaml bug means we can't declare these types
// locally to the GetYAML methods.
type machineStatusNoMarshal machineStatus

func (s machineStatus) MarshalJSON() ([]byte, error) {
	if s.Err != nil {
		return json.Marshal(errorStatus{s.Err.Error()})
	}
	return json.Marshal(machineStatusNoMarshal(s))
}

func (s machineStatus) GetYAML() (tag string, value interface{}) {
	if s.Err != nil {
		return "", errorStatus{s.Err.Error()}
	}
	// TODO(rog) rename mNoMethods to noMethods (and also in
	// the other GetYAML methods) when people are using the non-buggy
	// goyaml version.
	type mNoMethods machineStatus
	return "", mNoMethods(s)
}

type serviceStatus struct {
	Err           error                 `json:"-" yaml:",omitempty"`
	Charm         string                `json:"charm" yaml:"charm"`
	CanUpgradeTo  string                `json:"can-upgrade-to,omitempty" yaml:"can-upgrade-to,omitempty"`
	Exposed       bool                  `json:"exposed" yaml:"exposed"`
	Life          string                `json:"life,omitempty" yaml:"life,omitempty"`
	Relations     map[string][]string   `json:"relations,omitempty" yaml:"relations,omitempty"`
	Networks      map[string][]string   `json:"networks,omitempty" yaml:"networks,omitempty"`
	SubordinateTo []string              `json:"subordinate-to,omitempty" yaml:"subordinate-to,omitempty"`
	Units         map[string]unitStatus `json:"units,omitempty" yaml:"units,omitempty"`
}

type serviceStatusNoMarshal serviceStatus

func (s serviceStatus) MarshalJSON() ([]byte, error) {
	if s.Err != nil {
		return json.Marshal(errorStatus{s.Err.Error()})
	}
	type sNoMethods serviceStatus
	return json.Marshal(sNoMethods(s))
}

func (s serviceStatus) GetYAML() (tag string, value interface{}) {
	if s.Err != nil {
		return "", errorStatus{s.Err.Error()}
	}
	type sNoMethods serviceStatus
	return "", sNoMethods(s)
}

type unitStatus struct {
	Err            error                 `json:"-" yaml:",omitempty"`
	Charm          string                `json:"upgrading-from,omitempty" yaml:"upgrading-from,omitempty"`
	AgentState     params.Status         `json:"agent-state,omitempty" yaml:"agent-state,omitempty"`
	AgentStateInfo string                `json:"agent-state-info,omitempty" yaml:"agent-state-info,omitempty"`
	AgentVersion   string                `json:"agent-version,omitempty" yaml:"agent-version,omitempty"`
	Life           string                `json:"life,omitempty" yaml:"life,omitempty"`
	Machine        string                `json:"machine,omitempty" yaml:"machine,omitempty"`
	OpenedPorts    []string              `json:"open-ports,omitempty" yaml:"open-ports,omitempty"`
	PublicAddress  string                `json:"public-address,omitempty" yaml:"public-address,omitempty"`
	Subordinates   map[string]unitStatus `json:"subordinates,omitempty" yaml:"subordinates,omitempty"`
}

type unitStatusNoMarshal unitStatus

func (s unitStatus) MarshalJSON() ([]byte, error) {
	if s.Err != nil {
		return json.Marshal(errorStatus{s.Err.Error()})
	}
	return json.Marshal(unitStatusNoMarshal(s))
}

func (s unitStatus) GetYAML() (tag string, value interface{}) {
	if s.Err != nil {
		return "", errorStatus{s.Err.Error()}
	}
	type uNoMethods unitStatus
	return "", unitStatusNoMarshal(s)
}

func formatStatus(status *api.Status) formattedStatus {
	if status == nil {
		return formattedStatus{}
	}
	out := formattedStatus{
		Environment: status.EnvironmentName,
		Machines:    make(map[string]machineStatus),
		Services:    make(map[string]serviceStatus),
	}
	for k, m := range status.Machines {
		out.Machines[k] = formatMachine(m)
	}
	for k, s := range status.Services {
		out.Services[k] = formatService(s)
	}
	return out
}

func formatMachine(machine api.MachineStatus) machineStatus {
	out := machineStatus{
		Err:            machine.Err,
		AgentState:     machine.AgentState,
		AgentStateInfo: machine.AgentStateInfo,
		AgentVersion:   machine.AgentVersion,
		DNSName:        machine.DNSName,
		InstanceId:     machine.InstanceId,
		InstanceState:  machine.InstanceState,
		Life:           machine.Life,
		Series:         machine.Series,
		Id:             machine.Id,
		Containers:     make(map[string]machineStatus),
		Hardware:       machine.Hardware,
		Jobs:           machine.Jobs,
	}
	for k, m := range machine.Containers {
		out.Containers[k] = formatMachine(m)
	}

	for _, job := range machine.Jobs {
		if job == params.JobManageEnviron {
			out.HAStatus = makeHAStatus(machine.HasVote, machine.WantsVote)
			break
		}
	}
	return out
}

func makeHAStatus(hasVote, wantsVote bool) string {
	var s string
	switch {
	case hasVote && wantsVote:
		s = "has vote"
	case hasVote && !wantsVote:
		s = "removing vote"
	case !hasVote && wantsVote:
		s = "adding vote"
	case !hasVote && !wantsVote:
		s = "no vote"
	}
	return s
}

func formatService(service api.ServiceStatus) serviceStatus {
	out := serviceStatus{
		Err:           service.Err,
		Charm:         service.Charm,
		Exposed:       service.Exposed,
		Life:          service.Life,
		Relations:     service.Relations,
		Networks:      make(map[string][]string),
		CanUpgradeTo:  service.CanUpgradeTo,
		SubordinateTo: service.SubordinateTo,
		Units:         make(map[string]unitStatus),
	}
	if len(service.Networks.Enabled) > 0 {
		out.Networks["enabled"] = service.Networks.Enabled
	}
	if len(service.Networks.Disabled) > 0 {
		out.Networks["disabled"] = service.Networks.Disabled
	}
	for k, m := range service.Units {
		out.Units[k] = formatUnit(m)
	}
	return out
}

func formatUnit(unit api.UnitStatus) unitStatus {
	out := unitStatus{
		Err:            unit.Err,
		AgentState:     unit.AgentState,
		AgentStateInfo: unit.AgentStateInfo,
		AgentVersion:   unit.AgentVersion,
		Life:           unit.Life,
		Machine:        unit.Machine,
		OpenedPorts:    unit.OpenedPorts,
		PublicAddress:  unit.PublicAddress,
		Charm:          unit.Charm,
		Subordinates:   make(map[string]unitStatus),
	}
	for k, m := range unit.Subordinates {
		out.Subordinates[k] = formatUnit(m)
	}
	return out
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"encoding/xml"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"sync/atomic"
	"time"

	"github.com/egonelbre/fedwiki"
	"github.com/egonelbre/fedwiki/item"
	"github.com/egonelbre/fedwiki/template"

	"github.com/raintreeinc/knowledgebase/ditaconv"
	"github.com/raintreeinc/knowledgebase/ditaconv/xmlconv"
)

var (
	addr      = flag.String("listen", ":80", "listening `address`")
	ditamap   = flag.String("ditamap", os.Getenv("DITAMAP"), "main `ditamap`")
	clientdir = flag.String("client", os.Getenv("CLIENT"), "client `directory`")
	pagesdir  = flag.String("pagesdir", "pages", "output `directory`")

	dirviews = flag.String("views", "views", "`directory` for page templates")

	global        atomic.Value
	triggerReload = make(chan struct{}, 1e6)
)

type convertErr struct {
	Slug   fedwiki.Slug
	Fatal  error
	Errors []error
}

type rendered struct {
	Page *fedwiki.Page
	JSON []byte
}

type Store struct {
	Pages   map[fedwiki.Slug]*rendered
	Headers []*fedwiki.PageHeader
	Slugs   []fedwiki.Slug

	Created time.Time

	LoadErrs    []error
	MappingErrs []error
	ConvertErrs []convertErr
}

func (s *Store) ErrorPage() *fedwiki.Page {
	page := &fedwiki.Page{}
	page.Slug = "/system/errors"
	page.Title = "Errors"
	page.Date = fedwiki.NewDate(s.Created)

	page.Story.Append(item.HTML(`<form action='/system/reload' target="_blank" method='POST'><input type='submit' value='Reload'></form>`))

	page.Story.Append(item.HTML("
Loading
"))
	for _, err := range s.LoadErrs {
		page.Story.Append(item.Paragraph(err.Error()))
	}

	page.Story.Append(item.HTML("
Mapping
"))
	for _, err := range s.MappingErrs {
		page.Story.Append(item.Paragraph(err.Error()))
	}

	page.Story.Append(item.HTML("
Converting
"))
	for _, errs := range s.ConvertErrs {
		text := "
[" + string(errs.Slug) + "]
"
		for _, err := range errs.Errors {
			text += "
" + err.Error() + "
"
		}
		page.Story.Append(item.HTML(text))
	}

	return page
}

func (s *Store) HomePage() *fedwiki.Page {
	page := &fedwiki.Page{}
	page.Slug = "/home"
	page.Title = "Home"
	page.Date = fedwiki.NewDate(s.Created)

	content := "
Pages:
"
	content += "
"
	for _, h := range s.Headers {
		content += fmt.Sprintf("
%s
", h.Slug, h.Title)
	}
	content += "
"
	page.Story.Append(item.HTML(content))

	return page
}

func reload() (*Store, error) {
	if *pagesdir != "" {
		os.RemoveAll(*pagesdir)
		os.MkdirAll(*pagesdir, 0755)
	}

	store := &Store{
		Pages:   make(map[fedwiki.Slug]*rendered),
		Created: time.Now(),
	}

	index, errs := ditaconv.LoadIndex(*ditamap)
	store.LoadErrs = errs

	mapping, errs := ditaconv.CreateMapping(index)
	store.MappingErrs = errs

	mapping.Rules.Merge(CustomRules())

	for slug, topic := range mapping.BySlug {
		page, fatal, errs := mapping.Convert(topic)
		if fatal != nil {
			store.ConvertErrs = append(store.ConvertErrs, convertErr{Slug: slug, Fatal: fatal})
			continue
		} else if len(errs) > 0 {
			store.ConvertErrs = append(store.ConvertErrs, convertErr{Slug: slug, Errors: errs})
		}

		rendered := &rendered{}
		rendered.Page = page
		rendered.JSON, _ = json.Marshal(page)

		if *pagesdir != "" {
			filename := string(page.Slug) + ".json"
			err := ioutil.WriteFile(filepath.Join(*pagesdir, filename), rendered.JSON, 0755)
			if err != nil {
				log.Println(err)
			}
		}

		store.Pages[slug] = rendered
		store.Headers = append(store.Headers, &page.PageHeader)
		store.Slugs = append(store.Slugs, slug)
	}

	sort.Sort(ByTitle(store.Headers))
	sort.Sort(BySlug(store.Slugs))

	return store, nil
}

type ByTitle []*fedwiki.PageHeader

func (s ByTitle) Len() int           { return len(s) }
func (s ByTitle) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s ByTitle) Less(i, j int) bool { return s[i].Title < s[j].Title }

type BySlug []fedwiki.Slug

func (s BySlug) Len() int           { return len(s) }
func (s BySlug) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s BySlug) Less(i, j int) bool { return s[i] < s[j] }

func reloader() {
	for {
		log.Println("Reloading")
		store, err := reload()
		log.Println("Reloaded")

		if err == nil {
			global.Store(store)
		} else {
			log.Println(err)
		}

		// clear reload channel
	clearReload:
		for {
			select {
			case <-triggerReload:
			default:
				break clearReload
			}
		}

		// wait for reload
		select {
		case <-time.After(1 * time.Hour):
		case <-triggerReload:
		}
	}
}

func main() {
	flag.Parse()
	if *ditamap == "" {
		fmt.Printf("specifying a ditamap is required")
		flag.Usage()
		os.Exit(1)
	}

	host, port := os.Getenv("HOST"), os.Getenv("PORT")
	if host != "" || port != "" {
		*addr = host + ":" + port
	}

	if *clientdir == "" {
		*clientdir = filepath.Join("..", "..", "client")
	}

	go reloader()

	templates := template.New(filepath.Join(*dirviews, "*"))

	server := &fedwiki.Server{
		Handler:  fedwiki.HandlerFunc(serve),
		Template: templates,
	}

	http.Handle("/client/", http.StripPrefix("/client/", http.FileServer(http.Dir(*clientdir))))
	http.Handle("/",
		http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			rw.Header().Set("Access-Control-Allow-Origin", "*")
			rw.Header().Set("Access-Control-Allow-Methods", "GET")
			rw.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
			if r.URL.Path == "" || r.URL.Path == "/" {
				http.ServeFile(rw, r, filepath.Join(*clientdir, "index.html"))
				return
			}

			if r.Method == "POST" && r.URL.Path == "/system/reload" {
				triggerReload <- struct{}{}
				http.Error(rw, "", http.StatusOK)
				return
			}

			server.ServeHTTP(rw, r)
		}))

	log.Println("listening on", *addr)
	log.Fatal(http.ListenAndServe(*addr, nil))
}

func serve(r *http.Request) (code int, template string, data interface{}) {
	if r.Method != "GET" {
		return fedwiki.ErrorResponse(http.StatusForbidden, "Method %s is not allowed", r.Method)
	}

	store, ok := global.Load().(*Store)
	if !ok {
		return fedwiki.ErrorResponse(http.StatusNotFound, "Page %s not loaded", r.URL.Path)
	}

	switch r.URL.Path {
	case "/system/sitemap":
		return http.StatusOK, "sitemap", store.Headers
	case "/system/slugs":
		return http.StatusOK, "slugs", store.Slugs
	case "/system/errors":
		return http.StatusOK, "", store.ErrorPage()
	case "/home":
		return http.StatusOK, "", store.HomePage()
	}

	slug := fedwiki.Slugify(r.URL.Path[1:])
	page, found := store.Pages[slug]
	if found {
		return http.StatusOK, "", page.Page
	} else {
		return fedwiki.ErrorResponse(http.StatusNotFound, "Page %s not found", r.URL.Path)
	}
}

func CustomRules() *xmlconv.Rules {
	return &xmlconv.Rules{
		Translate: map[string]string{
			"keystroke": "span",
			"secright":  "span",

			// faq
			"faq":          "dl",
			"faq-question": "dt",
			"faq-answer":   "dd",

			//UI items
			"ui-item-list": "dl",

			"ui-item-name":        "dt",
			"ui-item-description": "dd",

			// setup options
			"setup-options": "dl",

			"setup-option-name":        "dt",
			"setup-option-description": "dd",

			"settingdesc": "div",
			"settingname": "h3",
		},
		Remove: map[string]bool{
			"settinghead": true,
		},
		Unwrap: map[string]bool{
			"ui-item":      true,
			"faq-item":     true,
			"setup-option": true,

			"settings": true,
			"setting":  true,
		},
		Callback: map[string]xmlconv.Callback{
			"settingdefault": func(enc xmlconv.Encoder, dec *xml.Decoder, start *xml.StartElement) error {
				val, _ := xmlconv.Text(dec, start)
				if val != "" {
					err := enc.WriteRaw("
Default value: " + val + "
")
					if err != nil {
						return err
					}
				}
				return nil
			},
			"settinglevels": func(enc xmlconv.Encoder, dec *xml.Decoder, start *xml.StartElement) error {
				err := enc.WriteRaw("
Levels where it can be defined:
")
				if err != nil {
					return err
				}
				if err := enc.Rules().ConvertChildren(enc, dec, start); err != nil {
					return err
				}
				return nil
			},
		},
	}
}
<commit_msg>Added custom rule for settingsample.<commit_after>package main

import (
	"encoding/json"
	"encoding/xml"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"sort"
	"sync/atomic"
	"time"

	"github.com/egonelbre/fedwiki"
	"github.com/egonelbre/fedwiki/item"
	"github.com/egonelbre/fedwiki/template"

	"github.com/raintreeinc/knowledgebase/ditaconv"
	"github.com/raintreeinc/knowledgebase/ditaconv/xmlconv"
)

var (
	addr      = flag.String("listen", ":80", "listening `address`")
	ditamap   = flag.String("ditamap", os.Getenv("DITAMAP"), "main `ditamap`")
	clientdir = flag.String("client", os.Getenv("CLIENT"), "client `directory`")
	pagesdir  = flag.String("pagesdir", "pages", "output `directory`")

	dirviews = flag.String("views", "views", "`directory` for page templates")

	global        atomic.Value
	triggerReload = make(chan struct{}, 1e6)
)

type convertErr struct {
	Slug   fedwiki.Slug
	Fatal  error
	Errors []error
}

type rendered struct {
	Page *fedwiki.Page
	JSON []byte
}

type Store struct {
	Pages   map[fedwiki.Slug]*rendered
	Headers []*fedwiki.PageHeader
	Slugs   []fedwiki.Slug

	Created time.Time

	LoadErrs    []error
	MappingErrs []error
	ConvertErrs []convertErr
}

func (s *Store) ErrorPage() *fedwiki.Page {
	page := &fedwiki.Page{}
	page.Slug = "/system/errors"
	page.Title = "Errors"
	page.Date = fedwiki.NewDate(s.Created)

	page.Story.Append(item.HTML(`<form action='/system/reload' target="_blank" method='POST'><input type='submit' value='Reload'></form>`))

	page.Story.Append(item.HTML("
Loading
"))
	for _, err := range s.LoadErrs {
		page.Story.Append(item.Paragraph(err.Error()))
	}

	page.Story.Append(item.HTML("
Mapping
"))
	for _, err := range s.MappingErrs {
		page.Story.Append(item.Paragraph(err.Error()))
	}

	page.Story.Append(item.HTML("
Converting
"))
	for _, errs := range s.ConvertErrs {
		text := "
[" + string(errs.Slug) + "]
"
		for _, err := range errs.Errors {
			text += "
" + err.Error() + "
"
		}
		page.Story.Append(item.HTML(text))
	}

	return page
}

func (s *Store) HomePage() *fedwiki.Page {
	page := &fedwiki.Page{}
	page.Slug = "/home"
	page.Title = "Home"
	page.Date = fedwiki.NewDate(s.Created)

	content := "
Pages:
"
	content += "
"
	for _, h := range s.Headers {
		content += fmt.Sprintf("
%s
", h.Slug, h.Title)
	}
	content += "
"
	page.Story.Append(item.HTML(content))

	return page
}

func reload() (*Store, error) {
	if *pagesdir != "" {
		os.RemoveAll(*pagesdir)
		os.MkdirAll(*pagesdir, 0755)
	}

	store := &Store{
		Pages:   make(map[fedwiki.Slug]*rendered),
		Created: time.Now(),
	}

	index, errs := ditaconv.LoadIndex(*ditamap)
	store.LoadErrs = errs

	mapping, errs := ditaconv.CreateMapping(index)
	store.MappingErrs = errs

	mapping.Rules.Merge(CustomRules())

	for slug, topic := range mapping.BySlug {
		page, fatal, errs := mapping.Convert(topic)
		if fatal != nil {
			store.ConvertErrs = append(store.ConvertErrs, convertErr{Slug: slug, Fatal: fatal})
			continue
		} else if len(errs) > 0 {
			store.ConvertErrs = append(store.ConvertErrs, convertErr{Slug: slug, Errors: errs})
		}

		rendered := &rendered{}
		rendered.Page = page
		rendered.JSON, _ = json.Marshal(page)

		if *pagesdir != "" {
			filename := string(page.Slug) + ".json"
			err := ioutil.WriteFile(filepath.Join(*pagesdir, filename), rendered.JSON, 0755)
			if err != nil {
				log.Println(err)
			}
		}

		store.Pages[slug] = rendered
		store.Headers = append(store.Headers, &page.PageHeader)
		store.Slugs = append(store.Slugs, slug)
	}

	sort.Sort(ByTitle(store.Headers))
	sort.Sort(BySlug(store.Slugs))

	return store, nil
}

type ByTitle []*fedwiki.PageHeader

func (s ByTitle) Len() int           { return len(s) }
func (s ByTitle) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s ByTitle) Less(i, j int) bool { return s[i].Title < s[j].Title }

type BySlug []fedwiki.Slug

func (s BySlug) Len() int           { return len(s) }
func (s BySlug) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
func (s BySlug) Less(i, j int) bool { return s[i] < s[j] }

func reloader() {
	for {
		log.Println("Reloading")
		store, err := reload()
		log.Println("Reloaded")

		if err == nil {
			global.Store(store)
		} else {
			log.Println(err)
		}

		// clear reload channel
	clearReload:
		for {
			select {
			case <-triggerReload:
			default:
				break clearReload
			}
		}

		// wait for reload
		select {
		case <-time.After(1 * time.Hour):
		case <-triggerReload:
		}
	}
}

func main() {
	flag.Parse()
	if *ditamap == "" {
		fmt.Printf("specifying a ditamap is required")
		flag.Usage()
		os.Exit(1)
	}

	host, port := os.Getenv("HOST"), os.Getenv("PORT")
	if host != "" || port != "" {
		*addr = host + ":" + port
	}

	if *clientdir == "" {
		*clientdir = filepath.Join("..", "..", "client")
	}

	go reloader()

	templates := template.New(filepath.Join(*dirviews, "*"))

	server := &fedwiki.Server{
		Handler:  fedwiki.HandlerFunc(serve),
		Template: templates,
	}

	http.Handle("/client/", http.StripPrefix("/client/", http.FileServer(http.Dir(*clientdir))))
	http.Handle("/",
		http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
			rw.Header().Set("Access-Control-Allow-Origin", "*")
			rw.Header().Set("Access-Control-Allow-Methods", "GET")
			rw.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
			if r.URL.Path == "" || r.URL.Path == "/" {
				http.ServeFile(rw, r, filepath.Join(*clientdir, "index.html"))
				return
			}

			if r.Method == "POST" && r.URL.Path == "/system/reload" {
				triggerReload <- struct{}{}
				http.Error(rw, "", http.StatusOK)
				return
			}

			server.ServeHTTP(rw, r)
		}))

	log.Println("listening on", *addr)
	log.Fatal(http.ListenAndServe(*addr, nil))
}

func serve(r *http.Request) (code int, template string, data interface{}) {
	if r.Method != "GET" {
		return fedwiki.ErrorResponse(http.StatusForbidden, "Method %s is not allowed", r.Method)
	}

	store, ok := global.Load().(*Store)
	if !ok {
		return fedwiki.ErrorResponse(http.StatusNotFound, "Page %s not loaded", r.URL.Path)
	}

	switch r.URL.Path {
	case "/system/sitemap":
		return http.StatusOK, "sitemap", store.Headers
	case "/system/slugs":
		return http.StatusOK, "slugs", store.Slugs
	case "/system/errors":
		return http.StatusOK, "", store.ErrorPage()
	case "/home":
		return http.StatusOK, "", store.HomePage()
	}

	slug := fedwiki.Slugify(r.URL.Path[1:])
	page, found := store.Pages[slug]
	if found {
		return http.StatusOK, "", page.Page
	} else {
		return fedwiki.ErrorResponse(http.StatusNotFound, "Page %s not found", r.URL.Path)
	}
}

func CustomRules() *xmlconv.Rules {
	return &xmlconv.Rules{
		Translate: map[string]string{
			"keystroke": "span",
			"secright":  "span",

			// faq
			"faq":          "dl",
			"faq-question": "dt",
			"faq-answer":   "dd",

			//UI items
			"ui-item-list": "dl",

			"ui-item-name":        "dt",
			"ui-item-description": "dd",

			// setup options
			"setup-options": "dl",

			"setup-option-name":        "dt",
			"setup-option-description": "dd",

			"settingdesc": "div",
			"settingname": "h3",
		},
		Remove: map[string]bool{
			"settinghead": true,
		},
		Unwrap: map[string]bool{
			"ui-item":      true,
			"faq-item":     true,
			"setup-option": true,

			"settings": true,
			"setting":  true,
		},
		Callback: map[string]xmlconv.Callback{
			"settingdefault": func(enc xmlconv.Encoder, dec *xml.Decoder, start *xml.StartElement) error {
				val, _ := xmlconv.Text(dec, start)
				if val != "" {
					err := enc.WriteRaw("
Default value: " + val + "
")
					if err != nil {
						return err
					}
				}
				return nil
			},
			"settinglevels": func(enc xmlconv.Encoder, dec *xml.Decoder, start *xml.StartElement) error {
				err := enc.WriteRaw("
Levels where it can be defined:
")
				if err != nil {
					return err
				}
				if err := enc.Rules().ConvertChildren(enc, dec, start); err != nil {
					return err
				}
				return nil
			},
			"settingsample": func(enc xmlconv.Encoder, dec *xml.Decoder, start *xml.StartElement) error {
				err := enc.WriteRaw("
Example:
")
				if err != nil {
					return err
				}
				if err := enc.Rules().ConvertChildren(enc, dec, start); err != nil {
					return err
				}
				return nil
			},
		},
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	kgit "k8s.io/release/pkg/git"
	"k8s.io/release/pkg/util"
)

type ffOptions struct {
	branch         string
	masterRef      string
	nonInteractive bool
}

var ffOpts = &ffOptions{}

// ffCmd represents the base command when called without any subcommands
var ffCmd = &cobra.Command{
	Use:   "ff --branch <release-branch> [--ref <master-ref>] [--nomock] [--cleanup]",
	Short: "ff fast forwards a Kubernetes release branch",
	Long: `ff fast forwards a branch to a specified master object reference
(defaults to HEAD), and then prepares the branch as a Kubernetes release branch:

- Run hack/update-all.sh to ensure compliance of generated files`,
	Example:       "krel ff --branch release-1.17 --ref HEAD --cleanup",
	SilenceUsage:  true,
	SilenceErrors: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		return runFf(ffOpts, rootOpts)
	},
}

func init() {
	ffCmd.PersistentFlags().StringVar(&ffOpts.branch, "branch", "", "branch")
	ffCmd.PersistentFlags().StringVar(&ffOpts.masterRef, "ref", kgit.DefaultMasterRef, "ref on master")

	rootCmd.AddCommand(ffCmd)
}

func runFf(opts *ffOptions, rootOpts *rootOptions) error {
	branch := opts.branch
	if branch == "" {
		return errors.New("please specify valid release branch")
	}
	masterRef := opts.masterRef
	remoteMaster := kgit.Remotify(kgit.Master)

	logrus.Infof("Preparing to fast-forward master@%s onto the %s branch", masterRef, branch)
	repo, err := kgit.CloneOrOpenDefaultGitHubRepoSSH(rootOpts.repoPath)
	if err != nil {
		return err
	}

	if !rootOpts.nomock {
		logrus.Info("Using dry mode, which does not modify any remote content")
		repo.SetDry()
	}

	logrus.Infof("Checking if %q is a release branch", branch)
	if isReleaseBranch := kgit.IsReleaseBranch(branch); !isReleaseBranch {
		return errors.Errorf("%s is not a release branch", branch)
	}

	logrus.Info("Checking if branch is available on the default remote")
	if err := repo.HasRemoteBranch(branch); err != nil {
		return err
	}

	logrus.Info("Checking out release branch")
	if err := repo.Checkout(branch); err != nil {
		return err
	}

	cleanup := rootOpts.cleanup
	if cleanup {
		defer repo.Cleanup() // nolint: errcheck
	}

	logrus.Infof("Finding merge base between %q and %q", kgit.Master, branch)
	mergeBase, err := repo.MergeBase(kgit.Master, branch)
	if err != nil {
		return err
	}

	// Verify the tags
	masterTag, err := repo.DescribeTag(remoteMaster)
	if err != nil {
		return err
	}
	mergeBaseTag, err := repo.DescribeTag(mergeBase)
	if err != nil {
		return err
	}
	logrus.Infof("Merge base tag is: %s", mergeBaseTag)

	if masterTag != mergeBaseTag {
		return errors.Errorf(
			"unable to fast forward: tag %q does not match %q",
			masterTag, mergeBaseTag,
		)
	}
	logrus.Infof("Verified that the latest master tag is the same as the merge base tag")

	releaseRev, err := repo.Head()
	if err != nil {
		return err
	}
	logrus.Infof("Latest release branch revision is %s", releaseRev)

	logrus.Info("Merging master changes into release branch")
	if err := repo.Merge(remoteMaster); err != nil {
		return err
	}

	headRev, err := repo.Head()
	if err != nil {
		return err
	}

	prepushMessage(repo.Dir(), kgit.DefaultRemote, branch, kgit.DefaultGithubOrg, releaseRev, headRev)

	pushUpstream := false
	if opts.nonInteractive {
		pushUpstream = true
	} else {
		_, pushUpstream, err = util.Ask("Are you ready to push the local branch fast-forward changes upstream? Please only answer after you have validated the changes.", "yes", 3)
		if err != nil {
			return err
		}
	}

	if pushUpstream {
		logrus.Infof("Pushing %s branch", branch)
		if err := repo.Push(branch); err != nil {
			return err
		}
	}

	return nil
}

func prepushMessage(gitRoot, remote, branch, org, releaseRev, headRev string) {
	fmt.Printf(`Go look around in %s to make sure things look okay before pushing...

Check for files left uncommitted using:

	git status -s

Validate the fast-forward commit using:

	git show

Validate the changes pulled in from master using:

	git log %s/%s..HEAD

Once the branch fast-forward is complete, the diff will be available after push at:

	https://github.com/%s/%s/compare/%s...%s"

`, gitRoot, remote, branch, org, kgit.DefaultGithubRepo, releaseRev, headRev)
}
<commit_msg>Restore checked out branch on krel ff<commit_after>/*
Copyright 2019 The Kubernetes Authors.

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

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

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

package cmd

import (
	"fmt"

	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"github.com/spf13/cobra"

	kgit "k8s.io/release/pkg/git"
	"k8s.io/release/pkg/util"
)

type ffOptions struct {
	branch         string
	masterRef      string
	nonInteractive bool
}

var ffOpts = &ffOptions{}

// ffCmd represents the base command when called without any subcommands
var ffCmd = &cobra.Command{
	Use:   "ff --branch <release-branch> [--ref <master-ref>] [--nomock] [--cleanup]",
	Short: "ff fast forwards a Kubernetes release branch",
	Long: `ff fast forwards a branch to a specified master object reference
(defaults to HEAD), and then prepares the branch as a Kubernetes release branch:

- Run hack/update-all.sh to ensure compliance of generated files`,
	Example:       "krel ff --branch release-1.17 --ref HEAD --cleanup",
	SilenceUsage:  true,
	SilenceErrors: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		return runFf(ffOpts, rootOpts)
	},
}

func init() {
	ffCmd.PersistentFlags().StringVar(&ffOpts.branch, "branch", "", "branch")
	ffCmd.PersistentFlags().StringVar(&ffOpts.masterRef, "ref", kgit.DefaultMasterRef, "ref on master")

	rootCmd.AddCommand(ffCmd)
}

func runFf(opts *ffOptions, rootOpts *rootOptions) error {
	branch := opts.branch
	if branch == "" {
		return errors.New("please specify valid release branch")
	}
	masterRef := opts.masterRef
	remoteMaster := kgit.Remotify(kgit.Master)

	logrus.Infof("Preparing to fast-forward master@%s onto the %s branch", masterRef, branch)
	repo, err := kgit.CloneOrOpenDefaultGitHubRepoSSH(rootOpts.repoPath)
	if err != nil {
		return err
	}

	if !rootOpts.nomock {
		logrus.Info("Using dry mode, which does not modify any remote content")
		repo.SetDry()
	}

	logrus.Infof("Checking if %q is a release branch", branch)
	if isReleaseBranch := kgit.IsReleaseBranch(branch); !isReleaseBranch {
		return errors.Errorf("%s is not a release branch", branch)
	}

	logrus.Info("Checking if branch is available on the default remote")
	if err := repo.HasRemoteBranch(branch); err != nil {
		return err
	}

	// Restore the currently checked out branch afterwards
	currentBranch, err := repo.CurrentBranch()
	if err != nil {
		return errors.Wrap(err, "unable to retrieve current branch")
	}
	defer func() {
		if err := repo.Checkout(currentBranch); err != nil {
			logrus.Errorf("unable to restore branch %s: %v", currentBranch, err)
		}
	}()
	logrus.Info("Checking out release branch")
	if err := repo.Checkout(branch); err != nil {
		return errors.Wrapf(err, "checking out branch %s", branch)
	}

	cleanup := rootOpts.cleanup
	if cleanup {
		defer repo.Cleanup() // nolint: errcheck
	}

	logrus.Infof("Finding merge base between %q and %q", kgit.Master, branch)
	mergeBase, err := repo.MergeBase(kgit.Master, branch)
	if err != nil {
		return err
	}

	// Verify the tags
	masterTag, err := repo.DescribeTag(remoteMaster)
	if err != nil {
		return err
	}
	mergeBaseTag, err := repo.DescribeTag(mergeBase)
	if err != nil {
		return err
	}
	logrus.Infof("Merge base tag is: %s", mergeBaseTag)

	if masterTag != mergeBaseTag {
		return errors.Errorf(
			"unable to fast forward: tag %q does not match %q",
			masterTag, mergeBaseTag,
		)
	}
	logrus.Infof("Verified that the latest master tag is the same as the merge base tag")

	releaseRev, err := repo.Head()
	if err != nil {
		return err
	}
	logrus.Infof("Latest release branch revision is %s", releaseRev)

	logrus.Info("Merging master changes into release branch")
	if err := repo.Merge(remoteMaster); err != nil {
		return err
	}

	headRev, err := repo.Head()
	if err != nil {
		return err
	}

	prepushMessage(repo.Dir(), kgit.DefaultRemote, branch, kgit.DefaultGithubOrg, releaseRev, headRev)

	pushUpstream := false
	if opts.nonInteractive {
		pushUpstream = true
	} else {
		_, pushUpstream, err = util.Ask("Are you ready to push the local branch fast-forward changes upstream? Please only answer after you have validated the changes.", "yes", 3)
		if err != nil {
			return err
		}
	}

	if pushUpstream {
		logrus.Infof("Pushing %s branch", branch)
		if err := repo.Push(branch); err != nil {
			return err
		}
	}

	return nil
}

func prepushMessage(gitRoot, remote, branch, org, releaseRev, headRev string) {
	fmt.Printf(`Go look around in %s to make sure things look okay before pushing...

Check for files left uncommitted using:

	git status -s

Validate the fast-forward commit using:

	git show

Validate the changes pulled in from master using:

	git log %s/%s..HEAD

Once the branch fast-forward is complete, the diff will be available after push at:

	https://github.com/%s/%s/compare/%s...%s"

`, gitRoot, remote, branch, org, kgit.DefaultGithubRepo, releaseRev, headRev)
}
<|endoftext|>