<commit_before>package cmd

import (
	"bufio"
	"bytes"
	"fmt"
	"log"
	"os"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"text/template"

	"github.com/pkg/errors"
	"github.com/rsteube/carapace"
	"github.com/spf13/cobra"
	gitlab "github.com/xanzy/go-gitlab"
	"github.com/zaquestion/lab/internal/action"
	"github.com/zaquestion/lab/internal/git"
	lab "github.com/zaquestion/lab/internal/gitlab"
)

// mrCmd represents the mr command
var mrCreateCmd = &cobra.Command{
	Use:              "create [remote [branch]]",
	Aliases:          []string{"new"},
	Short:            "Open a merge request on GitLab",
	Long:             `Creates a merge request (default: MR created on default branch of origin)`,
	Args:             cobra.MaximumNArgs(2),
	PersistentPreRun: LabPersistentPreRun,
	Run:              runMRCreate,
}

func init() {
	mrCreateCmd.Flags().StringArrayP("message", "m", []string{}, "use the given <msg>; multiple -m are concatenated as separate paragraphs")
	mrCreateCmd.Flags().StringSliceP("assignee", "a", []string{}, "set assignee by username; can be specified multiple times for multiple assignees")
	mrCreateCmd.Flags().StringSliceP("label", "l", []string{}, "add label <label>; can be specified multiple times for multiple labels")
	mrCreateCmd.Flags().BoolP("remove-source-branch", "d", false, "remove source branch from remote after merge")
	mrCreateCmd.Flags().BoolP("squash", "s", false, "squash commits when merging")
	mrCreateCmd.Flags().Bool("allow-collaboration", false, "allow commits from other members")
	mrCreateCmd.Flags().String("milestone", "", "set milestone by milestone title or ID")
	mrCreateCmd.Flags().StringP("file", "F", "", "use the given file as the Description")
	mrCreateCmd.Flags().Bool("force-linebreak", false, "append 2 spaces to the end of each line to force markdown linebreaks")
	mrCreateCmd.Flags().BoolP("cover-letter", "c", false, "do not comment changelog and diffstat")
	mrCreateCmd.Flags().Bool("draft", false, "mark the merge request as draft")
	mergeRequestCmd.Flags().AddFlagSet(mrCreateCmd.Flags())

	mrCmd.AddCommand(mrCreateCmd)
	carapace.Gen(mrCreateCmd).PositionalCompletion(
		action.Remotes(),
		action.RemoteBranches(0),
	)
}

// getAssignee returns the assigneeID for use with other GitLab API calls.
// NOTE: It is also used by issue_create.go
func getAssigneeID(assignee string) *int {
	if assignee == "" {
		return nil
	}
	if assignee[0] == '@' {
		assignee = assignee[1:]
	}
	assigneeID, err := lab.UserIDFromUsername(assignee)
	if err != nil {
		return nil
	}
	if assigneeID == -1 {
		return nil
	}
	return gitlab.Int(assigneeID)
}

// getAssignees returns the assigneeIDs for use with other GitLab API calls.
func getAssigneeIDs(assignees []string) []int {
	var ids []int
	for _, a := range assignees {
		ids = append(ids, *getAssigneeID(a))
	}
	return ids
}

func runMRCreate(cmd *cobra.Command, args []string) {
	msgs, err := cmd.Flags().GetStringArray("message")
	if err != nil {
		log.Fatal(err)
	}
	assignees, err := cmd.Flags().GetStringSlice("assignee")
	if err != nil {
		log.Fatal(err)
	}
	filename, err := cmd.Flags().GetString("file")
	if err != nil {
		log.Fatal(err)
	}
	branch, err := git.CurrentBranch()
	if err != nil {
		log.Fatal(err)
	}

	sourceRemote := determineSourceRemote(branch)
	sourceProjectName, err := git.PathWithNameSpace(sourceRemote)
	if err != nil {
		log.Fatal(err)
	}

	remoteBranch, err := git.CurrentUpstreamBranch()
	if remoteBranch == "" {
		// Fall back to local branch
		remoteBranch, err = git.CurrentBranch()
	}

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

	p, err := lab.FindProject(sourceProjectName)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := lab.GetCommit(p.ID, remoteBranch); err != nil {
		err = errors.Wrapf(
			err,
			"aborting MR, source branch %s not present on remote %s. did you forget to push?",
			remoteBranch, sourceRemote)
		log.Fatal(err)
	}

	targetRemote := defaultRemote
	if len(args) > 0 {
		targetRemote = args[0]
		ok, err := git.IsRemote(targetRemote)
		if err != nil || !ok {
			log.Fatal(errors.Wrapf(err, "%s is not a valid remote", targetRemote))
		}
	}
	targetProjectName, err := git.PathWithNameSpace(targetRemote)
	if err != nil {
		log.Fatal(err)
	}
	targetProject, err := lab.FindProject(targetProjectName)
	if err != nil {
		log.Fatal(err)
	}

	targetBranch := targetProject.DefaultBranch
	if len(args) > 1 && targetBranch != args[1] {
		targetBranch = args[1]
		if _, err := lab.GetCommit(targetProject.ID, targetBranch); err != nil {
			err = errors.Wrapf(
				err,
				"aborting MR, %s:%s is not a valid target. Did you forget to push %s to %s?",
				targetRemote, branch, branch, targetRemote)
			log.Fatal(err)
		}
	}

	labelTerms, err := cmd.Flags().GetStringSlice("label")
	if err != nil {
		log.Fatal(err)
	}
	labels, err := MapLabels(targetProjectName, labelTerms)
	if err != nil {
		log.Fatal(err)
	}

	milestoneArg, _ := cmd.Flags().GetString("milestone")
	milestoneID, _ := strconv.Atoi(milestoneArg)

	var milestone *int
	if milestoneID > 0 {
		milestone = &milestoneID
	} else if milestoneArg != "" {
		ms, err := lab.MilestoneGet(targetProjectName, milestoneArg)
		if err != nil {
			log.Fatal(err)
		}
		milestone = &ms.ID
	} else {
		milestone = nil
	}

	var title, body string

	if filename != "" {
		file, err := os.Open(filename)
		if err != nil {
			log.Fatal(err)
		}

		fileScan := bufio.NewScanner(file)
		fileScan.Split(bufio.ScanLines)

		// The first line in the file is the title.
		fileScan.Scan()
		title = fileScan.Text()

		for fileScan.Scan() {
			body = body + fileScan.Text() + "\n"
		}

		file.Close()

	} else if len(msgs) > 0 {
		title, body = msgs[0], strings.Join(msgs[1:], "\n\n")
	} else {
		coverLetterFormat, _ := cmd.Flags().GetBool("cover-letter")
		msg, err := mrText(targetBranch, branch, sourceRemote, targetRemote, coverLetterFormat)
		if err != nil {
			log.Fatal(err)
		}

		title, body, err = git.Edit("MERGEREQ", msg)
		if err != nil {
			_, f, l, _ := runtime.Caller(0)
			log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
		}
	}

	linebreak, _ := cmd.Flags().GetBool("force-linebreak")
	if linebreak {
		body = textToMarkdown(body)
	}

	draft, _ := cmd.Flags().GetBool("draft")
	if draft {
		isWIP := strings.EqualFold(title[0:4], "wip:")
		isDraft := strings.EqualFold(title[0:6], "draft:") ||
			strings.EqualFold(title[0:7], "[draft]") ||
			strings.EqualFold(title[0:7], "(draft)")

		if !isWIP && !isDraft {
			title = "Draft: " + title
		}
	}

	removeSourceBranch, _ := cmd.Flags().GetBool("remove-source-branch")
	squash, _ := cmd.Flags().GetBool("squash")
	allowCollaboration, _ := cmd.Flags().GetBool("allow-collaboration")

	if title == "" {
		log.Fatal("aborting MR due to empty MR msg")
	}

	mrURL, err := lab.MRCreate(sourceProjectName, &gitlab.CreateMergeRequestOptions{
		SourceBranch:       &branch,
		TargetBranch:       gitlab.String(targetBranch),
		TargetProjectID:    &targetProject.ID,
		Title:              &title,
		Description:        &body,
		AssigneeIDs:        getAssigneeIDs(assignees),
		RemoveSourceBranch: &removeSourceBranch,
		Squash:             &squash,
		AllowCollaboration: &allowCollaboration,
		Labels:             labels,
		MilestoneID:        milestone,
	})
	if err != nil {
		// FIXME: not exiting fatal here to allow code coverage to
		// generate during Test_mrCreate. In the meantime API failures
		// will exit 0
		fmt.Fprintln(os.Stderr, err)
	}
	fmt.Println(mrURL + "/diffs")
}

func mrText(base, head, sourceRemote, targetRemote string, coverLetterFormat bool) (string, error) {
	var (
		commitMsg string
		err       error
	)
	remoteBase := fmt.Sprintf("%s/%s", targetRemote, base)
	commitMsg = ""
	if git.NumberCommits(remoteBase, head) == 1 {
		commitMsg, err = git.LastCommitMessage()
		if err != nil {
			return "", err
		}
	}

	const tmpl = `{{if .InitMsg}}{{.InitMsg}}{{end}}

{{if .Tmpl}}{{.Tmpl}}{{end}}
{{.CommentChar}} Requesting a merge into {{.Base}} from {{.Head}}
{{.CommentChar}}
{{.CommentChar}} Write a message for this merge request. The first block
{{.CommentChar}} of text is the title and the rest is the description.{{if .CommitLogs}}
{{.CommentChar}}
{{.CommentChar}} Changes:
{{.CommentChar}}
{{.CommitLogs}}{{end}}`

	mrTmpl := lab.LoadGitLabTmpl(lab.TmplMR)

	commitLogs, err := git.Log(remoteBase, head)
	if err != nil {
		return "", err
	}
	commitLogs = strings.TrimSpace(commitLogs)
	commentChar := git.CommentChar()

	if !coverLetterFormat {
		startRegexp := regexp.MustCompilePOSIX("^")
		commitLogs = startRegexp.ReplaceAllString(commitLogs, fmt.Sprintf("%s ", commentChar))
	} else {
		commitLogs = "\n" + strings.TrimSpace(commitLogs)
	}

	t, err := template.New("tmpl").Parse(tmpl)
	if err != nil {
		return "", err
	}

	msg := &struct {
		InitMsg     string
		Tmpl        string
		CommentChar string
		Base        string
		Head        string
		CommitLogs  string
	}{
		InitMsg:     commitMsg,
		Tmpl:        mrTmpl,
		CommentChar: commentChar,
		Base:        targetRemote + ":" + base,
		Head:        sourceRemote + ":" + head,
		CommitLogs:  commitLogs,
	}

	var b bytes.Buffer
	err = t.Execute(&b, msg)
	if err != nil {
		return "", err
	}

	return b.String(), nil
}
<commit_msg>mr_create: check for empty msg before acting<commit_after>package cmd

import (
	"bufio"
	"bytes"
	"fmt"
	"log"
	"os"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"text/template"

	"github.com/pkg/errors"
	"github.com/rsteube/carapace"
	"github.com/spf13/cobra"
	gitlab "github.com/xanzy/go-gitlab"
	"github.com/zaquestion/lab/internal/action"
	"github.com/zaquestion/lab/internal/git"
	lab "github.com/zaquestion/lab/internal/gitlab"
)

// mrCmd represents the mr command
var mrCreateCmd = &cobra.Command{
	Use:              "create [remote [branch]]",
	Aliases:          []string{"new"},
	Short:            "Open a merge request on GitLab",
	Long:             `Creates a merge request (default: MR created on default branch of origin)`,
	Args:             cobra.MaximumNArgs(2),
	PersistentPreRun: LabPersistentPreRun,
	Run:              runMRCreate,
}

func init() {
	mrCreateCmd.Flags().StringArrayP("message", "m", []string{}, "use the given <msg>; multiple -m are concatenated as separate paragraphs")
	mrCreateCmd.Flags().StringSliceP("assignee", "a", []string{}, "set assignee by username; can be specified multiple times for multiple assignees")
	mrCreateCmd.Flags().StringSliceP("label", "l", []string{}, "add label <label>; can be specified multiple times for multiple labels")
	mrCreateCmd.Flags().BoolP("remove-source-branch", "d", false, "remove source branch from remote after merge")
	mrCreateCmd.Flags().BoolP("squash", "s", false, "squash commits when merging")
	mrCreateCmd.Flags().Bool("allow-collaboration", false, "allow commits from other members")
	mrCreateCmd.Flags().String("milestone", "", "set milestone by milestone title or ID")
	mrCreateCmd.Flags().StringP("file", "F", "", "use the given file as the Description")
	mrCreateCmd.Flags().Bool("force-linebreak", false, "append 2 spaces to the end of each line to force markdown linebreaks")
	mrCreateCmd.Flags().BoolP("cover-letter", "c", false, "do not comment changelog and diffstat")
	mrCreateCmd.Flags().Bool("draft", false, "mark the merge request as draft")
	mergeRequestCmd.Flags().AddFlagSet(mrCreateCmd.Flags())

	mrCmd.AddCommand(mrCreateCmd)
	carapace.Gen(mrCreateCmd).PositionalCompletion(
		action.Remotes(),
		action.RemoteBranches(0),
	)
}

// getAssignee returns the assigneeID for use with other GitLab API calls.
// NOTE: It is also used by issue_create.go
func getAssigneeID(assignee string) *int {
	if assignee == "" {
		return nil
	}
	if assignee[0] == '@' {
		assignee = assignee[1:]
	}
	assigneeID, err := lab.UserIDFromUsername(assignee)
	if err != nil {
		return nil
	}
	if assigneeID == -1 {
		return nil
	}
	return gitlab.Int(assigneeID)
}

// getAssignees returns the assigneeIDs for use with other GitLab API calls.
func getAssigneeIDs(assignees []string) []int {
	var ids []int
	for _, a := range assignees {
		ids = append(ids, *getAssigneeID(a))
	}
	return ids
}

func runMRCreate(cmd *cobra.Command, args []string) {
	msgs, err := cmd.Flags().GetStringArray("message")
	if err != nil {
		log.Fatal(err)
	}
	assignees, err := cmd.Flags().GetStringSlice("assignee")
	if err != nil {
		log.Fatal(err)
	}
	filename, err := cmd.Flags().GetString("file")
	if err != nil {
		log.Fatal(err)
	}
	branch, err := git.CurrentBranch()
	if err != nil {
		log.Fatal(err)
	}

	sourceRemote := determineSourceRemote(branch)
	sourceProjectName, err := git.PathWithNameSpace(sourceRemote)
	if err != nil {
		log.Fatal(err)
	}

	remoteBranch, err := git.CurrentUpstreamBranch()
	if remoteBranch == "" {
		// Fall back to local branch
		remoteBranch, err = git.CurrentBranch()
	}

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

	p, err := lab.FindProject(sourceProjectName)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := lab.GetCommit(p.ID, remoteBranch); err != nil {
		err = errors.Wrapf(
			err,
			"aborting MR, source branch %s not present on remote %s. did you forget to push?",
			remoteBranch, sourceRemote)
		log.Fatal(err)
	}

	targetRemote := defaultRemote
	if len(args) > 0 {
		targetRemote = args[0]
		ok, err := git.IsRemote(targetRemote)
		if err != nil || !ok {
			log.Fatal(errors.Wrapf(err, "%s is not a valid remote", targetRemote))
		}
	}
	targetProjectName, err := git.PathWithNameSpace(targetRemote)
	if err != nil {
		log.Fatal(err)
	}
	targetProject, err := lab.FindProject(targetProjectName)
	if err != nil {
		log.Fatal(err)
	}

	targetBranch := targetProject.DefaultBranch
	if len(args) > 1 && targetBranch != args[1] {
		targetBranch = args[1]
		if _, err := lab.GetCommit(targetProject.ID, targetBranch); err != nil {
			err = errors.Wrapf(
				err,
				"aborting MR, %s:%s is not a valid target. Did you forget to push %s to %s?",
				targetRemote, branch, branch, targetRemote)
			log.Fatal(err)
		}
	}

	labelTerms, err := cmd.Flags().GetStringSlice("label")
	if err != nil {
		log.Fatal(err)
	}
	labels, err := MapLabels(targetProjectName, labelTerms)
	if err != nil {
		log.Fatal(err)
	}

	milestoneArg, _ := cmd.Flags().GetString("milestone")
	milestoneID, _ := strconv.Atoi(milestoneArg)

	var milestone *int
	if milestoneID > 0 {
		milestone = &milestoneID
	} else if milestoneArg != "" {
		ms, err := lab.MilestoneGet(targetProjectName, milestoneArg)
		if err != nil {
			log.Fatal(err)
		}
		milestone = &ms.ID
	} else {
		milestone = nil
	}

	var title, body string

	if filename != "" {
		file, err := os.Open(filename)
		if err != nil {
			log.Fatal(err)
		}

		fileScan := bufio.NewScanner(file)
		fileScan.Split(bufio.ScanLines)

		// The first line in the file is the title.
		fileScan.Scan()
		title = fileScan.Text()

		for fileScan.Scan() {
			body = body + fileScan.Text() + "\n"
		}

		file.Close()

	} else if len(msgs) > 0 {
		title, body = msgs[0], strings.Join(msgs[1:], "\n\n")
	} else {
		coverLetterFormat, _ := cmd.Flags().GetBool("cover-letter")
		msg, err := mrText(targetBranch, branch, sourceRemote, targetRemote, coverLetterFormat)
		if err != nil {
			log.Fatal(err)
		}

		title, body, err = git.Edit("MERGEREQ", msg)
		if err != nil {
			_, f, l, _ := runtime.Caller(0)
			log.Fatal(f+":"+strconv.Itoa(l)+" ", err)
		}
	}

	if title == "" {
		log.Fatal("aborting MR due to empty MR msg")
	}

	linebreak, _ := cmd.Flags().GetBool("force-linebreak")
	if linebreak {
		body = textToMarkdown(body)
	}

	draft, _ := cmd.Flags().GetBool("draft")
	if draft {
		isWIP := strings.EqualFold(title[0:4], "wip:")
		isDraft := strings.EqualFold(title[0:6], "draft:") ||
			strings.EqualFold(title[0:7], "[draft]") ||
			strings.EqualFold(title[0:7], "(draft)")

		if !isWIP && !isDraft {
			title = "Draft: " + title
		}
	}

	removeSourceBranch, _ := cmd.Flags().GetBool("remove-source-branch")
	squash, _ := cmd.Flags().GetBool("squash")
	allowCollaboration, _ := cmd.Flags().GetBool("allow-collaboration")

	mrURL, err := lab.MRCreate(sourceProjectName, &gitlab.CreateMergeRequestOptions{
		SourceBranch:       &branch,
		TargetBranch:       gitlab.String(targetBranch),
		TargetProjectID:    &targetProject.ID,
		Title:              &title,
		Description:        &body,
		AssigneeIDs:        getAssigneeIDs(assignees),
		RemoveSourceBranch: &removeSourceBranch,
		Squash:             &squash,
		AllowCollaboration: &allowCollaboration,
		Labels:             labels,
		MilestoneID:        milestone,
	})
	if err != nil {
		// FIXME: not exiting fatal here to allow code coverage to
		// generate during Test_mrCreate. In the meantime API failures
		// will exit 0
		fmt.Fprintln(os.Stderr, err)
	}
	fmt.Println(mrURL + "/diffs")
}

func mrText(base, head, sourceRemote, targetRemote string, coverLetterFormat bool) (string, error) {
	var (
		commitMsg string
		err       error
	)
	remoteBase := fmt.Sprintf("%s/%s", targetRemote, base)
	commitMsg = ""
	if git.NumberCommits(remoteBase, head) == 1 {
		commitMsg, err = git.LastCommitMessage()
		if err != nil {
			return "", err
		}
	}

	const tmpl = `{{if .InitMsg}}{{.InitMsg}}{{end}}

{{if .Tmpl}}{{.Tmpl}}{{end}}
{{.CommentChar}} Requesting a merge into {{.Base}} from {{.Head}}
{{.CommentChar}}
{{.CommentChar}} Write a message for this merge request. The first block
{{.CommentChar}} of text is the title and the rest is the description.{{if .CommitLogs}}
{{.CommentChar}}
{{.CommentChar}} Changes:
{{.CommentChar}}
{{.CommitLogs}}{{end}}`

	mrTmpl := lab.LoadGitLabTmpl(lab.TmplMR)

	commitLogs, err := git.Log(remoteBase, head)
	if err != nil {
		return "", err
	}
	commitLogs = strings.TrimSpace(commitLogs)
	commentChar := git.CommentChar()

	if !coverLetterFormat {
		startRegexp := regexp.MustCompilePOSIX("^")
		commitLogs = startRegexp.ReplaceAllString(commitLogs, fmt.Sprintf("%s ", commentChar))
	} else {
		commitLogs = "\n" + strings.TrimSpace(commitLogs)
	}

	t, err := template.New("tmpl").Parse(tmpl)
	if err != nil {
		return "", err
	}

	msg := &struct {
		InitMsg     string
		Tmpl        string
		CommentChar string
		Base        string
		Head        string
		CommitLogs  string
	}{
		InitMsg:     commitMsg,
		Tmpl:        mrTmpl,
		CommentChar: commentChar,
		Base:        targetRemote + ":" + base,
		Head:        sourceRemote + ":" + head,
		CommitLogs:  commitLogs,
	}

	var b bytes.Buffer
	err = t.Execute(&b, msg)
	if err != nil {
		return "", err
	}

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


<commit_before>package cmd

import (
	"github.com/bpicode/fritzctl/logger"
	"github.com/spf13/cobra"
)

var sessionIDCmd = &cobra.Command{
	Use:     "sessionid",
	Short:   "Obtain a session ID",
	Long:    "Obtain a session ID by solving the FRITZ!Box login challenge. The session ID can be used for subsequent requests until it gets invalidated.",
	Example: "fritzctl sessionid",
	RunE:    sessionID,
}

func init() {
	RootCmd.AddCommand(sessionIDCmd)
}

func sessionID(cmd *cobra.Command, args []string) error {
	client := clientLogin()
	logger.Success("Successfully obtained session ID:", client.SessionInfo.SID)
	return nil
}
<commit_msg>link to official documentation in help on sessionid command<commit_after>package cmd

import (
	"github.com/bpicode/fritzctl/logger"
	"github.com/spf13/cobra"
)

var sessionIDCmd = &cobra.Command{
	Use:     "sessionid",
	Short:   "Obtain a session ID",
	Long:    `Obtain a session ID by solving the FRITZ!Box login challenge. The session ID can be used for subsequent requests until it gets invalidated.
Visit https://avm.de/fileadmin/user_upload/Global/Service/Schnittstellen/AVM_Technical_Note_-_Session_ID.pdf for more information.`,
	Example: "fritzctl sessionid",
	RunE:    sessionID,
}

func init() {
	RootCmd.AddCommand(sessionIDCmd)
}

func sessionID(cmd *cobra.Command, args []string) error {
	client := clientLogin()
	logger.Success("Successfully obtained session ID:", client.SessionInfo.SID)
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"text/template"
	"time"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func hwaf_make_cmd_waf_bdist_rpm() *commander.Command {
	cmd := &commander.Command{
		Run:       hwaf_run_cmd_waf_bdist_rpm,
		UsageLine: "bdist-rpm [rpm-name]",
		Short:     "create a RPM from the local project/packages",
		Long: `
bdist-rpm creates a RPM from the local project/packages.

ex:
 $ hwaf bdist-rpm
 $ hwaf bdist-rpm -name=mana
 $ hwaf bdist-rpm -name=mana -version=20130101
`,
		Flag: *flag.NewFlagSet("hwaf-bdist-rpm", flag.ExitOnError),
	}
	cmd.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
	cmd.Flag.String("name", "", "name of the binary distribution (default: project name)")
	cmd.Flag.String("version", "", "version of the binary distribution (default: project version)")
	cmd.Flag.String("release", "1", "release version of the binary distribution (default: 1)")
	cmd.Flag.String("cmtcfg", "", "CMTCFG quadruplet for the binary distribution (default: project CMTCFG)")
	cmd.Flag.String("spec", "", "RPM SPEC file for the binary distribution")
	cmd.Flag.String("url", "", "URL for the RPM binary distribution")
	return cmd
}

func hwaf_run_cmd_waf_bdist_rpm(cmd *commander.Command, args []string) {
	var err error
	n := "hwaf-" + cmd.Name()

	switch len(args) {
	case 0:
	default:
		err = fmt.Errorf("%s: too many arguments (%s)", n, len(args))
		handle_err(err)
	}

	quiet := cmd.Flag.Lookup("q").Value.Get().(bool)

	bdist_name := cmd.Flag.Lookup("name").Value.Get().(string)
	bdist_vers := cmd.Flag.Lookup("version").Value.Get().(string)
	bdist_release := cmd.Flag.Lookup("release").Value.Get().(string)
	bdist_cmtcfg := cmd.Flag.Lookup("cmtcfg").Value.Get().(string)
	bdist_spec := cmd.Flag.Lookup("spec").Value.Get().(string)

	bdist_url := cmd.Flag.Lookup("url").Value.Get().(string)
	if bdist_url == "" {
		bdist_url = "http://cern.ch/mana-fwk"
	}

	type RpmInfo struct {
		Name      string // RPM package name
		Vers      string // RPM package version
		Release   string // RPM package release
		CmtCfg    string // RPM CMTCFG quadruplet
		BuildRoot string // RPM build directory
		Url       string // URL home page
	}

	workdir, err := get_workarea_root()
	if err != nil {
		// not a git repo... assume we are at the root, then...
		workdir, err = os.Getwd()
	}
	handle_err(err)

	if bdist_name == "" {
		bdist_name = workdir
		bdist_name = filepath.Base(bdist_name)
	}
	if bdist_vers == "" {
		bdist_vers = time.Now().Format("20060102")
	}
	if bdist_cmtcfg == "" {
		// FIXME: get actual value from waf, somehow
		pinfo_name := filepath.Join(workdir, "__build__", "c4che", "_cache.py")
		if !path_exists(pinfo_name) {
			err = fmt.Errorf(
				"no such file [%s]. did you run \"hwaf configure\" ?",
				pinfo_name,
			)
			handle_err(err)
		}
		pinfo, err := NewProjectInfo(pinfo_name)
		handle_err(err)
		bdist_cmtcfg, err = pinfo.Get("CMTCFG")
		handle_err(err)
	}
	fname := bdist_name + "-" + bdist_vers + "-" + bdist_cmtcfg
	rpmbldroot, err := ioutil.TempDir("", "hwaf-rpm-buildroot-")
	handle_err(err)
	defer os.RemoveAll(rpmbldroot)
	for _, dir := range []string{
		"RPMS", "SRPMS", "BUILD", "SOURCES", "SPECS", "tmp",
	} {
		err = os.MkdirAll(filepath.Join(rpmbldroot, dir), 0700)
		handle_err(err)
	}

	specfile, err := os.Create(filepath.Join(rpmbldroot, "SPECS", bdist_name+".spec"))
	handle_err(err)

	rpminfos := RpmInfo{
		Name:      bdist_name,
		Vers:      bdist_vers,
		Release:   bdist_release,
		CmtCfg:    bdist_cmtcfg,
		BuildRoot: rpmbldroot,
		Url:       bdist_url,
	}

	// get tarball from 'hwaf bdist'...
	bdist_fname := strings.Replace(fname, ".rpm", "", 1) + ".tar.gz"
	if !path_exists(bdist_fname) {
		err = fmt.Errorf("no such file [%s]. did you run \"hwaf bdist\" ?", bdist_fname)
		handle_err(err)
	}
	bdist_fname, err = filepath.Abs(bdist_fname)
	handle_err(err)
	{
		// first, massage the tar ball to something rpmbuild expects...

		// ok, now we're done.
		dst, err := os.Create(filepath.Join(rpmbldroot, "SOURCES", filepath.Base(bdist_fname)))
		handle_err(err)
		src, err := os.Open(bdist_fname)
		handle_err(err)
		_, err = io.Copy(dst, src)
		handle_err(err)
	}

	if bdist_spec != "" {
		bdist_spec = os.ExpandEnv(bdist_spec)
		bdist_spec, err = filepath.Abs(bdist_spec)
		handle_err(err)

		if !path_exists(bdist_spec) {
			err = fmt.Errorf("no such file [%s]", bdist_spec)
			handle_err(err)
		}
		user_spec, err := os.Open(bdist_spec)
		handle_err(err)
		defer user_spec.Close()

		_, err = io.Copy(specfile, user_spec)
		handle_err(err)
	} else {
		bdist_spec = specfile.Name()

		var spec_tmpl *template.Template
		spec_tmpl, err = template.New("SPEC").Parse(`
%define __spec_install_post %{nil}
%define   debug_package %{nil}
%define __os_install_post %{_dbpath}/brp-compress
%define   cmtcfg {{.CmtCfg}}
%define _topdir {{.BuildRoot}}
%define _tmppath  %{_topdir}/tmp

Summary: hwaf generated RPM for {{.Name}}
Name: {{.Name}}
Version: {{.Vers}}
Release: {{.Release}}
License: Unknown
Group: Development/Tools
SOURCE0 : %{name}-%{version}-%{cmtcfg}.tar.gz
URL: {{.Url}}

BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root

%description
%{summary}

%prep
%setup -q

%build
# Empty section.

%install
rm -rf %{buildroot}
mkdir -p  %{buildroot}

# in builddir
cp -a * %{buildroot}

%clean
rm -rf %{buildroot}

%files
%defattr(-,root,root,-)
/*
`) // */ for emacs...
		handle_err(err)

		err = spec_tmpl.Execute(specfile, rpminfos)
		handle_err(err)
	}

	err = specfile.Sync()
	handle_err(err)
	err = specfile.Close()
	handle_err(err)

	if !strings.HasSuffix(fname, ".rpm") {
		fname = fname + ".rpm"
	}

	if !quiet {
		fmt.Printf("%s: building RPM [%s]...\n", n, fname)
	}

	rpmbld, err := exec.LookPath("rpmbuild")
	handle_err(err)

	rpm := exec.Command(rpmbld,
		"-bb",
		fmt.Sprintf("SPECS/%s.spec", rpminfos.Name),
	)
	rpm.Dir = rpmbldroot
	if !quiet {
		rpm.Stdin = os.Stdin
		rpm.Stdout = os.Stdout
		rpm.Stderr = os.Stderr
	}
	err = rpm.Run()
	handle_err(err)

	dst, err := os.Create(fname)
	handle_err(err)
	defer dst.Close()

	rpmarch := ""
	switch runtime.GOARCH {
	case "amd64":
		rpmarch = "x86_64"
	case "i386":
		rpmarch = "i386"
	default:
		err = fmt.Errorf("unhandled GOARCH [%s]", runtime.GOARCH)
		handle_err(err)
	}
	srcname := fmt.Sprintf(
		"%s-%s-%s.%s.rpm",
		rpminfos.Name,
		rpminfos.Vers,
		rpminfos.Release,
		rpmarch)

	src, err := os.Open(filepath.Join(rpmbldroot, "RPMS", rpmarch, srcname))
	handle_err(err)
	defer src.Close()

	_, err = io.Copy(dst, src)
	handle_err(err)
	err = dst.Sync()
	handle_err(err)

	if !quiet {
		fmt.Printf("%s: building RPM [%s]...[ok]\n", n, fname)
	}
}

// EOF
<commit_msg>rpm: 32b arch is spelled i686. not i386<commit_after>package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"text/template"
	"time"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
)

func hwaf_make_cmd_waf_bdist_rpm() *commander.Command {
	cmd := &commander.Command{
		Run:       hwaf_run_cmd_waf_bdist_rpm,
		UsageLine: "bdist-rpm [rpm-name]",
		Short:     "create a RPM from the local project/packages",
		Long: `
bdist-rpm creates a RPM from the local project/packages.

ex:
 $ hwaf bdist-rpm
 $ hwaf bdist-rpm -name=mana
 $ hwaf bdist-rpm -name=mana -version=20130101
`,
		Flag: *flag.NewFlagSet("hwaf-bdist-rpm", flag.ExitOnError),
	}
	cmd.Flag.Bool("q", true, "only print error and warning messages, all other output will be suppressed")
	cmd.Flag.String("name", "", "name of the binary distribution (default: project name)")
	cmd.Flag.String("version", "", "version of the binary distribution (default: project version)")
	cmd.Flag.String("release", "1", "release version of the binary distribution (default: 1)")
	cmd.Flag.String("cmtcfg", "", "CMTCFG quadruplet for the binary distribution (default: project CMTCFG)")
	cmd.Flag.String("spec", "", "RPM SPEC file for the binary distribution")
	cmd.Flag.String("url", "", "URL for the RPM binary distribution")
	return cmd
}

func hwaf_run_cmd_waf_bdist_rpm(cmd *commander.Command, args []string) {
	var err error
	n := "hwaf-" + cmd.Name()

	switch len(args) {
	case 0:
	default:
		err = fmt.Errorf("%s: too many arguments (%s)", n, len(args))
		handle_err(err)
	}

	quiet := cmd.Flag.Lookup("q").Value.Get().(bool)

	bdist_name := cmd.Flag.Lookup("name").Value.Get().(string)
	bdist_vers := cmd.Flag.Lookup("version").Value.Get().(string)
	bdist_release := cmd.Flag.Lookup("release").Value.Get().(string)
	bdist_cmtcfg := cmd.Flag.Lookup("cmtcfg").Value.Get().(string)
	bdist_spec := cmd.Flag.Lookup("spec").Value.Get().(string)

	bdist_url := cmd.Flag.Lookup("url").Value.Get().(string)
	if bdist_url == "" {
		bdist_url = "http://cern.ch/mana-fwk"
	}

	type RpmInfo struct {
		Name      string // RPM package name
		Vers      string // RPM package version
		Release   string // RPM package release
		CmtCfg    string // RPM CMTCFG quadruplet
		BuildRoot string // RPM build directory
		Url       string // URL home page
	}

	workdir, err := get_workarea_root()
	if err != nil {
		// not a git repo... assume we are at the root, then...
		workdir, err = os.Getwd()
	}
	handle_err(err)

	if bdist_name == "" {
		bdist_name = workdir
		bdist_name = filepath.Base(bdist_name)
	}
	if bdist_vers == "" {
		bdist_vers = time.Now().Format("20060102")
	}
	if bdist_cmtcfg == "" {
		// FIXME: get actual value from waf, somehow
		pinfo_name := filepath.Join(workdir, "__build__", "c4che", "_cache.py")
		if !path_exists(pinfo_name) {
			err = fmt.Errorf(
				"no such file [%s]. did you run \"hwaf configure\" ?",
				pinfo_name,
			)
			handle_err(err)
		}
		pinfo, err := NewProjectInfo(pinfo_name)
		handle_err(err)
		bdist_cmtcfg, err = pinfo.Get("CMTCFG")
		handle_err(err)
	}
	fname := bdist_name + "-" + bdist_vers + "-" + bdist_cmtcfg
	rpmbldroot, err := ioutil.TempDir("", "hwaf-rpm-buildroot-")
	handle_err(err)
	defer os.RemoveAll(rpmbldroot)
	for _, dir := range []string{
		"RPMS", "SRPMS", "BUILD", "SOURCES", "SPECS", "tmp",
	} {
		err = os.MkdirAll(filepath.Join(rpmbldroot, dir), 0700)
		handle_err(err)
	}

	specfile, err := os.Create(filepath.Join(rpmbldroot, "SPECS", bdist_name+".spec"))
	handle_err(err)

	rpminfos := RpmInfo{
		Name:      bdist_name,
		Vers:      bdist_vers,
		Release:   bdist_release,
		CmtCfg:    bdist_cmtcfg,
		BuildRoot: rpmbldroot,
		Url:       bdist_url,
	}

	// get tarball from 'hwaf bdist'...
	bdist_fname := strings.Replace(fname, ".rpm", "", 1) + ".tar.gz"
	if !path_exists(bdist_fname) {
		err = fmt.Errorf("no such file [%s]. did you run \"hwaf bdist\" ?", bdist_fname)
		handle_err(err)
	}
	bdist_fname, err = filepath.Abs(bdist_fname)
	handle_err(err)
	{
		// first, massage the tar ball to something rpmbuild expects...

		// ok, now we're done.
		dst, err := os.Create(filepath.Join(rpmbldroot, "SOURCES", filepath.Base(bdist_fname)))
		handle_err(err)
		src, err := os.Open(bdist_fname)
		handle_err(err)
		_, err = io.Copy(dst, src)
		handle_err(err)
	}

	if bdist_spec != "" {
		bdist_spec = os.ExpandEnv(bdist_spec)
		bdist_spec, err = filepath.Abs(bdist_spec)
		handle_err(err)

		if !path_exists(bdist_spec) {
			err = fmt.Errorf("no such file [%s]", bdist_spec)
			handle_err(err)
		}
		user_spec, err := os.Open(bdist_spec)
		handle_err(err)
		defer user_spec.Close()

		_, err = io.Copy(specfile, user_spec)
		handle_err(err)
	} else {
		bdist_spec = specfile.Name()

		var spec_tmpl *template.Template
		spec_tmpl, err = template.New("SPEC").Parse(`
%define __spec_install_post %{nil}
%define   debug_package %{nil}
%define __os_install_post %{_dbpath}/brp-compress
%define   cmtcfg {{.CmtCfg}}
%define _topdir {{.BuildRoot}}
%define _tmppath  %{_topdir}/tmp

Summary: hwaf generated RPM for {{.Name}}
Name: {{.Name}}
Version: {{.Vers}}
Release: {{.Release}}
License: Unknown
Group: Development/Tools
SOURCE0 : %{name}-%{version}-%{cmtcfg}.tar.gz
URL: {{.Url}}

BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root

%description
%{summary}

%prep
%setup -q

%build
# Empty section.

%install
rm -rf %{buildroot}
mkdir -p  %{buildroot}

# in builddir
cp -a * %{buildroot}

%clean
rm -rf %{buildroot}

%files
%defattr(-,root,root,-)
/*
`) // */ for emacs...
		handle_err(err)

		err = spec_tmpl.Execute(specfile, rpminfos)
		handle_err(err)
	}

	err = specfile.Sync()
	handle_err(err)
	err = specfile.Close()
	handle_err(err)

	if !strings.HasSuffix(fname, ".rpm") {
		fname = fname + ".rpm"
	}

	if !quiet {
		fmt.Printf("%s: building RPM [%s]...\n", n, fname)
	}

	rpmbld, err := exec.LookPath("rpmbuild")
	handle_err(err)

	rpm := exec.Command(rpmbld,
		"-bb",
		fmt.Sprintf("SPECS/%s.spec", rpminfos.Name),
	)
	rpm.Dir = rpmbldroot
	if !quiet {
		rpm.Stdin = os.Stdin
		rpm.Stdout = os.Stdout
		rpm.Stderr = os.Stderr
	}
	err = rpm.Run()
	handle_err(err)

	dst, err := os.Create(fname)
	handle_err(err)
	defer dst.Close()

	rpmarch := ""
	switch runtime.GOARCH {
	case "amd64":
		rpmarch = "x86_64"
	case "i386":
		rpmarch = "i686"
	default:
		err = fmt.Errorf("unhandled GOARCH [%s]", runtime.GOARCH)
		handle_err(err)
	}
	srcname := fmt.Sprintf(
		"%s-%s-%s.%s.rpm",
		rpminfos.Name,
		rpminfos.Vers,
		rpminfos.Release,
		rpmarch)

	src, err := os.Open(filepath.Join(rpmbldroot, "RPMS", rpmarch, srcname))
	handle_err(err)
	defer src.Close()

	_, err = io.Copy(dst, src)
	handle_err(err)
	err = dst.Sync()
	handle_err(err)

	if !quiet {
		fmt.Printf("%s: building RPM [%s]...[ok]\n", n, fname)
	}
}

// EOF
<|endoftext|>


<commit_before>// Copyright (c) 2013-2017 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package txscript

import (
	"github.com/decred/dcrd/dcrec"
)

const (
	// MaxDataCarrierSize is the maximum number of bytes allowed in pushed
	// data to be considered a nulldata transaction.
	MaxDataCarrierSize = 256
)

// ScriptClass is an enumeration for the list of standard types of script.
type ScriptClass byte

// Classes of script payment known about in the blockchain.
const (
	NonStandardTy     ScriptClass = iota // None of the recognized forms.
	PubKeyTy                             // Pay pubkey.
	PubKeyHashTy                         // Pay pubkey hash.
	ScriptHashTy                         // Pay to script hash.
	MultiSigTy                           // Multi signature.
	NullDataTy                           // Empty data-only (provably prunable).
	StakeSubmissionTy                    // Stake submission.
	StakeGenTy                           // Stake generation
	StakeRevocationTy                    // Stake revocation.
	StakeSubChangeTy                     // Change for stake submission tx.
	PubkeyAltTy                          // Alternative signature pubkey.
	PubkeyHashAltTy                      // Alternative signature pubkey hash.
	TreasuryAddTy                        // Add value to treasury
	TreasuryGenTy                        // Generate utxos from treasury account
)

// scriptClassToName houses the human-readable strings which describe each
// script class.
var scriptClassToName = []string{
	NonStandardTy:     "nonstandard",
	PubKeyTy:          "pubkey",
	PubkeyAltTy:       "pubkeyalt",
	PubKeyHashTy:      "pubkeyhash",
	PubkeyHashAltTy:   "pubkeyhashalt",
	ScriptHashTy:      "scripthash",
	MultiSigTy:        "multisig",
	NullDataTy:        "nulldata",
	StakeSubmissionTy: "stakesubmission",
	StakeGenTy:        "stakegen",
	StakeRevocationTy: "stakerevoke",
	StakeSubChangeTy:  "sstxchange",
	TreasuryAddTy:     "treasuryadd",
	TreasuryGenTy:     "treasurygen",
}

// String implements the Stringer interface by returning the name of
// the enum script class. If the enum is invalid then "Invalid" will be
// returned.
func (t ScriptClass) String() string {
	if int(t) > len(scriptClassToName) || int(t) < 0 {
		return "Invalid"
	}
	return scriptClassToName[t]
}

// extractCompressedPubKey extracts a compressed public key from the passed
// script if it is a standard pay-to-compressed-secp256k1-pubkey script.  It
// will return nil otherwise.
func extractCompressedPubKey(script []byte) []byte {
	// A pay-to-compressed-pubkey script is of the form:
	//  OP_DATA_33 <33-byte compressed pubkey> OP_CHECKSIG

	// All compressed secp256k1 public keys must start with 0x02 or 0x03.
	if len(script) == 35 &&
		script[34] == OP_CHECKSIG &&
		script[0] == OP_DATA_33 &&
		(script[1] == 0x02 || script[1] == 0x03) {

		return script[1:34]
	}
	return nil
}

// isStandardAltSignatureType returns whether or not the provided opcode
// represents a push of a standard alt signature type.
func isStandardAltSignatureType(op byte) bool {
	if !IsSmallInt(op) {
		return false
	}

	sigType := AsSmallInt(op)
	return sigType == dcrec.STEd25519 || sigType == dcrec.STSchnorrSecp256k1
}

// extractPubKeyHashAltDetails extracts the public key hash and signature type
// from the passed script if it is a standard pay-to-alt-pubkey-hash script.  It
// will return nil otherwise.
func extractPubKeyHashAltDetails(script []byte) ([]byte, dcrec.SignatureType) {
	// A pay-to-alt-pubkey-hash script is of the form:
	//  DUP HASH160 <20-byte hash> EQUALVERIFY SIGTYPE CHECKSIG
	//
	// The only two currently supported alternative signature types are ed25519
	// and schnorr + secp256k1 (with a compressed pubkey).
	//
	//  DUP HASH160 <20-byte hash> EQUALVERIFY <1-byte ed25519 sigtype> CHECKSIG
	//  DUP HASH160 <20-byte hash> EQUALVERIFY <1-byte schnorr+secp sigtype> CHECKSIG
	//
	//  Notice that OP_0 is not specified since signature type 0 disabled.

	if len(script) == 26 &&
		script[0] == OP_DUP &&
		script[1] == OP_HASH160 &&
		script[2] == OP_DATA_20 &&
		script[23] == OP_EQUALVERIFY &&
		isStandardAltSignatureType(script[24]) &&
		script[25] == OP_CHECKSIGALT {

		return script[3:23], dcrec.SignatureType(AsSmallInt(script[24]))
	}

	return nil, 0
}

// isPubKeyHashAltScript returns whether or not the passed script is a standard
// pay-to-alt-pubkey-hash script.
func isPubKeyHashAltScript(script []byte) bool {
	pk, _ := extractPubKeyHashAltDetails(script)
	return pk != nil
}
<commit_msg>txscript: Remove unused extractCompressedPubKey.<commit_after>// Copyright (c) 2013-2017 The btcsuite developers
// Copyright (c) 2015-2021 The Decred developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package txscript

import (
	"github.com/decred/dcrd/dcrec"
)

const (
	// MaxDataCarrierSize is the maximum number of bytes allowed in pushed
	// data to be considered a nulldata transaction.
	MaxDataCarrierSize = 256
)

// ScriptClass is an enumeration for the list of standard types of script.
type ScriptClass byte

// Classes of script payment known about in the blockchain.
const (
	NonStandardTy     ScriptClass = iota // None of the recognized forms.
	PubKeyTy                             // Pay pubkey.
	PubKeyHashTy                         // Pay pubkey hash.
	ScriptHashTy                         // Pay to script hash.
	MultiSigTy                           // Multi signature.
	NullDataTy                           // Empty data-only (provably prunable).
	StakeSubmissionTy                    // Stake submission.
	StakeGenTy                           // Stake generation
	StakeRevocationTy                    // Stake revocation.
	StakeSubChangeTy                     // Change for stake submission tx.
	PubkeyAltTy                          // Alternative signature pubkey.
	PubkeyHashAltTy                      // Alternative signature pubkey hash.
	TreasuryAddTy                        // Add value to treasury
	TreasuryGenTy                        // Generate utxos from treasury account
)

// scriptClassToName houses the human-readable strings which describe each
// script class.
var scriptClassToName = []string{
	NonStandardTy:     "nonstandard",
	PubKeyTy:          "pubkey",
	PubkeyAltTy:       "pubkeyalt",
	PubKeyHashTy:      "pubkeyhash",
	PubkeyHashAltTy:   "pubkeyhashalt",
	ScriptHashTy:      "scripthash",
	MultiSigTy:        "multisig",
	NullDataTy:        "nulldata",
	StakeSubmissionTy: "stakesubmission",
	StakeGenTy:        "stakegen",
	StakeRevocationTy: "stakerevoke",
	StakeSubChangeTy:  "sstxchange",
	TreasuryAddTy:     "treasuryadd",
	TreasuryGenTy:     "treasurygen",
}

// String implements the Stringer interface by returning the name of
// the enum script class. If the enum is invalid then "Invalid" will be
// returned.
func (t ScriptClass) String() string {
	if int(t) > len(scriptClassToName) || int(t) < 0 {
		return "Invalid"
	}
	return scriptClassToName[t]
}

// isStandardAltSignatureType returns whether or not the provided opcode
// represents a push of a standard alt signature type.
func isStandardAltSignatureType(op byte) bool {
	if !IsSmallInt(op) {
		return false
	}

	sigType := AsSmallInt(op)
	return sigType == dcrec.STEd25519 || sigType == dcrec.STSchnorrSecp256k1
}

// extractPubKeyHashAltDetails extracts the public key hash and signature type
// from the passed script if it is a standard pay-to-alt-pubkey-hash script.  It
// will return nil otherwise.
func extractPubKeyHashAltDetails(script []byte) ([]byte, dcrec.SignatureType) {
	// A pay-to-alt-pubkey-hash script is of the form:
	//  DUP HASH160 <20-byte hash> EQUALVERIFY SIGTYPE CHECKSIG
	//
	// The only two currently supported alternative signature types are ed25519
	// and schnorr + secp256k1 (with a compressed pubkey).
	//
	//  DUP HASH160 <20-byte hash> EQUALVERIFY <1-byte ed25519 sigtype> CHECKSIG
	//  DUP HASH160 <20-byte hash> EQUALVERIFY <1-byte schnorr+secp sigtype> CHECKSIG
	//
	//  Notice that OP_0 is not specified since signature type 0 disabled.

	if len(script) == 26 &&
		script[0] == OP_DUP &&
		script[1] == OP_HASH160 &&
		script[2] == OP_DATA_20 &&
		script[23] == OP_EQUALVERIFY &&
		isStandardAltSignatureType(script[24]) &&
		script[25] == OP_CHECKSIGALT {

		return script[3:23], dcrec.SignatureType(AsSmallInt(script[24]))
	}

	return nil, 0
}

// isPubKeyHashAltScript returns whether or not the passed script is a standard
// pay-to-alt-pubkey-hash script.
func isPubKeyHashAltScript(script []byte) bool {
	pk, _ := extractPubKeyHashAltDetails(script)
	return pk != nil
}
<|endoftext|>


<commit_before>//go:build integration

package cmd

import (
	"github.com/qiniu/qshell/v2/cmd"
	"github.com/qiniu/qshell/v2/cmd_test/test"
	"os"
	"testing"
)

var accessKey = test.AccessKey
var secretKey = test.SecretKey

func TestUser(t *testing.T) {
	defer func() {
		os.Args = []string{"qshell", accessKey, secretKey, "QShell"}
		cmd.Execute()
	}()

	if test.Local {
		return
	}

	if test.ShouldTestUser {
		TestUserIntegration(t)
	}
}

func TestUserIntegration(t *testing.T) {
	success, err := cleanUser()
	if len(err) > 0 || !success {
		t.Fatal("clean first not success:", err)
	}

	has, err := hasUser()
	if len(err) > 0 || has {
		t.Fatal("shouldn't has user after clean first:", err)
	}

	// 增加 1
	userName := "test_add_1"
	success, err = addUser(userName, accessKey, secretKey)
	if len(err) > 0 || !success {
		t.Fatal("add user not success:", err)
	}

	has, err = hasUser()
	if len(err) > 0 || !has {
		t.Fatal("should has user after add:", err)
	}

	has, err = containUser(userName)
	if len(err) > 0 || !has {
		t.Fatal("should contain user after add:", err)
	}

	has, err = lookupUser(userName)
	if len(err) > 0 || !has {
		t.Fatal("should lookup user success after add:", err)
	}

	is, err := currentUserIs(userName)
	if len(err) > 0 || !is {
		t.Fatal("should change current user after add:", err)
	}

	// 增加 2
	userName = "test_add_2"
	success, err = addUserWithLongOptions(userName, accessKey, secretKey)
	if len(err) > 0 || !success {
		t.Fatal("add user 2 not success:", err)
	}

	has, err = hasUser()
	if len(err) > 0 || !has {
		t.Fatal("should has user after add 2:", err)
	}

	has, err = containUser(userName)
	if len(err) > 0 || !has {
		t.Fatal("shouldn contain user after add 2:", err)
	}

	has, err = lookupUser(userName)
	if len(err) > 0 || !has {
		t.Fatal("should lookup user success after add 2:", err)
	}

	is, err = currentUserIs(userName)
	if len(err) > 0 || !is {
		t.Fatal("should change current user after add 2:", err)
	}

	// 改
	userName = "test_add_1"
	success, err = changeCurrentUser(userName)
	if len(err) > 0 || !success {
		t.Fatal("change current user not success:", err)
	}

	is, err = currentUserIs(userName)
	if len(err) > 0 || !is {
		t.Fatal("should change current user after change :", err)
	}

	// 删除
	success, err = deleteUser(userName)
	if len(err) > 0 || !success {
		t.Fatal("remove user not success:", err)
	}

	has, err = lookupUser(userName)
	if len(err) > 0 || has {
		t.Fatal("shouldn't lookup user success after remove:", err)
	}

	is, err = currentUserIs(userName)
	if len(err) > 0 || !is {
		t.Fatal("shouldn't change current user after delete current user :", err)
	}

	// 清除
	success, err = cleanUser()
	if len(err) > 0 || !success {
		t.Fatal("clean end not success:", err)
	}

	has, err = hasUser()
	if len(err) > 0 || has {
		t.Fatal("shouldn't has user after clean end:", err)
	}

	// 添加测试账号
	userName = "QShell"
	success, err = addUser(userName, accessKey, secretKey)
	if len(err) > 0 || !success {
		t.Fatal("add user not success:", err)
	}
}
<commit_msg>optimize test case<commit_after>//go:build integration

package cmd

import (
	"github.com/qiniu/qshell/v2/cmd"
	"github.com/qiniu/qshell/v2/cmd_test/test"
	"os"
	"testing"
)

var accessKey = test.AccessKey
var secretKey = test.SecretKey

func TestUser(t *testing.T) {
	defer func() {
		os.Args = []string{"qshell", "user", "add", accessKey, secretKey, "QShell"}
		cmd.Execute()
	}()

	if test.Local {
		return
	}

	if test.ShouldTestUser {
		TestUserIntegration(t)
	}
}

func TestUserIntegration(t *testing.T) {
	success, err := cleanUser()
	if len(err) > 0 || !success {
		t.Fatal("clean first not success:", err)
	}

	has, err := hasUser()
	if len(err) > 0 || has {
		t.Fatal("shouldn't has user after clean first:", err)
	}

	// 增加 1
	userName := "test_add_1"
	success, err = addUser(userName, accessKey, secretKey)
	if len(err) > 0 || !success {
		t.Fatal("add user not success:", err)
	}

	has, err = hasUser()
	if len(err) > 0 || !has {
		t.Fatal("should has user after add:", err)
	}

	has, err = containUser(userName)
	if len(err) > 0 || !has {
		t.Fatal("should contain user after add:", err)
	}

	has, err = lookupUser(userName)
	if len(err) > 0 || !has {
		t.Fatal("should lookup user success after add:", err)
	}

	is, err := currentUserIs(userName)
	if len(err) > 0 || !is {
		t.Fatal("should change current user after add:", err)
	}

	// 增加 2
	userName = "test_add_2"
	success, err = addUserWithLongOptions(userName, accessKey, secretKey)
	if len(err) > 0 || !success {
		t.Fatal("add user 2 not success:", err)
	}

	has, err = hasUser()
	if len(err) > 0 || !has {
		t.Fatal("should has user after add 2:", err)
	}

	has, err = containUser(userName)
	if len(err) > 0 || !has {
		t.Fatal("shouldn contain user after add 2:", err)
	}

	has, err = lookupUser(userName)
	if len(err) > 0 || !has {
		t.Fatal("should lookup user success after add 2:", err)
	}

	is, err = currentUserIs(userName)
	if len(err) > 0 || !is {
		t.Fatal("should change current user after add 2:", err)
	}

	// 改
	userName = "test_add_1"
	success, err = changeCurrentUser(userName)
	if len(err) > 0 || !success {
		t.Fatal("change current user not success:", err)
	}

	is, err = currentUserIs(userName)
	if len(err) > 0 || !is {
		t.Fatal("should change current user after change :", err)
	}

	// 删除
	success, err = deleteUser(userName)
	if len(err) > 0 || !success {
		t.Fatal("remove user not success:", err)
	}

	has, err = lookupUser(userName)
	if len(err) > 0 || has {
		t.Fatal("shouldn't lookup user success after remove:", err)
	}

	is, err = currentUserIs(userName)
	if len(err) > 0 || !is {
		t.Fatal("shouldn't change current user after delete current user :", err)
	}

	// 清除
	success, err = cleanUser()
	if len(err) > 0 || !success {
		t.Fatal("clean end not success:", err)
	}

	has, err = hasUser()
	if len(err) > 0 || has {
		t.Fatal("shouldn't has user after clean end:", err)
	}

	// 添加测试账号
	userName = "QShell"
	success, err = addUser(userName, accessKey, secretKey)
	if len(err) > 0 || !success {
		t.Fatal("add user not success:", err)
	}
}
<|endoftext|>


<commit_before>// Copyright © 2013 Steve Francia <spf@spf13.com>.
//
// Licensed under the Simple Public 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://opensource.org/licenses/Simple-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 commands

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/mostafah/fsync"
	"github.com/spf13/cobra"
	"github.com/spf13/hugo/helpers"
	"github.com/spf13/hugo/hugolib"
	"github.com/spf13/hugo/livereload"
	"github.com/spf13/hugo/utils"
	"github.com/spf13/hugo/watcher"
	jww "github.com/spf13/jwalterweatherman"
	"github.com/spf13/nitro"
	"github.com/spf13/viper"
)

//var Config *hugolib.Config
var HugoCmd = &cobra.Command{
	Use:   "hugo",
	Short: "Hugo is a very fast static site generator",
	Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go.

Complete documentation is available at http://hugo.spf13.com`,
	Run: func(cmd *cobra.Command, args []string) {
		InitializeConfig()
		build()
	},
}

var hugoCmdV *cobra.Command

var BuildWatch, Draft, Future, UglyUrls, Verbose, Logging, VerboseLog, DisableRSS, DisableSitemap, PluralizeListTitles bool
var Source, Destination, Theme, BaseUrl, CfgFile, LogFile string

func Execute() {
	AddCommands()
	utils.StopOnErr(HugoCmd.Execute())
}

func AddCommands() {
	HugoCmd.AddCommand(serverCmd)
	HugoCmd.AddCommand(version)
	HugoCmd.AddCommand(check)
	HugoCmd.AddCommand(benchmark)
	HugoCmd.AddCommand(convertCmd)
	HugoCmd.AddCommand(newCmd)
}

func init() {
	HugoCmd.PersistentFlags().BoolVarP(&Draft, "buildDrafts", "D", false, "include content marked as draft")
	HugoCmd.PersistentFlags().BoolVarP(&Future, "buildFuture", "F", false, "include content with datePublished in the future")
	HugoCmd.PersistentFlags().BoolVar(&DisableRSS, "disableRSS", false, "Do not build RSS files")
	HugoCmd.PersistentFlags().BoolVar(&DisableSitemap, "disableSitemap", false, "Do not build Sitemap file")
	HugoCmd.PersistentFlags().StringVarP(&Source, "source", "s", "", "filesystem path to read files relative from")
	HugoCmd.PersistentFlags().StringVarP(&Destination, "destination", "d", "", "filesystem path to write files to")
	HugoCmd.PersistentFlags().StringVarP(&Theme, "theme", "t", "", "theme to use (located in /themes/THEMENAME/)")
	HugoCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
	HugoCmd.PersistentFlags().BoolVar(&UglyUrls, "uglyUrls", false, "if true, use /filename.html instead of /filename/")
	HugoCmd.PersistentFlags().StringVarP(&BaseUrl, "baseUrl", "b", "", "hostname (and path) to the root eg. http://spf13.com/")
	HugoCmd.PersistentFlags().StringVar(&CfgFile, "config", "", "config file (default is path/config.yaml|json|toml)")
	HugoCmd.PersistentFlags().BoolVar(&Logging, "log", false, "Enable Logging")
	HugoCmd.PersistentFlags().StringVar(&LogFile, "logFile", "", "Log File path (if set, logging enabled automatically)")
	HugoCmd.PersistentFlags().BoolVar(&VerboseLog, "verboseLog", false, "verbose logging")
	HugoCmd.PersistentFlags().BoolVar(&nitro.AnalysisOn, "stepAnalysis", false, "display memory and timing of different steps of the program")
	HugoCmd.PersistentFlags().BoolVar(&PluralizeListTitles, "pluralizeListTitles", true, "Pluralize titles in lists using inflect")
	HugoCmd.Flags().BoolVarP(&BuildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
	hugoCmdV = HugoCmd
}

func InitializeConfig() {
	viper.SetConfigFile(CfgFile)
	viper.AddConfigPath(Source)
	err := viper.ReadInConfig()
	if err != nil {
		jww.ERROR.Println("Config not found... using only defaults, stuff may not work")
	}

	viper.RegisterAlias("taxonomies", "indexes")

	viper.SetDefault("Watch", false)
	viper.SetDefault("MetaDataFormat", "toml")
	viper.SetDefault("DisableRSS", false)
	viper.SetDefault("DisableSitemap", false)
	viper.SetDefault("ContentDir", "content")
	viper.SetDefault("LayoutDir", "layouts")
	viper.SetDefault("StaticDir", "static")
	viper.SetDefault("ArchetypeDir", "archetypes")
	viper.SetDefault("PublishDir", "public")
	viper.SetDefault("DefaultLayout", "post")
	viper.SetDefault("BuildDrafts", false)
	viper.SetDefault("BuildFuture", false)
	viper.SetDefault("UglyUrls", false)
	viper.SetDefault("Verbose", false)
	viper.SetDefault("CanonifyUrls", false)
	viper.SetDefault("Indexes", map[string]string{"tag": "tags", "category": "categories"})
	viper.SetDefault("Permalinks", make(hugolib.PermalinkOverrides, 0))
	viper.SetDefault("Sitemap", hugolib.Sitemap{Priority: -1})
	viper.SetDefault("PygmentsStyle", "monokai")
	viper.SetDefault("PygmentsUseClasses", false)
	viper.SetDefault("DisableLiveReload", false)
	viper.SetDefault("PluralizeListTitles", true)

	if hugoCmdV.PersistentFlags().Lookup("buildDrafts").Changed {
		viper.Set("BuildDrafts", Draft)
	}

	if hugoCmdV.PersistentFlags().Lookup("buildFuture").Changed {
		viper.Set("BuildFuture", Future)
	}

	if hugoCmdV.PersistentFlags().Lookup("uglyUrls").Changed {
		viper.Set("UglyUrls", UglyUrls)
	}

	if hugoCmdV.PersistentFlags().Lookup("disableRSS").Changed {
		viper.Set("DisableRSS", DisableRSS)
	}

	if hugoCmdV.PersistentFlags().Lookup("disableSitemap").Changed {
		viper.Set("DisableSitemap", DisableSitemap)
	}

	if hugoCmdV.PersistentFlags().Lookup("verbose").Changed {
		viper.Set("Verbose", Verbose)
	}

	if hugoCmdV.PersistentFlags().Lookup("pluralizeListTitles").Changed {
		viper.Set("PluralizeListTitles", PluralizeListTitles)
	}

	if hugoCmdV.PersistentFlags().Lookup("logFile").Changed {
		viper.Set("LogFile", LogFile)
	}
	if BaseUrl != "" {
		if !strings.HasSuffix(BaseUrl, "/") {
			BaseUrl = BaseUrl + "/"
		}
		viper.Set("BaseUrl", BaseUrl)
	}

	if Theme != "" {
		viper.Set("theme", Theme)
	}

	if Destination != "" {
		viper.Set("PublishDir", Destination)
	}

	if Source != "" {
		viper.Set("WorkingDir", Source)
	} else {
		dir, _ := helpers.FindCWD()
		viper.Set("WorkingDir", dir)
	}

	if VerboseLog || Logging || (viper.IsSet("LogFile") && viper.GetString("LogFile") != "") {
		if viper.IsSet("LogFile") && viper.GetString("LogFile") != "" {
			jww.SetLogFile(viper.GetString("LogFile"))
		} else {
			jww.UseTempLogFile("hugo")
		}
	} else {
		jww.DiscardLogging()
	}

	if viper.GetBool("verbose") {
		jww.SetStdoutThreshold(jww.LevelInfo)
	}

	if VerboseLog {
		jww.SetLogThreshold(jww.LevelInfo)
	}

	jww.INFO.Println("Using config file:", viper.ConfigFileUsed())
}

func build(watches ...bool) {
	utils.CheckErr(copyStatic(), fmt.Sprintf("Error copying static files to %s", helpers.AbsPathify(viper.GetString("PublishDir"))))
	watch := false
	if len(watches) > 0 && watches[0] {
		watch = true
	}
	utils.StopOnErr(buildSite(BuildWatch || watch))

	if BuildWatch {
		jww.FEEDBACK.Println("Watching for changes in", helpers.AbsPathify(viper.GetString("ContentDir")))
		jww.FEEDBACK.Println("Press ctrl+c to stop")
		utils.CheckErr(NewWatcher(0))
	}
}

func copyStatic() error {
	staticDir := helpers.AbsPathify(viper.GetString("StaticDir")) + "/"
	if _, err := os.Stat(staticDir); os.IsNotExist(err) {
		jww.ERROR.Println("Unable to find Static Directory:", viper.GetString("theme"), "in", staticDir)
		return nil
	}

	publishDir := helpers.AbsPathify(viper.GetString("PublishDir")) + "/"

	if themeSet() {
		themeDir := helpers.AbsPathify("themes/"+viper.GetString("theme")) + "/static/"
		if _, err := os.Stat(themeDir); os.IsNotExist(err) {
			jww.ERROR.Println("Unable to find static directory for theme :", viper.GetString("theme"), "in", themeDir)
			return nil
		}

		// Copy Static to Destination
		jww.INFO.Println("syncing from", themeDir, "to", publishDir)
		fsync.Sync(publishDir, themeDir)
	}

	// Copy Static to Destination
	jww.INFO.Println("syncing from", staticDir, "to", publishDir)
	return fsync.Sync(publishDir, staticDir)
}

func getDirList() []string {
	var a []string
	walker := func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			jww.ERROR.Println("Walker: ", err)
			return nil
		}

		if fi.IsDir() {
			a = append(a, path)
		}
		return nil
	}

	filepath.Walk(helpers.AbsPathify(viper.GetString("ContentDir")), walker)
	filepath.Walk(helpers.AbsPathify(viper.GetString("LayoutDir")), walker)
	filepath.Walk(helpers.AbsPathify(viper.GetString("StaticDir")), walker)
	if themeSet() {
		filepath.Walk(helpers.AbsPathify("themes/"+viper.GetString("theme")), walker)
	}

	return a
}

func themeSet() bool {
	return viper.GetString("theme") != ""
}

func buildSite(watching ...bool) (err error) {
	startTime := time.Now()
	site := &hugolib.Site{}
	if len(watching) > 0 && watching[0] {
		site.RunMode.Watching = true
	}
	err = site.Build()
	if err != nil {
		return err
	}
	site.Stats()
	jww.FEEDBACK.Printf("in %v ms\n", int(1000*time.Since(startTime).Seconds()))

	return nil
}

func NewWatcher(port int) error {
	if runtime.GOOS == "darwin" {
		tweakLimit()
	}

	watcher, err := watcher.New(1 * time.Second)
	var wg sync.WaitGroup

	if err != nil {
		fmt.Println(err)
		return err
	}

	defer watcher.Close()

	wg.Add(1)

	for _, d := range getDirList() {
		if d != "" {
			_ = watcher.Watch(d)
		}
	}

	go func() {
		for {
			select {
			case evs := <-watcher.Event:
				jww.INFO.Println(evs)

				static_changed := false
				dynamic_changed := false

				for _, ev := range evs {
					ext := filepath.Ext(ev.Name)
					istemp := strings.HasSuffix(ext, "~") || (ext == ".swp") || (ext == ".tmp")
					if istemp {
						continue
					}
					// renames are always followed with Create/Modify
					if ev.IsRename() {
						continue
					}

					isstatic := strings.HasPrefix(ev.Name, helpers.AbsPathify(viper.GetString("StaticDir"))) || strings.HasPrefix(ev.Name, helpers.AbsPathify("themes/"+viper.GetString("theme"))+"/static/")
					static_changed = static_changed || isstatic
					dynamic_changed = dynamic_changed || !isstatic

					// add new directory to watch list
					if s, err := os.Stat(ev.Name); err == nil && s.Mode().IsDir() {
						if ev.IsCreate() {
							watcher.Watch(ev.Name)
						}
					}
				}

				if static_changed {
					fmt.Print("Static file changed, syncing\n\n")
					utils.StopOnErr(copyStatic(), fmt.Sprintf("Error copying static files to %s", helpers.AbsPathify(viper.GetString("PublishDir"))))

					livereload.ForceRefresh()
				}

				if dynamic_changed {
					fmt.Print("Change detected, rebuilding site\n\n")
					utils.StopOnErr(buildSite(true))

					livereload.ForceRefresh()
				}
			case err := <-watcher.Error:
				if err != nil {
					fmt.Println("error:", err)
				}
			}
		}
	}()

	if port > 0 {
		if !viper.GetBool("DisableLiveReload") {
			livereload.Initialize()
			http.HandleFunc("/livereload.js", livereload.ServeJS)
			http.HandleFunc("/livereload", livereload.Handler)
		}

		go serve(port)
	}

	wg.Wait()
	return nil
}
<commit_msg>LiveReloadDisabled works with Watching properly. Fixed #335.<commit_after>// Copyright © 2013 Steve Francia <spf@spf13.com>.
//
// Licensed under the Simple Public 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://opensource.org/licenses/Simple-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 commands

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"sync"
	"time"

	"github.com/mostafah/fsync"
	"github.com/spf13/cobra"
	"github.com/spf13/hugo/helpers"
	"github.com/spf13/hugo/hugolib"
	"github.com/spf13/hugo/livereload"
	"github.com/spf13/hugo/utils"
	"github.com/spf13/hugo/watcher"
	jww "github.com/spf13/jwalterweatherman"
	"github.com/spf13/nitro"
	"github.com/spf13/viper"
)

//var Config *hugolib.Config
var HugoCmd = &cobra.Command{
	Use:   "hugo",
	Short: "Hugo is a very fast static site generator",
	Long: `A Fast and Flexible Static Site Generator built with
love by spf13 and friends in Go.

Complete documentation is available at http://hugo.spf13.com`,
	Run: func(cmd *cobra.Command, args []string) {
		InitializeConfig()
		build()
	},
}

var hugoCmdV *cobra.Command

var BuildWatch, Draft, Future, UglyUrls, Verbose, Logging, VerboseLog, DisableRSS, DisableSitemap, PluralizeListTitles bool
var Source, Destination, Theme, BaseUrl, CfgFile, LogFile string

func Execute() {
	AddCommands()
	utils.StopOnErr(HugoCmd.Execute())
}

func AddCommands() {
	HugoCmd.AddCommand(serverCmd)
	HugoCmd.AddCommand(version)
	HugoCmd.AddCommand(check)
	HugoCmd.AddCommand(benchmark)
	HugoCmd.AddCommand(convertCmd)
	HugoCmd.AddCommand(newCmd)
}

func init() {
	HugoCmd.PersistentFlags().BoolVarP(&Draft, "buildDrafts", "D", false, "include content marked as draft")
	HugoCmd.PersistentFlags().BoolVarP(&Future, "buildFuture", "F", false, "include content with datePublished in the future")
	HugoCmd.PersistentFlags().BoolVar(&DisableRSS, "disableRSS", false, "Do not build RSS files")
	HugoCmd.PersistentFlags().BoolVar(&DisableSitemap, "disableSitemap", false, "Do not build Sitemap file")
	HugoCmd.PersistentFlags().StringVarP(&Source, "source", "s", "", "filesystem path to read files relative from")
	HugoCmd.PersistentFlags().StringVarP(&Destination, "destination", "d", "", "filesystem path to write files to")
	HugoCmd.PersistentFlags().StringVarP(&Theme, "theme", "t", "", "theme to use (located in /themes/THEMENAME/)")
	HugoCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")
	HugoCmd.PersistentFlags().BoolVar(&UglyUrls, "uglyUrls", false, "if true, use /filename.html instead of /filename/")
	HugoCmd.PersistentFlags().StringVarP(&BaseUrl, "baseUrl", "b", "", "hostname (and path) to the root eg. http://spf13.com/")
	HugoCmd.PersistentFlags().StringVar(&CfgFile, "config", "", "config file (default is path/config.yaml|json|toml)")
	HugoCmd.PersistentFlags().BoolVar(&Logging, "log", false, "Enable Logging")
	HugoCmd.PersistentFlags().StringVar(&LogFile, "logFile", "", "Log File path (if set, logging enabled automatically)")
	HugoCmd.PersistentFlags().BoolVar(&VerboseLog, "verboseLog", false, "verbose logging")
	HugoCmd.PersistentFlags().BoolVar(&nitro.AnalysisOn, "stepAnalysis", false, "display memory and timing of different steps of the program")
	HugoCmd.PersistentFlags().BoolVar(&PluralizeListTitles, "pluralizeListTitles", true, "Pluralize titles in lists using inflect")
	HugoCmd.Flags().BoolVarP(&BuildWatch, "watch", "w", false, "watch filesystem for changes and recreate as needed")
	hugoCmdV = HugoCmd
}

func InitializeConfig() {
	viper.SetConfigFile(CfgFile)
	viper.AddConfigPath(Source)
	err := viper.ReadInConfig()
	if err != nil {
		jww.ERROR.Println("Config not found... using only defaults, stuff may not work")
	}

	viper.RegisterAlias("taxonomies", "indexes")

	viper.SetDefault("Watch", false)
	viper.SetDefault("MetaDataFormat", "toml")
	viper.SetDefault("DisableRSS", false)
	viper.SetDefault("DisableSitemap", false)
	viper.SetDefault("ContentDir", "content")
	viper.SetDefault("LayoutDir", "layouts")
	viper.SetDefault("StaticDir", "static")
	viper.SetDefault("ArchetypeDir", "archetypes")
	viper.SetDefault("PublishDir", "public")
	viper.SetDefault("DefaultLayout", "post")
	viper.SetDefault("BuildDrafts", false)
	viper.SetDefault("BuildFuture", false)
	viper.SetDefault("UglyUrls", false)
	viper.SetDefault("Verbose", false)
	viper.SetDefault("CanonifyUrls", false)
	viper.SetDefault("Indexes", map[string]string{"tag": "tags", "category": "categories"})
	viper.SetDefault("Permalinks", make(hugolib.PermalinkOverrides, 0))
	viper.SetDefault("Sitemap", hugolib.Sitemap{Priority: -1})
	viper.SetDefault("PygmentsStyle", "monokai")
	viper.SetDefault("PygmentsUseClasses", false)
	viper.SetDefault("DisableLiveReload", false)
	viper.SetDefault("PluralizeListTitles", true)

	if hugoCmdV.PersistentFlags().Lookup("buildDrafts").Changed {
		viper.Set("BuildDrafts", Draft)
	}

	if hugoCmdV.PersistentFlags().Lookup("buildFuture").Changed {
		viper.Set("BuildFuture", Future)
	}

	if hugoCmdV.PersistentFlags().Lookup("uglyUrls").Changed {
		viper.Set("UglyUrls", UglyUrls)
	}

	if hugoCmdV.PersistentFlags().Lookup("disableRSS").Changed {
		viper.Set("DisableRSS", DisableRSS)
	}

	if hugoCmdV.PersistentFlags().Lookup("disableSitemap").Changed {
		viper.Set("DisableSitemap", DisableSitemap)
	}

	if hugoCmdV.PersistentFlags().Lookup("verbose").Changed {
		viper.Set("Verbose", Verbose)
	}

	if hugoCmdV.PersistentFlags().Lookup("pluralizeListTitles").Changed {
		viper.Set("PluralizeListTitles", PluralizeListTitles)
	}

	if hugoCmdV.PersistentFlags().Lookup("logFile").Changed {
		viper.Set("LogFile", LogFile)
	}
	if BaseUrl != "" {
		if !strings.HasSuffix(BaseUrl, "/") {
			BaseUrl = BaseUrl + "/"
		}
		viper.Set("BaseUrl", BaseUrl)
	}

	if Theme != "" {
		viper.Set("theme", Theme)
	}

	if Destination != "" {
		viper.Set("PublishDir", Destination)
	}

	if Source != "" {
		viper.Set("WorkingDir", Source)
	} else {
		dir, _ := helpers.FindCWD()
		viper.Set("WorkingDir", dir)
	}

	if VerboseLog || Logging || (viper.IsSet("LogFile") && viper.GetString("LogFile") != "") {
		if viper.IsSet("LogFile") && viper.GetString("LogFile") != "" {
			jww.SetLogFile(viper.GetString("LogFile"))
		} else {
			jww.UseTempLogFile("hugo")
		}
	} else {
		jww.DiscardLogging()
	}

	if viper.GetBool("verbose") {
		jww.SetStdoutThreshold(jww.LevelInfo)
	}

	if VerboseLog {
		jww.SetLogThreshold(jww.LevelInfo)
	}

	jww.INFO.Println("Using config file:", viper.ConfigFileUsed())
}

func build(watches ...bool) {
	utils.CheckErr(copyStatic(), fmt.Sprintf("Error copying static files to %s", helpers.AbsPathify(viper.GetString("PublishDir"))))
	watch := false
	if len(watches) > 0 && watches[0] {
		watch = true
	}
	utils.StopOnErr(buildSite(BuildWatch || watch))

	if BuildWatch {
		jww.FEEDBACK.Println("Watching for changes in", helpers.AbsPathify(viper.GetString("ContentDir")))
		jww.FEEDBACK.Println("Press ctrl+c to stop")
		utils.CheckErr(NewWatcher(0))
	}
}

func copyStatic() error {
	staticDir := helpers.AbsPathify(viper.GetString("StaticDir")) + "/"
	if _, err := os.Stat(staticDir); os.IsNotExist(err) {
		jww.ERROR.Println("Unable to find Static Directory:", viper.GetString("theme"), "in", staticDir)
		return nil
	}

	publishDir := helpers.AbsPathify(viper.GetString("PublishDir")) + "/"

	if themeSet() {
		themeDir := helpers.AbsPathify("themes/"+viper.GetString("theme")) + "/static/"
		if _, err := os.Stat(themeDir); os.IsNotExist(err) {
			jww.ERROR.Println("Unable to find static directory for theme :", viper.GetString("theme"), "in", themeDir)
			return nil
		}

		// Copy Static to Destination
		jww.INFO.Println("syncing from", themeDir, "to", publishDir)
		fsync.Sync(publishDir, themeDir)
	}

	// Copy Static to Destination
	jww.INFO.Println("syncing from", staticDir, "to", publishDir)
	return fsync.Sync(publishDir, staticDir)
}

func getDirList() []string {
	var a []string
	walker := func(path string, fi os.FileInfo, err error) error {
		if err != nil {
			jww.ERROR.Println("Walker: ", err)
			return nil
		}

		if fi.IsDir() {
			a = append(a, path)
		}
		return nil
	}

	filepath.Walk(helpers.AbsPathify(viper.GetString("ContentDir")), walker)
	filepath.Walk(helpers.AbsPathify(viper.GetString("LayoutDir")), walker)
	filepath.Walk(helpers.AbsPathify(viper.GetString("StaticDir")), walker)
	if themeSet() {
		filepath.Walk(helpers.AbsPathify("themes/"+viper.GetString("theme")), walker)
	}

	return a
}

func themeSet() bool {
	return viper.GetString("theme") != ""
}

func buildSite(watching ...bool) (err error) {
	startTime := time.Now()
	site := &hugolib.Site{}
	if len(watching) > 0 && watching[0] {
		site.RunMode.Watching = true
	}
	err = site.Build()
	if err != nil {
		return err
	}
	site.Stats()
	jww.FEEDBACK.Printf("in %v ms\n", int(1000*time.Since(startTime).Seconds()))

	return nil
}

func NewWatcher(port int) error {
	if runtime.GOOS == "darwin" {
		tweakLimit()
	}

	watcher, err := watcher.New(1 * time.Second)
	var wg sync.WaitGroup

	if err != nil {
		fmt.Println(err)
		return err
	}

	defer watcher.Close()

	wg.Add(1)

	for _, d := range getDirList() {
		if d != "" {
			_ = watcher.Watch(d)
		}
	}

	go func() {
		for {
			select {
			case evs := <-watcher.Event:
				jww.INFO.Println("File System Event:", evs)

				static_changed := false
				dynamic_changed := false

				for _, ev := range evs {
					ext := filepath.Ext(ev.Name)
					istemp := strings.HasSuffix(ext, "~") || (ext == ".swp") || (ext == ".tmp")
					if istemp {
						continue
					}
					// renames are always followed with Create/Modify
					if ev.IsRename() {
						continue
					}

					isstatic := strings.HasPrefix(ev.Name, helpers.AbsPathify(viper.GetString("StaticDir"))) || strings.HasPrefix(ev.Name, helpers.AbsPathify("themes/"+viper.GetString("theme"))+"/static/")
					static_changed = static_changed || isstatic
					dynamic_changed = dynamic_changed || !isstatic

					// add new directory to watch list
					if s, err := os.Stat(ev.Name); err == nil && s.Mode().IsDir() {
						if ev.IsCreate() {
							watcher.Watch(ev.Name)
						}
					}
				}

				if static_changed {
					fmt.Print("Static file changed, syncing\n\n")
					utils.StopOnErr(copyStatic(), fmt.Sprintf("Error copying static files to %s", helpers.AbsPathify(viper.GetString("PublishDir"))))

					if !viper.GetBool("DisableLiveReload") {
						// Will block forever trying to write to a channel that nobody is reading if livereload isn't initalized
						livereload.ForceRefresh()
					}
				}

				if dynamic_changed {
					fmt.Print("Change detected, rebuilding site\n\n")
					utils.StopOnErr(buildSite(true))

					if !viper.GetBool("DisableLiveReload") {
						// Will block forever trying to write to a channel that nobody is reading if livereload isn't initalized
						livereload.ForceRefresh()
					}
				}
			case err := <-watcher.Error:
				if err != nil {
					fmt.Println("error:", err)
				}
			}
		}
	}()

	if port > 0 {
		if !viper.GetBool("DisableLiveReload") {
			livereload.Initialize()
			http.HandleFunc("/livereload.js", livereload.ServeJS)
			http.HandleFunc("/livereload", livereload.Handler)
		}

		go serve(port)
	}

	wg.Wait()
	return nil
}
<|endoftext|>


<commit_before>package commands

import (
	"path/filepath"
	"regexp"
	"strings"

	"github.com/github/hub/github"
	"github.com/github/hub/utils"
)

var cmdInit = &Command{
	Run:          gitInit,
	GitExtension: true,
	Usage:        "init -g",
	Long: `Initialize a git repository and add a remote pointing to GitHub.

## Options:
	-g
		After initializing the repository locally, add the "origin" remote pointing
		to "<USER>/<REPO>" repository on GitHub.

		<USER> is your GitHub username, while <REPO> is the name of the current
		working directory.

## Examples:
		$ hub init -g
		> git init
		> git remote add origin git@github.com:USER/REPO.git

## See also:

hub-create(1), hub(1), git-init(1)
`,
}

func init() {
	CmdRunner.Use(cmdInit)
}

func gitInit(command *Command, args *Args) {
	err := transformInitArgs(args)
	utils.Check(err)
}

func transformInitArgs(args *Args) error {
	if !parseInitFlag(args) {
		return nil
	}

	var err error
	dirToInit := "."
	hasValueRegexp := regexp.MustCompile("^--(template|separate-git-dir|shared)$")

	// Find the first argument that isn't related to any of the init flags.
	// We assume this is the optional `directory` argument to git init.
	for i := 0; i < args.ParamsSize(); i++ {
		arg := args.Params[i]
		if hasValueRegexp.MatchString(arg) {
			i++
		} else if !strings.HasPrefix(arg, "-") {
			dirToInit = arg
			break
		}
	}

	dirToInit, err = filepath.Abs(dirToInit)
	if err != nil {
		return err
	}

	config := github.CurrentConfig()
	host, err := config.DefaultHost()
	if err != nil {
		utils.Check(github.FormatError("initializing repository", err))
	}

	// Assume that the name of the working directory is going to be the name of
	// the project on GitHub.
	projectName := strings.Replace(filepath.Base(dirToInit), " ", "-", -1)
	project := github.NewProject(host.User, projectName, "")
	url := project.GitURL("", "", true)

	addRemote := []string{
		"git", "--git-dir", filepath.Join(dirToInit, ".git"),
		"remote", "add", "origin", url,
	}
	args.After(addRemote...)

	return nil
}

func parseInitFlag(args *Args) bool {
	if i := args.IndexOfParam("-g"); i != -1 {
		args.RemoveParam(i)
		return true
	}

	return false
}
<commit_msg>Respect chosen Enterprise host on `hub init -g`<commit_after>package commands

import (
	"path/filepath"
	"regexp"
	"strings"

	"github.com/github/hub/github"
	"github.com/github/hub/utils"
)

var cmdInit = &Command{
	Run:          gitInit,
	GitExtension: true,
	Usage:        "init -g",
	Long: `Initialize a git repository and add a remote pointing to GitHub.

## Options:
	-g
		After initializing the repository locally, add the "origin" remote pointing
		to "<USER>/<REPO>" repository on GitHub.

		<USER> is your GitHub username, while <REPO> is the name of the current
		working directory.

## Examples:
		$ hub init -g
		> git init
		> git remote add origin git@github.com:USER/REPO.git

## See also:

hub-create(1), hub(1), git-init(1)
`,
}

func init() {
	CmdRunner.Use(cmdInit)
}

func gitInit(command *Command, args *Args) {
	err := transformInitArgs(args)
	utils.Check(err)
}

func transformInitArgs(args *Args) error {
	if !parseInitFlag(args) {
		return nil
	}

	var err error
	dirToInit := "."
	hasValueRegexp := regexp.MustCompile("^--(template|separate-git-dir|shared)$")

	// Find the first argument that isn't related to any of the init flags.
	// We assume this is the optional `directory` argument to git init.
	for i := 0; i < args.ParamsSize(); i++ {
		arg := args.Params[i]
		if hasValueRegexp.MatchString(arg) {
			i++
		} else if !strings.HasPrefix(arg, "-") {
			dirToInit = arg
			break
		}
	}

	dirToInit, err = filepath.Abs(dirToInit)
	if err != nil {
		return err
	}

	config := github.CurrentConfig()
	host, err := config.DefaultHost()
	if err != nil {
		utils.Check(github.FormatError("initializing repository", err))
	}

	// Assume that the name of the working directory is going to be the name of
	// the project on GitHub.
	projectName := strings.Replace(filepath.Base(dirToInit), " ", "-", -1)
	project := github.NewProject(host.User, projectName, host.Host)
	url := project.GitURL("", "", true)

	addRemote := []string{
		"git", "--git-dir", filepath.Join(dirToInit, ".git"),
		"remote", "add", "origin", url,
	}
	args.After(addRemote...)

	return nil
}

func parseInitFlag(args *Args) bool {
	if i := args.IndexOfParam("-g"); i != -1 {
		args.RemoveParam(i)
		return true
	}

	return false
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors 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 e2e

import (
	"encoding/json"
	"fmt"
	"time"

	cadvisorapi "github.com/google/cadvisor/info/v1"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/pkg/api/unversioned"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/util/wait"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const (
	mb = 1024 * 1024
	gb = 1024 * mb

	// TODO(madhusudancs): find a way to query kubelet's disk space manager to obtain this value. 256MB
	// is the default that is set today. This test might break if the default value changes. This value
	// can be configured by setting the "low-diskspace-threshold-mb" flag while starting a kubelet.
	// However, kubelets are started as part of the cluster start up, once, before any e2e test is run,
	// and remain unchanged until all the tests are run and the cluster is brought down. Changing the
	// flag value affects all the e2e tests. So we are hard-coding this value for now.
	lowDiskSpaceThreshold uint64 = 256 * mb

	nodeOODTimeOut = 1 * time.Minute

	numNodeOODPods = 3
)

// Plan:
// 1. Fill disk space on all nodes except one. One node is left out so that we can schedule pods
//    on that node. Arbitrarily choose that node to be node with index 0.
// 2. Get the CPU capacity on unfilled node.
// 3. Divide the available CPU into one less than the number of pods we want to schedule. We want
//    to schedule 3 pods, so divide CPU capacity by 2.
// 4. Request the divided CPU for each pod.
// 5. Observe that 2 of the pods schedule onto the node whose disk is not full, and the remaining
//    pod stays pending and does not schedule onto the nodes whose disks are full nor the node
//    with the other two pods, since there is not enough free CPU capacity there.
// 6. Recover disk space from one of the nodes whose disk space was previously filled. Arbritrarily
//    choose that node to be node with index 1.
// 7. Observe that the pod in pending status schedules on that node.
//
var _ = Describe("NodeOutOfDisk", func() {
	var c *client.Client
	var unfilledNodeName, recoveredNodeName string
	framework := Framework{BaseName: "node-outofdisk"}

	BeforeEach(func() {
		framework.beforeEach()
		c = framework.Client

		nodelist, err := listNodes(c, labels.Everything(), fields.Everything())
		expectNoError(err, "Error retrieving nodes")
		Expect(len(nodelist.Items)).To(BeNumerically(">", 1))

		unfilledNodeName = nodelist.Items[0].Name
		for _, node := range nodelist.Items[1:] {
			fillDiskSpace(c, &node)
		}
	})

	AfterEach(func() {
		defer framework.afterEach()

		nodelist, err := listNodes(c, labels.Everything(), fields.Everything())
		expectNoError(err, "Error retrieving nodes")
		Expect(len(nodelist.Items)).ToNot(BeZero())
		for _, node := range nodelist.Items {
			if unfilledNodeName == node.Name || recoveredNodeName == node.Name {
				continue
			}
			recoverDiskSpace(c, &node)
		}
	})

	It("runs out of disk space", func() {
		unfilledNode, err := c.Nodes().Get(unfilledNodeName)
		expectNoError(err)

		By(fmt.Sprintf("Calculating CPU availability on node %s", unfilledNode.Name))
		milliCpu, err := availCpu(c, unfilledNode)
		expectNoError(err)

		// Per pod CPU should be just enough to fit only (numNodeOODPods - 1) pods on the given
		// node. We compute this value by dividing the available CPU capacity on the node by
		// (numNodeOODPods - 1) and subtracting ϵ from it. We arbitrarily choose ϵ to be 1%
		// of the available CPU per pod, i.e. 0.01 * milliCpu/(numNodeOODPods-1). Instead of
		// subtracting 1% from the value, we directly use 0.99 as the multiplier.
		podCPU := int64(float64(milliCpu/(numNodeOODPods-1)) * 0.99)

		ns := framework.Namespace.Name
		podClient := c.Pods(ns)

		By("Creating pods and waiting for all but one pods to be scheduled")

		for i := 0; i < numNodeOODPods-1; i++ {
			name := fmt.Sprintf("pod-node-outofdisk-%d", i)
			createOutOfDiskPod(c, ns, name, podCPU)

			expectNoError(framework.WaitForPodRunning(name))
			pod, err := podClient.Get(name)
			expectNoError(err)
			Expect(pod.Spec.NodeName).To(Equal(unfilledNodeName))
		}

		pendingPodName := fmt.Sprintf("pod-node-outofdisk-%d", numNodeOODPods-1)
		createOutOfDiskPod(c, ns, pendingPodName, podCPU)

		By(fmt.Sprintf("Finding a failed scheduler event for pod %s", pendingPodName))
		wait.Poll(2*time.Second, 5*time.Minute, func() (bool, error) {
			selector := fields.Set{
				"involvedObject.kind":      "Pod",
				"involvedObject.name":      pendingPodName,
				"involvedObject.namespace": ns,
				"source":                   "scheduler",
				"reason":                   "FailedScheduling",
			}.AsSelector()
			options := unversioned.ListOptions{FieldSelector: unversioned.FieldSelector{selector}}
			schedEvents, err := c.Events(ns).List(options)
			expectNoError(err)

			if len(schedEvents.Items) > 0 {
				return true, nil
			} else {
				return false, nil
			}
		})

		nodelist, err := listNodes(c, labels.Everything(), fields.Everything())
		expectNoError(err, "Error retrieving nodes")
		Expect(len(nodelist.Items)).To(BeNumerically(">", 1))

		nodeToRecover := nodelist.Items[1]
		Expect(nodeToRecover.Name).ToNot(Equal(unfilledNodeName))

		recoverDiskSpace(c, &nodeToRecover)
		recoveredNodeName = nodeToRecover.Name

		By(fmt.Sprintf("Verifying that pod %s schedules on node %s", pendingPodName, recoveredNodeName))
		expectNoError(framework.WaitForPodRunning(pendingPodName))
		pendingPod, err := podClient.Get(pendingPodName)
		expectNoError(err)
		Expect(pendingPod.Spec.NodeName).To(Equal(recoveredNodeName))
	})
})

// createOutOfDiskPod creates a pod in the given namespace with the requested amount of CPU.
func createOutOfDiskPod(c *client.Client, ns, name string, milliCPU int64) {
	podClient := c.Pods(ns)

	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name: name,
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{
					Name:  "pause",
					Image: "beta.gcr.io/google_containers/pause:2.0",
					Resources: api.ResourceRequirements{
						Requests: api.ResourceList{
							// Request enough CPU to fit only two pods on a given node.
							api.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI),
						},
					},
				},
			},
		},
	}

	_, err := podClient.Create(pod)
	expectNoError(err)
}

// availCpu calculates the available CPU on a given node by subtracting the CPU requested by
// all the pods from the total available CPU capacity on the node.
func availCpu(c *client.Client, node *api.Node) (int64, error) {
	podClient := c.Pods(api.NamespaceAll)

	selector := fields.Set{"spec.nodeName": node.Name}.AsSelector()
	options := unversioned.ListOptions{FieldSelector: unversioned.FieldSelector{selector}}
	pods, err := podClient.List(options)
	if err != nil {
		return 0, fmt.Errorf("failed to retrieve all the pods on node %s: %v", node.Name, err)
	}
	avail := node.Status.Capacity.Cpu().MilliValue()
	for _, pod := range pods.Items {
		for _, cont := range pod.Spec.Containers {
			avail -= cont.Resources.Requests.Cpu().MilliValue()
		}
	}
	return avail, nil
}

// availSize returns the available disk space on a given node by querying node stats which
// is in turn obtained internally from cadvisor.
func availSize(c *client.Client, node *api.Node) (uint64, error) {
	statsResource := fmt.Sprintf("api/v1/proxy/nodes/%s/stats/", node.Name)
	Logf("Querying stats for node %s using url %s", node.Name, statsResource)
	res, err := c.Get().AbsPath(statsResource).Timeout(timeout).Do().Raw()
	if err != nil {
		return 0, fmt.Errorf("error querying cAdvisor API: %v", err)
	}
	ci := cadvisorapi.ContainerInfo{}
	err = json.Unmarshal(res, &ci)
	if err != nil {
		return 0, fmt.Errorf("couldn't unmarshal container info: %v", err)
	}
	return ci.Stats[len(ci.Stats)-1].Filesystem[0].Available, nil
}

// fillDiskSpace fills the available disk space on a given node by creating a large file. The disk
// space on the node is filled in such a way that the available space after filling the disk is just
// below the lowDiskSpaceThreshold mark.
func fillDiskSpace(c *client.Client, node *api.Node) {
	avail, err := availSize(c, node)
	expectNoError(err, "Node %s: couldn't obtain available disk size %v", node.Name, err)

	fillSize := (avail - lowDiskSpaceThreshold + (100 * mb))

	Logf("Node %s: disk space available %d bytes", node.Name, avail)
	By(fmt.Sprintf("Node %s: creating a file of size %d bytes to fill the available disk space", node.Name, fillSize))

	cmd := fmt.Sprintf("fallocate -l %d test.img", fillSize)
	expectNoError(issueSSHCommand(cmd, testContext.Provider, node))

	ood := waitForNodeToBe(c, node.Name, api.NodeOutOfDisk, true, nodeOODTimeOut)
	Expect(ood).To(BeTrue(), "Node %s did not run out of disk within %v", node.Name, nodeOODTimeOut)

	avail, err = availSize(c, node)
	Logf("Node %s: disk space available %d bytes", node.Name, avail)
	Expect(avail < lowDiskSpaceThreshold).To(BeTrue())
}

// recoverDiskSpace recovers disk space, filled by creating a large file, on a given node.
func recoverDiskSpace(c *client.Client, node *api.Node) {
	By(fmt.Sprintf("Recovering disk space on node %s", node.Name))
	cmd := "rm -f test.img"
	expectNoError(issueSSHCommand(cmd, testContext.Provider, node))

	ood := waitForNodeToBe(c, node.Name, api.NodeOutOfDisk, false, nodeOODTimeOut)
	Expect(ood).To(BeTrue(), "Node %s's out of disk condition status did not change to false within %v", node.Name, nodeOODTimeOut)
}
<commit_msg>Increase the node condition status change observation time out to 5 minutes.<commit_after>/*
Copyright 2015 The Kubernetes Authors 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 e2e

import (
	"encoding/json"
	"fmt"
	"time"

	cadvisorapi "github.com/google/cadvisor/info/v1"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/api/resource"
	"k8s.io/kubernetes/pkg/api/unversioned"
	client "k8s.io/kubernetes/pkg/client/unversioned"
	"k8s.io/kubernetes/pkg/fields"
	"k8s.io/kubernetes/pkg/labels"
	"k8s.io/kubernetes/pkg/util/wait"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

const (
	mb = 1024 * 1024
	gb = 1024 * mb

	// TODO(madhusudancs): find a way to query kubelet's disk space manager to obtain this value. 256MB
	// is the default that is set today. This test might break if the default value changes. This value
	// can be configured by setting the "low-diskspace-threshold-mb" flag while starting a kubelet.
	// However, kubelets are started as part of the cluster start up, once, before any e2e test is run,
	// and remain unchanged until all the tests are run and the cluster is brought down. Changing the
	// flag value affects all the e2e tests. So we are hard-coding this value for now.
	lowDiskSpaceThreshold uint64 = 256 * mb

	nodeOODTimeOut = 5 * time.Minute

	numNodeOODPods = 3
)

// Plan:
// 1. Fill disk space on all nodes except one. One node is left out so that we can schedule pods
//    on that node. Arbitrarily choose that node to be node with index 0.
// 2. Get the CPU capacity on unfilled node.
// 3. Divide the available CPU into one less than the number of pods we want to schedule. We want
//    to schedule 3 pods, so divide CPU capacity by 2.
// 4. Request the divided CPU for each pod.
// 5. Observe that 2 of the pods schedule onto the node whose disk is not full, and the remaining
//    pod stays pending and does not schedule onto the nodes whose disks are full nor the node
//    with the other two pods, since there is not enough free CPU capacity there.
// 6. Recover disk space from one of the nodes whose disk space was previously filled. Arbritrarily
//    choose that node to be node with index 1.
// 7. Observe that the pod in pending status schedules on that node.
//
var _ = Describe("NodeOutOfDisk", func() {
	var c *client.Client
	var unfilledNodeName, recoveredNodeName string
	framework := Framework{BaseName: "node-outofdisk"}

	BeforeEach(func() {
		framework.beforeEach()
		c = framework.Client

		nodelist, err := listNodes(c, labels.Everything(), fields.Everything())
		expectNoError(err, "Error retrieving nodes")
		Expect(len(nodelist.Items)).To(BeNumerically(">", 1))

		unfilledNodeName = nodelist.Items[0].Name
		for _, node := range nodelist.Items[1:] {
			fillDiskSpace(c, &node)
		}
	})

	AfterEach(func() {
		defer framework.afterEach()

		nodelist, err := listNodes(c, labels.Everything(), fields.Everything())
		expectNoError(err, "Error retrieving nodes")
		Expect(len(nodelist.Items)).ToNot(BeZero())
		for _, node := range nodelist.Items {
			if unfilledNodeName == node.Name || recoveredNodeName == node.Name {
				continue
			}
			recoverDiskSpace(c, &node)
		}
	})

	It("runs out of disk space", func() {
		unfilledNode, err := c.Nodes().Get(unfilledNodeName)
		expectNoError(err)

		By(fmt.Sprintf("Calculating CPU availability on node %s", unfilledNode.Name))
		milliCpu, err := availCpu(c, unfilledNode)
		expectNoError(err)

		// Per pod CPU should be just enough to fit only (numNodeOODPods - 1) pods on the given
		// node. We compute this value by dividing the available CPU capacity on the node by
		// (numNodeOODPods - 1) and subtracting ϵ from it. We arbitrarily choose ϵ to be 1%
		// of the available CPU per pod, i.e. 0.01 * milliCpu/(numNodeOODPods-1). Instead of
		// subtracting 1% from the value, we directly use 0.99 as the multiplier.
		podCPU := int64(float64(milliCpu/(numNodeOODPods-1)) * 0.99)

		ns := framework.Namespace.Name
		podClient := c.Pods(ns)

		By("Creating pods and waiting for all but one pods to be scheduled")

		for i := 0; i < numNodeOODPods-1; i++ {
			name := fmt.Sprintf("pod-node-outofdisk-%d", i)
			createOutOfDiskPod(c, ns, name, podCPU)

			expectNoError(framework.WaitForPodRunning(name))
			pod, err := podClient.Get(name)
			expectNoError(err)
			Expect(pod.Spec.NodeName).To(Equal(unfilledNodeName))
		}

		pendingPodName := fmt.Sprintf("pod-node-outofdisk-%d", numNodeOODPods-1)
		createOutOfDiskPod(c, ns, pendingPodName, podCPU)

		By(fmt.Sprintf("Finding a failed scheduler event for pod %s", pendingPodName))
		wait.Poll(2*time.Second, 5*time.Minute, func() (bool, error) {
			selector := fields.Set{
				"involvedObject.kind":      "Pod",
				"involvedObject.name":      pendingPodName,
				"involvedObject.namespace": ns,
				"source":                   "scheduler",
				"reason":                   "FailedScheduling",
			}.AsSelector()
			options := unversioned.ListOptions{FieldSelector: unversioned.FieldSelector{selector}}
			schedEvents, err := c.Events(ns).List(options)
			expectNoError(err)

			if len(schedEvents.Items) > 0 {
				return true, nil
			} else {
				return false, nil
			}
		})

		nodelist, err := listNodes(c, labels.Everything(), fields.Everything())
		expectNoError(err, "Error retrieving nodes")
		Expect(len(nodelist.Items)).To(BeNumerically(">", 1))

		nodeToRecover := nodelist.Items[1]
		Expect(nodeToRecover.Name).ToNot(Equal(unfilledNodeName))

		recoverDiskSpace(c, &nodeToRecover)
		recoveredNodeName = nodeToRecover.Name

		By(fmt.Sprintf("Verifying that pod %s schedules on node %s", pendingPodName, recoveredNodeName))
		expectNoError(framework.WaitForPodRunning(pendingPodName))
		pendingPod, err := podClient.Get(pendingPodName)
		expectNoError(err)
		Expect(pendingPod.Spec.NodeName).To(Equal(recoveredNodeName))
	})
})

// createOutOfDiskPod creates a pod in the given namespace with the requested amount of CPU.
func createOutOfDiskPod(c *client.Client, ns, name string, milliCPU int64) {
	podClient := c.Pods(ns)

	pod := &api.Pod{
		ObjectMeta: api.ObjectMeta{
			Name: name,
		},
		Spec: api.PodSpec{
			Containers: []api.Container{
				{
					Name:  "pause",
					Image: "beta.gcr.io/google_containers/pause:2.0",
					Resources: api.ResourceRequirements{
						Requests: api.ResourceList{
							// Request enough CPU to fit only two pods on a given node.
							api.ResourceCPU: *resource.NewMilliQuantity(milliCPU, resource.DecimalSI),
						},
					},
				},
			},
		},
	}

	_, err := podClient.Create(pod)
	expectNoError(err)
}

// availCpu calculates the available CPU on a given node by subtracting the CPU requested by
// all the pods from the total available CPU capacity on the node.
func availCpu(c *client.Client, node *api.Node) (int64, error) {
	podClient := c.Pods(api.NamespaceAll)

	selector := fields.Set{"spec.nodeName": node.Name}.AsSelector()
	options := unversioned.ListOptions{FieldSelector: unversioned.FieldSelector{selector}}
	pods, err := podClient.List(options)
	if err != nil {
		return 0, fmt.Errorf("failed to retrieve all the pods on node %s: %v", node.Name, err)
	}
	avail := node.Status.Capacity.Cpu().MilliValue()
	for _, pod := range pods.Items {
		for _, cont := range pod.Spec.Containers {
			avail -= cont.Resources.Requests.Cpu().MilliValue()
		}
	}
	return avail, nil
}

// availSize returns the available disk space on a given node by querying node stats which
// is in turn obtained internally from cadvisor.
func availSize(c *client.Client, node *api.Node) (uint64, error) {
	statsResource := fmt.Sprintf("api/v1/proxy/nodes/%s/stats/", node.Name)
	Logf("Querying stats for node %s using url %s", node.Name, statsResource)
	res, err := c.Get().AbsPath(statsResource).Timeout(timeout).Do().Raw()
	if err != nil {
		return 0, fmt.Errorf("error querying cAdvisor API: %v", err)
	}
	ci := cadvisorapi.ContainerInfo{}
	err = json.Unmarshal(res, &ci)
	if err != nil {
		return 0, fmt.Errorf("couldn't unmarshal container info: %v", err)
	}
	return ci.Stats[len(ci.Stats)-1].Filesystem[0].Available, nil
}

// fillDiskSpace fills the available disk space on a given node by creating a large file. The disk
// space on the node is filled in such a way that the available space after filling the disk is just
// below the lowDiskSpaceThreshold mark.
func fillDiskSpace(c *client.Client, node *api.Node) {
	avail, err := availSize(c, node)
	expectNoError(err, "Node %s: couldn't obtain available disk size %v", node.Name, err)

	fillSize := (avail - lowDiskSpaceThreshold + (100 * mb))

	Logf("Node %s: disk space available %d bytes", node.Name, avail)
	By(fmt.Sprintf("Node %s: creating a file of size %d bytes to fill the available disk space", node.Name, fillSize))

	cmd := fmt.Sprintf("fallocate -l %d test.img", fillSize)
	expectNoError(issueSSHCommand(cmd, testContext.Provider, node))

	ood := waitForNodeToBe(c, node.Name, api.NodeOutOfDisk, true, nodeOODTimeOut)
	Expect(ood).To(BeTrue(), "Node %s did not run out of disk within %v", node.Name, nodeOODTimeOut)

	avail, err = availSize(c, node)
	Logf("Node %s: disk space available %d bytes", node.Name, avail)
	Expect(avail < lowDiskSpaceThreshold).To(BeTrue())
}

// recoverDiskSpace recovers disk space, filled by creating a large file, on a given node.
func recoverDiskSpace(c *client.Client, node *api.Node) {
	By(fmt.Sprintf("Recovering disk space on node %s", node.Name))
	cmd := "rm -f test.img"
	expectNoError(issueSSHCommand(cmd, testContext.Provider, node))

	ood := waitForNodeToBe(c, node.Name, api.NodeOutOfDisk, false, nodeOODTimeOut)
	Expect(ood).To(BeTrue(), "Node %s's out of disk condition status did not change to false within %v", node.Name, nodeOODTimeOut)
}
<|endoftext|>