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

// Cgo; see gmp.go for an overview.

// TODO(rsc):
//	Emit correct line number annotations.
//	Make 6g understand the annotations.

package main

import (
	"crypto/md5"
	"flag"
	"fmt"
	"go/ast"
	"go/token"
	"io"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"strings"
)

// A Package collects information about the package we're going to write.
type Package struct {
	PackageName string // name of package
	PackagePath string
	PtrSize     int64
	GccOptions  []string
	CgoFlags    map[string]string // #cgo flags (CFLAGS, LDFLAGS)
	Written     map[string]bool
	Name        map[string]*Name    // accumulated Name from Files
	Typedef     map[string]ast.Expr // accumulated Typedef from Files
	ExpFunc     []*ExpFunc          // accumulated ExpFunc from Files
	Decl        []ast.Decl
	GoFiles     []string // list of Go files
	GccFiles    []string // list of gcc output files
}

// A File collects information about a single Go input file.
type File struct {
	AST      *ast.File           // parsed AST
	Comments []*ast.CommentGroup // comments from file
	Package  string              // Package name
	Preamble string              // C preamble (doc comment on import "C")
	Ref      []*Ref              // all references to C.xxx in AST
	ExpFunc  []*ExpFunc          // exported functions for this file
	Name     map[string]*Name    // map from Go name to Name
	Typedef  map[string]ast.Expr // translations of all necessary types from C
}

// A Ref refers to an expression of the form C.xxx in the AST.
type Ref struct {
	Name    *Name
	Expr    *ast.Expr
	Context string // "type", "expr", "call", or "call2"
}

func (r *Ref) Pos() token.Pos {
	return (*r.Expr).Pos()
}

// A Name collects information about C.xxx.
type Name struct {
	Go       string // name used in Go referring to package C
	Mangle   string // name used in generated Go
	C        string // name used in C
	Define   string // #define expansion
	Kind     string // "const", "type", "var", "func", "not-type"
	Type     *Type  // the type of xxx
	FuncType *FuncType
	AddError bool
	Const    string // constant definition
}

// A ExpFunc is an exported function, callable from C.
// Such functions are identified in the Go input file
// by doc comments containing the line //export ExpName
type ExpFunc struct {
	Func    *ast.FuncDecl
	ExpName string // name to use from C
}

// A TypeRepr contains the string representation of a type.
type TypeRepr struct {
	Repr       string
	FormatArgs []interface{}
}

// A Type collects information about a type in both the C and Go worlds.
type Type struct {
	Size       int64
	Align      int64
	C          *TypeRepr
	Go         ast.Expr
	EnumValues map[string]int64
}

// A FuncType collects information about a function type in both the C and Go worlds.
type FuncType struct {
	Params []*Type
	Result *Type
	Go     *ast.FuncType
}

func usage() {
	fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n")
	flag.PrintDefaults()
	os.Exit(2)
}

var ptrSizeMap = map[string]int64{
	"386":   4,
	"amd64": 8,
	"arm":   4,
}

var cPrefix string

var fset = token.NewFileSet()

var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
var dynout = flag.String("dynout", "", "write -dynobj output to this file")

// These flags are for bootstrapping a new Go implementation,
// to generate Go and C headers that match the data layout and
// constant values used in the host's C libraries and system calls.
var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output")
var objDir = flag.String("objdir", "", "object directory")

var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
var goarch, goos string

func main() {
	flag.Usage = usage
	flag.Parse()

	if *dynobj != "" {
		// cgo -dynimport is essentially a separate helper command
		// built into the cgo binary.  It scans a gcc-produced executable
		// and dumps information about the imported symbols and the
		// imported libraries.  The Make.pkg rules for cgo prepare an
		// appropriate executable and then use its import information
		// instead of needing to make the linkers duplicate all the
		// specialized knowledge gcc has about where to look for imported
		// symbols and which ones to use.
		dynimport(*dynobj)
		return
	}

	if *godefs && *cdefs {
		fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
		os.Exit(2)
	}

	args := flag.Args()
	if len(args) < 1 {
		usage()
	}

	// Find first arg that looks like a go file and assume everything before
	// that are options to pass to gcc.
	var i int
	for i = len(args); i > 0; i-- {
		if !strings.HasSuffix(args[i-1], ".go") {
			break
		}
	}
	if i == len(args) {
		usage()
	}

	goFiles := args[i:]

	p := newPackage(args[:i])

	// Need a unique prefix for the global C symbols that
	// we use to coordinate between gcc and ourselves.
	// We already put _cgo_ at the beginning, so the main
	// concern is other cgo wrappers for the same functions.
	// Use the beginning of the md5 of the input to disambiguate.
	h := md5.New()
	for _, input := range goFiles {
		f, err := os.Open(input)
		if err != nil {
			fatalf("%s", err)
		}
		io.Copy(h, f)
		f.Close()
	}
	cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])

	fs := make([]*File, len(goFiles))
	for i, input := range goFiles {
		// Parse flags for all files before translating due to CFLAGS.
		f := new(File)
		f.ReadGo(input)
		p.ParseFlags(f, input)
		fs[i] = f
	}

	if *objDir == "" {
		// make sure that _obj directory exists, so that we can write
		// all the output files there.
		os.Mkdir("_obj", 0777)
		*objDir = "_obj"
	}
	*objDir += string(filepath.Separator)

	for i, input := range goFiles {
		f := fs[i]
		p.Translate(f)
		for _, cref := range f.Ref {
			switch cref.Context {
			case "call", "call2":
				if cref.Name.Kind != "type" {
					break
				}
				*cref.Expr = cref.Name.Type.Go
			}
		}
		if nerrors > 0 {
			os.Exit(2)
		}
		pkg := f.Package
		if dir := os.Getenv("CGOPKGPATH"); dir != "" {
			pkg = filepath.Join(dir, pkg)
		}
		p.PackagePath = pkg
		p.Record(f)
		if *godefs {
			os.Stdout.WriteString(p.godefs(f, input))
		} else if *cdefs {
			os.Stdout.WriteString(p.cdefs(f, input))
		} else {
			p.writeOutput(f, input)
		}
	}

	if !*godefs && !*cdefs {
		p.writeDefs()
	}
	if nerrors > 0 {
		os.Exit(2)
	}
}

// newPackage returns a new Package that will invoke
// gcc with the additional arguments specified in args.
func newPackage(args []string) *Package {
	// Copy the gcc options to a new slice so the list
	// can grow without overwriting the slice that args is in.
	gccOptions := make([]string, len(args))
	copy(gccOptions, args)

	goarch = runtime.GOARCH
	if s := os.Getenv("GOARCH"); s != "" {
		goarch = s
	}
	goos = runtime.GOOS
	if s := os.Getenv("GOOS"); s != "" {
		goos = s
	}
	ptrSize := ptrSizeMap[goarch]
	if ptrSize == 0 {
		fatalf("unknown $GOARCH %q", goarch)
	}

	// Reset locale variables so gcc emits English errors [sic].
	os.Setenv("LANG", "en_US.UTF-8")
	os.Setenv("LC_ALL", "C")

	p := &Package{
		PtrSize:    ptrSize,
		GccOptions: gccOptions,
		CgoFlags:   make(map[string]string),
		Written:    make(map[string]bool),
	}
	return p
}

// Record what needs to be recorded about f.
func (p *Package) Record(f *File) {
	if p.PackageName == "" {
		p.PackageName = f.Package
	} else if p.PackageName != f.Package {
		error_(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
	}

	if p.Name == nil {
		p.Name = f.Name
	} else {
		for k, v := range f.Name {
			if p.Name[k] == nil {
				p.Name[k] = v
			} else if !reflect.DeepEqual(p.Name[k], v) {
				error_(token.NoPos, "inconsistent definitions for C.%s", k)
			}
		}
	}

	p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
	p.Decl = append(p.Decl, f.AST.Decls...)
}
<commit_msg>cmd/cgo: omit //line in -godefs, -cdefs output<commit_after>// Copyright 2009 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Cgo; see gmp.go for an overview.

// TODO(rsc):
//	Emit correct line number annotations.
//	Make 6g understand the annotations.

package main

import (
	"crypto/md5"
	"flag"
	"fmt"
	"go/ast"
	"go/printer"
	"go/token"
	"io"
	"os"
	"path/filepath"
	"reflect"
	"runtime"
	"strings"
)

// A Package collects information about the package we're going to write.
type Package struct {
	PackageName string // name of package
	PackagePath string
	PtrSize     int64
	GccOptions  []string
	CgoFlags    map[string]string // #cgo flags (CFLAGS, LDFLAGS)
	Written     map[string]bool
	Name        map[string]*Name    // accumulated Name from Files
	Typedef     map[string]ast.Expr // accumulated Typedef from Files
	ExpFunc     []*ExpFunc          // accumulated ExpFunc from Files
	Decl        []ast.Decl
	GoFiles     []string // list of Go files
	GccFiles    []string // list of gcc output files
}

// A File collects information about a single Go input file.
type File struct {
	AST      *ast.File           // parsed AST
	Comments []*ast.CommentGroup // comments from file
	Package  string              // Package name
	Preamble string              // C preamble (doc comment on import "C")
	Ref      []*Ref              // all references to C.xxx in AST
	ExpFunc  []*ExpFunc          // exported functions for this file
	Name     map[string]*Name    // map from Go name to Name
	Typedef  map[string]ast.Expr // translations of all necessary types from C
}

// A Ref refers to an expression of the form C.xxx in the AST.
type Ref struct {
	Name    *Name
	Expr    *ast.Expr
	Context string // "type", "expr", "call", or "call2"
}

func (r *Ref) Pos() token.Pos {
	return (*r.Expr).Pos()
}

// A Name collects information about C.xxx.
type Name struct {
	Go       string // name used in Go referring to package C
	Mangle   string // name used in generated Go
	C        string // name used in C
	Define   string // #define expansion
	Kind     string // "const", "type", "var", "func", "not-type"
	Type     *Type  // the type of xxx
	FuncType *FuncType
	AddError bool
	Const    string // constant definition
}

// A ExpFunc is an exported function, callable from C.
// Such functions are identified in the Go input file
// by doc comments containing the line //export ExpName
type ExpFunc struct {
	Func    *ast.FuncDecl
	ExpName string // name to use from C
}

// A TypeRepr contains the string representation of a type.
type TypeRepr struct {
	Repr       string
	FormatArgs []interface{}
}

// A Type collects information about a type in both the C and Go worlds.
type Type struct {
	Size       int64
	Align      int64
	C          *TypeRepr
	Go         ast.Expr
	EnumValues map[string]int64
}

// A FuncType collects information about a function type in both the C and Go worlds.
type FuncType struct {
	Params []*Type
	Result *Type
	Go     *ast.FuncType
}

func usage() {
	fmt.Fprint(os.Stderr, "usage: cgo -- [compiler options] file.go ...\n")
	flag.PrintDefaults()
	os.Exit(2)
}

var ptrSizeMap = map[string]int64{
	"386":   4,
	"amd64": 8,
	"arm":   4,
}

var cPrefix string

var fset = token.NewFileSet()

var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
var dynout = flag.String("dynout", "", "write -dynobj output to this file")

// These flags are for bootstrapping a new Go implementation,
// to generate Go and C headers that match the data layout and
// constant values used in the host's C libraries and system calls.
var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output")
var objDir = flag.String("objdir", "", "object directory")

var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
var goarch, goos string

func main() {
	flag.Usage = usage
	flag.Parse()

	if *dynobj != "" {
		// cgo -dynimport is essentially a separate helper command
		// built into the cgo binary.  It scans a gcc-produced executable
		// and dumps information about the imported symbols and the
		// imported libraries.  The Make.pkg rules for cgo prepare an
		// appropriate executable and then use its import information
		// instead of needing to make the linkers duplicate all the
		// specialized knowledge gcc has about where to look for imported
		// symbols and which ones to use.
		dynimport(*dynobj)
		return
	}

	if *godefs && *cdefs {
		fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
		os.Exit(2)
	}

	if *godefs || *cdefs {
		// Generating definitions pulled from header files,
		// to be checked into Go repositories.
		// Line numbers are just noise.
		conf.Mode &^= printer.SourcePos
	}

	args := flag.Args()
	if len(args) < 1 {
		usage()
	}

	// Find first arg that looks like a go file and assume everything before
	// that are options to pass to gcc.
	var i int
	for i = len(args); i > 0; i-- {
		if !strings.HasSuffix(args[i-1], ".go") {
			break
		}
	}
	if i == len(args) {
		usage()
	}

	goFiles := args[i:]

	p := newPackage(args[:i])

	// Need a unique prefix for the global C symbols that
	// we use to coordinate between gcc and ourselves.
	// We already put _cgo_ at the beginning, so the main
	// concern is other cgo wrappers for the same functions.
	// Use the beginning of the md5 of the input to disambiguate.
	h := md5.New()
	for _, input := range goFiles {
		f, err := os.Open(input)
		if err != nil {
			fatalf("%s", err)
		}
		io.Copy(h, f)
		f.Close()
	}
	cPrefix = fmt.Sprintf("_%x", h.Sum(nil)[0:6])

	fs := make([]*File, len(goFiles))
	for i, input := range goFiles {
		// Parse flags for all files before translating due to CFLAGS.
		f := new(File)
		f.ReadGo(input)
		p.ParseFlags(f, input)
		fs[i] = f
	}

	if *objDir == "" {
		// make sure that _obj directory exists, so that we can write
		// all the output files there.
		os.Mkdir("_obj", 0777)
		*objDir = "_obj"
	}
	*objDir += string(filepath.Separator)

	for i, input := range goFiles {
		f := fs[i]
		p.Translate(f)
		for _, cref := range f.Ref {
			switch cref.Context {
			case "call", "call2":
				if cref.Name.Kind != "type" {
					break
				}
				*cref.Expr = cref.Name.Type.Go
			}
		}
		if nerrors > 0 {
			os.Exit(2)
		}
		pkg := f.Package
		if dir := os.Getenv("CGOPKGPATH"); dir != "" {
			pkg = filepath.Join(dir, pkg)
		}
		p.PackagePath = pkg
		p.Record(f)
		if *godefs {
			os.Stdout.WriteString(p.godefs(f, input))
		} else if *cdefs {
			os.Stdout.WriteString(p.cdefs(f, input))
		} else {
			p.writeOutput(f, input)
		}
	}

	if !*godefs && !*cdefs {
		p.writeDefs()
	}
	if nerrors > 0 {
		os.Exit(2)
	}
}

// newPackage returns a new Package that will invoke
// gcc with the additional arguments specified in args.
func newPackage(args []string) *Package {
	// Copy the gcc options to a new slice so the list
	// can grow without overwriting the slice that args is in.
	gccOptions := make([]string, len(args))
	copy(gccOptions, args)

	goarch = runtime.GOARCH
	if s := os.Getenv("GOARCH"); s != "" {
		goarch = s
	}
	goos = runtime.GOOS
	if s := os.Getenv("GOOS"); s != "" {
		goos = s
	}
	ptrSize := ptrSizeMap[goarch]
	if ptrSize == 0 {
		fatalf("unknown $GOARCH %q", goarch)
	}

	// Reset locale variables so gcc emits English errors [sic].
	os.Setenv("LANG", "en_US.UTF-8")
	os.Setenv("LC_ALL", "C")

	p := &Package{
		PtrSize:    ptrSize,
		GccOptions: gccOptions,
		CgoFlags:   make(map[string]string),
		Written:    make(map[string]bool),
	}
	return p
}

// Record what needs to be recorded about f.
func (p *Package) Record(f *File) {
	if p.PackageName == "" {
		p.PackageName = f.Package
	} else if p.PackageName != f.Package {
		error_(token.NoPos, "inconsistent package names: %s, %s", p.PackageName, f.Package)
	}

	if p.Name == nil {
		p.Name = f.Name
	} else {
		for k, v := range f.Name {
			if p.Name[k] == nil {
				p.Name[k] = v
			} else if !reflect.DeepEqual(p.Name[k], v) {
				error_(token.NoPos, "inconsistent definitions for C.%s", k)
			}
		}
	}

	p.ExpFunc = append(p.ExpFunc, f.ExpFunc...)
	p.Decl = append(p.Decl, f.AST.Decls...)
}
<|endoftext|>


<commit_before>package commands

import (
	"fmt"
	"os"
	"syscall"

	"../conio"
	"../interpreter"
)

func cmd_del(cmd *interpreter.Interpreter) (interpreter.NextT, error) {
	n := len(cmd.Args)
	if n <= 1 {
		fmt.Fprintln(cmd.Stderr, "Usage: del   FILE(S)...")
		fmt.Fprintln(cmd.Stderr, "       erase FILE(S)...")
		return interpreter.CONTINUE, nil
	}
	all := false
	for i := 1; i < n; i++ {
		path := cmd.Args[i]
		stat, statErr := os.Stat(path)
		if statErr != nil {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s: %s\n",
				i, n-1, path, statErr.Error())
			continue
		}
		if mode := stat.Mode(); mode.IsDir() {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s is directory and passed.\n",
				i, n-1, path)
			continue
		}
		if all {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s: Remove ", i, n-1, path)
		} else {
			fmt.Fprintf(cmd.Stdout,
				"(%d/%d) %s: Remove ? [Yes/No/All/Quit] ",
				i, n-1, path)
			ch := conio.GetCh()
			fmt.Fprintf(cmd.Stdout, "%c ", ch)
			switch ch {
			case 'q', 'Q':
				fmt.Fprintln(cmd.Stdout)
				return interpreter.CONTINUE, nil
			case 'y', 'Y':
				break
			case 'a', 'A':
				all = true
			default: // for 'n','N'
				fmt.Println("-> canceled")
				continue
			}
		}
		err := syscall.Unlink(path)
		if err != nil {
			return interpreter.CONTINUE, err
		}
		fmt.Println("-> done.")
	}
	return interpreter.CONTINUE, nil
}
<commit_msg>Fix: Could not broken symbolic link with DEL #44<commit_after>package commands

import (
	"fmt"
	"os"
	"syscall"

	"../conio"
	"../interpreter"
)

func cmd_del(cmd *interpreter.Interpreter) (interpreter.NextT, error) {
	n := len(cmd.Args)
	if n <= 1 {
		fmt.Fprintln(cmd.Stderr, "Usage: del   FILE(S)...")
		fmt.Fprintln(cmd.Stderr, "       erase FILE(S)...")
		return interpreter.CONTINUE, nil
	}
	all := false
	for i := 1; i < n; i++ {
		path := cmd.Args[i]
		stat, statErr := os.Lstat(path)
		if statErr != nil {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s: %s\n",
				i, n-1, path, statErr.Error())
			continue
		}
		if mode := stat.Mode(); mode.IsDir() {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s is directory and passed.\n",
				i, n-1, path)
			continue
		}
		if all {
			fmt.Fprintf(cmd.Stdout, "(%d/%d) %s: Remove ", i, n-1, path)
		} else {
			fmt.Fprintf(cmd.Stdout,
				"(%d/%d) %s: Remove ? [Yes/No/All/Quit] ",
				i, n-1, path)
			ch := conio.GetCh()
			fmt.Fprintf(cmd.Stdout, "%c ", ch)
			switch ch {
			case 'q', 'Q':
				fmt.Fprintln(cmd.Stdout)
				return interpreter.CONTINUE, nil
			case 'y', 'Y':
				break
			case 'a', 'A':
				all = true
			default: // for 'n','N'
				fmt.Println("-> canceled")
				continue
			}
		}
		err := syscall.Unlink(path)
		if err != nil {
			return interpreter.CONTINUE, err
		}
		fmt.Println("-> done.")
	}
	return interpreter.CONTINUE, nil
}
<|endoftext|>


<commit_before>// Copyright 2022 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 build

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"

	"github.com/moby/buildkit/client"
	"github.com/moby/buildkit/frontend/dockerfile/builder"
	"github.com/moby/buildkit/session"
	"github.com/moby/buildkit/session/auth/authprovider"
	"github.com/moby/buildkit/session/secrets/secretsprovider"
	"github.com/moby/buildkit/util/progress/progresswriter"
	tsuruprovtypes "github.com/tsuru/tsuru/types/provision"
	"golang.org/x/sync/errgroup"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"gopkg.in/yaml.v3"

	pb "github.com/tsuru/deploy-agent/v2/api/v1alpha1"
)

var _ pb.BuildServer = (*Docker)(nil)

type DockerOptions struct {
	TempDir string
}

func NewDocker(c *client.Client, opts DockerOptions) *Docker {
	return &Docker{cli: c, opts: opts}
}

type Docker struct {
	*pb.UnimplementedBuildServer

	cli  *client.Client
	opts DockerOptions
}

func (d *Docker) Build(req *pb.BuildRequest, stream pb.Build_BuildServer) error {
	fmt.Println("Build RPC called")
	defer fmt.Println("Finishing Build RPC call")

	ctx := stream.Context()
	if err := ctx.Err(); err != nil { // e.g. context deadline exceeded
		return err
	}

	w := &BuildResponseOutputWriter{stream: stream}
	fmt.Fprintln(w, "---> Starting container image build")

	// TODO: check if mandatory field were provided
	tsuruFiles, err := ExtractTsuruAppFilesFromAppSourceContext(ctx, bytes.NewReader(req.Data))
	if err != nil {
		return err
	}

	if err = stream.Send(&pb.BuildResponse{
		Data: &pb.BuildResponse_TsuruConfig{
			TsuruConfig: &pb.TsuruConfig{
				Procfile:  tsuruFiles.Procfile,
				TsuruYaml: tsuruFiles.TsuruYaml,
			},
		}}); err != nil {
		return status.Errorf(codes.Unknown, "failed to send tsuru app files: %s", err)
	}

	if err = d.build(ctx, req, tsuruFiles, bytes.NewReader(req.Data), w); err != nil {
		return status.Errorf(codes.Internal, "failed to build container image: %s", err)
	}

	fmt.Fprintln(w, "--> Container image build finished")

	return nil
}

func (d *Docker) build(ctx context.Context, req *pb.BuildRequest, tsuruAppFiles *TsuruAppFiles, appData io.Reader, w *BuildResponseOutputWriter) error {
	if err := ctx.Err(); err != nil { // e.g. context deadline exceeded
		return err
	}

	tmpDir, cleanFunc, err := generateBuildLocalDir(ctx, d.opts.TempDir, req, tsuruAppFiles, appData)
	if err != nil {
		return err
	}
	defer cleanFunc()

	pw, err := progresswriter.NewPrinter(context.Background(), w, "plain") // using an empty context intentionally
	if err != nil {
		return err
	}

	eg, _ := errgroup.WithContext(ctx)

	eg.Go(func() error {
		secrets, err := secretsprovider.NewStore([]secretsprovider.Source{{
			ID:       "tsuru-app-envvars",
			FilePath: filepath.Join(tmpDir, "envs.sh"),
		}})
		if err != nil {
			return err
		}

		var (
			insecureRegistry bool        // disabled by default
			pushImage        bool = true // enabled by default
		)
		if pots := req.PushOptions; pots != nil {
			pushImage = !pots.Disable
			insecureRegistry = pots.InsecureRegistry
		}

		opts := client.SolveOpt{
			LocalDirs: map[string]string{
				"context":    tmpDir,
				"dockerfile": tmpDir,
			},
			Exports: []client.ExportEntry{
				{
					Type: client.ExporterImage,
					Attrs: map[string]string{
						"name":              strings.Join(req.DestinationImages, ","),
						"push":              strconv.FormatBool(pushImage),
						"registry.insecure": strconv.FormatBool(insecureRegistry),
					},
				},
			},
			Session: []session.Attachable{
				authprovider.NewDockerAuthProvider(w),
				secretsprovider.NewSecretProvider(secrets),
			},
		}
		_, err = d.cli.Build(ctx, opts, "deploy-agent", builder.Build, progresswriter.ResetTime(pw).Status())
		return err
	})

	eg.Go(func() error {
		<-pw.Done()
		return pw.Err()
	})

	if err = eg.Wait(); err != nil {
		return err
	}

	return nil
}

func generateBuildLocalDir(ctx context.Context, baseDir string, req *pb.BuildRequest, tsuruAppFiles *TsuruAppFiles, appData io.Reader) (string, func(), error) {
	noopFunc := func() {}

	if err := ctx.Err(); err != nil {
		return "", noopFunc, err
	}

	contextRootDir, err := os.MkdirTemp(baseDir, "deploy-agent-*")
	if err != nil {
		return "", noopFunc, status.Errorf(codes.Internal, "failed to create temp dir: %s", err)
	}

	eg, _ := errgroup.WithContext(ctx)

	eg.Go(func() error {
		dockerfile, err := os.Create(filepath.Join(contextRootDir, "Dockerfile"))
		if err != nil {
			return status.Errorf(codes.Internal, "cannot create Dockerfile in %s: %s", contextRootDir, err)
		}
		defer dockerfile.Close()

		return generateContainerfile(dockerfile, req.SourceImage, tsuruAppFiles)
	})

	eg.Go(func() error {
		appArchive, err := os.Create(filepath.Join(contextRootDir, "application.tar.gz"))
		if err != nil {
			return status.Errorf(codes.Internal, "cannot create application archive: %s", err)
		}
		defer appArchive.Close()

		_, err = io.Copy(appArchive, appData)
		return err
	})

	eg.Go(func() error {
		envsFile, err := os.Create(filepath.Join(contextRootDir, "envs.sh"))
		if err != nil {
			return err
		}
		defer envsFile.Close()

		fmt.Fprintln(envsFile, "# File containing the env vars of Tsuru app. Generated by deploy-agent.")

		if req.App == nil {
			return nil
		}

		for k, v := range req.App.EnvVars {
			fmt.Fprintln(envsFile, fmt.Sprintf("%s=%q", k, v))
		}

		return nil
	})

	if err = eg.Wait(); err != nil {
		return "", noopFunc, err
	}

	return contextRootDir, func() { os.RemoveAll(contextRootDir) }, nil
}

func generateContainerfile(w io.Writer, image string, tsuruAppFiles *TsuruAppFiles) error {
	var tsuruYaml tsuruprovtypes.TsuruYamlData
	if tsuruAppFiles != nil {
		if err := yaml.Unmarshal([]byte(tsuruAppFiles.TsuruYaml), &tsuruYaml); err != nil {
			return err
		}
	}

	var buildHooks []string
	if hooks := tsuruYaml.Hooks; hooks != nil {
		buildHooks = hooks.Build
	}

	dockerfile, err := BuildContainerfile(BuildContainerfileParams{
		Image:      image,
		BuildHooks: buildHooks,
	})
	if err != nil {
		return err
	}

	_, err = io.WriteString(w, dockerfile)
	return err
}

type BuildResponseOutputWriter struct {
	stream pb.Build_BuildServer
}

func (w *BuildResponseOutputWriter) Write(p []byte) (int, error) {
	if len(p) == 0 {
		return 0, nil
	}

	return len(p), w.stream.Send(&pb.BuildResponse{Data: &pb.BuildResponse_Output{Output: string(p)}})
}

func (w *BuildResponseOutputWriter) Read(p []byte) (int, error) { // required to implement console.File
	return 0, nil
}

func (w *BuildResponseOutputWriter) Close() error { // required to implement console.File
	return nil
}

func (w *BuildResponseOutputWriter) Fd() uintptr { // required to implement console.File
	return uintptr(0)
}

func (w *BuildResponseOutputWriter) Name() string { // required to implement console.File
	return ""
}
<commit_msg>fix(docker): turning output writer thread safe<commit_after>// Copyright 2022 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 build

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"

	"github.com/moby/buildkit/client"
	"github.com/moby/buildkit/frontend/dockerfile/builder"
	"github.com/moby/buildkit/session"
	"github.com/moby/buildkit/session/auth/authprovider"
	"github.com/moby/buildkit/session/secrets/secretsprovider"
	"github.com/moby/buildkit/util/progress/progresswriter"
	tsuruprovtypes "github.com/tsuru/tsuru/types/provision"
	"golang.org/x/sync/errgroup"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"gopkg.in/yaml.v3"

	pb "github.com/tsuru/deploy-agent/v2/api/v1alpha1"
)

var _ pb.BuildServer = (*Docker)(nil)

type DockerOptions struct {
	TempDir string
}

func NewDocker(c *client.Client, opts DockerOptions) *Docker {
	return &Docker{cli: c, opts: opts}
}

type Docker struct {
	*pb.UnimplementedBuildServer

	cli  *client.Client
	opts DockerOptions
}

func (d *Docker) Build(req *pb.BuildRequest, stream pb.Build_BuildServer) error {
	fmt.Println("Build RPC called")
	defer fmt.Println("Finishing Build RPC call")

	ctx := stream.Context()
	if err := ctx.Err(); err != nil { // e.g. context deadline exceeded
		return err
	}

	w := &BuildResponseOutputWriter{stream: stream}
	fmt.Fprintln(w, "---> Starting container image build")

	// TODO: check if mandatory field were provided
	tsuruFiles, err := ExtractTsuruAppFilesFromAppSourceContext(ctx, bytes.NewReader(req.Data))
	if err != nil {
		return err
	}

	if err = stream.Send(&pb.BuildResponse{
		Data: &pb.BuildResponse_TsuruConfig{
			TsuruConfig: &pb.TsuruConfig{
				Procfile:  tsuruFiles.Procfile,
				TsuruYaml: tsuruFiles.TsuruYaml,
			},
		}}); err != nil {
		return status.Errorf(codes.Unknown, "failed to send tsuru app files: %s", err)
	}

	if err = d.build(ctx, req, tsuruFiles, bytes.NewReader(req.Data), w); err != nil {
		return status.Errorf(codes.Internal, "failed to build container image: %s", err)
	}

	fmt.Fprintln(w, "--> Container image build finished")

	return nil
}

func (d *Docker) build(ctx context.Context, req *pb.BuildRequest, tsuruAppFiles *TsuruAppFiles, appData io.Reader, w *BuildResponseOutputWriter) error {
	if err := ctx.Err(); err != nil { // e.g. context deadline exceeded
		return err
	}

	tmpDir, cleanFunc, err := generateBuildLocalDir(ctx, d.opts.TempDir, req, tsuruAppFiles, appData)
	if err != nil {
		return err
	}
	defer cleanFunc()

	pw, err := progresswriter.NewPrinter(context.Background(), w, "plain") // using an empty context intentionally
	if err != nil {
		return err
	}

	eg, _ := errgroup.WithContext(ctx)

	eg.Go(func() error {
		secrets, err := secretsprovider.NewStore([]secretsprovider.Source{{
			ID:       "tsuru-app-envvars",
			FilePath: filepath.Join(tmpDir, "envs.sh"),
		}})
		if err != nil {
			return err
		}

		var (
			insecureRegistry bool        // disabled by default
			pushImage        bool = true // enabled by default
		)
		if pots := req.PushOptions; pots != nil {
			pushImage = !pots.Disable
			insecureRegistry = pots.InsecureRegistry
		}

		opts := client.SolveOpt{
			LocalDirs: map[string]string{
				"context":    tmpDir,
				"dockerfile": tmpDir,
			},
			Exports: []client.ExportEntry{
				{
					Type: client.ExporterImage,
					Attrs: map[string]string{
						"name":              strings.Join(req.DestinationImages, ","),
						"push":              strconv.FormatBool(pushImage),
						"registry.insecure": strconv.FormatBool(insecureRegistry),
					},
				},
			},
			Session: []session.Attachable{
				authprovider.NewDockerAuthProvider(w),
				secretsprovider.NewSecretProvider(secrets),
			},
		}
		_, err = d.cli.Build(ctx, opts, "deploy-agent", builder.Build, progresswriter.ResetTime(pw).Status())
		return err
	})

	eg.Go(func() error {
		<-pw.Done()
		return pw.Err()
	})

	if err = eg.Wait(); err != nil {
		return err
	}

	return nil
}

func generateBuildLocalDir(ctx context.Context, baseDir string, req *pb.BuildRequest, tsuruAppFiles *TsuruAppFiles, appData io.Reader) (string, func(), error) {
	noopFunc := func() {}

	if err := ctx.Err(); err != nil {
		return "", noopFunc, err
	}

	contextRootDir, err := os.MkdirTemp(baseDir, "deploy-agent-*")
	if err != nil {
		return "", noopFunc, status.Errorf(codes.Internal, "failed to create temp dir: %s", err)
	}

	eg, _ := errgroup.WithContext(ctx)

	eg.Go(func() error {
		dockerfile, err := os.Create(filepath.Join(contextRootDir, "Dockerfile"))
		if err != nil {
			return status.Errorf(codes.Internal, "cannot create Dockerfile in %s: %s", contextRootDir, err)
		}
		defer dockerfile.Close()

		return generateContainerfile(dockerfile, req.SourceImage, tsuruAppFiles)
	})

	eg.Go(func() error {
		appArchive, err := os.Create(filepath.Join(contextRootDir, "application.tar.gz"))
		if err != nil {
			return status.Errorf(codes.Internal, "cannot create application archive: %s", err)
		}
		defer appArchive.Close()

		_, err = io.Copy(appArchive, appData)
		return err
	})

	eg.Go(func() error {
		envsFile, err := os.Create(filepath.Join(contextRootDir, "envs.sh"))
		if err != nil {
			return err
		}
		defer envsFile.Close()

		fmt.Fprintln(envsFile, "# File containing the env vars of Tsuru app. Generated by deploy-agent.")

		if req.App == nil {
			return nil
		}

		for k, v := range req.App.EnvVars {
			fmt.Fprintln(envsFile, fmt.Sprintf("%s=%q", k, v))
		}

		return nil
	})

	if err = eg.Wait(); err != nil {
		return "", noopFunc, err
	}

	return contextRootDir, func() { os.RemoveAll(contextRootDir) }, nil
}

func generateContainerfile(w io.Writer, image string, tsuruAppFiles *TsuruAppFiles) error {
	var tsuruYaml tsuruprovtypes.TsuruYamlData
	if tsuruAppFiles != nil {
		if err := yaml.Unmarshal([]byte(tsuruAppFiles.TsuruYaml), &tsuruYaml); err != nil {
			return err
		}
	}

	var buildHooks []string
	if hooks := tsuruYaml.Hooks; hooks != nil {
		buildHooks = hooks.Build
	}

	dockerfile, err := BuildContainerfile(BuildContainerfileParams{
		Image:      image,
		BuildHooks: buildHooks,
	})
	if err != nil {
		return err
	}

	_, err = io.WriteString(w, dockerfile)
	return err
}

type BuildResponseOutputWriter struct {
	stream pb.Build_BuildServer
	mu     sync.Mutex
}

func (w *BuildResponseOutputWriter) Write(p []byte) (int, error) {
	w.mu.Lock()
	defer w.mu.Unlock()

	if len(p) == 0 {
		return 0, nil
	}

	return len(p), w.stream.Send(&pb.BuildResponse{Data: &pb.BuildResponse_Output{Output: string(p)}})
}

func (w *BuildResponseOutputWriter) Read(p []byte) (int, error) { // required to implement console.File
	return 0, nil
}

func (w *BuildResponseOutputWriter) Close() error { // required to implement console.File
	return nil
}

func (w *BuildResponseOutputWriter) Fd() uintptr { // required to implement console.File
	return uintptr(0)
}

func (w *BuildResponseOutputWriter) Name() string { // required to implement console.File
	return ""
}
<|endoftext|>


<commit_before>// Copyright 2013-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.

package cpio

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"
	"time"
)

// Linux mode_t bits.
const (
	modeTypeMask    = 0170000
	modeSocket      = 0140000
	modeSymlink     = 0120000
	modeFile        = 0100000
	modeBlock       = 0060000
	modeDir         = 0040000
	modeChar        = 0020000
	modeFIFO        = 0010000
	modeSUID        = 0004000
	modeSGID        = 0002000
	modeSticky      = 0001000
	modePermissions = 0000777
)

var modeMap = map[uint64]os.FileMode{
	modeSocket:  os.ModeSocket,
	modeSymlink: os.ModeSymlink,
	modeFile:    0,
	modeBlock:   os.ModeDevice,
	modeDir:     os.ModeDir,
	modeChar:    os.ModeCharDevice,
	modeFIFO:    os.ModeNamedPipe,
}

// modes sets the modes, changing the easy ones first and the harder ones last.
// In this way, we set as much as we can before bailing out. It's not an error
// to not be able to set uid and gid, at least not yet.
// For now we also ignore sticky bits.
func setModes(r Record) error {
	if err := os.Chmod(r.Name, os.FileMode(perm(r))); err != nil {
		return err
	}
	if err := os.Chtimes(r.Name, time.Time{}, time.Unix(int64(r.MTime), 0)); err != nil {
		return err
	}
	if err := os.Chown(r.Name, int(r.UID), int(r.GID)); err != nil {
		return err
	}
	// TODO: only set SUID and GUID if we can set the owner.
	return nil
}

func perm(r Record) uint32 {
	return uint32(r.Mode) & modePermissions
}

func dev(r Record) int {
	return int(r.Rmajor<<8 | r.Rminor)
}

func linuxModeToMode(m uint64) (os.FileMode, error) {
	if t, ok := modeMap[m&modeTypeMask]; ok {
		return t, nil
	}
	return 0, fmt.Errorf("Invalid file type %#o", m&modeTypeMask)
}

func CreateFile(f Record) error {
	m, err := linuxModeToMode(f.Mode)
	if err != nil {
		return err
	}

	dir, _ := filepath.Split(f.Name)
	// The problem: many cpio archives do not specify the directories
	// and hence the permissions. They just specify the whole path.
	// In order to create files in these directories, we have to make them at least
	// mode 755.
	if dir != "" {
		switch m {
		case os.FileMode(0),
			os.ModeDevice,
			os.ModeCharDevice,
			os.ModeSymlink:
			if err := os.MkdirAll(dir, 0755); err != nil {
				return err
			}
		}
	}

	switch m {
	case os.ModeSocket, os.ModeNamedPipe:
		return fmt.Errorf("%q: type %v: cannot create IPC endpoints", f.Name, m)

	case os.FileMode(0):
		nf, err := os.Create(f.Name)
		if err != nil {
			return err
		}
		defer nf.Close()
		if _, err := io.Copy(nf, f); err != nil {
			return err
		}
		return setModes(f)

	case os.ModeDir:
		if err := os.MkdirAll(f.Name, os.FileMode(perm(f))); err != nil {
			return err
		}
		return setModes(f)

	case os.ModeDevice:
		if err := syscall.Mknod(f.Name, perm(f)|syscall.S_IFBLK, dev(f)); err != nil {
			return err
		}
		return setModes(f)

	case os.ModeCharDevice:
		if err := syscall.Mknod(f.Name, perm(f)|syscall.S_IFCHR, dev(f)); err != nil {
			return err
		}
		return setModes(f)

	case os.ModeSymlink:
		content, err := ioutil.ReadAll(f)
		if err != nil {
			return err
		}
		return os.Symlink(string(content), f.Name)

	default:
		return fmt.Errorf("%v: Unknown type %#o", f.Name, m)
	}
}

// Inumber and devnumbers are unique to Unix-like
// operating systems. You can not uniquely disambiguate a file in a
// Unix system with just an inumber, you need a device number too.
// To handle hard links (unique to Unix) we need to figure out if a
// given file has been seen before. To do this we see if a file has the
// same [dev,ino] tuple as one we have seen. If so, we won't bother
// reading it in.

type devInode struct {
	dev uint64
	ino uint64
}

var (
	inodeMap = map[devInode]Info{}
	inumber  uint64
)

// Certain elements of the file can not be set by cpio:
// the Inode #
// the Dev
// maintaining these elements leaves us with a non-reproducible
// output stream. In this function, we figure out what inumber
// we need to use, and clear out anything we can.
// We always zero the Dev.
// We try to find the matching inode. If found, we use its inumber.
// If not, we get a new inumber for it and save the inode away.
// This eliminates two of the messier parts of creating reproducible
// output streams.
func inode(i Info) (Info, bool) {
	d := devInode{dev: i.Dev, ino: i.Ino}
	i.Dev = 0

	if d, ok := inodeMap[d]; ok {
		i.Ino = d.Ino
		return i, true
	}

	i.Ino = inumber
	inumber++
	inodeMap[d] = i

	return i, false
}

func GetRecord(path string) (Record, error) {
	fi, err := os.Lstat(path)
	if err != nil {
		return Record{}, err
	}

	sys := fi.Sys().(*syscall.Stat_t)
	info, done := inode(sysInfo(path, sys))

	switch fi.Mode() & os.ModeType {
	case 0: // Regular file.
		if done {
			return Record{Info: info}, nil
		}
		return Record{Info: info, ReadCloser: NewDeferReadCloser(path)}, nil

	case os.ModeSymlink:
		linkname, err := os.Readlink(path)
		if err != nil {
			return Record{}, err
		}
		return StaticRecord([]byte(linkname), info), nil

	default:
		return StaticRecord(nil, info), nil
	}
}
<commit_msg>cpio: on extract, honor unix bits like SUID, GUID, and sticky<commit_after>// Copyright 2013-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.

package cpio

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"syscall"
	"time"

	"golang.org/x/sys/unix"
)

// Linux mode_t bits.
const (
	modeTypeMask    = 0170000
	modeSocket      = 0140000
	modeSymlink     = 0120000
	modeFile        = 0100000
	modeBlock       = 0060000
	modeDir         = 0040000
	modeChar        = 0020000
	modeFIFO        = 0010000
	modeSUID        = 0004000
	modeSGID        = 0002000
	modeSticky      = 0001000
	modePermissions = 0000777
)

var modeMap = map[uint64]os.FileMode{
	modeSocket:  os.ModeSocket,
	modeSymlink: os.ModeSymlink,
	modeFile:    0,
	modeBlock:   os.ModeDevice,
	modeDir:     os.ModeDir,
	modeChar:    os.ModeCharDevice,
	modeFIFO:    os.ModeNamedPipe,
}

// setModes sets the modes, changing the easy ones first and the harder ones last.
// In this way, we set as much as we can before bailing out.
// N.B.: if you set something with S_ISUID, then change the owner,
// the kernel (Linux, OSX, etc.) clears S_ISUID (a good idea). So, the simple thing:
// Do the chmod operations in order of difficulty, and give up as soon as we fail.
// Set the basic permissions -- not including SUID, GUID, etc.
// Set the times
// Set the owner
// Set ALL the mode bits, in case we need to do SUID, etc. If we could not
// set the owner, we won't even try this operation of course, so we won't
// have SUID incorrectly set for the wrong user.
func setModes(r Record) error {
	if err := os.Chmod(r.Name, toFileMode(r)&os.ModePerm); err != nil {
		return err
	}
	if err := os.Chtimes(r.Name, time.Time{}, time.Unix(int64(r.MTime), 0)); err != nil {
		return err
	}
	if err := os.Chown(r.Name, int(r.UID), int(r.GID)); err != nil {
		return err
	}
	if err := os.Chmod(r.Name, toFileMode(r)); err != nil {
		return err
	}
	return nil
}

func toFileMode(r Record) os.FileMode {
	m := os.FileMode(perm(r))
	if r.Mode&unix.S_ISUID != 0 {
		m |= os.ModeSetuid
	}
	if r.Mode&unix.S_ISGID != 0 {
		m |= os.ModeSetgid
	}
	if r.Mode&unix.S_ISVTX != 0 {
		m |= os.ModeSticky
	}
	return m
}

func perm(r Record) uint32 {
	return uint32(r.Mode) & modePermissions
}

func dev(r Record) int {
	return int(r.Rmajor<<8 | r.Rminor)
}

func linuxModeToFileType(m uint64) (os.FileMode, error) {
	if t, ok := modeMap[m&modeTypeMask]; ok {
		return t, nil
	}
	return 0, fmt.Errorf("Invalid file type %#o", m&modeTypeMask)
}

func CreateFile(f Record) error {
	m, err := linuxModeToFileType(f.Mode)
	if err != nil {
		return err
	}

	dir, _ := filepath.Split(f.Name)
	// The problem: many cpio archives do not specify the directories
	// and hence the permissions. They just specify the whole path.
	// In order to create files in these directories, we have to make them at least
	// mode 755.
	if dir != "" {
		switch m {
		case os.FileMode(0),
			os.ModeDevice,
			os.ModeCharDevice,
			os.ModeSymlink:
			if err := os.MkdirAll(dir, 0755); err != nil {
				return err
			}
		}
	}

	switch m {
	case os.ModeSocket, os.ModeNamedPipe:
		return fmt.Errorf("%q: type %v: cannot create IPC endpoints", f.Name, m)

	case os.FileMode(0):
		nf, err := os.Create(f.Name)
		if err != nil {
			return err
		}
		defer nf.Close()
		if _, err := io.Copy(nf, f); err != nil {
			return err
		}
		return setModes(f)

	case os.ModeDir:
		if err := os.MkdirAll(f.Name, toFileMode(f)); err != nil {
			return err
		}
		return setModes(f)

	case os.ModeDevice:
		if err := syscall.Mknod(f.Name, perm(f)|syscall.S_IFBLK, dev(f)); err != nil {
			return err
		}
		return setModes(f)

	case os.ModeCharDevice:
		if err := syscall.Mknod(f.Name, perm(f)|syscall.S_IFCHR, dev(f)); err != nil {
			return err
		}
		return setModes(f)

	case os.ModeSymlink:
		content, err := ioutil.ReadAll(f)
		if err != nil {
			return err
		}
		return os.Symlink(string(content), f.Name)

	default:
		return fmt.Errorf("%v: Unknown type %#o", f.Name, m)
	}
}

// Inumber and devnumbers are unique to Unix-like
// operating systems. You can not uniquely disambiguate a file in a
// Unix system with just an inumber, you need a device number too.
// To handle hard links (unique to Unix) we need to figure out if a
// given file has been seen before. To do this we see if a file has the
// same [dev,ino] tuple as one we have seen. If so, we won't bother
// reading it in.

type devInode struct {
	dev uint64
	ino uint64
}

var (
	inodeMap = map[devInode]Info{}
	inumber  uint64
)

// Certain elements of the file can not be set by cpio:
// the Inode #
// the Dev
// maintaining these elements leaves us with a non-reproducible
// output stream. In this function, we figure out what inumber
// we need to use, and clear out anything we can.
// We always zero the Dev.
// We try to find the matching inode. If found, we use its inumber.
// If not, we get a new inumber for it and save the inode away.
// This eliminates two of the messier parts of creating reproducible
// output streams.
func inode(i Info) (Info, bool) {
	d := devInode{dev: i.Dev, ino: i.Ino}
	i.Dev = 0

	if d, ok := inodeMap[d]; ok {
		i.Ino = d.Ino
		return i, true
	}

	i.Ino = inumber
	inumber++
	inodeMap[d] = i

	return i, false
}

func GetRecord(path string) (Record, error) {
	fi, err := os.Lstat(path)
	if err != nil {
		return Record{}, err
	}

	sys := fi.Sys().(*syscall.Stat_t)
	info, done := inode(sysInfo(path, sys))

	switch fi.Mode() & os.ModeType {
	case 0: // Regular file.
		if done {
			return Record{Info: info}, nil
		}
		return Record{Info: info, ReadCloser: NewDeferReadCloser(path)}, nil

	case os.ModeSymlink:
		linkname, err := os.Readlink(path)
		if err != nil {
			return Record{}, err
		}
		return StaticRecord([]byte(linkname), info), nil

	default:
		return StaticRecord(nil, info), nil
	}
}
<|endoftext|>


<commit_before>package db

import (
	r "github.com/dancannon/gorethink"
	"log"
)

var Session *r.Session

func Init() error {

	log.Println("Connecting to RethinkDB...")

	// TODO: Set up actual production configuration.
	Session, err := r.Connect(r.ConnectOpts{
		Address:  "localhost:28015",
		Database: "test",
		MaxIdle:  10,
		MaxOpen:  10,
	})
	if err != nil {
		log.Println("Error connecting to RethinkdB:")
		log.Println(err.Error())
		return err
	}

	Session.SetMaxOpenConns(5)

	log.Println("Successfully connected to RethinkDB.")

	setupTables()

	return nil
}

func Close() error {
	log.Println("Closing connection to RethinkDB...")
	err := Session.Close()
	if err != nil {
		log.Println("Error closing connection to RethinkDB:")
		log.Println(err.Error())
		return err
	}
	log.Println("Successfully closed connection to RethinkDB.")
	return nil
}

func setupTables() {

	log.Println("Setting up tables...")

	// Set up the initial user table.
	// TODO Maybe handle the table already existing?
	r.DB("test").TableCreate("users").RunWrite(Session)
	r.Table("users").IndexCreate("Username").RunWrite(Session)

	log.Println("Done setting up tables.")
}
<commit_msg>gb: Do not set up tables yet.<commit_after>package db

import (
	r "github.com/dancannon/gorethink"
	"log"
)

var Session *r.Session

func Init() error {

	log.Println("Connecting to RethinkDB...")

	// TODO: Set up actual production configuration.
	Session, err := r.Connect(r.ConnectOpts{
		Address:  "localhost:28015",
		Database: "test",
		MaxIdle:  10,
		MaxOpen:  10,
	})
	if err != nil {
		log.Println("Error connecting to RethinkdB:")
		log.Println(err.Error())
		return err
	}

	Session.SetMaxOpenConns(5)

	log.Println("Successfully connected to RethinkDB.")

	setupTables()

	return nil
}

func Close() error {
	log.Println("Closing connection to RethinkDB...")
	err := Session.Close()
	if err != nil {
		log.Println("Error closing connection to RethinkDB:")
		log.Println(err.Error())
		return err
	}
	log.Println("Successfully closed connection to RethinkDB.")
	return nil
}

func setupTables() {

	log.Println("Setting up tables...")

	// Set up the initial user table.
	// TODO Maybe handle the table already existing?
	//r.DB("test").TableCreate("users").RunWrite(Session)
	//r.Table("users").IndexCreate("Username").RunWrite(Session)

	log.Println("Done setting up tables.")
}
<|endoftext|>


<commit_before>// +build js

package select_menu

import (
	"net/url"
	"strings"

	"github.com/gopherjs/gopherjs/js"
	"github.com/shurcooL/go/gopherjs_http/jsutil"
	"honnef.co/go/js/dom"
)

func init() {
	js.Global.Set("SelectMenuOnInput", jsutil.Wrap(SelectMenuOnInput))
}

func SelectMenuOnInput(event dom.Event, object dom.HTMLElement, defaultOption, queryParameter string) {
	rawQuery := strings.TrimPrefix(dom.GetWindow().Location().Search, "?")
	query, _ := url.ParseQuery(rawQuery)

	selectElement := object.(*dom.HTMLSelectElement)

	/*selectedIndex := selectElement.Underlying().Get("selectedIndex").Int()
	selected := selectElement.Options()[selectedIndex].Text*/
	selected := selectElement.Underlying().Get("selectedOptions").Index(0).Get("text").String()

	if selected == defaultOption {
		query.Del(queryParameter)
	} else {
		query.Set(queryParameter, selected)
	}

	dom.GetWindow().Location().Search = "?" + query.Encode()
}
<commit_msg>select_menu: Use dom.HTMLSelectElement method.<commit_after>// +build js

package select_menu

import (
	"net/url"
	"strings"

	"github.com/gopherjs/gopherjs/js"
	"github.com/shurcooL/go/gopherjs_http/jsutil"
	"honnef.co/go/js/dom"
)

func init() {
	js.Global.Set("SelectMenuOnInput", jsutil.Wrap(SelectMenuOnInput))
}

func SelectMenuOnInput(event dom.Event, object dom.HTMLElement, defaultOption, queryParameter string) {
	rawQuery := strings.TrimPrefix(dom.GetWindow().Location().Search, "?")
	query, _ := url.ParseQuery(rawQuery)

	selectElement := object.(*dom.HTMLSelectElement)

	selected := selectElement.SelectedOptions()[0].Text

	if selected == defaultOption {
		query.Del(queryParameter)
	} else {
		query.Set(queryParameter, selected)
	}

	dom.GetWindow().Location().Search = "?" + query.Encode()
}
<|endoftext|>


<commit_before>package kafka

import (
	"log"
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/gafka/ctx"
)

// Config is the configuration of kafka pkg.
type Config struct {
	async bool

	Sarama *sarama.Config
}

// DefaultConfig creates a default Config as async producer.
func DefaultConfig() *Config {
	cf := sarama.NewConfig()
	// common for sync and async
	cf.ChannelBufferSize = 256 * 4 // default was 256
	cf.Producer.Retry.Backoff = time.Millisecond * 300
	cf.Producer.Retry.Max = 5
	cf.Producer.RequiredAcks = sarama.WaitForLocal

	// async
	cf.Producer.Return.Errors = true
	cf.Producer.Return.Successes = true
	cf.Producer.Flush.Frequency = time.Second
	cf.Producer.Flush.Messages = 2000 // TODO
	cf.Producer.Flush.MaxMessages = 0 // unlimited
	//cf.Producer.Flush.Bytes = 64 << 10

	return &Config{
		Sarama: cf,
		async:  true,
	}
}

func (c *Config) Ack(ack sarama.RequiredAcks) *Config {
	c.Sarama.Producer.RequiredAcks = ack
	return c
}

func (c *Config) SyncMode() *Config {
	c.async = false
	return c
}

func (c *Config) AsyncMode() *Config {
	c.async = true
	return c
}

func init() {
	ctx.LoadFromHome()
	log.SetFlags(log.LstdFlags | log.Lshortfile) // for sarama
}
<commit_msg>BUG FIX: sync mode will reconfigure the sarama<commit_after>package kafka

import (
	"log"
	"time"

	"github.com/Shopify/sarama"
	"github.com/funkygao/gafka/ctx"
)

// Config is the configuration of kafka pkg.
type Config struct {
	async bool

	Sarama *sarama.Config
}

// DefaultConfig creates a default Config as async producer.
func DefaultConfig() *Config {
	cf := sarama.NewConfig()
	// common for sync and async
	cf.ChannelBufferSize = 256 * 4 // default was 256
	cf.Producer.Retry.Backoff = time.Millisecond * 300
	cf.Producer.Retry.Max = 5
	cf.Producer.RequiredAcks = sarama.WaitForLocal

	// async
	cf.Producer.Return.Errors = true
	cf.Producer.Return.Successes = true
	cf.Producer.Flush.Frequency = time.Second
	cf.Producer.Flush.Messages = 2000 // TODO
	cf.Producer.Flush.MaxMessages = 0 // unlimited
	//cf.Producer.Flush.Bytes = 64 << 10

	return &Config{
		Sarama: cf,
		async:  true,
	}
}

func (c *Config) Ack(ack sarama.RequiredAcks) *Config {
	c.Sarama.Producer.RequiredAcks = ack
	return c
}

func (c *Config) SyncMode() *Config {
	c.async = false

	// explicitly zero batch
	c.Sarama.Producer.Flush.Frequency = 0
	c.Sarama.Producer.Flush.Bytes = 0
	c.Sarama.Producer.Flush.Messages = 0

	c.Sarama.Producer.Return.Successes = false
	return c
}

func (c *Config) AsyncMode() *Config {
	c.async = true
	return c
}

func init() {
	ctx.LoadFromHome()
	log.SetFlags(log.LstdFlags | log.Lshortfile) // for sarama
}
<|endoftext|>


<commit_before>// Copyright 2017-2018 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.

package ldd

import (
	"fmt"
	"io/ioutil"
	"os"
	"strings"
	"testing"
)

// TestLdd tests Ldd against /bin/date.
// This is just about guaranteed to have
// some output on most linux systems.
func TestLdd(t *testing.T) {
	n, err := Ldd([]string{"/bin/date"})
	if err != nil {
		t.Fatalf("Ldd on /bin/date: want nil, got %v", err)
	}
	t.Logf("TestLdd: /bin/date has deps of")
	for i := range n {
		t.Logf("\t%v", n[i])
	}
}

// lddOne is a helper that runs Ldd on one file. It returns
// the list so we can use elements from the list on another
// test. We do it this way because, unlike /bin/date, there's
// almost nothing else we can assume exists, e.g. /lib/libc.so
// is a different name on almost every *ix* system.
func lddOne(name string) ([]string, error) {
	var libMap = make(map[string]bool)
	n, err := Ldd([]string{name})
	if err != nil {
		return nil, fmt.Errorf("Ldd on %v: want nil, got %v", name, err)
	}
	l, err := List([]string{name})
	if err != nil {
		return nil, fmt.Errorf("LddList on %v: want nil, got %v", name, err)
	}
	if len(n) != len(l) {
		return nil, fmt.Errorf("%v: Len of Ldd(%v) and LddList(%v): want same, got different", name, len(n), len(l))
	}
	for i := range n {
		libMap[n[i].FullName] = true
	}
	for i := range n {
		if !libMap[l[i]] {
			return nil, fmt.Errorf("%v: %v was in LddList but not in Ldd", name, l[i])
		}
	}
	return l, nil
}

// TestLddList tests that the LddList is the
// same as the info returned by Ldd
func TestLddList(t *testing.T) {
	n, err := lddOne("/bin/date")
	if err != nil {
		t.Fatal(err)
	}
	// Find the first name in the array that contains "lib"
	// Test 'em all
	for _, f := range n {
		if !strings.Contains(f, "lib") {
			continue
		}
		t.Logf("Test %v", f)
		n, err := lddOne(f)
		if err != nil {
			t.Error(err)
		}
		t.Logf("%v has deps of %v", f, n)
	}
}

// This could have been a great test, if ld.so actually followed ITS OWN DOCS
// and used LD_LIBRARY_PATH. It doesn't.
func testLddBadSo(t *testing.T) {
	tempDir, err := ioutil.TempDir("", "ldd")
	if err != nil {
		t.Fatalf("TempDir: %v", err)
	}
	defer os.RemoveAll(tempDir)
	if err := os.Setenv("LD_LIBRARY_PATH", tempDir); err != nil {
		t.Fatalf("Setting LDD_LIBRARY_PATH to %v: want nil, got %v", tempDir, err)
	}
	if _, err := Ldd([]string{"/bin/date"}); err == nil {
		t.Fatalf("Ldd on /bin/date: want err, got nil")
	}
	t.Logf("Err on bad dir is %v", err)

}
<commit_msg>ldd: remove unused test<commit_after>// Copyright 2017-2018 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.

package ldd

import (
	"fmt"
	"strings"
	"testing"
)

// TestLdd tests Ldd against /bin/date.
// This is just about guaranteed to have
// some output on most linux systems.
func TestLdd(t *testing.T) {
	n, err := Ldd([]string{"/bin/date"})
	if err != nil {
		t.Fatalf("Ldd on /bin/date: want nil, got %v", err)
	}
	t.Logf("TestLdd: /bin/date has deps of")
	for i := range n {
		t.Logf("\t%v", n[i])
	}
}

// lddOne is a helper that runs Ldd on one file. It returns
// the list so we can use elements from the list on another
// test. We do it this way because, unlike /bin/date, there's
// almost nothing else we can assume exists, e.g. /lib/libc.so
// is a different name on almost every *ix* system.
func lddOne(name string) ([]string, error) {
	var libMap = make(map[string]bool)
	n, err := Ldd([]string{name})
	if err != nil {
		return nil, fmt.Errorf("Ldd on %v: want nil, got %v", name, err)
	}
	l, err := List([]string{name})
	if err != nil {
		return nil, fmt.Errorf("LddList on %v: want nil, got %v", name, err)
	}
	if len(n) != len(l) {
		return nil, fmt.Errorf("%v: Len of Ldd(%v) and LddList(%v): want same, got different", name, len(n), len(l))
	}
	for i := range n {
		libMap[n[i].FullName] = true
	}
	for i := range n {
		if !libMap[l[i]] {
			return nil, fmt.Errorf("%v: %v was in LddList but not in Ldd", name, l[i])
		}
	}
	return l, nil
}

// TestLddList tests that the LddList is the
// same as the info returned by Ldd
func TestLddList(t *testing.T) {
	n, err := lddOne("/bin/date")
	if err != nil {
		t.Fatal(err)
	}
	// Find the first name in the array that contains "lib"
	// Test 'em all
	for _, f := range n {
		if !strings.Contains(f, "lib") {
			continue
		}
		t.Logf("Test %v", f)
		n, err := lddOne(f)
		if err != nil {
			t.Error(err)
		}
		t.Logf("%v has deps of %v", f, n)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2011 Google Inc.

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

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

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

package server

import (
	"bytes"
	"errors"
	"fmt"
	"image"
	"image/jpeg"
	"image/png"
	"io"
	"log"
	"net/http"
	"strings"

	"camlistore.org/pkg/blobref"
	"camlistore.org/pkg/blobserver"
	"camlistore.org/pkg/magic"
	"camlistore.org/pkg/misc/resize"
	"camlistore.org/pkg/schema"
)

type ImageHandler struct {
	Fetcher             blobref.StreamingFetcher
	Cache               blobserver.Storage // optional
	MaxWidth, MaxHeight int
	Square              bool
	sc                  ScaledImage // optional cache for scaled images
}

func (ih *ImageHandler) storageSeekFetcher() (blobref.SeekFetcher, error) {
	return blobref.SeekerFromStreamingFetcher(ih.Fetcher) // TODO: pass ih.Cache?
}

type subImager interface {
	SubImage(image.Rectangle) image.Image
}

func squareImage(i image.Image) image.Image {
	si, ok := i.(subImager)
	if !ok {
		log.Fatalf("image %T isn't a subImager", i)
	}
	b := i.Bounds()
	if b.Dx() > b.Dy() {
		thin := (b.Dx() - b.Dy()) / 2
		newB := b
		newB.Min.X += thin
		newB.Max.X -= thin
		return si.SubImage(newB)
	}
	thin := (b.Dy() - b.Dx()) / 2
	newB := b
	newB.Min.Y += thin
	newB.Max.Y -= thin
	return si.SubImage(newB)
}

func (ih *ImageHandler) cache(tr io.Reader, name string) (*blobref.BlobRef, error) {
	br, err := schema.WriteFileFromReaderRolling(ih.Cache, name, tr)
	if err != nil {
		return br, errors.New("failed to cache " + name + ": " + err.Error())
	}
	log.Printf("Imache Cache: saved as %v\n", br)
	return br, nil
}

// CacheScaled saves in the image handler's cache the scaled image read
// from tr, and puts its blobref in the scaledImage under the key name.
func (ih *ImageHandler) cacheScaled(tr io.Reader, name string) error {
	br, err := ih.cache(tr, name)
	if err != nil {
		return err
	}
	ih.sc.Put(name, br)
	return nil
}

func (ih *ImageHandler) cached(br *blobref.BlobRef) (fr *schema.FileReader, err error) {
	fetchSeeker, err := blobref.SeekerFromStreamingFetcher(ih.Cache)
	if err != nil {
		return nil, err
	}

	fr, err = schema.NewFileReader(fetchSeeker, br)
	if err != nil {
		return nil, err
	}
	log.Printf("Image Cache: hit: %v\n", br)
	return fr, nil
}

// Key format: "scaled:" + bref + ":" + width "x" + height
// where bref is the blobref of the unscaled image.
func cacheKey(bref string, width int, height int) string {
	return fmt.Sprintf("scaled:%v:%dx%d", bref, width, height)
}

// ScaledCached reads the scaled version of the image in file,
// if it is in cache. On success, the image format is returned.
func (ih *ImageHandler) scaledCached(buf *bytes.Buffer, file *blobref.BlobRef) (format string, err error) {
	name := cacheKey(file.String(), ih.MaxWidth, ih.MaxHeight)
	br, err := ih.sc.Get(name)
	if err != nil {
		return format, fmt.Errorf("%v: %v", name, err)
	}
	fr, err := ih.cached(br)
	if err != nil {
		return format, fmt.Errorf("No cache hit for %v: %v", br, err)
	}
	_, err = io.Copy(buf, fr)
	if err != nil {
		return format, fmt.Errorf("error reading cached thumbnail %v: %v", name, err)
	}
	mime := magic.MimeType(buf.Bytes())
	if mime == "" {
		return format, fmt.Errorf("error with cached thumbnail %v: unknown mime type", name)
	}
	pieces := strings.Split(mime, "/")
	if len(pieces) < 2 {
		return format, fmt.Errorf("error with cached thumbnail %v: bogus mime type", name)
	}
	if pieces[0] != "image" {
		return format, fmt.Errorf("error with cached thumbnail %v: not an image", name)
	}
	return pieces[1], nil
}

func (ih *ImageHandler) scaleImage(buf *bytes.Buffer, file *blobref.BlobRef) (format string, err error) {
	mw, mh := ih.MaxWidth, ih.MaxHeight

	fetchSeeker, err := ih.storageSeekFetcher()
	if err != nil {
		return format, err
	}

	fr, err := schema.NewFileReader(fetchSeeker, file)
	if err != nil {
		return format, err
	}

	_, err = io.Copy(buf, fr)
	if err != nil {
		return format, fmt.Errorf("image resize: error reading image %s: %v", file, err)
	}
	i, format, err := image.Decode(bytes.NewBuffer(buf.Bytes()))
	if err != nil {
		return format, err
	}
	b := i.Bounds()

	useBytesUnchanged := true

	isSquare := b.Dx() == b.Dy()
	if ih.Square && !isSquare {
		useBytesUnchanged = false
		i = squareImage(i)
		b = i.Bounds()
	}

	// only do downscaling, otherwise just serve the original image
	if mw < b.Dx() || mh < b.Dy() {
		useBytesUnchanged = false

		const huge = 2400
		// If it's gigantic, it's more efficient to downsample first
		// and then resize; resizing will smooth out the roughness.
		// (trusting the moustachio guys on that one).
		if b.Dx() > huge || b.Dy() > huge {
			w, h := mw*2, mh*2
			if b.Dx() > b.Dy() {
				w = b.Dx() * h / b.Dy()
			} else {
				h = b.Dy() * w / b.Dx()
			}
			i = resize.Resample(i, i.Bounds(), w, h)
			b = i.Bounds()
		}
		// conserve proportions. use the smallest of the two as the decisive one.
		if mw > mh {
			mw = b.Dx() * mh / b.Dy()
		} else {
			mh = b.Dy() * mw / b.Dx()
		}
	}

	if !useBytesUnchanged {
		i = resize.Resize(i, b, mw, mh)
		// Encode as a new image
		buf.Reset()
		switch format {
		case "jpeg":
			err = jpeg.Encode(buf, i, nil)
		default:
			err = png.Encode(buf, i)
		}
		if err != nil {
			return format, err
		}
	}
	return format, nil
}

func (ih *ImageHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request, file *blobref.BlobRef) {
	if req.Method != "GET" && req.Method != "HEAD" {
		http.Error(rw, "Invalid method", 400)
		return
	}
	mw, mh := ih.MaxWidth, ih.MaxHeight
	if mw == 0 || mh == 0 || mw > 2000 || mh > 2000 {
		http.Error(rw, "bogus dimensions", 400)
		return
	}

	var buf bytes.Buffer
	var err error
	format := ""
	cacheHit := false
	if ih.sc != nil {
		format, err = ih.scaledCached(&buf, file)
		if err != nil {
			log.Printf("image resize: %v", err)
		} else {
			cacheHit = true
		}
	}

	if !cacheHit {
		format, err = ih.scaleImage(&buf, file)
		if err != nil {
			http.Error(rw, err.Error(), 500)
			return
		}
		if ih.sc != nil {
			name := cacheKey(file.String(), mw, mh)
			bufcopy := buf.Bytes()
			err = ih.cacheScaled(bytes.NewBuffer(bufcopy), name)
			if err != nil {
				log.Printf("image resize: %v", err)
			}
		}
	}

	rw.Header().Set("Content-Type", imageContentTypeOfFormat(format))
	size := buf.Len()
	rw.Header().Set("Content-Length", fmt.Sprintf("%d", size))
	n, err := io.Copy(rw, &buf)
	if err != nil {
		log.Printf("error serving thumbnail of file schema %s: %v", file, err)
		return
	}
	if n != int64(size) {
		log.Printf("error serving thumbnail of file schema %s: sent %d, expected size of %d",
			file, n, size)
		return
	}
}

func imageContentTypeOfFormat(format string) string {
	if format == "jpeg" {
		return "image/jpeg"
	}
	return "image/png"
}
<commit_msg>typo<commit_after>/*
Copyright 2011 Google Inc.

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

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

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

package server

import (
	"bytes"
	"errors"
	"fmt"
	"image"
	"image/jpeg"
	"image/png"
	"io"
	"log"
	"net/http"
	"strings"

	"camlistore.org/pkg/blobref"
	"camlistore.org/pkg/blobserver"
	"camlistore.org/pkg/magic"
	"camlistore.org/pkg/misc/resize"
	"camlistore.org/pkg/schema"
)

type ImageHandler struct {
	Fetcher             blobref.StreamingFetcher
	Cache               blobserver.Storage // optional
	MaxWidth, MaxHeight int
	Square              bool
	sc                  ScaledImage // optional cache for scaled images
}

func (ih *ImageHandler) storageSeekFetcher() (blobref.SeekFetcher, error) {
	return blobref.SeekerFromStreamingFetcher(ih.Fetcher) // TODO: pass ih.Cache?
}

type subImager interface {
	SubImage(image.Rectangle) image.Image
}

func squareImage(i image.Image) image.Image {
	si, ok := i.(subImager)
	if !ok {
		log.Fatalf("image %T isn't a subImager", i)
	}
	b := i.Bounds()
	if b.Dx() > b.Dy() {
		thin := (b.Dx() - b.Dy()) / 2
		newB := b
		newB.Min.X += thin
		newB.Max.X -= thin
		return si.SubImage(newB)
	}
	thin := (b.Dy() - b.Dx()) / 2
	newB := b
	newB.Min.Y += thin
	newB.Max.Y -= thin
	return si.SubImage(newB)
}

func (ih *ImageHandler) cache(tr io.Reader, name string) (*blobref.BlobRef, error) {
	br, err := schema.WriteFileFromReaderRolling(ih.Cache, name, tr)
	if err != nil {
		return br, errors.New("failed to cache " + name + ": " + err.Error())
	}
	log.Printf("Image Cache: saved as %v\n", br)
	return br, nil
}

// CacheScaled saves in the image handler's cache the scaled image read
// from tr, and puts its blobref in the scaledImage under the key name.
func (ih *ImageHandler) cacheScaled(tr io.Reader, name string) error {
	br, err := ih.cache(tr, name)
	if err != nil {
		return err
	}
	ih.sc.Put(name, br)
	return nil
}

func (ih *ImageHandler) cached(br *blobref.BlobRef) (fr *schema.FileReader, err error) {
	fetchSeeker, err := blobref.SeekerFromStreamingFetcher(ih.Cache)
	if err != nil {
		return nil, err
	}

	fr, err = schema.NewFileReader(fetchSeeker, br)
	if err != nil {
		return nil, err
	}
	log.Printf("Image Cache: hit: %v\n", br)
	return fr, nil
}

// Key format: "scaled:" + bref + ":" + width "x" + height
// where bref is the blobref of the unscaled image.
func cacheKey(bref string, width int, height int) string {
	return fmt.Sprintf("scaled:%v:%dx%d", bref, width, height)
}

// ScaledCached reads the scaled version of the image in file,
// if it is in cache. On success, the image format is returned.
func (ih *ImageHandler) scaledCached(buf *bytes.Buffer, file *blobref.BlobRef) (format string, err error) {
	name := cacheKey(file.String(), ih.MaxWidth, ih.MaxHeight)
	br, err := ih.sc.Get(name)
	if err != nil {
		return format, fmt.Errorf("%v: %v", name, err)
	}
	fr, err := ih.cached(br)
	if err != nil {
		return format, fmt.Errorf("No cache hit for %v: %v", br, err)
	}
	_, err = io.Copy(buf, fr)
	if err != nil {
		return format, fmt.Errorf("error reading cached thumbnail %v: %v", name, err)
	}
	mime := magic.MimeType(buf.Bytes())
	if mime == "" {
		return format, fmt.Errorf("error with cached thumbnail %v: unknown mime type", name)
	}
	pieces := strings.Split(mime, "/")
	if len(pieces) < 2 {
		return format, fmt.Errorf("error with cached thumbnail %v: bogus mime type", name)
	}
	if pieces[0] != "image" {
		return format, fmt.Errorf("error with cached thumbnail %v: not an image", name)
	}
	return pieces[1], nil
}

func (ih *ImageHandler) scaleImage(buf *bytes.Buffer, file *blobref.BlobRef) (format string, err error) {
	mw, mh := ih.MaxWidth, ih.MaxHeight

	fetchSeeker, err := ih.storageSeekFetcher()
	if err != nil {
		return format, err
	}

	fr, err := schema.NewFileReader(fetchSeeker, file)
	if err != nil {
		return format, err
	}

	_, err = io.Copy(buf, fr)
	if err != nil {
		return format, fmt.Errorf("image resize: error reading image %s: %v", file, err)
	}
	i, format, err := image.Decode(bytes.NewBuffer(buf.Bytes()))
	if err != nil {
		return format, err
	}
	b := i.Bounds()

	useBytesUnchanged := true

	isSquare := b.Dx() == b.Dy()
	if ih.Square && !isSquare {
		useBytesUnchanged = false
		i = squareImage(i)
		b = i.Bounds()
	}

	// only do downscaling, otherwise just serve the original image
	if mw < b.Dx() || mh < b.Dy() {
		useBytesUnchanged = false

		const huge = 2400
		// If it's gigantic, it's more efficient to downsample first
		// and then resize; resizing will smooth out the roughness.
		// (trusting the moustachio guys on that one).
		if b.Dx() > huge || b.Dy() > huge {
			w, h := mw*2, mh*2
			if b.Dx() > b.Dy() {
				w = b.Dx() * h / b.Dy()
			} else {
				h = b.Dy() * w / b.Dx()
			}
			i = resize.Resample(i, i.Bounds(), w, h)
			b = i.Bounds()
		}
		// conserve proportions. use the smallest of the two as the decisive one.
		if mw > mh {
			mw = b.Dx() * mh / b.Dy()
		} else {
			mh = b.Dy() * mw / b.Dx()
		}
	}

	if !useBytesUnchanged {
		i = resize.Resize(i, b, mw, mh)
		// Encode as a new image
		buf.Reset()
		switch format {
		case "jpeg":
			err = jpeg.Encode(buf, i, nil)
		default:
			err = png.Encode(buf, i)
		}
		if err != nil {
			return format, err
		}
	}
	return format, nil
}

func (ih *ImageHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request, file *blobref.BlobRef) {
	if req.Method != "GET" && req.Method != "HEAD" {
		http.Error(rw, "Invalid method", 400)
		return
	}
	mw, mh := ih.MaxWidth, ih.MaxHeight
	if mw == 0 || mh == 0 || mw > 2000 || mh > 2000 {
		http.Error(rw, "bogus dimensions", 400)
		return
	}

	var buf bytes.Buffer
	var err error
	format := ""
	cacheHit := false
	if ih.sc != nil {
		format, err = ih.scaledCached(&buf, file)
		if err != nil {
			log.Printf("image resize: %v", err)
		} else {
			cacheHit = true
		}
	}

	if !cacheHit {
		format, err = ih.scaleImage(&buf, file)
		if err != nil {
			http.Error(rw, err.Error(), 500)
			return
		}
		if ih.sc != nil {
			name := cacheKey(file.String(), mw, mh)
			bufcopy := buf.Bytes()
			err = ih.cacheScaled(bytes.NewBuffer(bufcopy), name)
			if err != nil {
				log.Printf("image resize: %v", err)
			}
		}
	}

	rw.Header().Set("Content-Type", imageContentTypeOfFormat(format))
	size := buf.Len()
	rw.Header().Set("Content-Length", fmt.Sprintf("%d", size))
	n, err := io.Copy(rw, &buf)
	if err != nil {
		log.Printf("error serving thumbnail of file schema %s: %v", file, err)
		return
	}
	if n != int64(size) {
		log.Printf("error serving thumbnail of file schema %s: sent %d, expected size of %d",
			file, n, size)
		return
	}
}

func imageContentTypeOfFormat(format string) string {
	if format == "jpeg" {
		return "image/jpeg"
	}
	return "image/png"
}
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package version

// Base version information.
//
// This is the fallback data used when version information from git is not
// provided via go ldflags. It provides an approximation of the Kubernetes
// version for ad-hoc builds (e.g. `go build`) that cannot get the version
// information from git.
//
// If you are looking at these fields in the git tree, they look
// strange. They are modified on the fly by the build process. The
// in-tree values are dummy values used for "git archive", which also
// works for GitHub tar downloads.
//
// When releasing a new Kubernetes version, this file is updated by
// build/mark_new_version.sh to reflect the new version, and then a
// git annotated tag (using format vX.Y where X == Major version and Y
// == Minor version) is created to point to the commit that updates
// pkg/version/base.go
var (
	// TODO: Deprecate gitMajor and gitMinor, use only gitVersion
	// instead. First step in deprecation, keep the fields but make
	// them irrelevant. (Next we'll take it out, which may muck with
	// scripts consuming the kubectl version output - but most of
	// these should be looking at gitVersion already anyways.)
	gitMajor string = "1" // major version, always numeric
	gitMinor string = "4" // minor version, numeric possibly followed by "+"

	// semantic version, derived by build scripts (see
	// https://github.com/kubernetes/kubernetes/blob/master/docs/design/versioning.md
	// for a detailed discussion of this field)
	//
	// TODO: This field is still called "gitVersion" for legacy
	// reasons. For prerelease versions, the build metadata on the
	// semantic version is a git hash, but the version itself is no
	// longer the direct output of "git describe", but a slight
	// translation to be semver compliant.
	gitVersion   string = "v1.4.4+$Format:%h$"
	gitCommit    string = "$Format:%H$"    // sha1 from git, output of $(git rev-parse HEAD)
	gitTreeState string = "not a git tree" // state of git tree, either "clean" or "dirty"

	buildDate string = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
)
<commit_msg>Kubernetes version v1.4.5-beta.0<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package version

// Base version information.
//
// This is the fallback data used when version information from git is not
// provided via go ldflags. It provides an approximation of the Kubernetes
// version for ad-hoc builds (e.g. `go build`) that cannot get the version
// information from git.
//
// If you are looking at these fields in the git tree, they look
// strange. They are modified on the fly by the build process. The
// in-tree values are dummy values used for "git archive", which also
// works for GitHub tar downloads.
//
// When releasing a new Kubernetes version, this file is updated by
// build/mark_new_version.sh to reflect the new version, and then a
// git annotated tag (using format vX.Y where X == Major version and Y
// == Minor version) is created to point to the commit that updates
// pkg/version/base.go
var (
	// TODO: Deprecate gitMajor and gitMinor, use only gitVersion
	// instead. First step in deprecation, keep the fields but make
	// them irrelevant. (Next we'll take it out, which may muck with
	// scripts consuming the kubectl version output - but most of
	// these should be looking at gitVersion already anyways.)
	gitMajor string = "1"  // major version, always numeric
	gitMinor string = "4+" // minor version, numeric possibly followed by "+"

	// semantic version, derived by build scripts (see
	// https://github.com/kubernetes/kubernetes/blob/master/docs/design/versioning.md
	// for a detailed discussion of this field)
	//
	// TODO: This field is still called "gitVersion" for legacy
	// reasons. For prerelease versions, the build metadata on the
	// semantic version is a git hash, but the version itself is no
	// longer the direct output of "git describe", but a slight
	// translation to be semver compliant.
	gitVersion   string = "v1.4.5-beta.0+$Format:%h$"
	gitCommit    string = "$Format:%H$"    // sha1 from git, output of $(git rev-parse HEAD)
	gitTreeState string = "not a git tree" // state of git tree, either "clean" or "dirty"

	buildDate string = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
)
<|endoftext|>


<commit_before>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package version

// Base version information.
//
// This is the fallback data used when version information from git is not
// provided via go ldflags. It provides an approximation of the Kubernetes
// version for ad-hoc builds (e.g. `go build`) that cannot get the version
// information from git.
//
// If you are looking at these fields in the git tree, they look
// strange. They are modified on the fly by the build process. The
// in-tree values are dummy values used for "git archive", which also
// works for GitHub tar downloads.
//
// When releasing a new Kubernetes version, this file is updated by
// build/mark_new_version.sh to reflect the new version, and then a
// git annotated tag (using format vX.Y where X == Major version and Y
// == Minor version) is created to point to the commit that updates
// pkg/version/base.go
var (
	// TODO: Deprecate gitMajor and gitMinor, use only gitVersion
	// instead. First step in deprecation, keep the fields but make
	// them irrelevant. (Next we'll take it out, which may muck with
	// scripts consuming the kubectl version output - but most of
	// these should be looking at gitVersion already anyways.)
	gitMajor string = "1"  // major version, always numeric
	gitMinor string = "4+" // minor version, numeric possibly followed by "+"

	// semantic version, derived by build scripts (see
	// https://github.com/kubernetes/kubernetes/blob/master/docs/design/versioning.md
	// for a detailed discussion of this field)
	//
	// TODO: This field is still called "gitVersion" for legacy
	// reasons. For prerelease versions, the build metadata on the
	// semantic version is a git hash, but the version itself is no
	// longer the direct output of "git describe", but a slight
	// translation to be semver compliant.
	gitVersion   string = "v1.4.9-beta.0+$Format:%h$"
	gitCommit    string = "$Format:%H$"    // sha1 from git, output of $(git rev-parse HEAD)
	gitTreeState string = "not a git tree" // state of git tree, either "clean" or "dirty"

	buildDate string = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
)
<commit_msg>Kubernetes version v1.4.9<commit_after>/*
Copyright 2014 The Kubernetes Authors.

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

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

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

package version

// Base version information.
//
// This is the fallback data used when version information from git is not
// provided via go ldflags. It provides an approximation of the Kubernetes
// version for ad-hoc builds (e.g. `go build`) that cannot get the version
// information from git.
//
// If you are looking at these fields in the git tree, they look
// strange. They are modified on the fly by the build process. The
// in-tree values are dummy values used for "git archive", which also
// works for GitHub tar downloads.
//
// When releasing a new Kubernetes version, this file is updated by
// build/mark_new_version.sh to reflect the new version, and then a
// git annotated tag (using format vX.Y where X == Major version and Y
// == Minor version) is created to point to the commit that updates
// pkg/version/base.go
var (
	// TODO: Deprecate gitMajor and gitMinor, use only gitVersion
	// instead. First step in deprecation, keep the fields but make
	// them irrelevant. (Next we'll take it out, which may muck with
	// scripts consuming the kubectl version output - but most of
	// these should be looking at gitVersion already anyways.)
	gitMajor string = "1" // major version, always numeric
	gitMinor string = "4" // minor version, numeric possibly followed by "+"

	// semantic version, derived by build scripts (see
	// https://github.com/kubernetes/kubernetes/blob/master/docs/design/versioning.md
	// for a detailed discussion of this field)
	//
	// TODO: This field is still called "gitVersion" for legacy
	// reasons. For prerelease versions, the build metadata on the
	// semantic version is a git hash, but the version itself is no
	// longer the direct output of "git describe", but a slight
	// translation to be semver compliant.
	gitVersion   string = "v1.4.9+$Format:%h$"
	gitCommit    string = "$Format:%H$"    // sha1 from git, output of $(git rev-parse HEAD)
	gitTreeState string = "not a git tree" // state of git tree, either "clean" or "dirty"

	buildDate string = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ')
)
<|endoftext|>