<commit_before>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cmd

import (
	"archive/tar"
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"
	"time"

	"github.com/loadimpact/k6/ui"

	"github.com/loadimpact/k6/core"
	"github.com/loadimpact/k6/core/local"
	"github.com/loadimpact/k6/js"
	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/loader"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/afero"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	null "gopkg.in/guregu/null.v3"
)

const (
	typeJS      = "js"
	typeArchive = "archive"
)

var (
	runType       string
	linger        bool
	noUsageReport bool
)

// runCmd represents the run command.
var runCmd = &cobra.Command{
	Use:   "run",
	Short: "Start a load test",
	Long: `Start a load test.

This also exposes a REST API to interact with it. Various k6 subcommands offer
a commandline interface for interacting with it.`,
	Example: `
  # Run a single VU, once.
  k6 run script.js

  # Run a single VU, 10 times.
  k6 run -i 10 script.js

  # Run 5 VUs, splitting 10 iterations between them.
  k6 run -u 5 -i 10 script.js

  # Run 5 VUs for 10s.
  k6 run -u 5 -d 10s script.js

  # Ramp VUs from 0 to 100 over 10s, stay there for 60s, then 10s down to 0.
  k6 run -u 0 -s 10s:100 -s 60s -s 10s:0`[1:],
	Args: cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		// Create the Runner.
		pwd, err := os.Getwd()
		if err != nil {
			return err
		}
		src, err := readSource(args[0], pwd, afero.NewOsFs(), os.Stdin)
		if err != nil {
			return err
		}
		r, err := newRunner(src, runType, afero.NewOsFs())
		if err != nil {
			return err
		}

		// Assemble options; start with the CLI-provided options to get shadowed (non-Valid)
		// defaults in there, override with Runner-provided ones, then merge the CLI opts in
		// on top to give them priority.
		cliOpts, err := getOptions(cmd.Flags())
		if err != nil {
			return err
		}
		opts := cliOpts.Apply(r.GetOptions()).Apply(cliOpts)

		// If -m/--max isn't specified, figure out the max that should be needed.
		if !opts.VUsMax.Valid {
			opts.VUsMax = null.IntFrom(opts.VUs.Int64)
			for _, stage := range opts.Stages {
				if stage.Target.Valid && stage.Target.Int64 > opts.VUsMax.Int64 {
					opts.VUsMax = stage.Target
				}
			}
		}
		// If -d/--duration, -i/--iterations and -s/--stage are all unset, run to one iteration.
		if !opts.Duration.Valid && !opts.Iterations.Valid && opts.Stages == nil {
			opts.Iterations = null.IntFrom(1)
		}

		// Write options back to the runner too.
		r.ApplyOptions(opts)

		// Create an engine with a local executor, wrapping the Runner.
		engine, err := core.NewEngine(local.New(r), opts)
		if err != nil {
			return err
		}

		// Trap signals, run the engine until it exits on its own, or a signal is trapped.
		ctx, cancel := context.WithCancel(context.Background())
		defer cancel()

		sigC := make(chan os.Signal, 1)
		signal.Notify(sigC, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
		defer signal.Stop(sigC)

		errC := make(chan error)
		go func() { errC <- engine.Run(ctx) }()

		// Show progress to the user.
		progress := ui.ProgressBar{
			Width: 60,
			Left: func() string {
				if engine.Executor.IsPaused() {
					return " paused"
				} else if engine.Executor.IsRunning() {
					return "running"
				} else {
					return "   done"
				}
			},
			Right: func() string {
				if endIt := engine.Executor.GetEndIterations(); endIt.Valid {
					return fmt.Sprintf("%d / %d", engine.Executor.GetIterations(), endIt.Int64)
				}
				precision := 100 * time.Millisecond
				atT := engine.Executor.GetTime()
				if endT := engine.Executor.GetEndTime(); endT.Valid {
					return fmt.Sprintf("%s / %s",
						(atT/precision)*precision,
						(time.Duration(endT.Duration)/precision)*precision,
					)
				}
				return ((atT / precision) * precision).String()
			},
		}
		ticker2 := time.NewTicker(500 * time.Millisecond)
		ticker := time.NewTicker(50 * time.Millisecond)
	mainLoop:
		for {
			select {
			case <-ticker.C:
				var prog float64
				if endIt := engine.Executor.GetEndIterations(); endIt.Valid {
					prog = float64(engine.Executor.GetIterations()) / float64(endIt.Int64)
				} else if endT := engine.Executor.GetEndTime(); endT.Valid {
					prog = float64(engine.Executor.GetTime()) / float64(endT.Duration)
				}
				progress.Progress = prog
				fmt.Fprintf(stdout, "%s\x1b[0K\r", progress.String())
			case <-ticker2.C:
				log.Info("hi")
			case err := <-errC:
				if err != nil {
					log.WithError(err).Error("Engine error")
				} else {
					log.Debug("Engine terminated cleanly")
				}
				cancel()
				break mainLoop
			case sig := <-sigC:
				log.WithField("sig", sig).Debug("Exiting in response to signal")
				cancel()
			}
		}
		progress.Progress = 1
		fmt.Fprintf(stdout, "%s\x1b[0K\n", progress.String())

		log.Infof("Test ended after: %s", engine.Executor.GetTime())
		return nil
	},
}

func init() {
	RootCmd.AddCommand(runCmd)

	runCmd.Flags().SortFlags = false
	registerOptions(runCmd.Flags())

	flags := pflag.NewFlagSet("", 0)
	flags.SortFlags = false
	flags.StringVarP(&runType, "type", "t", "", "override file `type`, \"js\" or \"archive\"")
	flags.BoolVarP(&linger, "linger", "l", false, "keep the API server alive past test end")
	flags.BoolVar(&noUsageReport, "no-usage-report", false, "don't send analytics to the maintainers")
}

// Reads a source file from any supported destination.
func readSource(src, pwd string, fs afero.Fs, stdin io.Reader) (*lib.SourceData, error) {
	if src == "-" {
		data, err := ioutil.ReadAll(stdin)
		if err != nil {
			return nil, err
		}
		return &lib.SourceData{Filename: "-", Data: data}, nil
	}
	abspath := filepath.Join(pwd, src)
	if ok, _ := afero.Exists(fs, abspath); ok {
		src = abspath
	}
	return loader.Load(fs, pwd, src)
}

// Creates a new runner.
func newRunner(src *lib.SourceData, typ string, fs afero.Fs) (lib.Runner, error) {
	switch typ {
	case "":
		if _, err := tar.NewReader(bytes.NewReader(src.Data)).Next(); err == nil {
			return newRunner(src, typeArchive, fs)
		}
		return newRunner(src, typeJS, fs)
	case typeJS:
		return js.New(src, fs)
	case typeArchive:
		arc, err := lib.ReadArchive(bytes.NewReader(src.Data))
		if err != nil {
			return nil, err
		}
		switch arc.Type {
		case typeJS:
			return js.NewFromArchive(arc)
		default:
			return nil, errors.Errorf("archive requests unsupported runner: %s", arc.Type)
		}
	default:
		return nil, errors.Errorf("unknown -t/--type: %s", typ)
	}
}
<commit_msg>Sensible quiet and non-TTY behaviour<commit_after>/*
 *
 * k6 - a next-generation load testing tool
 * Copyright (C) 2016 Load Impact
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package cmd

import (
	"archive/tar"
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/signal"
	"path/filepath"
	"syscall"
	"time"

	"github.com/loadimpact/k6/ui"

	"github.com/loadimpact/k6/core"
	"github.com/loadimpact/k6/core/local"
	"github.com/loadimpact/k6/js"
	"github.com/loadimpact/k6/lib"
	"github.com/loadimpact/k6/loader"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/afero"
	"github.com/spf13/cobra"
	"github.com/spf13/pflag"
	null "gopkg.in/guregu/null.v3"
)

const (
	typeJS      = "js"
	typeArchive = "archive"
)

var (
	runType       string
	linger        bool
	noUsageReport bool
)

// runCmd represents the run command.
var runCmd = &cobra.Command{
	Use:   "run",
	Short: "Start a load test",
	Long: `Start a load test.

This also exposes a REST API to interact with it. Various k6 subcommands offer
a commandline interface for interacting with it.`,
	Example: `
  # Run a single VU, once.
  k6 run script.js

  # Run a single VU, 10 times.
  k6 run -i 10 script.js

  # Run 5 VUs, splitting 10 iterations between them.
  k6 run -u 5 -i 10 script.js

  # Run 5 VUs for 10s.
  k6 run -u 5 -d 10s script.js

  # Ramp VUs from 0 to 100 over 10s, stay there for 60s, then 10s down to 0.
  k6 run -u 0 -s 10s:100 -s 60s -s 10s:0`[1:],
	Args: cobra.ExactArgs(1),
	RunE: func(cmd *cobra.Command, args []string) error {
		// Create the Runner.
		pwd, err := os.Getwd()
		if err != nil {
			return err
		}
		src, err := readSource(args[0], pwd, afero.NewOsFs(), os.Stdin)
		if err != nil {
			return err
		}
		r, err := newRunner(src, runType, afero.NewOsFs())
		if err != nil {
			return err
		}

		// Assemble options; start with the CLI-provided options to get shadowed (non-Valid)
		// defaults in there, override with Runner-provided ones, then merge the CLI opts in
		// on top to give them priority.
		cliOpts, err := getOptions(cmd.Flags())
		if err != nil {
			return err
		}
		opts := cliOpts.Apply(r.GetOptions()).Apply(cliOpts)

		// If -m/--max isn't specified, figure out the max that should be needed.
		if !opts.VUsMax.Valid {
			opts.VUsMax = null.IntFrom(opts.VUs.Int64)
			for _, stage := range opts.Stages {
				if stage.Target.Valid && stage.Target.Int64 > opts.VUsMax.Int64 {
					opts.VUsMax = stage.Target
				}
			}
		}
		// If -d/--duration, -i/--iterations and -s/--stage are all unset, run to one iteration.
		if !opts.Duration.Valid && !opts.Iterations.Valid && opts.Stages == nil {
			opts.Iterations = null.IntFrom(1)
		}

		// Write options back to the runner too.
		r.ApplyOptions(opts)

		// Create an engine with a local executor, wrapping the Runner.
		engine, err := core.NewEngine(local.New(r), opts)
		if err != nil {
			return err
		}

		// Run the engine with a cancellable context.
		ctx, cancel := context.WithCancel(context.Background())
		errC := make(chan error)
		go func() { errC <- engine.Run(ctx) }()

		// Trap Interrupts, SIGINTs and SIGTERMs.
		sigC := make(chan os.Signal, 1)
		signal.Notify(sigC, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
		defer signal.Stop(sigC)

		// Prepare a progress bar.
		progress := ui.ProgressBar{
			Width: 60,
			Left: func() string {
				if engine.Executor.IsPaused() {
					return " paused"
				} else if engine.Executor.IsRunning() {
					return "running"
				} else {
					return "   done"
				}
			},
			Right: func() string {
				if endIt := engine.Executor.GetEndIterations(); endIt.Valid {
					return fmt.Sprintf("%d / %d", engine.Executor.GetIterations(), endIt.Int64)
				}
				precision := 100 * time.Millisecond
				atT := engine.Executor.GetTime()
				if endT := engine.Executor.GetEndTime(); endT.Valid {
					return fmt.Sprintf("%s / %s",
						(atT/precision)*precision,
						(time.Duration(endT.Duration)/precision)*precision,
					)
				}
				return ((atT / precision) * precision).String()
			},
		}
		ticker2 := time.NewTicker(500 * time.Millisecond)

		// Ticker for progress bar updates. Less frequent updates for non-TTYs, none if quiet.
		updateFreq := 50 * time.Millisecond
		if !stdoutTTY {
			updateFreq = 1 * time.Second
		}
		ticker := time.NewTicker(updateFreq)
		if quiet {
			ticker.Stop()
		}
	mainLoop:
		for {
			select {
			case <-ticker.C:
				if quiet || !stdoutTTY {
					l := log.WithFields(log.Fields{
						"t": engine.Executor.GetTime(),
						"i": engine.Executor.GetIterations(),
					})
					fn := l.Info
					if quiet {
						fn = l.Debug
					}
					if engine.Executor.IsPaused() {
						fn("Paused")
					} else {
						fn("Running")
					}
					break
				}

				var prog float64
				if endIt := engine.Executor.GetEndIterations(); endIt.Valid {
					prog = float64(engine.Executor.GetIterations()) / float64(endIt.Int64)
				} else if endT := engine.Executor.GetEndTime(); endT.Valid {
					prog = float64(engine.Executor.GetTime()) / float64(endT.Duration)
				}
				progress.Progress = prog
				fmt.Fprintf(stdout, "%s\x1b[0K\r", progress.String())
			case <-ticker2.C:
				log.Info("hi")
			case err := <-errC:
				if err != nil {
					log.WithError(err).Error("Engine error")
				} else {
					log.Debug("Engine terminated cleanly")
				}
				cancel()
				break mainLoop
			case sig := <-sigC:
				log.WithField("sig", sig).Debug("Exiting in response to signal")
				cancel()
			}
		}
		if quiet || !stdoutTTY {
			e := log.WithFields(log.Fields{
				"t": engine.Executor.GetTime(),
				"i": engine.Executor.GetIterations(),
			})
			fn := e.Info
			if quiet {
				fn = e.Debug
			}
			fn("Test finished")
		} else {
			progress.Progress = 1
			fmt.Fprintf(stdout, "%s\x1b[0K\n", progress.String())
		}

		return nil
	},
}

func init() {
	RootCmd.AddCommand(runCmd)

	runCmd.Flags().SortFlags = false
	registerOptions(runCmd.Flags())

	flags := pflag.NewFlagSet("", 0)
	flags.SortFlags = false
	flags.StringVarP(&runType, "type", "t", "", "override file `type`, \"js\" or \"archive\"")
	flags.BoolVarP(&linger, "linger", "l", false, "keep the API server alive past test end")
	flags.BoolVar(&noUsageReport, "no-usage-report", false, "don't send analytics to the maintainers")
}

// Reads a source file from any supported destination.
func readSource(src, pwd string, fs afero.Fs, stdin io.Reader) (*lib.SourceData, error) {
	if src == "-" {
		data, err := ioutil.ReadAll(stdin)
		if err != nil {
			return nil, err
		}
		return &lib.SourceData{Filename: "-", Data: data}, nil
	}
	abspath := filepath.Join(pwd, src)
	if ok, _ := afero.Exists(fs, abspath); ok {
		src = abspath
	}
	return loader.Load(fs, pwd, src)
}

// Creates a new runner.
func newRunner(src *lib.SourceData, typ string, fs afero.Fs) (lib.Runner, error) {
	switch typ {
	case "":
		if _, err := tar.NewReader(bytes.NewReader(src.Data)).Next(); err == nil {
			return newRunner(src, typeArchive, fs)
		}
		return newRunner(src, typeJS, fs)
	case typeJS:
		return js.New(src, fs)
	case typeArchive:
		arc, err := lib.ReadArchive(bytes.NewReader(src.Data))
		if err != nil {
			return nil, err
		}
		switch arc.Type {
		case typeJS:
			return js.NewFromArchive(arc)
		default:
			return nil, errors.Errorf("archive requests unsupported runner: %s", arc.Type)
		}
	default:
		return nil, errors.Errorf("unknown -t/--type: %s", typ)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"

	"mvdan.cc/sh/v3/fileutil"
	"mvdan.cc/sh/v3/syntax"
)

var (
	showVersion = flag.Bool("version", false, "")

	list   = flag.Bool("l", false, "")
	write  = flag.Bool("w", false, "")
	simple = flag.Bool("s", false, "")
	find   = flag.Bool("f", false, "")
	diff   = flag.Bool("d", false, "")

	langStr = flag.String("ln", "", "")
	posix   = flag.Bool("p", false, "")

	indent      = flag.Uint("i", 0, "")
	binNext     = flag.Bool("bn", false, "")
	caseIndent  = flag.Bool("ci", false, "")
	spaceRedirs = flag.Bool("sr", false, "")
	keepPadding = flag.Bool("kp", false, "")
	minify      = flag.Bool("mn", false, "")

	toJSON = flag.Bool("tojson", false, "")

	parser            *syntax.Parser
	printer           *syntax.Printer
	readBuf, writeBuf bytes.Buffer

	copyBuf = make([]byte, 32*1024)

	in  io.Reader = os.Stdin
	out io.Writer = os.Stdout

	version = "v3.0.0-alpha0"
)

func main() {
	flag.Usage = func() {
		fmt.Fprint(os.Stderr, `usage: shfmt [flags] [path ...]

If no arguments are given, standard input will be used. If a given path
is a directory, it will be recursively searched for shell files - both
by filename extension and by shebang.

  -version  show version and exit

  -l        list files whose formatting differs from shfmt's
  -w        write result to file instead of stdout
  -d        error with a diff when the formatting differs
  -s        simplify the code

Parser options:

  -ln str   language variant to parse (bash/posix/mksh, default "bash")
  -p        shorthand for -ln=posix

Printer options:

  -i uint   indent: 0 for tabs (default), >0 for number of spaces
  -bn       binary ops like && and | may start a line
  -ci       switch cases will be indented
  -sr       redirect operators will be followed by a space
  -kp       keep column alignment paddings
  -mn       minify program to reduce its size (implies -s)

Utilities:

  -f        recursively find all shell files and print the paths
  -tojson   print syntax tree to stdout as a typed JSON
`)
	}
	flag.Parse()

	if *showVersion {
		fmt.Println(version)
		return
	}
	if *posix && *langStr != "" {
		fmt.Fprintf(os.Stderr, "-p and -ln=lang cannot coexist\n")
		os.Exit(1)
	}
	lang := syntax.LangBash
	switch *langStr {
	case "bash", "":
	case "posix":
		lang = syntax.LangPOSIX
	case "mksh":
		lang = syntax.LangMirBSDKorn
	default:
		fmt.Fprintf(os.Stderr, "unknown shell language: %s\n", *langStr)
		os.Exit(1)
	}
	if *posix {
		lang = syntax.LangPOSIX
	}
	if *minify {
		*simple = true
	}
	parser = syntax.NewParser(syntax.KeepComments, syntax.Variant(lang))
	printer = syntax.NewPrinter(func(p *syntax.Printer) {
		syntax.Indent(*indent)(p)
		if *binNext {
			syntax.BinaryNextLine(p)
		}
		if *caseIndent {
			syntax.SwitchCaseIndent(p)
		}
		if *spaceRedirs {
			syntax.SpaceRedirects(p)
		}
		if *keepPadding {
			syntax.KeepPadding(p)
		}
		if *minify {
			syntax.Minify(p)
		}
	})
	if flag.NArg() == 0 {
		if err := formatStdin(); err != nil {
			if err != errChangedWithDiff {
				fmt.Fprintln(os.Stderr, err)
			}
			os.Exit(1)
		}
		return
	}
	if *toJSON {
		fmt.Fprintln(os.Stderr, "-tojson can only be used with stdin/out")
		os.Exit(1)
	}
	anyErr := false
	for _, path := range flag.Args() {
		walk(path, func(err error) {
			if err != errChangedWithDiff {
				fmt.Fprintln(os.Stderr, err)
			}
			anyErr = true
		})
	}
	if anyErr {
		os.Exit(1)
	}
}

var errChangedWithDiff = fmt.Errorf("")

func formatStdin() error {
	if *write {
		return fmt.Errorf("-w cannot be used on standard input")
	}
	src, err := ioutil.ReadAll(in)
	if err != nil {
		return err
	}
	return formatBytes(src, "<standard input>")
}

var vcsDir = regexp.MustCompile(`^\.(git|svn|hg)$`)

func walk(path string, onError func(error)) {
	info, err := os.Stat(path)
	if err != nil {
		onError(err)
		return
	}
	if !info.IsDir() {
		if err := formatPath(path, false); err != nil {
			onError(err)
		}
		return
	}
	filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() && vcsDir.MatchString(info.Name()) {
			return filepath.SkipDir
		}
		if err != nil {
			onError(err)
			return nil
		}
		conf := fileutil.CouldBeScript(info)
		if conf == fileutil.ConfNotScript {
			return nil
		}
		err = formatPath(path, conf == fileutil.ConfIfShebang)
		if err != nil && !os.IsNotExist(err) {
			onError(err)
		}
		return nil
	})
}

func formatPath(path string, checkShebang bool) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()
	readBuf.Reset()
	if checkShebang {
		n, err := f.Read(copyBuf[:32])
		if err != nil {
			return err
		}
		if !fileutil.HasShebang(copyBuf[:n]) {
			return nil
		}
		readBuf.Write(copyBuf[:n])
	}
	if *find {
		fmt.Fprintln(out, path)
		return nil
	}
	if _, err := io.CopyBuffer(&readBuf, f, copyBuf); err != nil {
		return err
	}
	f.Close()
	return formatBytes(readBuf.Bytes(), path)
}

func formatBytes(src []byte, path string) error {
	prog, err := parser.Parse(bytes.NewReader(src), path)
	if err != nil {
		return err
	}
	if *simple {
		syntax.Simplify(prog)
	}
	if *toJSON {
		// must be standard input; fine to return
		return writeJSON(out, prog, true)
	}
	writeBuf.Reset()
	printer.Print(&writeBuf, prog)
	res := writeBuf.Bytes()
	if !bytes.Equal(src, res) {
		if *list {
			if _, err := fmt.Fprintln(out, path); err != nil {
				return err
			}
		}
		if *write {
			f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0)
			if err != nil {
				return err
			}
			if _, err := f.Write(res); err != nil {
				return err
			}
			if err := f.Close(); err != nil {
				return err
			}
		}
		if *diff {
			data, err := diffBytes(src, res, path)
			if err != nil {
				return fmt.Errorf("computing diff: %s", err)
			}
			out.Write(data)
			return errChangedWithDiff
		}
	}
	if !*list && !*write && !*diff {
		if _, err := out.Write(res); err != nil {
			return err
		}
	}
	return nil
}

func writeTempFile(dir, prefix string, data []byte) (string, error) {
	file, err := ioutil.TempFile(dir, prefix)
	if err != nil {
		return "", err
	}
	_, err = file.Write(data)
	if err1 := file.Close(); err == nil {
		err = err1
	}
	if err != nil {
		os.Remove(file.Name())
		return "", err
	}
	return file.Name(), nil
}

func diffBytes(b1, b2 []byte, path string) ([]byte, error) {
	fmt.Fprintf(out, "diff -u %s %s\n",
		filepath.ToSlash(path+".orig"),
		filepath.ToSlash(path))
	f1, err := writeTempFile("", "shfmt", b1)
	if err != nil {
		return nil, err
	}
	defer os.Remove(f1)

	f2, err := writeTempFile("", "shfmt", b2)
	if err != nil {
		return nil, err
	}
	defer os.Remove(f2)

	data, err := exec.Command("diff", "-u", f1, f2).Output()
	if len(data) == 0 {
		// No diff, or something went wrong; don't check for err
		// as diff will return non-zero if the files differ.
		return nil, err
	}
	// We already print the filename, so remove the
	// temporary filenames printed by diff.
	lines := bytes.Split(data, []byte("\n"))
	for i, line := range lines {
		switch {
		case bytes.HasPrefix(line, []byte("---")):
		case bytes.HasPrefix(line, []byte("+++")):
		default:
			return bytes.Join(lines[i:], []byte("\n")), nil
		}
	}
	return data, nil
}
<commit_msg>all: bump to 3.0.0-alpha1<commit_after>// Copyright (c) 2016, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package main

import (
	"bytes"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"

	"mvdan.cc/sh/v3/fileutil"
	"mvdan.cc/sh/v3/syntax"
)

var (
	showVersion = flag.Bool("version", false, "")

	list   = flag.Bool("l", false, "")
	write  = flag.Bool("w", false, "")
	simple = flag.Bool("s", false, "")
	find   = flag.Bool("f", false, "")
	diff   = flag.Bool("d", false, "")

	langStr = flag.String("ln", "", "")
	posix   = flag.Bool("p", false, "")

	indent      = flag.Uint("i", 0, "")
	binNext     = flag.Bool("bn", false, "")
	caseIndent  = flag.Bool("ci", false, "")
	spaceRedirs = flag.Bool("sr", false, "")
	keepPadding = flag.Bool("kp", false, "")
	minify      = flag.Bool("mn", false, "")

	toJSON = flag.Bool("tojson", false, "")

	parser            *syntax.Parser
	printer           *syntax.Printer
	readBuf, writeBuf bytes.Buffer

	copyBuf = make([]byte, 32*1024)

	in  io.Reader = os.Stdin
	out io.Writer = os.Stdout

	version = "v3.0.0-alpha1"
)

func main() {
	flag.Usage = func() {
		fmt.Fprint(os.Stderr, `usage: shfmt [flags] [path ...]

If no arguments are given, standard input will be used. If a given path
is a directory, it will be recursively searched for shell files - both
by filename extension and by shebang.

  -version  show version and exit

  -l        list files whose formatting differs from shfmt's
  -w        write result to file instead of stdout
  -d        error with a diff when the formatting differs
  -s        simplify the code

Parser options:

  -ln str   language variant to parse (bash/posix/mksh, default "bash")
  -p        shorthand for -ln=posix

Printer options:

  -i uint   indent: 0 for tabs (default), >0 for number of spaces
  -bn       binary ops like && and | may start a line
  -ci       switch cases will be indented
  -sr       redirect operators will be followed by a space
  -kp       keep column alignment paddings
  -mn       minify program to reduce its size (implies -s)

Utilities:

  -f        recursively find all shell files and print the paths
  -tojson   print syntax tree to stdout as a typed JSON
`)
	}
	flag.Parse()

	if *showVersion {
		fmt.Println(version)
		return
	}
	if *posix && *langStr != "" {
		fmt.Fprintf(os.Stderr, "-p and -ln=lang cannot coexist\n")
		os.Exit(1)
	}
	lang := syntax.LangBash
	switch *langStr {
	case "bash", "":
	case "posix":
		lang = syntax.LangPOSIX
	case "mksh":
		lang = syntax.LangMirBSDKorn
	default:
		fmt.Fprintf(os.Stderr, "unknown shell language: %s\n", *langStr)
		os.Exit(1)
	}
	if *posix {
		lang = syntax.LangPOSIX
	}
	if *minify {
		*simple = true
	}
	parser = syntax.NewParser(syntax.KeepComments, syntax.Variant(lang))
	printer = syntax.NewPrinter(func(p *syntax.Printer) {
		syntax.Indent(*indent)(p)
		if *binNext {
			syntax.BinaryNextLine(p)
		}
		if *caseIndent {
			syntax.SwitchCaseIndent(p)
		}
		if *spaceRedirs {
			syntax.SpaceRedirects(p)
		}
		if *keepPadding {
			syntax.KeepPadding(p)
		}
		if *minify {
			syntax.Minify(p)
		}
	})
	if flag.NArg() == 0 {
		if err := formatStdin(); err != nil {
			if err != errChangedWithDiff {
				fmt.Fprintln(os.Stderr, err)
			}
			os.Exit(1)
		}
		return
	}
	if *toJSON {
		fmt.Fprintln(os.Stderr, "-tojson can only be used with stdin/out")
		os.Exit(1)
	}
	anyErr := false
	for _, path := range flag.Args() {
		walk(path, func(err error) {
			if err != errChangedWithDiff {
				fmt.Fprintln(os.Stderr, err)
			}
			anyErr = true
		})
	}
	if anyErr {
		os.Exit(1)
	}
}

var errChangedWithDiff = fmt.Errorf("")

func formatStdin() error {
	if *write {
		return fmt.Errorf("-w cannot be used on standard input")
	}
	src, err := ioutil.ReadAll(in)
	if err != nil {
		return err
	}
	return formatBytes(src, "<standard input>")
}

var vcsDir = regexp.MustCompile(`^\.(git|svn|hg)$`)

func walk(path string, onError func(error)) {
	info, err := os.Stat(path)
	if err != nil {
		onError(err)
		return
	}
	if !info.IsDir() {
		if err := formatPath(path, false); err != nil {
			onError(err)
		}
		return
	}
	filepath.Walk(path, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() && vcsDir.MatchString(info.Name()) {
			return filepath.SkipDir
		}
		if err != nil {
			onError(err)
			return nil
		}
		conf := fileutil.CouldBeScript(info)
		if conf == fileutil.ConfNotScript {
			return nil
		}
		err = formatPath(path, conf == fileutil.ConfIfShebang)
		if err != nil && !os.IsNotExist(err) {
			onError(err)
		}
		return nil
	})
}

func formatPath(path string, checkShebang bool) error {
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()
	readBuf.Reset()
	if checkShebang {
		n, err := f.Read(copyBuf[:32])
		if err != nil {
			return err
		}
		if !fileutil.HasShebang(copyBuf[:n]) {
			return nil
		}
		readBuf.Write(copyBuf[:n])
	}
	if *find {
		fmt.Fprintln(out, path)
		return nil
	}
	if _, err := io.CopyBuffer(&readBuf, f, copyBuf); err != nil {
		return err
	}
	f.Close()
	return formatBytes(readBuf.Bytes(), path)
}

func formatBytes(src []byte, path string) error {
	prog, err := parser.Parse(bytes.NewReader(src), path)
	if err != nil {
		return err
	}
	if *simple {
		syntax.Simplify(prog)
	}
	if *toJSON {
		// must be standard input; fine to return
		return writeJSON(out, prog, true)
	}
	writeBuf.Reset()
	printer.Print(&writeBuf, prog)
	res := writeBuf.Bytes()
	if !bytes.Equal(src, res) {
		if *list {
			if _, err := fmt.Fprintln(out, path); err != nil {
				return err
			}
		}
		if *write {
			f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0)
			if err != nil {
				return err
			}
			if _, err := f.Write(res); err != nil {
				return err
			}
			if err := f.Close(); err != nil {
				return err
			}
		}
		if *diff {
			data, err := diffBytes(src, res, path)
			if err != nil {
				return fmt.Errorf("computing diff: %s", err)
			}
			out.Write(data)
			return errChangedWithDiff
		}
	}
	if !*list && !*write && !*diff {
		if _, err := out.Write(res); err != nil {
			return err
		}
	}
	return nil
}

func writeTempFile(dir, prefix string, data []byte) (string, error) {
	file, err := ioutil.TempFile(dir, prefix)
	if err != nil {
		return "", err
	}
	_, err = file.Write(data)
	if err1 := file.Close(); err == nil {
		err = err1
	}
	if err != nil {
		os.Remove(file.Name())
		return "", err
	}
	return file.Name(), nil
}

func diffBytes(b1, b2 []byte, path string) ([]byte, error) {
	fmt.Fprintf(out, "diff -u %s %s\n",
		filepath.ToSlash(path+".orig"),
		filepath.ToSlash(path))
	f1, err := writeTempFile("", "shfmt", b1)
	if err != nil {
		return nil, err
	}
	defer os.Remove(f1)

	f2, err := writeTempFile("", "shfmt", b2)
	if err != nil {
		return nil, err
	}
	defer os.Remove(f2)

	data, err := exec.Command("diff", "-u", f1, f2).Output()
	if len(data) == 0 {
		// No diff, or something went wrong; don't check for err
		// as diff will return non-zero if the files differ.
		return nil, err
	}
	// We already print the filename, so remove the
	// temporary filenames printed by diff.
	lines := bytes.Split(data, []byte("\n"))
	for i, line := range lines {
		switch {
		case bytes.HasPrefix(line, []byte("---")):
		case bytes.HasPrefix(line, []byte("+++")):
		default:
			return bytes.Join(lines[i:], []byte("\n")), nil
		}
	}
	return data, nil
}
<|endoftext|>


<commit_before>package helpers

// The StringWriter type
type StringWriter struct {
	Bytes []byte
}

// Making a new StringWriter
func NewStringWriter() *StringWriter {
	return &StringWriter{
		Bytes: make([]byte, 0),
	}
}

// Writing bytes to the string writer
func (this *StringWriter) Write(p []byte) (int, error) {
	this.Bytes = append(this.Bytes, p...)
	return len(p), nil
}

// Converting the StringWriter's bytes to a string
func (this *StringWriter) String() string { return string(this.Bytes) }
<commit_msg>Revert "Forgot to add a dependency for the new templater functions."<commit_after><|endoftext|>


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

// boot allows to handover a system running linuxboot/u-root
// to a legacy preinstalled operating system by replacing the traditional
// bootloader path

//
// Synopsis:
//	boot
//
// Description:
//	If returns to u-root shell, the code didn't found a local bootable option
//
// Notes:
//	The code is looking for boot/grub/grub.cfg file as to identify the
//	boot option.
//	The first bootable device found in the block device tree is the one used
//	Windows is not supported (that is a work in progress)
//
// Example:
//	boot -v 	- Start the script in verbose mode for debugging purpose

package main

import (
	"bufio"
	"encoding/binary"
	"errors"
	"fmt"
	"github.com/u-root/u-root/pkg/kexec"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"flag"
	"syscall"
)

const (
	bootableMBR = 0xaa55
	signatureOffset = 510
)

var verbose bool
type options struct {
        verbose bool
}

func blkDevicesList(blkpath string, devpath string) ([]string,error) {
	var blkDevices []string
	files, err := ioutil.ReadDir(blkpath)
	if err != nil {
		return blkDevices,err
	}
	for _, file := range files {
		check,err := os.Stat(blkpath + file.Name() + devpath)
		if ( check == nil ) {
                        continue
                }
                if ( err != nil ) {
                        continue
                }
		deviceEntry, err := ioutil.ReadDir(blkpath + file.Name() + devpath)
		if err != nil {
			if ( verbose ) {
				log.Printf("can t read directory")
			}
			continue
		}
		blkDevices = append(blkDevices, deviceEntry[0].Name())
	}
	return blkDevices,nil
}

// checkForBootableMBR is looking for bootable MBR signature
// Current support is limited to Hard disk devices and USB devices
func checkForBootableMBR(path string) error {
	var sig uint16
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	if err := binary.Read(io.NewSectionReader(f, signatureOffset, 2), binary.LittleEndian, &sig); err != nil {
		return err
	}
	if sig != bootableMBR {
		err := errors.New("Not a bootable device")
		return err
	}
	return nil
}

// getDevicePartList returns all devices attached to a specific name like /dev/sdaX where X can move from 0 to 127
// FIXME no support for devices which are included into subdirectory within /dev
func getDevicePartList(path string) ([]string,error) {
	var returnValue []string
	files, err := ioutil.ReadDir("/dev/")
	if err != nil {
		return returnValue, err
	}
	for _, file := range files {
		if strings.HasPrefix(file.Name(), path) {
			// We shall not return full device name
			if file.Name() != path {
				// We shall check that the remaining part is a number
				returnValue = append(returnValue, file.Name())
			}
		}
	}
	return returnValue, nil
}

// getSupportedFilesystem returns all block file system supported by the linuxboot kernel
func getSupportedFilesystem() ([]string, error) {
	var returnValue []string
	var err error
	fs, err := ioutil.ReadFile("/proc/filesystems")
	if err != nil {
		return returnValue, err
	}
	for _, f := range strings.Split(string(fs), "\n") {
		n := strings.Fields(f)
		if len(n) != 1 {
			continue
		}
		returnValue=append(returnValue,n[0])
	}
	return returnValue, err

}

// mountEntry tries to mount a specific block device
func mountEntry(path string, supportedFilesystem []string) (bool,error) {
	var returnValue bool
	var err error
	exist, err := os.Stat("/u-root")
        if exist == nil {
                err=syscall.Mkdir("/u-root", 0777)
                if ( err != nil ) {
                        return false,err
                }
        }
	var flags uintptr
	// Was supposed to be unecessary for kernel 4.x.x
	if verbose {
		log.Printf("/dev/" + path)
	}
	for _, filesystem := range supportedFilesystem {
		flags = syscall.MS_MGC_VAL
		// Need to load the filesystem kind supported
		exist, err = os.Stat("/u-root/"+path)
                if exist == nil {
                        err = syscall.Mkdir("/u-root/"+path, 0777)
                        if ( err != nil ) {
                                return false,err
                        }
                }
		err := syscall.Mount("/dev/"+path, "/u-root/"+path, filesystem, flags, "")
		if err == nil {
			return true, nil
		}
	}
	returnValue = false
	return returnValue, nil
}

func umountEntry(path string) bool {
	var returnValue bool
	var flags int
	// Was supposed to be unecessary for kernel 4.x.x
	flags = syscall.MNT_DETACH
	err := syscall.Unmount(path, flags)
	if err == nil {
		return true
	}
	returnValue = false
	return returnValue
}

// checkBootEntry is looking for grub.cfg file
// and return absolute path to it
func checkBootEntry(mountPoint string) string {
	_, err := os.Stat(mountPoint + "/boot")
	if err == nil {
		// The boot directory is there
		_, err2 := os.Stat(mountPoint + "/boot" + "/grub")
		if err2 == nil {
			_, err3 := os.Stat(mountPoint + "/boot" + "/grub" + "/grub.cfg")
			if err3 == nil {
				// found
				return (mountPoint + "/boot" + "/grub")
			}
		}
	}
	return ""

}

// getFileMenuContent is parsing a grub.cfg file
// input: absolute directory path to grub.cfg
// output: Return a list of strings with the following format
//	 line[3*x] - menuconfig
//	 line[3*x+1] - linux kernel + boot options
// 	 line[3*x+2] - initrd
// and the default boot entry configured into grub.cfg
func getFileMenuContent(path string) ([]string, int, error) {
	var returnValue []string
	var err error
	file, err := os.Open(path + "/grub.cfg")
	if ( err != nil ) {
		return returnValue,0,err
	}
	scanner := bufio.NewScanner(file)
	if err = scanner.Err(); err != nil {
		return returnValue,0,err
	}
	var status int
	var intReturn int
	intReturn = 0
	status = 0
	// When status = 0 we are looking for a menu entry
	// When status = 1 we are looking for a linux entry
	// When status = 2 we are looking for a initrd entry
	var trimmedLine string
	for scanner.Scan() {
		trimmedLine = strings.TrimSpace(scanner.Text())
		trimmedLine = strings.Join(strings.Fields(trimmedLine), " ")
		if strings.HasPrefix(trimmedLine, "#") {
			continue
		}
		if (strings.HasPrefix(trimmedLine, "set default=") ) && (status == 0) {
			fmt.Sscanf(trimmedLine, "set default=\"%d\"", &intReturn)
		}
		if (strings.HasPrefix(trimmedLine, "menuentry ")) && (status == 0) {
			status = 1
			returnValue = append(returnValue, trimmedLine)
		}
		if (strings.HasPrefix(trimmedLine, "linux ")) && (status == 1) {
			status = 2
			returnValue = append(returnValue, trimmedLine)
		}
		if (strings.HasPrefix(trimmedLine, "initrd ")) && (status == 2) {
			status = 0
			returnValue = append(returnValue, trimmedLine)
		}
	}
	err = file.Close()
	return returnValue, intReturn, err

}

func copyLocal(path string) (string,error) {
	var dest string
	var err error
	result := strings.Split(path, "/")
	for _, entry := range result {
		dest = entry
	}
	dest = "/tmp/" + dest
	srcFile, err := os.Open(path)
	if ( err != nil ) {
		return dest, err
	}

	destFile, err := os.Create(dest) // creates if file doesn't exist
	if ( err != nil ) {
		return dest, err
        }

	_, err = io.Copy(destFile, srcFile) // check first var for number of bytes copied
	if ( err != nil ) {
		return dest, err
        }

	err = destFile.Sync()
	if ( err != nil ) {
		return dest, err
        }
	err = destFile.Close()
	if ( err != nil ) {
		return dest, err
        }
	err = srcFile.Close()
	if ( err != nil ) {
		return dest, err
        }
	return dest, nil
}

// kexecEntry is booting new kernel based on the content of grub.cfg
func kexecEntry(grubConfPath string, mountPoint string) error {
	var fileMenuContent []string
	var entry int
	var localKernelPath string
	var localInitrdPath string
	if verbose {
		log.Printf(grubConfPath)
	}
	fileMenuContent, entry, err := getFileMenuContent(grubConfPath)
	if ( err != nil ) {
		return err
	}
	var kernel string
	var kernelParameter string
	var initrd string
	var kernelInfos []string
	kernelInfos = strings.Fields(fileMenuContent[3*entry+1])
	kernel = kernelInfos[1]
	var count int
	count = 0
	for _, field := range kernelInfos {
		if count > 1 {
			kernelParameter = kernelParameter + " " + field
		}
		count = count + 1
	}
	fmt.Sscanf(fileMenuContent[3*entry+2], "initrd %s", &initrd)
	if verbose {
		log.Printf("************** boot parameters  ********************")
		log.Printf(kernel)
		log.Printf(kernelParameter)
		log.Printf(initrd)
		log.Printf("****************************************************")
	}
	localKernelPath,err = copyLocal(mountPoint + kernel)
	if ( err != nil ) {
		return err
	}
	localInitrdPath,err = copyLocal(mountPoint + initrd)
	if ( err != nil ) {
		return err
	}
	if verbose {
		log.Printf(localKernelPath)
	}
	umountEntry(mountPoint)
	// We can kexec the kernel with localKernelPath as kernel entry, kernelParameter as parameter and initrd as initrd !
	log.Printf("Loading %s for kernel\n", localKernelPath)

	kernelDesc, err := os.OpenFile(localKernelPath, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	// defer kernelDesc.Close()

	var ramfs *os.File
	ramfs, err = os.OpenFile(localInitrdPath, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	// defer ramfs.Close()

	if err := kexec.FileLoad(kernelDesc, ramfs, kernelParameter); err != nil {
		return err
	}
 	err = ramfs.Close()
	if ( err != nil ) {
		return err
	}
	err = kernelDesc.Close()
	if ( err != nil ) {
		return err
	}
	if err := kexec.Reboot(); err != nil {
		return err
	}
	return err

}

// init parse input parameters
func init {
        flag.CommandLine..BoolVar(&verbose, "v", false, "Set verbose output")
}

func main() {
	var blkList []string
	var supportedFilesystem []string
	verbose = false
	flag.Parse()

	supportedFilesystem, err := getSupportedFilesystem()
	if ( err != nil ) {
                log.Panic("No filesystem support found")
        }
	if verbose {
		log.Printf("************** Supported Filesystem by current linuxboot ********************")
		for _, filesystem := range supportedFilesystem {
			log.Printf(filesystem)
		}
		log.Printf("*****************************************************************************")
	}
	blkList,err = blkDevicesList("/sys/dev/block/", "/device/block/")
	if ( err != nil ) {
		log.Fatal("No available block devices to boot from")
	}
	// We must validate if the MBR is bootable or not and keep the
	// devices which do have such support
	// drive are easy to detect
	for _, entry := range blkList {
		dev := filepath.Join("/dev", entry)
		err := checkForBootableMBR(dev)
		if err != nil {
			// Not sure it matters; there can be many bogus entries?
			log.Printf("MBR for %s failed: %v", dev, err)
			continue
		}
		fmt.Println("Bootable device found")
		// We need to loop on the device entries which are into /dev/<device>X
		// and mount each partitions as to find /boot entry if it is available somewhere
		var devicePartList []string
		devicePartList,err = getDevicePartList(entry)
		if ( err != nil ) {
			continue
		}
		for _, deviceList := range devicePartList {
			mount, err := mountEntry(deviceList, supportedFilesystem)
			if ( err != nil ) {
				continue
			}
			if mount {
				if verbose {
					log.Printf("mount succeed")
				}
				var grubConfPath = checkBootEntry("/u-root/" + deviceList)
				if grubConfPath != "" {
					if verbose {
						log.Printf("calling basic kexec")
					}
					err = kexecEntry(grubConfPath, "/u-root/"+deviceList)
					if ( err != nil ) {
						log.Fatal("kexec failed")
					}
				}
			}
			umountEntry("/u-root/" + deviceList)
		}
	}
	log.Printf("Sorry no bootable device found")
}
<commit_msg>Move parameter parsing to init function<commit_after>// Copyright 2012-2017 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// boot allows to handover a system running linuxboot/u-root
// to a legacy preinstalled operating system by replacing the traditional
// bootloader path

//
// Synopsis:
//	boot
//
// Description:
//	If returns to u-root shell, the code didn't found a local bootable option
//
// Notes:
//	The code is looking for boot/grub/grub.cfg file as to identify the
//	boot option.
//	The first bootable device found in the block device tree is the one used
//	Windows is not supported (that is a work in progress)
//
// Example:
//	boot -v 	- Start the script in verbose mode for debugging purpose

package main

import (
	"bufio"
	"encoding/binary"
	"errors"
	"fmt"
	"github.com/u-root/u-root/pkg/kexec"
	"io"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"strings"
	"flag"
	"syscall"
)

const (
	bootableMBR = 0xaa55
	signatureOffset = 510
)

var verbose bool
type options struct {
        verbose bool
}

func blkDevicesList(blkpath string, devpath string) ([]string,error) {
	var blkDevices []string
	files, err := ioutil.ReadDir(blkpath)
	if err != nil {
		return blkDevices,err
	}
	for _, file := range files {
		check,err := os.Stat(blkpath + file.Name() + devpath)
		if ( check == nil ) {
                        continue
                }
                if ( err != nil ) {
                        continue
                }
		deviceEntry, err := ioutil.ReadDir(blkpath + file.Name() + devpath)
		if err != nil {
			if ( verbose ) {
				log.Printf("can t read directory")
			}
			continue
		}
		blkDevices = append(blkDevices, deviceEntry[0].Name())
	}
	return blkDevices,nil
}

// checkForBootableMBR is looking for bootable MBR signature
// Current support is limited to Hard disk devices and USB devices
func checkForBootableMBR(path string) error {
	var sig uint16
	f, err := os.Open(path)
	if err != nil {
		return err
	}
	if err := binary.Read(io.NewSectionReader(f, signatureOffset, 2), binary.LittleEndian, &sig); err != nil {
		return err
	}
	if sig != bootableMBR {
		err := errors.New("Not a bootable device")
		return err
	}
	return nil
}

// getDevicePartList returns all devices attached to a specific name like /dev/sdaX where X can move from 0 to 127
// FIXME no support for devices which are included into subdirectory within /dev
func getDevicePartList(path string) ([]string,error) {
	var returnValue []string
	files, err := ioutil.ReadDir("/dev/")
	if err != nil {
		return returnValue, err
	}
	for _, file := range files {
		if strings.HasPrefix(file.Name(), path) {
			// We shall not return full device name
			if file.Name() != path {
				// We shall check that the remaining part is a number
				returnValue = append(returnValue, file.Name())
			}
		}
	}
	return returnValue, nil
}

// getSupportedFilesystem returns all block file system supported by the linuxboot kernel
func getSupportedFilesystem() ([]string, error) {
	var returnValue []string
	var err error
	fs, err := ioutil.ReadFile("/proc/filesystems")
	if err != nil {
		return returnValue, err
	}
	for _, f := range strings.Split(string(fs), "\n") {
		n := strings.Fields(f)
		if len(n) != 1 {
			continue
		}
		returnValue=append(returnValue,n[0])
	}
	return returnValue, err

}

// mountEntry tries to mount a specific block device
func mountEntry(path string, supportedFilesystem []string) (bool,error) {
	var returnValue bool
	var err error
	exist, err := os.Stat("/u-root")
        if exist == nil {
                err=syscall.Mkdir("/u-root", 0777)
                if ( err != nil ) {
                        return false,err
                }
        }
	var flags uintptr
	// Was supposed to be unecessary for kernel 4.x.x
	if verbose {
		log.Printf("/dev/" + path)
	}
	for _, filesystem := range supportedFilesystem {
		flags = syscall.MS_MGC_VAL
		// Need to load the filesystem kind supported
		exist, err = os.Stat("/u-root/"+path)
                if exist == nil {
                        err = syscall.Mkdir("/u-root/"+path, 0777)
                        if ( err != nil ) {
                                return false,err
                        }
                }
		err := syscall.Mount("/dev/"+path, "/u-root/"+path, filesystem, flags, "")
		if err == nil {
			return true, nil
		}
	}
	returnValue = false
	return returnValue, nil
}

func umountEntry(path string) bool {
	var returnValue bool
	var flags int
	// Was supposed to be unecessary for kernel 4.x.x
	flags = syscall.MNT_DETACH
	err := syscall.Unmount(path, flags)
	if err == nil {
		return true
	}
	returnValue = false
	return returnValue
}

// checkBootEntry is looking for grub.cfg file
// and return absolute path to it
func checkBootEntry(mountPoint string) string {
	_, err := os.Stat(mountPoint + "/boot")
	if err == nil {
		// The boot directory is there
		_, err2 := os.Stat(mountPoint + "/boot" + "/grub")
		if err2 == nil {
			_, err3 := os.Stat(mountPoint + "/boot" + "/grub" + "/grub.cfg")
			if err3 == nil {
				// found
				return (mountPoint + "/boot" + "/grub")
			}
		}
	}
	return ""

}

// getFileMenuContent is parsing a grub.cfg file
// input: absolute directory path to grub.cfg
// output: Return a list of strings with the following format
//	 line[3*x] - menuconfig
//	 line[3*x+1] - linux kernel + boot options
// 	 line[3*x+2] - initrd
// and the default boot entry configured into grub.cfg
func getFileMenuContent(path string) ([]string, int, error) {
	var returnValue []string
	var err error
	file, err := os.Open(path + "/grub.cfg")
	if ( err != nil ) {
		return returnValue,0,err
	}
	scanner := bufio.NewScanner(file)
	if err = scanner.Err(); err != nil {
		return returnValue,0,err
	}
	var status int
	var intReturn int
	intReturn = 0
	status = 0
	// When status = 0 we are looking for a menu entry
	// When status = 1 we are looking for a linux entry
	// When status = 2 we are looking for a initrd entry
	var trimmedLine string
	for scanner.Scan() {
		trimmedLine = strings.TrimSpace(scanner.Text())
		trimmedLine = strings.Join(strings.Fields(trimmedLine), " ")
		if strings.HasPrefix(trimmedLine, "#") {
			continue
		}
		if (strings.HasPrefix(trimmedLine, "set default=") ) && (status == 0) {
			fmt.Sscanf(trimmedLine, "set default=\"%d\"", &intReturn)
		}
		if (strings.HasPrefix(trimmedLine, "menuentry ")) && (status == 0) {
			status = 1
			returnValue = append(returnValue, trimmedLine)
		}
		if (strings.HasPrefix(trimmedLine, "linux ")) && (status == 1) {
			status = 2
			returnValue = append(returnValue, trimmedLine)
		}
		if (strings.HasPrefix(trimmedLine, "initrd ")) && (status == 2) {
			status = 0
			returnValue = append(returnValue, trimmedLine)
		}
	}
	err = file.Close()
	return returnValue, intReturn, err

}

func copyLocal(path string) (string,error) {
	var dest string
	var err error
	result := strings.Split(path, "/")
	for _, entry := range result {
		dest = entry
	}
	dest = "/tmp/" + dest
	srcFile, err := os.Open(path)
	if ( err != nil ) {
		return dest, err
	}

	destFile, err := os.Create(dest) // creates if file doesn't exist
	if ( err != nil ) {
		return dest, err
        }

	_, err = io.Copy(destFile, srcFile) // check first var for number of bytes copied
	if ( err != nil ) {
		return dest, err
        }

	err = destFile.Sync()
	if ( err != nil ) {
		return dest, err
        }
	err = destFile.Close()
	if ( err != nil ) {
		return dest, err
        }
	err = srcFile.Close()
	if ( err != nil ) {
		return dest, err
        }
	return dest, nil
}

// kexecEntry is booting new kernel based on the content of grub.cfg
func kexecEntry(grubConfPath string, mountPoint string) error {
	var fileMenuContent []string
	var entry int
	var localKernelPath string
	var localInitrdPath string
	if verbose {
		log.Printf(grubConfPath)
	}
	fileMenuContent, entry, err := getFileMenuContent(grubConfPath)
	if ( err != nil ) {
		return err
	}
	var kernel string
	var kernelParameter string
	var initrd string
	var kernelInfos []string
	kernelInfos = strings.Fields(fileMenuContent[3*entry+1])
	kernel = kernelInfos[1]
	var count int
	count = 0
	for _, field := range kernelInfos {
		if count > 1 {
			kernelParameter = kernelParameter + " " + field
		}
		count = count + 1
	}
	fmt.Sscanf(fileMenuContent[3*entry+2], "initrd %s", &initrd)
	if verbose {
		log.Printf("************** boot parameters  ********************")
		log.Printf(kernel)
		log.Printf(kernelParameter)
		log.Printf(initrd)
		log.Printf("****************************************************")
	}
	localKernelPath,err = copyLocal(mountPoint + kernel)
	if ( err != nil ) {
		return err
	}
	localInitrdPath,err = copyLocal(mountPoint + initrd)
	if ( err != nil ) {
		return err
	}
	if verbose {
		log.Printf(localKernelPath)
	}
	umountEntry(mountPoint)
	// We can kexec the kernel with localKernelPath as kernel entry, kernelParameter as parameter and initrd as initrd !
	log.Printf("Loading %s for kernel\n", localKernelPath)

	kernelDesc, err := os.OpenFile(localKernelPath, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	// defer kernelDesc.Close()

	var ramfs *os.File
	ramfs, err = os.OpenFile(localInitrdPath, os.O_RDONLY, 0)
	if err != nil {
		return err
	}
	// defer ramfs.Close()

	if err := kexec.FileLoad(kernelDesc, ramfs, kernelParameter); err != nil {
		return err
	}
 	err = ramfs.Close()
	if ( err != nil ) {
		return err
	}
	err = kernelDesc.Close()
	if ( err != nil ) {
		return err
	}
	if err := kexec.Reboot(); err != nil {
		return err
	}
	return err

}

// init parse input parameters
func init() {
        flag.CommandLine..BoolVar(&verbose, "v", false, "Set verbose output")
}

func main() {
	var blkList []string
	var supportedFilesystem []string
	verbose = false
	flag.Parse()

	supportedFilesystem, err := getSupportedFilesystem()
	if ( err != nil ) {
                log.Panic("No filesystem support found")
        }
	if verbose {
		log.Printf("************** Supported Filesystem by current linuxboot ********************")
		for _, filesystem := range supportedFilesystem {
			log.Printf(filesystem)
		}
		log.Printf("*****************************************************************************")
	}
	blkList,err = blkDevicesList("/sys/dev/block/", "/device/block/")
	if ( err != nil ) {
		log.Fatal("No available block devices to boot from")
	}
	// We must validate if the MBR is bootable or not and keep the
	// devices which do have such support
	// drive are easy to detect
	for _, entry := range blkList {
		dev := filepath.Join("/dev", entry)
		err := checkForBootableMBR(dev)
		if err != nil {
			// Not sure it matters; there can be many bogus entries?
			log.Printf("MBR for %s failed: %v", dev, err)
			continue
		}
		fmt.Println("Bootable device found")
		// We need to loop on the device entries which are into /dev/<device>X
		// and mount each partitions as to find /boot entry if it is available somewhere
		var devicePartList []string
		devicePartList,err = getDevicePartList(entry)
		if ( err != nil ) {
			continue
		}
		for _, deviceList := range devicePartList {
			mount, err := mountEntry(deviceList, supportedFilesystem)
			if ( err != nil ) {
				continue
			}
			if mount {
				if verbose {
					log.Printf("mount succeed")
				}
				var grubConfPath = checkBootEntry("/u-root/" + deviceList)
				if grubConfPath != "" {
					if verbose {
						log.Printf("calling basic kexec")
					}
					err = kexecEntry(grubConfPath, "/u-root/"+deviceList)
					if ( err != nil ) {
						log.Fatal("kexec failed")
					}
				}
			}
			umountEntry("/u-root/" + deviceList)
		}
	}
	log.Printf("Sorry no bootable device found")
}
<|endoftext|>


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

package api

import (
	"encoding/json"
	"net/http"

	"github.com/ajg/form"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/auth"
	tsuruErrors "github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/iaas"
	"github.com/tsuru/tsuru/permission"
	"github.com/tsuru/tsuru/provision/cluster"
	"github.com/tsuru/tsuru/provision/pool"
)

func createClusterMachine(c *cluster.Cluster) error {
	if len(c.CreateData) == 0 {
		return nil
	}
	if templateName, ok := c.CreateData["template"]; ok {
		var err error
		c.CreateData, err = iaas.ExpandTemplate(templateName, c.CreateData)
		if err != nil {
			return err
		}
	}
	m, err := iaas.CreateMachine(c.CreateData)
	if err != nil {
		return err
	}
	c.Addresses = append(c.Addresses, m.FormatNodeAddress())
	c.CaCert = m.CaCert
	c.ClientCert = m.ClientCert
	c.ClientKey = m.ClientKey
	return nil
}

// title: create provisioner cluster
// path: /provisioner/clusters
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
//   404: Pool not does not exist
//   409: Cluster already exists
func createCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterCreate)
	if !allowed {
		return permission.ErrUnauthorized
	}
	dec := form.NewDecoder(nil)
	dec.IgnoreCase(true)
	dec.IgnoreUnknownKeys(true)
	var provCluster cluster.Cluster
	err = r.ParseForm()
	if err == nil {
		err = dec.DecodeValues(&provCluster, r.Form)
	}
	if err != nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: provCluster.Name},
		Kind:       permission.PermClusterCreate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	_, err = cluster.ByName(provCluster.Name)
	if err == nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusConflict,
			Message: "cluster already exists",
		}
	}
	for _, poolName := range provCluster.Pools {
		_, err = pool.GetPoolByName(poolName)
		if err != nil {
			if err == pool.ErrPoolNotFound {
				return &tsuruErrors.HTTP{
					Code:    http.StatusNotFound,
					Message: err.Error(),
				}
			}
			return err
		}
	}
	err = createClusterMachine(&provCluster)
	if err != nil {
		return err
	}
	err = provCluster.Save()
	if err != nil {
		return errors.WithStack(err)
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

// title: update provisioner cluster
// path: /provisioner/clusters/{name}
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
//   404: Cluster not found
func updateCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterUpdate)
	if !allowed {
		return permission.ErrUnauthorized
	}
	dec := form.NewDecoder(nil)
	dec.IgnoreCase(true)
	dec.IgnoreUnknownKeys(true)
	var provCluster cluster.Cluster
	err = r.ParseForm()
	if err == nil {
		err = dec.DecodeValues(&provCluster, r.Form)
	}
	provCluster.Name = r.URL.Query().Get(":name")
	if err != nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: provCluster.Name},
		Kind:       permission.PermClusterUpdate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	_, err = cluster.ByName(provCluster.Name)
	if err != nil {
		if err == cluster.ErrClusterNotFound {
			return &tsuruErrors.HTTP{
				Code:    http.StatusNotFound,
				Message: err.Error(),
			}
		}
		return err
	}
	err = provCluster.Save()
	if err != nil {
		return errors.WithStack(err)
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

// title: list provisioner clusters
// path: /provisioner/clusters
// method: GET
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   204: No Content
//   401: Unauthorized
func listClusters(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterRead)
	if !allowed {
		return permission.ErrUnauthorized
	}
	clusters, err := cluster.AllClusters()
	if err != nil {
		if err == cluster.ErrNoCluster {
			w.WriteHeader(http.StatusNoContent)
			return nil
		}
		return err
	}
	return json.NewEncoder(w).Encode(clusters)
}

// title: delete provisioner cluster
// path: /provisioner/clusters/{name}
// method: GET
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   401: Unauthorized
//   404: Cluster not found
func deleteCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterDelete)
	if !allowed {
		return permission.ErrUnauthorized
	}
	r.ParseForm()
	clusterName := r.URL.Query().Get(":name")
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: clusterName},
		Kind:       permission.PermClusterDelete,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	err = cluster.DeleteCluster(clusterName)
	if err != nil {
		if errors.Cause(err) == cluster.ErrClusterNotFound {
			return &tsuruErrors.HTTP{
				Code:    http.StatusNotFound,
				Message: err.Error(),
			}
		}
		return err
	}
	return nil
}
<commit_msg>Check if pools exist when updating a cluster<commit_after>// Copyright 2017 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package api

import (
	"encoding/json"
	"net/http"

	"github.com/ajg/form"
	"github.com/pkg/errors"
	"github.com/tsuru/tsuru/auth"
	tsuruErrors "github.com/tsuru/tsuru/errors"
	"github.com/tsuru/tsuru/event"
	"github.com/tsuru/tsuru/iaas"
	"github.com/tsuru/tsuru/permission"
	"github.com/tsuru/tsuru/provision/cluster"
	"github.com/tsuru/tsuru/provision/pool"
)

func createClusterMachine(c *cluster.Cluster) error {
	if len(c.CreateData) == 0 {
		return nil
	}
	if templateName, ok := c.CreateData["template"]; ok {
		var err error
		c.CreateData, err = iaas.ExpandTemplate(templateName, c.CreateData)
		if err != nil {
			return err
		}
	}
	m, err := iaas.CreateMachine(c.CreateData)
	if err != nil {
		return err
	}
	c.Addresses = append(c.Addresses, m.FormatNodeAddress())
	c.CaCert = m.CaCert
	c.ClientCert = m.ClientCert
	c.ClientKey = m.ClientKey
	return nil
}

// title: create provisioner cluster
// path: /provisioner/clusters
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
//   404: Pool not does not exist
//   409: Cluster already exists
func createCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterCreate)
	if !allowed {
		return permission.ErrUnauthorized
	}
	dec := form.NewDecoder(nil)
	dec.IgnoreCase(true)
	dec.IgnoreUnknownKeys(true)
	var provCluster cluster.Cluster
	err = r.ParseForm()
	if err == nil {
		err = dec.DecodeValues(&provCluster, r.Form)
	}
	if err != nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: provCluster.Name},
		Kind:       permission.PermClusterCreate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	_, err = cluster.ByName(provCluster.Name)
	if err == nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusConflict,
			Message: "cluster already exists",
		}
	}
	for _, poolName := range provCluster.Pools {
		_, err = pool.GetPoolByName(poolName)
		if err != nil {
			if err == pool.ErrPoolNotFound {
				return &tsuruErrors.HTTP{
					Code:    http.StatusNotFound,
					Message: err.Error(),
				}
			}
			return err
		}
	}
	err = createClusterMachine(&provCluster)
	if err != nil {
		return err
	}
	err = provCluster.Save()
	if err != nil {
		return errors.WithStack(err)
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

// title: update provisioner cluster
// path: /provisioner/clusters/{name}
// method: POST
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   400: Invalid data
//   401: Unauthorized
//   404: Cluster not found
func updateCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterUpdate)
	if !allowed {
		return permission.ErrUnauthorized
	}
	dec := form.NewDecoder(nil)
	dec.IgnoreCase(true)
	dec.IgnoreUnknownKeys(true)
	var provCluster cluster.Cluster
	err = r.ParseForm()
	if err == nil {
		err = dec.DecodeValues(&provCluster, r.Form)
	}
	provCluster.Name = r.URL.Query().Get(":name")
	if err != nil {
		return &tsuruErrors.HTTP{
			Code:    http.StatusBadRequest,
			Message: err.Error(),
		}
	}
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: provCluster.Name},
		Kind:       permission.PermClusterUpdate,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	_, err = cluster.ByName(provCluster.Name)
	if err != nil {
		if err == cluster.ErrClusterNotFound {
			return &tsuruErrors.HTTP{
				Code:    http.StatusNotFound,
				Message: err.Error(),
			}
		}
		return err
	}
	for _, poolName := range provCluster.Pools {
		_, err = pool.GetPoolByName(poolName)
		if err != nil {
			if err == pool.ErrPoolNotFound {
				return &tsuruErrors.HTTP{
					Code:    http.StatusBadRequest,
					Message: err.Error(),
				}
			}
			return err
		}
	}
	err = provCluster.Save()
	if err != nil {
		return errors.WithStack(err)
	}
	w.WriteHeader(http.StatusOK)
	return nil
}

// title: list provisioner clusters
// path: /provisioner/clusters
// method: GET
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   204: No Content
//   401: Unauthorized
func listClusters(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterRead)
	if !allowed {
		return permission.ErrUnauthorized
	}
	clusters, err := cluster.AllClusters()
	if err != nil {
		if err == cluster.ErrNoCluster {
			w.WriteHeader(http.StatusNoContent)
			return nil
		}
		return err
	}
	return json.NewEncoder(w).Encode(clusters)
}

// title: delete provisioner cluster
// path: /provisioner/clusters/{name}
// method: GET
// consume: application/x-www-form-urlencoded
// produce: application/json
// responses:
//   200: Ok
//   401: Unauthorized
//   404: Cluster not found
func deleteCluster(w http.ResponseWriter, r *http.Request, t auth.Token) (err error) {
	allowed := permission.Check(t, permission.PermClusterDelete)
	if !allowed {
		return permission.ErrUnauthorized
	}
	r.ParseForm()
	clusterName := r.URL.Query().Get(":name")
	evt, err := event.New(&event.Opts{
		Target:     event.Target{Type: event.TargetTypeCluster, Value: clusterName},
		Kind:       permission.PermClusterDelete,
		Owner:      t,
		CustomData: event.FormToCustomData(r.Form),
		Allowed:    event.Allowed(permission.PermClusterReadEvents),
	})
	if err != nil {
		return err
	}
	defer func() { evt.Done(err) }()
	err = cluster.DeleteCluster(clusterName)
	if err != nil {
		if errors.Cause(err) == cluster.ErrClusterNotFound {
			return &tsuruErrors.HTTP{
				Code:    http.StatusNotFound,
				Message: err.Error(),
			}
		}
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package api

// Logical is used to perform logical backend operations on Vault.
type Logical struct {
	c *Client
}

// Logical is used to return the client for logical-backend API calls.
func (c *Client) Logical() *Logical {
	return &Logical{c: c}
}

func (c *Logical) Read(path string) (*Secret, error) {
	r := c.c.NewRequest("GET", "/v1/"+path)
	resp, err := c.c.RawRequest(r)
	if resp != nil {
		defer resp.Body.Close()
	}
	if resp != nil && resp.StatusCode == 404 {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}

	return ParseSecret(resp.Body)
}

func (c *Logical) List(path string) (*Secret, error) {
	r := c.c.NewRequest("LIST", "/v1/"+path)
	resp, err := c.c.RawRequest(r)
	if resp != nil && resp.StatusCode == 404 {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	return ParseSecret(resp.Body)
}

func (c *Logical) Write(path string, data map[string]interface{}) (*Secret, error) {
	r := c.c.NewRequest("PUT", "/v1/"+path)
	if err := r.SetJSONBody(data); err != nil {
		return nil, err
	}

	resp, err := c.c.RawRequest(r)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return nil, err
	}

	if resp.StatusCode == 200 {
		return ParseSecret(resp.Body)
	}

	return nil, nil
}

func (c *Logical) Delete(path string) (*Secret, error) {
	r := c.c.NewRequest("DELETE", "/v1/"+path)
	resp, err := c.c.RawRequest(r)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return nil, err
	}

	if resp.StatusCode == 200 {
		return ParseSecret(resp.Body)
	}

	return nil, nil
}
<commit_msg>Fix body closing in List method<commit_after>package api

// Logical is used to perform logical backend operations on Vault.
type Logical struct {
	c *Client
}

// Logical is used to return the client for logical-backend API calls.
func (c *Client) Logical() *Logical {
	return &Logical{c: c}
}

func (c *Logical) Read(path string) (*Secret, error) {
	r := c.c.NewRequest("GET", "/v1/"+path)
	resp, err := c.c.RawRequest(r)
	if resp != nil {
		defer resp.Body.Close()
	}
	if resp != nil && resp.StatusCode == 404 {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}

	return ParseSecret(resp.Body)
}

func (c *Logical) List(path string) (*Secret, error) {
	r := c.c.NewRequest("LIST", "/v1/"+path)
	resp, err := c.c.RawRequest(r)
	if resp != nil {
		defer resp.Body.Close()
	}
	if resp != nil && resp.StatusCode == 404 {
		return nil, nil
	}
	if err != nil {
		return nil, err
	}

	return ParseSecret(resp.Body)
}

func (c *Logical) Write(path string, data map[string]interface{}) (*Secret, error) {
	r := c.c.NewRequest("PUT", "/v1/"+path)
	if err := r.SetJSONBody(data); err != nil {
		return nil, err
	}

	resp, err := c.c.RawRequest(r)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return nil, err
	}

	if resp.StatusCode == 200 {
		return ParseSecret(resp.Body)
	}

	return nil, nil
}

func (c *Logical) Delete(path string) (*Secret, error) {
	r := c.c.NewRequest("DELETE", "/v1/"+path)
	resp, err := c.c.RawRequest(r)
	if resp != nil {
		defer resp.Body.Close()
	}
	if err != nil {
		return nil, err
	}

	if resp.StatusCode == 200 {
		return ParseSecret(resp.Body)
	}

	return nil, nil
}
<|endoftext|>


<commit_before>package lnd

import (
	"fmt"
	"net"

	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/wire"
	"github.com/lightningnetwork/lnd/chanbackup"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/channelnotifier"
)

// addrSource is an interface that allow us to get the addresses for a target
// node. We'll need this in order to be able to properly proxy the
// notifications to create SCBs.
type addrSource interface {
	// AddrsForNode returns all known addresses for the target node public
	// key.
	AddrsForNode(nodePub *btcec.PublicKey) ([]net.Addr, error)
}

// channelNotifier is an implementation of the chanbackup.ChannelNotifier
// interface using the existing channelnotifier.ChannelNotifier struct. This
// implementation allows us to satisfy all the dependencies of the
// chanbackup.SubSwapper struct.
type channelNotifier struct {
	// chanNotifier is the based channel notifier that we'll proxy requests
	// from.
	chanNotifier *channelnotifier.ChannelNotifier

	// addrs is an implementation of the addrSource interface that allows
	// us to get the latest set of addresses for a given node. We'll need
	// this to be able to create an SCB for new channels.
	addrs addrSource
}

// SubscribeChans requests a new channel subscription relative to the initial
// set of known channels. We use the knownChans as a synchronization point to
// ensure that the chanbackup.SubSwapper does not miss any channel open or
// close events in the period between when it's created, and when it requests
// the channel subscription.
//
// NOTE: This is part of the chanbackup.ChannelNotifier interface.
func (c *channelNotifier) SubscribeChans(startingChans map[wire.OutPoint]struct{}) (
	*chanbackup.ChannelSubscription, error) {

	ltndLog.Infof("Channel backup proxy channel notifier starting")

	// TODO(roasbeef): read existing set of chans and diff

	quit := make(chan struct{})
	chanUpdates := make(chan chanbackup.ChannelEvent, 1)

	// sendChanOpenUpdate is a closure that sends a ChannelEvent to the
	// chanUpdates channel to inform subscribers about new pending or
	// confirmed channels.
	sendChanOpenUpdate := func(newOrPendingChan *channeldb.OpenChannel) {
		nodeAddrs, err := c.addrs.AddrsForNode(
			newOrPendingChan.IdentityPub,
		)
		if err != nil {
			pub := newOrPendingChan.IdentityPub
			ltndLog.Errorf("unable to fetch addrs for %x: %v",
				pub.SerializeCompressed(), err)
		}

		chanEvent := chanbackup.ChannelEvent{
			NewChans: []chanbackup.ChannelWithAddrs{
				{
					OpenChannel: newOrPendingChan,
					Addrs:       nodeAddrs,
				},
			},
		}

		select {
		case chanUpdates <- chanEvent:
		case <-quit:
			return
		}
	}

	// In order to adhere to the interface, we'll proxy the events from the
	// channel notifier to the sub-swapper in a format it understands.
	go func() {
		// First, we'll subscribe to the primary channel notifier so we can
		// obtain events for new opened/closed channels.
		chanSubscription, err := c.chanNotifier.SubscribeChannelEvents()
		if err != nil {
			panic(fmt.Sprintf("unable to subscribe to chans: %v",
				err))
		}

		defer chanSubscription.Cancel()

		for {
			select {

			// A new event has been sent by the chanNotifier, we'll
			// filter out the events we actually care about and
			// send them to the sub-swapper.
			case e := <-chanSubscription.Updates():
				// TODO(roasbeef): batch dispatch ntnfs

				switch event := e.(type) {
				// A new channel has been opened and is still
				// pending. We can still create a backup, even
				// if the final channel ID is not yet available.
				case channelnotifier.PendingOpenChannelEvent:
					pendingChan := event.PendingChannel
					sendChanOpenUpdate(pendingChan)

				// A new channel has been confirmed, we'll
				// obtain the node address, then send to the
				// sub-swapper.
				case channelnotifier.OpenChannelEvent:
					sendChanOpenUpdate(event.Channel)

				// An existing channel has been closed, we'll
				// send only the chanPoint of the closed
				// channel to the sub-swapper.
				case channelnotifier.ClosedChannelEvent:
					chanPoint := event.CloseSummary.ChanPoint
					chanEvent := chanbackup.ChannelEvent{
						ClosedChans: []wire.OutPoint{
							chanPoint,
						},
					}

					select {
					case chanUpdates <- chanEvent:
					case <-quit:
						return
					}
				}

			// The cancel method has been called, signalling us to
			// exit
			case <-quit:
				return
			}
		}
	}()

	return &chanbackup.ChannelSubscription{
		ChanUpdates: chanUpdates,
		Cancel: func() {
			close(quit)
		},
	}, nil
}

// A compile-time constraint to ensure channelNotifier implements
// chanbackup.ChannelNotifier.
var _ chanbackup.ChannelNotifier = (*channelNotifier)(nil)
<commit_msg>channel_notifier: keep chan in SCB on local foce close<commit_after>package lnd

import (
	"fmt"
	"net"

	"github.com/btcsuite/btcd/btcec"
	"github.com/btcsuite/btcd/wire"
	"github.com/lightningnetwork/lnd/chanbackup"
	"github.com/lightningnetwork/lnd/channeldb"
	"github.com/lightningnetwork/lnd/channelnotifier"
)

// addrSource is an interface that allow us to get the addresses for a target
// node. We'll need this in order to be able to properly proxy the
// notifications to create SCBs.
type addrSource interface {
	// AddrsForNode returns all known addresses for the target node public
	// key.
	AddrsForNode(nodePub *btcec.PublicKey) ([]net.Addr, error)
}

// channelNotifier is an implementation of the chanbackup.ChannelNotifier
// interface using the existing channelnotifier.ChannelNotifier struct. This
// implementation allows us to satisfy all the dependencies of the
// chanbackup.SubSwapper struct.
type channelNotifier struct {
	// chanNotifier is the based channel notifier that we'll proxy requests
	// from.
	chanNotifier *channelnotifier.ChannelNotifier

	// addrs is an implementation of the addrSource interface that allows
	// us to get the latest set of addresses for a given node. We'll need
	// this to be able to create an SCB for new channels.
	addrs addrSource
}

// SubscribeChans requests a new channel subscription relative to the initial
// set of known channels. We use the knownChans as a synchronization point to
// ensure that the chanbackup.SubSwapper does not miss any channel open or
// close events in the period between when it's created, and when it requests
// the channel subscription.
//
// NOTE: This is part of the chanbackup.ChannelNotifier interface.
func (c *channelNotifier) SubscribeChans(startingChans map[wire.OutPoint]struct{}) (
	*chanbackup.ChannelSubscription, error) {

	ltndLog.Infof("Channel backup proxy channel notifier starting")

	// TODO(roasbeef): read existing set of chans and diff

	quit := make(chan struct{})
	chanUpdates := make(chan chanbackup.ChannelEvent, 1)

	// sendChanOpenUpdate is a closure that sends a ChannelEvent to the
	// chanUpdates channel to inform subscribers about new pending or
	// confirmed channels.
	sendChanOpenUpdate := func(newOrPendingChan *channeldb.OpenChannel) {
		nodeAddrs, err := c.addrs.AddrsForNode(
			newOrPendingChan.IdentityPub,
		)
		if err != nil {
			pub := newOrPendingChan.IdentityPub
			ltndLog.Errorf("unable to fetch addrs for %x: %v",
				pub.SerializeCompressed(), err)
		}

		chanEvent := chanbackup.ChannelEvent{
			NewChans: []chanbackup.ChannelWithAddrs{
				{
					OpenChannel: newOrPendingChan,
					Addrs:       nodeAddrs,
				},
			},
		}

		select {
		case chanUpdates <- chanEvent:
		case <-quit:
			return
		}
	}

	// In order to adhere to the interface, we'll proxy the events from the
	// channel notifier to the sub-swapper in a format it understands.
	go func() {
		// First, we'll subscribe to the primary channel notifier so we can
		// obtain events for new opened/closed channels.
		chanSubscription, err := c.chanNotifier.SubscribeChannelEvents()
		if err != nil {
			panic(fmt.Sprintf("unable to subscribe to chans: %v",
				err))
		}

		defer chanSubscription.Cancel()

		for {
			select {

			// A new event has been sent by the chanNotifier, we'll
			// filter out the events we actually care about and
			// send them to the sub-swapper.
			case e := <-chanSubscription.Updates():
				// TODO(roasbeef): batch dispatch ntnfs

				switch event := e.(type) {
				// A new channel has been opened and is still
				// pending. We can still create a backup, even
				// if the final channel ID is not yet available.
				case channelnotifier.PendingOpenChannelEvent:
					pendingChan := event.PendingChannel
					sendChanOpenUpdate(pendingChan)

				// A new channel has been confirmed, we'll
				// obtain the node address, then send to the
				// sub-swapper.
				case channelnotifier.OpenChannelEvent:
					sendChanOpenUpdate(event.Channel)

				// An existing channel has been closed, we'll
				// send only the chanPoint of the closed
				// channel to the sub-swapper.
				case channelnotifier.ClosedChannelEvent:
					chanPoint := event.CloseSummary.ChanPoint
					closeType := event.CloseSummary.CloseType

					// Because we see the contract as closed
					// once our local force close TX
					// confirms, the channel arbitrator
					// already fires on this event. But
					// because our funds can be in limbo for
					// up to 2 weeks worst case we don't
					// want to remove the crucial info we
					// need for sweeping that time locked
					// output before we've actually done so.
					if closeType == channeldb.LocalForceClose {
						ltndLog.Debugf("Channel %v "+
							"was force closed by "+
							"us, not removing "+
							"from channel backup "+
							"until fully resolved",
							chanPoint)

						continue
					}

					chanEvent := chanbackup.ChannelEvent{
						ClosedChans: []wire.OutPoint{
							chanPoint,
						},
					}

					select {
					case chanUpdates <- chanEvent:
					case <-quit:
						return
					}

				// A channel was fully resolved on chain. This
				// should only really interest us if it was a
				// locally force closed channel where we didn't
				// remove the channel already when the close
				// event was fired.
				case channelnotifier.FullyResolvedChannelEvent:
					chanEvent := chanbackup.ChannelEvent{
						ClosedChans: []wire.OutPoint{
							*event.ChannelPoint,
						},
					}

					select {
					case chanUpdates <- chanEvent:
					case <-quit:
						return
					}
				}

			// The cancel method has been called, signalling us to
			// exit
			case <-quit:
				return
			}
		}
	}()

	return &chanbackup.ChannelSubscription{
		ChanUpdates: chanUpdates,
		Cancel: func() {
			close(quit)
		},
	}, nil
}

// A compile-time constraint to ensure channelNotifier implements
// chanbackup.ChannelNotifier.
var _ chanbackup.ChannelNotifier = (*channelNotifier)(nil)
<|endoftext|>


<commit_before>package godingtalk

import (
    "fmt"
    "net/url"
)

type User struct {
    OAPIResponse
    Userid string
    Name string
    Mobile string
    Tel string
    Remark string
    Order int
    IsAdmin bool
    IsBoss bool
    IsLeader bool
	IsSys bool `json:"is_sys"`
	SysLevel int `json:"sys_level"`
    Active bool
    Department []int
    Position string
    Email string
    Avatar string
    Extattr interface{}
}

type UserList struct {
    OAPIResponse
    HasMore bool
    Userlist []User
}

type Department struct {
    OAPIResponse
    Id int
    Name string
    ParentId int
    Order int
    DeptPerimits string
    UserPerimits string
    OuterDept bool
    OuterPermitDepts string
    OuterPermitUsers string
    OrgDeptOwner string
    DeptManagerUseridList string
}

type DepartmentList struct {
    OAPIResponse
    Departments []Department `json:"department"`
}

// DepartmentList is 获取部门列表
func (c *DingTalkClient) DepartmentList() (DepartmentList, error) {
    var data DepartmentList
    err := c.httpRPC("department/list", nil, nil, &data)
    return data, err
}

//DepartmentDetail is 获取部门详情
func (c *DingTalkClient) DepartmentDetail(id int) (Department, error) {
    var data Department
    params := url.Values{}
    params.Add("id", fmt.Sprintf("%d", id))
    err :=c.httpRPC("department/get", params, nil, &data)
    return data, err
}

//UserList is 获取部门成员
func (c *DingTalkClient) UserList(departmentID, offset, size int) (UserList, error) {
    var data UserList
    if size > 100 {
	return data, fmt.Errorf("size 最大100")
    }

    params := url.Values{}
    params.Add("department_id", fmt.Sprintf("%d", departmentID))
    params.Add("offset", fmt.Sprintf("%d", offset))
    params.Add("size", fmt.Sprintf("%d", size))
    err :=c.httpRPC("user/list", params, nil, &data)
    return data, err
}

//CreateChat is
func (c *DingTalkClient) CreateChat(name string, owner string, useridlist []string) (string, error) {
    var data struct {
        OAPIResponse
        Chatid string
    }
    request := map[string]interface{} {
        "name":name,
        "owner":owner,
        "useridlist":useridlist,
    }
    err :=c.httpRPC("chat/create", nil, request, &data)
    return data.Chatid, err
}

//UserInfoByCode 校验免登录码并换取用户身份
func (c *DingTalkClient) UserInfoByCode(code string) (User, error) {
    var data User
    params := url.Values{}
    params.Add("code", code)
    err :=c.httpRPC("user/getuserinfo", params, nil, &data)
    return data, err
}

//UseridByUnionId 通过UnionId获取玩家Userid
func (c *DingTalkClient) UseridByUnionId(unionid string) (string, error) {
    var data struct {
		OAPIResponse
		UserID string `json:"userid"`
	}

    params := url.Values{}
    params.Add("unionid", unionid)
    err :=c.httpRPC("user/getUseridByUnionid", params, nil, &data)
	if err!=nil {
		return "",err
	}

    return data.UserID, err
}

//UseridByMobile 通过手机号获取Userid
func (c *DingTalkClient) UseridByMobile(mobile string) (string, error) {
    var data struct{
        OAPIResponse
        UserID string `json:"userid"`
    }

    params := url.Values{}
    params.Add("mobile", mobile)
    err := c.httpRPC("user/get_by_mobile", params, nil, &data)
    return data.UserID, err
}
<commit_msg>支持获取企业邮箱<commit_after>package godingtalk

import (
    "fmt"
    "net/url"
)

type User struct {
    OAPIResponse
    Userid string
    Name string
    Mobile string
    Tel string
    Remark string
    Order int
    IsAdmin bool
    IsBoss bool
    IsLeader bool
    Active bool
    Department []int
    Position string
    Email string
    OrgEmail string
    Avatar string
    Extattr interface{}
}

type UserList struct {
    OAPIResponse
    HasMore bool
    Userlist []User
}

type Department struct {
    OAPIResponse
    Id int
    Name string
    ParentId int
    Order int
    DeptPerimits string
    UserPerimits string
    OuterDept bool
    OuterPermitDepts string
    OuterPermitUsers string
    OrgDeptOwner string
    DeptManagerUseridList string
}

type DepartmentList struct {
    OAPIResponse
    Departments []Department `json:"department"`
}

// DepartmentList is 获取部门列表
func (c *DingTalkClient) DepartmentList() (DepartmentList, error) {
    var data DepartmentList
    err := c.httpRPC("department/list", nil, nil, &data)
    return data, err
}

//DepartmentDetail is 获取部门详情
func (c *DingTalkClient) DepartmentDetail(id int) (Department, error) {
    var data Department
    params := url.Values{}
    params.Add("id", fmt.Sprintf("%d", id))
    err :=c.httpRPC("department/get", params, nil, &data)
    return data, err
}

//UserList is 获取部门成员
func (c *DingTalkClient) UserList(departmentID, offset, size int) (UserList, error) {
    var data UserList
    if size > 100 {
	return data, fmt.Errorf("size 最大100")
    }

    params := url.Values{}
    params.Add("department_id", fmt.Sprintf("%d", departmentID))
    params.Add("offset", fmt.Sprintf("%d", offset))
    params.Add("size", fmt.Sprintf("%d", size))
    err :=c.httpRPC("user/list", params, nil, &data)
    return data, err
}

//CreateChat is
func (c *DingTalkClient) CreateChat(name string, owner string, useridlist []string) (string, error) {
    var data struct {
        OAPIResponse
        Chatid string
    }
    request := map[string]interface{} {
        "name":name,
        "owner":owner,
        "useridlist":useridlist,
    }
    err :=c.httpRPC("chat/create", nil, request, &data)
    return data.Chatid, err
}

//UserInfoByCode 校验免登录码并换取用户身份
func (c *DingTalkClient) UserInfoByCode(code string) (User, error) {
    var data User
    params := url.Values{}
    params.Add("code", code)
    err :=c.httpRPC("user/getuserinfo", params, nil, &data)
    return data, err
}

//UseridByUnionId 通过UnionId获取玩家Userid
func (c *DingTalkClient) UseridByUnionId(unionid string) (string, error) {
    var data struct {
		OAPIResponse
		UserID string `json:"userid"`
	}

    params := url.Values{}
    params.Add("unionid", unionid)
    err :=c.httpRPC("user/getUseridByUnionid", params, nil, &data)
	if err!=nil {
		return "",err
	}

    return data.UserID, err
}

//UseridByMobile 通过手机号获取Userid
func (c *DingTalkClient) UseridByMobile(mobile string) (string, error) {
    var data struct{
        OAPIResponse
        UserID string `json:"userid"`
    }

    params := url.Values{}
    params.Add("mobile", mobile)
    err := c.httpRPC("user/get_by_mobile", params, nil, &data)
    return data.UserID, err
}
<|endoftext|>


<commit_before>package ccs_test

import (
	"log"

	"github.com/nbusy/gcm/ccs"
)

func Example() {
	c, err := ccs.Connect("gcm-preprod.googleapis.com:5236", "gcm_sender_id", "gcm_api_key", true)
	if err != nil {
		log.Fatalf("GCM CCS connection cannot be established.")
	}

	err = c.Send(&ccs.OutMsg{To: "device_registration_id", Data: map[string]string{"test_message": "GCM CCS client testing message."}})

	for {
		log.Printf("Waiting for incoming CCS messages")
		m, err := c.Receive()
		if err != nil {
			log.Printf("Incoming CCS error: %v\n", err)
		}

		go readHandler(m)
	}
}

func readHandler(m *ccs.InMsg) {
	log.Printf("Incoming CCS message: %v\n", m)
}
<commit_msg>log.Fatal any Send error<commit_after>package ccs_test

import (
	"log"

	"github.com/nbusy/gcm/ccs"
)

// Package level example demonstrating the use of CCS implementation in an application server.
func Example() {
	c, err := ccs.Connect("gcm-preprod.googleapis.com:5236", "gcm_sender_id", "gcm_api_key", true)
	if err != nil {
		log.Fatalf("GCM CCS connection cannot be established.")
	}

	err = c.Send(&ccs.OutMsg{To: "device_registration_id", Data: map[string]string{"test_message": "GCM CCS client testing message."}})
	if err != nil {
		log.Fatalf("Failed to send message to CCS server with error: %v\n", err)
	}

	for {
		log.Printf("Waiting for incoming CCS messages")
		m, err := c.Receive()
		if err != nil {
			log.Printf("Incoming CCS error: %v\n", err)
		}

		go readHandler(m)
	}
}

func readHandler(m *ccs.InMsg) {
	log.Printf("Incoming CCS message: %v\n", m)
}
<|endoftext|>


<commit_before>package main

import (
	"log"

	"github.com/xanzy/go-gitlab"
)

func projectExample() {
	git := gitlab.NewClient(nil, "yourtokengoeshere")

	// Create new project
	p := &gitlab.CreateProjectOptions{
		Name:                 "My Project",
		Description:          "Just a test project to play with",
		MergeRequestsEnabled: true,
		SnippetsEnabled:      true,
		VisibilityLevel:      gitlab.PublicVisibility,
	}
	project, _, err := git.Projects.CreateProject(p)
	if err != nil {
		log.Fatal(err)
	}

	// Add a new snippet
	s := &gitlab.CreateSnippetOptions{
		Title:           "Dummy Snippet",
		FileName:        "snippet.go",
		Code:            "package main....",
		VisibilityLevel: gitlab.PublicVisibility,
	}
	_, _, err = git.ProjectSnippets.CreateSnippet(project.ID, s)
	if err != nil {
		log.Fatal(err)
	}

	// List all project snippets
	snippets, _, err := git.ProjectSnippets.ListSnippets(project.PathWithNamespace)
	if err != nil {
		log.Fatal(err)
	}

	for _, snippet := range snippets {
		log.Printf("Found snippet: %s", snippet.Title)
	}
}
<commit_msg>Fixed examples<commit_after>package main

import (
	"log"

	"github.com/xanzy/go-gitlab"
)

func projectExample() {
	git := gitlab.NewClient(nil, "yourtokengoeshere")

	// Create new project
	p := &gitlab.CreateProjectOptions{
		Name:                 "My Project",
		Description:          "Just a test project to play with",
		MergeRequestsEnabled: true,
		SnippetsEnabled:      true,
		VisibilityLevel:      gitlab.PublicVisibility,
	}
	project, _, err := git.Projects.CreateProject(p)
	if err != nil {
		log.Fatal(err)
	}

	// Add a new snippet
	s := &gitlab.CreateSnippetOptions{
		Title:           "Dummy Snippet",
		FileName:        "snippet.go",
		Code:            "package main....",
		VisibilityLevel: gitlab.PublicVisibility,
	}
	_, _, err = git.ProjectSnippets.CreateSnippet(project.ID, s)
	if err != nil {
		log.Fatal(err)
	}

	// List all project snippets
	snippets, _, err := git.ProjectSnippets.ListSnippets(project.PathWithNamespace, &gitlab.ListSnippetsOptions{})
	if err != nil {
		log.Fatal(err)
	}

	for _, snippet := range snippets {
		log.Printf("Found snippet: %s", snippet.Title)
	}
}
<|endoftext|>