<commit_before>/*
Package raw provides utilities for mapping raw Go structs to byte slices.
*/
package raw

import (
	"unsafe"
)

// String represents an offset and pointer to a string in a byte slice.
type String struct {
	Offset int
	Length int
}

// Encode writes a string to a byte slice and updates the offset/length.
func (s *String) Encode(str string, value *[]byte) {
	s.Offset = len(*value)
	s.Length = len(str)
	*value = append(*value, []byte(str)...)
}

// Bytes returns a byte slice pointing to the string's contents.
func (s *String) Bytes(value []byte) []byte {
	return (*[0xFFFFFFF]byte)(unsafe.Pointer(&value[s.Offset]))[:s.Length]
}

// String returns a Go string of the string value from an encoded byte slice.
func (s *String) String(value []byte) string {
	return string(s.Bytes(value))
}
<commit_msg>Change raw.String to use a uint16 offset and len.<commit_after>/*
Package raw provides utilities for mapping raw Go structs to byte slices.
*/
package raw

import (
	"unsafe"
)

// String represents an offset and pointer to a string in a byte slice.
type String struct {
	Offset uint16
	Length uint16
}

// Encode writes a string to a byte slice and updates the offset/length.
func (s *String) Encode(str string, value *[]byte) {
	s.Offset = uint16(len(*value))
	s.Length = uint16(len(str))
	*value = append(*value, []byte(str)...)
}

// Bytes returns a byte slice pointing to the string's contents.
func (s *String) Bytes(value []byte) []byte {
	return (*[0xFFFF]byte)(unsafe.Pointer(&value[s.Offset]))[:s.Length]
}

// String returns a Go string of the string value from an encoded byte slice.
func (s *String) String(value []byte) string {
	return string(s.Bytes(value))
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// 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 rpmpack packs files to rpm files.
// It is designed to be simple to use and deploy, not requiring any filesystem access
// to create rpm files.
package rpmpack

import (
	"bytes"
	"compress/gzip"
	"crypto/sha256"
	"fmt"
	"io"
	"path"
	"sort"

	cpio "github.com/cavaliercoder/go-cpio"
	"github.com/pkg/errors"
	"github.com/ulikunitz/xz"
	"github.com/ulikunitz/xz/lzma"
)

var (
	// ErrWriteAfterClose is returned when a user calls Write() on a closed rpm.
	ErrWriteAfterClose = errors.New("rpm write after close")
	// ErrWrongFileOrder is returned when files are not sorted by name.
	ErrWrongFileOrder = errors.New("wrong file addition order")
)

// RPMMetaData contains meta info about the whole package.
type RPMMetaData struct {
	Name       string
	Version    string
	Release    string
	Arch       string
	Compressor string
}

// RPMFile contains a particular file's entry and data.
type RPMFile struct {
	Name  string
	Body  []byte
	Mode  uint
	Owner string
	Group string
	MTime uint32
}

// RPM holds the state of a particular rpm file. Please use NewRPM to instantiate it.
type RPM struct {
	RPMMetaData
	di                *dirIndex
	payload           *bytes.Buffer
	payloadSize       uint
	cpio              *cpio.Writer
	basenames         []string
	dirindexes        []uint32
	filesizes         []uint32
	filemodes         []uint16
	fileowners        []string
	filegroups        []string
	filemtimes        []uint32
	filedigests       []string
	filelinktos       []string
	closed            bool
	compressedPayload io.WriteCloser
	files             map[string]RPMFile
	prein             string
	postin            string
	preun             string
	postun            string
}

// NewRPM creates and returns a new RPM struct.
func NewRPM(m RPMMetaData) (rpm *RPM, err error) {
	if len(m.Compressor) == 0 {
		m.Compressor = "gzip"
	}

	p := &bytes.Buffer{}
	var z io.WriteCloser
	switch m.Compressor {
	case "gzip":
		z, err = gzip.NewWriterLevel(p, 9)
	case "lzma":
		z, err = lzma.NewWriter(p)
	case "xz":
		z, err = xz.NewWriter(p)
	default:
		err = fmt.Errorf("unknown compressor type %s", m.Compressor)
	}
	if err != nil {
		return nil, errors.Wrap(err, "failed to create compression writer")
	}
	return &RPM{
		RPMMetaData:       m,
		di:                newDirIndex(),
		payload:           p,
		compressedPayload: z,
		cpio:              cpio.NewWriter(z),
		files:             make(map[string]RPMFile),
	}, nil
}

// FullVersion properly combines version and release fields to a version string
func (r *RPM) FullVersion() string {
	if r.Release != "" {
		return fmt.Sprintf("%s-%s", r.Version, r.Release)
	}

	return r.Version
}

// Write closes the rpm and writes the whole rpm to an io.Writer
func (r *RPM) Write(w io.Writer) error {
	if r.closed {
		return ErrWriteAfterClose
	}
	// Add all of the files, sorted alphabetically.
	fnames := []string{}
	for fn := range r.files {
		fnames = append(fnames, fn)
	}
	sort.Strings(fnames)
	for _, fn := range fnames {
		if err := r.writeFile(r.files[fn]); err != nil {
			return errors.Wrapf(err, "failed to write file %q", fn)
		}
	}
	if err := r.cpio.Close(); err != nil {
		return errors.Wrap(err, "failed to close cpio payload")
	}
	if err := r.compressedPayload.Close(); err != nil {
		return errors.Wrap(err, "failed to close gzip payload")
	}

	if _, err := w.Write(lead(r.Name, r.FullVersion())); err != nil {
		return errors.Wrap(err, "failed to write lead")
	}
	// Write the regular header.
	h := newIndex(immutable)
	r.writeGenIndexes(h)
	r.writeFileIndexes(h)
	hb, err := h.Bytes()
	if err != nil {
		return errors.Wrap(err, "failed to retrieve header")
	}
	// Write the signatures
	s := newIndex(signatures)
	r.writeSignatures(s, hb)
	sb, err := s.Bytes()
	if err != nil {
		return errors.Wrap(err, "failed to retrieve signatures header")
	}

	if _, err := w.Write(sb); err != nil {
		return errors.Wrap(err, "failed to write signature bytes")
	}
	//Signatures are padded to 8-byte boundaries
	if _, err := w.Write(make([]byte, (8-len(sb)%8)%8)); err != nil {
		return errors.Wrap(err, "failed to write signature padding")
	}
	if _, err := w.Write(hb); err != nil {
		return errors.Wrap(err, "failed to write header body")
	}
	_, err = w.Write(r.payload.Bytes())
	return errors.Wrap(err, "failed to write payload")

}

// Only call this after the payload and header were written.
func (r *RPM) writeSignatures(sigHeader *index, regHeader []byte) {
	sigHeader.Add(sigSize, entry([]int32{int32(r.payload.Len() + len(regHeader))}))
	sigHeader.Add(sigSHA256, entry(fmt.Sprintf("%x", sha256.Sum256(regHeader))))
	sigHeader.Add(sigPayloadSize, entry([]int32{int32(r.payloadSize)}))
}

func (r *RPM) writeGenIndexes(h *index) {
	h.Add(tagHeaderI18NTable, entry("C"))
	h.Add(tagSize, entry([]int32{int32(r.payloadSize)}))
	h.Add(tagName, entry(r.Name))
	h.Add(tagVersion, entry(r.Version))
	h.Add(tagRelease, entry(r.Release))
	h.Add(tagPayloadFormat, entry("cpio"))
	h.Add(tagPayloadCompressor, entry(r.Compressor))
	h.Add(tagPayloadFlags, entry("9"))
	h.Add(tagOS, entry("linux"))
	h.Add(tagArch, entry(r.Arch))
	// A package must provide itself...
	h.Add(tagProvides, entry([]string{r.Name}))
	h.Add(tagProvideVersion, entry([]string{r.FullVersion()}))
	h.Add(tagProvideFlags, entry([]uint32{uint32(1 << 3)})) // means "="
	// rpm utilities look for the sourcerpm tag to deduce if this is not a source rpm (if it has a sourcerpm,
	// it is NOT a source rpm).
	h.Add(tagSourceRPM, entry(fmt.Sprintf("%s-%s.src.rpm", r.Name, r.FullVersion())))
	if r.prein != "" {
		h.Add(tagPrein, entry(r.prein))
		h.Add(tagPreinProg, entry("/bin/sh"))
	}
	if r.postin != "" {
		h.Add(tagPostin, entry(r.postin))
		h.Add(tagPostinProg, entry("/bin/sh"))
	}
	if r.preun != "" {
		h.Add(tagPreun, entry(r.preun))
		h.Add(tagPreunProg, entry("/bin/sh"))
	}
	if r.postun != "" {
		h.Add(tagPostun, entry(r.postun))
		h.Add(tagPostunProg, entry("/bin/sh"))
	}
}

// WriteFileIndexes writes file related index headers to the header
func (r *RPM) writeFileIndexes(h *index) {
	h.Add(tagBasenames, entry(r.basenames))
	h.Add(tagDirindexes, entry(r.dirindexes))
	h.Add(tagDirnames, entry(r.di.AllDirs()))
	h.Add(tagFileSizes, entry(r.filesizes))
	h.Add(tagFileModes, entry(r.filemodes))
	h.Add(tagFileUserName, entry(r.fileowners))
	h.Add(tagFileGroupName, entry(r.filegroups))
	h.Add(tagFileMTimes, entry(r.filemtimes))
	h.Add(tagFileDigests, entry(r.filedigests))
	h.Add(tagFileLinkTos, entry(r.filelinktos))

	inodes := make([]int32, len(r.dirindexes))
	digestAlgo := make([]int32, len(r.dirindexes))
	verifyFlags := make([]int32, len(r.dirindexes))
	fileFlags := make([]int32, len(r.dirindexes))
	fileRDevs := make([]int16, len(r.dirindexes))
	fileLangs := make([]string, len(r.dirindexes))

	for ii := range inodes {
		// is inodes just a range from 1..len(dirindexes)? maybe different with hard links
		inodes[ii] = int32(ii + 1)
		// We only use the sha256 digest algo, tag=8
		digestAlgo[ii] = int32(8)
		// With regular files, it seems like we can always enable all of the verify flags
		verifyFlags[ii] = int32(-1)
		fileFlags[ii] = int32(0)
		fileRDevs[ii] = int16(1)
	}
	h.Add(tagFileINodes, entry(inodes))
	h.Add(tagFileDigestAlgo, entry(digestAlgo))
	h.Add(tagFileVerifyFlags, entry(verifyFlags))
	h.Add(tagFileFlags, entry(fileFlags))
	h.Add(tagFileRDevs, entry(fileRDevs))
	h.Add(tagFileLangs, entry(fileLangs))
}

// AddPrein adds a prein sciptlet
func (r *RPM) AddPrein(s string) {
	r.prein = s
}

// AddPostin adds a postin sciptlet
func (r *RPM) AddPostin(s string) {
	r.postin = s
}

// AddPreun adds a preun sciptlet
func (r *RPM) AddPreun(s string) {
	r.preun = s
}

// AddPostun adds a postun sciptlet
func (r *RPM) AddPostun(s string) {
	r.postun = s
}

// AddFile adds an RPMFile to an existing rpm.
func (r *RPM) AddFile(f RPMFile) {
	if f.Name == "/" { // rpm does not allow the root dir to be included.
		return
	}
	r.files[f.Name] = f
}

// writeFile writes the file to the indexes and cpio.
func (r *RPM) writeFile(f RPMFile) error {
	dir, file := path.Split(f.Name)
	r.dirindexes = append(r.dirindexes, r.di.Get(dir))
	r.basenames = append(r.basenames, file)
	r.fileowners = append(r.fileowners, f.Group)
	r.filegroups = append(r.filegroups, f.Owner)
	r.filemtimes = append(r.filemtimes, f.MTime)
	links := 1
	switch {
	case f.Mode&040000 != 0: // directory
		r.filesizes = append(r.filesizes, 4096)
		r.filedigests = append(r.filedigests, "")
		r.filelinktos = append(r.filelinktos, "")
		links = 2
	case f.Mode&0120000 != 0: //  symlink
		r.filesizes = append(r.filesizes, uint32(len(f.Body)))
		r.filedigests = append(r.filedigests, "")
		r.filelinktos = append(r.filelinktos, string(f.Body))
	default: // regular file
		f.Mode = f.Mode | 0100000
		r.filesizes = append(r.filesizes, uint32(len(f.Body)))
		r.filedigests = append(r.filedigests, fmt.Sprintf("%x", sha256.Sum256(f.Body)))
		r.filelinktos = append(r.filelinktos, "")
	}
	r.filemodes = append(r.filemodes, uint16(f.Mode))
	return r.writePayload(f, links)
}

func (r *RPM) writePayload(f RPMFile, links int) error {
	hdr := &cpio.Header{
		Name:  f.Name,
		Mode:  cpio.FileMode(f.Mode),
		Size:  int64(len(f.Body)),
		Links: links,
	}
	if err := r.cpio.WriteHeader(hdr); err != nil {
		return errors.Wrap(err, "failed to write payload file header")
	}
	if _, err := r.cpio.Write(f.Body); err != nil {
		return errors.Wrap(err, "failed to write payload file content")
	}
	r.payloadSize += uint(len(f.Body))
	return nil
}
<commit_msg>Clean up based on feedback<commit_after>// Copyright 2019 Google LLC
//
// 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 rpmpack packs files to rpm files.
// It is designed to be simple to use and deploy, not requiring any filesystem access
// to create rpm files.
package rpmpack

import (
	"bytes"
	"compress/gzip"
	"crypto/sha256"
	"fmt"
	"io"
	"path"
	"sort"

	cpio "github.com/cavaliercoder/go-cpio"
	"github.com/pkg/errors"
	"github.com/ulikunitz/xz"
	"github.com/ulikunitz/xz/lzma"
)

var (
	// ErrWriteAfterClose is returned when a user calls Write() on a closed rpm.
	ErrWriteAfterClose = errors.New("rpm write after close")
	// ErrWrongFileOrder is returned when files are not sorted by name.
	ErrWrongFileOrder = errors.New("wrong file addition order")
)

// RPMMetaData contains meta info about the whole package.
type RPMMetaData struct {
	Name       string
	Version    string
	Release    string
	Arch       string
	Compressor string
}

// RPMFile contains a particular file's entry and data.
type RPMFile struct {
	Name  string
	Body  []byte
	Mode  uint
	Owner string
	Group string
	MTime uint32
}

// RPM holds the state of a particular rpm file. Please use NewRPM to instantiate it.
type RPM struct {
	RPMMetaData
	di                *dirIndex
	payload           *bytes.Buffer
	payloadSize       uint
	cpio              *cpio.Writer
	basenames         []string
	dirindexes        []uint32
	filesizes         []uint32
	filemodes         []uint16
	fileowners        []string
	filegroups        []string
	filemtimes        []uint32
	filedigests       []string
	filelinktos       []string
	closed            bool
	compressedPayload io.WriteCloser
	files             map[string]RPMFile
	prein             string
	postin            string
	preun             string
	postun            string
}

// NewRPM creates and returns a new RPM struct.
func NewRPM(m RPMMetaData) (*RPM, error) {
	var err error

	p := &bytes.Buffer{}
	var z io.WriteCloser
	switch m.Compressor {
	case "":
		m.Compressor = "gzip"
		fallthrough
	case "gzip":
		z, err = gzip.NewWriterLevel(p, 9)
	case "lzma":
		z, err = lzma.NewWriter(p)
	case "xz":
		z, err = xz.NewWriter(p)
	default:
		err = fmt.Errorf("unknown compressor type %s", m.Compressor)
	}
	if err != nil {
		return nil, errors.Wrap(err, "failed to create compression writer")
	}
	return &RPM{
		RPMMetaData:       m,
		di:                newDirIndex(),
		payload:           p,
		compressedPayload: z,
		cpio:              cpio.NewWriter(z),
		files:             make(map[string]RPMFile),
	}, nil
}

// FullVersion properly combines version and release fields to a version string
func (r *RPM) FullVersion() string {
	if r.Release != "" {
		return fmt.Sprintf("%s-%s", r.Version, r.Release)
	}

	return r.Version
}

// Write closes the rpm and writes the whole rpm to an io.Writer
func (r *RPM) Write(w io.Writer) error {
	if r.closed {
		return ErrWriteAfterClose
	}
	// Add all of the files, sorted alphabetically.
	fnames := []string{}
	for fn := range r.files {
		fnames = append(fnames, fn)
	}
	sort.Strings(fnames)
	for _, fn := range fnames {
		if err := r.writeFile(r.files[fn]); err != nil {
			return errors.Wrapf(err, "failed to write file %q", fn)
		}
	}
	if err := r.cpio.Close(); err != nil {
		return errors.Wrap(err, "failed to close cpio payload")
	}
	if err := r.compressedPayload.Close(); err != nil {
		return errors.Wrap(err, "failed to close gzip payload")
	}

	if _, err := w.Write(lead(r.Name, r.FullVersion())); err != nil {
		return errors.Wrap(err, "failed to write lead")
	}
	// Write the regular header.
	h := newIndex(immutable)
	r.writeGenIndexes(h)
	r.writeFileIndexes(h)
	hb, err := h.Bytes()
	if err != nil {
		return errors.Wrap(err, "failed to retrieve header")
	}
	// Write the signatures
	s := newIndex(signatures)
	r.writeSignatures(s, hb)
	sb, err := s.Bytes()
	if err != nil {
		return errors.Wrap(err, "failed to retrieve signatures header")
	}

	if _, err := w.Write(sb); err != nil {
		return errors.Wrap(err, "failed to write signature bytes")
	}
	//Signatures are padded to 8-byte boundaries
	if _, err := w.Write(make([]byte, (8-len(sb)%8)%8)); err != nil {
		return errors.Wrap(err, "failed to write signature padding")
	}
	if _, err := w.Write(hb); err != nil {
		return errors.Wrap(err, "failed to write header body")
	}
	_, err = w.Write(r.payload.Bytes())
	return errors.Wrap(err, "failed to write payload")

}

// Only call this after the payload and header were written.
func (r *RPM) writeSignatures(sigHeader *index, regHeader []byte) {
	sigHeader.Add(sigSize, entry([]int32{int32(r.payload.Len() + len(regHeader))}))
	sigHeader.Add(sigSHA256, entry(fmt.Sprintf("%x", sha256.Sum256(regHeader))))
	sigHeader.Add(sigPayloadSize, entry([]int32{int32(r.payloadSize)}))
}

func (r *RPM) writeGenIndexes(h *index) {
	h.Add(tagHeaderI18NTable, entry("C"))
	h.Add(tagSize, entry([]int32{int32(r.payloadSize)}))
	h.Add(tagName, entry(r.Name))
	h.Add(tagVersion, entry(r.Version))
	h.Add(tagRelease, entry(r.Release))
	h.Add(tagPayloadFormat, entry("cpio"))
	h.Add(tagPayloadCompressor, entry(r.Compressor))
	h.Add(tagPayloadFlags, entry("9"))
	h.Add(tagOS, entry("linux"))
	h.Add(tagArch, entry(r.Arch))
	// A package must provide itself...
	h.Add(tagProvides, entry([]string{r.Name}))
	h.Add(tagProvideVersion, entry([]string{r.FullVersion()}))
	h.Add(tagProvideFlags, entry([]uint32{uint32(1 << 3)})) // means "="
	// rpm utilities look for the sourcerpm tag to deduce if this is not a source rpm (if it has a sourcerpm,
	// it is NOT a source rpm).
	h.Add(tagSourceRPM, entry(fmt.Sprintf("%s-%s.src.rpm", r.Name, r.FullVersion())))
	if r.prein != "" {
		h.Add(tagPrein, entry(r.prein))
		h.Add(tagPreinProg, entry("/bin/sh"))
	}
	if r.postin != "" {
		h.Add(tagPostin, entry(r.postin))
		h.Add(tagPostinProg, entry("/bin/sh"))
	}
	if r.preun != "" {
		h.Add(tagPreun, entry(r.preun))
		h.Add(tagPreunProg, entry("/bin/sh"))
	}
	if r.postun != "" {
		h.Add(tagPostun, entry(r.postun))
		h.Add(tagPostunProg, entry("/bin/sh"))
	}
}

// WriteFileIndexes writes file related index headers to the header
func (r *RPM) writeFileIndexes(h *index) {
	h.Add(tagBasenames, entry(r.basenames))
	h.Add(tagDirindexes, entry(r.dirindexes))
	h.Add(tagDirnames, entry(r.di.AllDirs()))
	h.Add(tagFileSizes, entry(r.filesizes))
	h.Add(tagFileModes, entry(r.filemodes))
	h.Add(tagFileUserName, entry(r.fileowners))
	h.Add(tagFileGroupName, entry(r.filegroups))
	h.Add(tagFileMTimes, entry(r.filemtimes))
	h.Add(tagFileDigests, entry(r.filedigests))
	h.Add(tagFileLinkTos, entry(r.filelinktos))

	inodes := make([]int32, len(r.dirindexes))
	digestAlgo := make([]int32, len(r.dirindexes))
	verifyFlags := make([]int32, len(r.dirindexes))
	fileFlags := make([]int32, len(r.dirindexes))
	fileRDevs := make([]int16, len(r.dirindexes))
	fileLangs := make([]string, len(r.dirindexes))

	for ii := range inodes {
		// is inodes just a range from 1..len(dirindexes)? maybe different with hard links
		inodes[ii] = int32(ii + 1)
		// We only use the sha256 digest algo, tag=8
		digestAlgo[ii] = int32(8)
		// With regular files, it seems like we can always enable all of the verify flags
		verifyFlags[ii] = int32(-1)
		fileFlags[ii] = int32(0)
		fileRDevs[ii] = int16(1)
	}
	h.Add(tagFileINodes, entry(inodes))
	h.Add(tagFileDigestAlgo, entry(digestAlgo))
	h.Add(tagFileVerifyFlags, entry(verifyFlags))
	h.Add(tagFileFlags, entry(fileFlags))
	h.Add(tagFileRDevs, entry(fileRDevs))
	h.Add(tagFileLangs, entry(fileLangs))
}

// AddPrein adds a prein sciptlet
func (r *RPM) AddPrein(s string) {
	r.prein = s
}

// AddPostin adds a postin sciptlet
func (r *RPM) AddPostin(s string) {
	r.postin = s
}

// AddPreun adds a preun sciptlet
func (r *RPM) AddPreun(s string) {
	r.preun = s
}

// AddPostun adds a postun sciptlet
func (r *RPM) AddPostun(s string) {
	r.postun = s
}

// AddFile adds an RPMFile to an existing rpm.
func (r *RPM) AddFile(f RPMFile) {
	if f.Name == "/" { // rpm does not allow the root dir to be included.
		return
	}
	r.files[f.Name] = f
}

// writeFile writes the file to the indexes and cpio.
func (r *RPM) writeFile(f RPMFile) error {
	dir, file := path.Split(f.Name)
	r.dirindexes = append(r.dirindexes, r.di.Get(dir))
	r.basenames = append(r.basenames, file)
	r.fileowners = append(r.fileowners, f.Group)
	r.filegroups = append(r.filegroups, f.Owner)
	r.filemtimes = append(r.filemtimes, f.MTime)
	links := 1
	switch {
	case f.Mode&040000 != 0: // directory
		r.filesizes = append(r.filesizes, 4096)
		r.filedigests = append(r.filedigests, "")
		r.filelinktos = append(r.filelinktos, "")
		links = 2
	case f.Mode&0120000 != 0: //  symlink
		r.filesizes = append(r.filesizes, uint32(len(f.Body)))
		r.filedigests = append(r.filedigests, "")
		r.filelinktos = append(r.filelinktos, string(f.Body))
	default: // regular file
		f.Mode = f.Mode | 0100000
		r.filesizes = append(r.filesizes, uint32(len(f.Body)))
		r.filedigests = append(r.filedigests, fmt.Sprintf("%x", sha256.Sum256(f.Body)))
		r.filelinktos = append(r.filelinktos, "")
	}
	r.filemodes = append(r.filemodes, uint16(f.Mode))
	return r.writePayload(f, links)
}

func (r *RPM) writePayload(f RPMFile, links int) error {
	hdr := &cpio.Header{
		Name:  f.Name,
		Mode:  cpio.FileMode(f.Mode),
		Size:  int64(len(f.Body)),
		Links: links,
	}
	if err := r.cpio.WriteHeader(hdr); err != nil {
		return errors.Wrap(err, "failed to write payload file header")
	}
	if _, err := r.cpio.Write(f.Body); err != nil {
		return errors.Wrap(err, "failed to write payload file content")
	}
	r.payloadSize += uint(len(f.Body))
	return nil
}
<|endoftext|>


<commit_before>package buildah

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/containers/storage/pkg/archive"
	"github.com/containers/storage/pkg/ioutils"
	digest "github.com/opencontainers/go-digest"
	"github.com/opencontainers/runtime-spec/specs-go"
	"github.com/opencontainers/runtime-tools/generate"
	"github.com/pkg/errors"
)

const (
	// DefaultWorkingDir is used if none was specified.
	DefaultWorkingDir = "/"
	// DefaultRuntime is the default command to use to run the container.
	DefaultRuntime = "runc"
)

const (
	// DefaultTerminal indicates that this Run invocation should be
	// connected to a pseudoterminal if we're connected to a terminal.
	DefaultTerminal = iota
	// WithoutTerminal indicates that this Run invocation should NOT be
	// connected to a pseudoterminal.
	WithoutTerminal
	// WithTerminal indicates that this Run invocation should be connected
	// to a pseudoterminal.
	WithTerminal
)

// RunOptions can be used to alter how a command is run in the container.
type RunOptions struct {
	// Hostname is the hostname we set for the running container.
	Hostname string
	// Runtime is the name of the command to run.  It should accept the same arguments that runc does.
	Runtime string
	// Args adds global arguments for the runtime.
	Args []string
	// Mounts are additional mount points which we want to provide.
	Mounts []specs.Mount
	// Env is additional environment variables to set.
	Env []string
	// User is the user as whom to run the command.
	User string
	// WorkingDir is an override for the working directory.
	WorkingDir string
	// Cmd is an override for the configured default command.
	Cmd []string
	// Entrypoint is an override for the configured entry point.
	Entrypoint []string
	// NetworkDisabled puts the container into its own network namespace.
	NetworkDisabled bool
	// Terminal provides a way to specify whether or not the command should
	// be run with a pseudoterminal.  By default (DefaultTerminal), a
	// terminal is used if os.Stdout is connected to a terminal, but that
	// decision can be overridden by specifying either WithTerminal or
	// WithoutTerminal.
	Terminal int
}

func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, optionMounts []specs.Mount, bindFiles, volumes []string) error {
	// The passed-in mounts matter the most to us.
	mounts := make([]specs.Mount, len(optionMounts))
	copy(mounts, optionMounts)
	haveMount := func(destination string) bool {
		for _, mount := range mounts {
			if mount.Destination == destination {
				// Already have something to mount there.
				return true
			}
		}
		return false
	}
	// Add mounts from the generated list, unless they conflict.
	for _, specMount := range spec.Mounts {
		if haveMount(specMount.Destination) {
			// Already have something to mount there, so skip this one.
			continue
		}
		mounts = append(mounts, specMount)
	}
	// Add bind mounts for important files, unless they conflict.
	for _, boundFile := range bindFiles {
		if haveMount(boundFile) {
			// Already have something to mount there, so skip this one.
			continue
		}
		mounts = append(mounts, specs.Mount{
			Source:      boundFile,
			Destination: boundFile,
			Type:        "bind",
			Options:     []string{"rbind", "ro"},
		})
	}
	// Add temporary copies of the contents of volume locations at the
	// volume locations, unless we already have something there.
	for _, volume := range volumes {
		if haveMount(volume) {
			// Already mounting something there, no need to bother.
			continue
		}
		cdir, err := b.store.ContainerDirectory(b.ContainerID)
		if err != nil {
			return errors.Wrapf(err, "error determining work directory for container %q", b.ContainerID)
		}
		subdir := digest.Canonical.FromString(volume).Hex()
		volumePath := filepath.Join(cdir, "buildah-volumes", subdir)
		logrus.Debugf("using %q for volume at %q", volumePath, volume)
		// If we need to, initialize the volume path's initial contents.
		if _, err = os.Stat(volumePath); os.IsNotExist(err) {
			if err = os.MkdirAll(volumePath, 0755); err != nil {
				return errors.Wrapf(err, "error creating directory %q for volume %q in container %q", volumePath, volume, b.ContainerID)
			}
			srcPath := filepath.Join(mountPoint, volume)
			if err = archive.CopyWithTar(srcPath, volumePath); err != nil {
				return errors.Wrapf(err, "error populating directory %q for volume %q in container %q using contents of %q", volumePath, volume, b.ContainerID, srcPath)
			}

		}
		// Add the bind mount.
		mounts = append(mounts, specs.Mount{
			Source:      volumePath,
			Destination: volume,
			Type:        "bind",
			Options:     []string{"bind"},
		})
	}
	// Set the list in the spec.
	spec.Mounts = mounts
	return nil
}

// Run runs the specified command in the container's root filesystem.
func (b *Builder) Run(command []string, options RunOptions) error {
	var user specs.User
	path, err := ioutil.TempDir(os.TempDir(), Package)
	if err != nil {
		return err
	}
	logrus.Debugf("using %q to hold bundle data", path)
	defer func() {
		if err2 := os.RemoveAll(path); err2 != nil {
			logrus.Errorf("error removing %q: %v", path, err2)
		}
	}()
	g := generate.New()

	if b.OS() != "" {
		g.SetPlatformOS(b.OS())
	}
	if b.Architecture() != "" {
		g.SetPlatformArch(b.Architecture())
	}
	for _, envSpec := range append(b.Env(), options.Env...) {
		env := strings.SplitN(envSpec, "=", 2)
		if len(env) > 1 {
			g.AddProcessEnv(env[0], env[1])
		}
	}
	if len(command) > 0 {
		g.SetProcessArgs(command)
	} else {
		cmd := b.Cmd()
		if len(options.Cmd) > 0 {
			cmd = options.Cmd
		}
		ep := b.Entrypoint()
		if len(options.Entrypoint) > 0 {
			ep = options.Entrypoint
		}
		g.SetProcessArgs(append(ep, cmd...))
	}
	if options.WorkingDir != "" {
		g.SetProcessCwd(options.WorkingDir)
	} else if b.WorkDir() != "" {
		g.SetProcessCwd(b.WorkDir())
	}
	if options.Hostname != "" {
		g.SetHostname(options.Hostname)
	} else if b.Hostname() != "" {
		g.SetHostname(b.Hostname())
	}
	mountPoint, err := b.Mount("")
	if err != nil {
		return err
	}
	defer func() {
		if err2 := b.Unmount(); err2 != nil {
			logrus.Errorf("error unmounting container: %v", err2)
		}
	}()
	g.SetRootPath(mountPoint)
	switch options.Terminal {
	case DefaultTerminal:
		g.SetProcessTerminal(logrus.IsTerminal(os.Stdout))
	case WithTerminal:
		g.SetProcessTerminal(true)
	case WithoutTerminal:
		g.SetProcessTerminal(false)
	}
	if !options.NetworkDisabled {
		if err = g.RemoveLinuxNamespace("network"); err != nil {
			return errors.Wrapf(err, "error removing network namespace for run")
		}
	}
	if options.User != "" {
		user, err = getUser(mountPoint, options.User)
	} else {
		user, err = getUser(mountPoint, b.User())
	}
	if err != nil {
		return err
	}
	g.SetProcessUID(user.UID)
	g.SetProcessGID(user.GID)
	spec := g.Spec()
	if spec.Process.Cwd == "" {
		spec.Process.Cwd = DefaultWorkingDir
	}
	if err = os.MkdirAll(filepath.Join(mountPoint, b.WorkDir()), 0755); err != nil {
		return errors.Wrapf(err, "error ensuring working directory %q exists", b.WorkDir())
	}

	bindFiles := []string{"/etc/hosts", "/etc/resolv.conf"}
	err = b.setupMounts(mountPoint, spec, options.Mounts, bindFiles, b.Volumes())
	if err != nil {
		return errors.Wrapf(err, "error resolving mountpoints for container")
	}
	specbytes, err := json.Marshal(spec)
	if err != nil {
		return err
	}
	err = ioutils.AtomicWriteFile(filepath.Join(path, "config.json"), specbytes, 0600)
	if err != nil {
		return errors.Wrapf(err, "error storing runtime configuration")
	}
	logrus.Debugf("config = %v", string(specbytes))
	runtime := options.Runtime
	if runtime == "" {
		runtime = DefaultRuntime
	}
	args := append(options.Args, "run", "-b", path, Package+"-"+b.ContainerID)
	cmd := exec.Command(runtime, args...)
	cmd.Dir = mountPoint
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		logrus.Debugf("error running runc %v: %v", spec.Process.Args, err)
	}
	return err
}
<commit_msg>Stop trying to set the Platform in runtime specs<commit_after>package buildah

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"github.com/Sirupsen/logrus"
	"github.com/containers/storage/pkg/archive"
	"github.com/containers/storage/pkg/ioutils"
	digest "github.com/opencontainers/go-digest"
	"github.com/opencontainers/runtime-spec/specs-go"
	"github.com/opencontainers/runtime-tools/generate"
	"github.com/pkg/errors"
)

const (
	// DefaultWorkingDir is used if none was specified.
	DefaultWorkingDir = "/"
	// DefaultRuntime is the default command to use to run the container.
	DefaultRuntime = "runc"
)

const (
	// DefaultTerminal indicates that this Run invocation should be
	// connected to a pseudoterminal if we're connected to a terminal.
	DefaultTerminal = iota
	// WithoutTerminal indicates that this Run invocation should NOT be
	// connected to a pseudoterminal.
	WithoutTerminal
	// WithTerminal indicates that this Run invocation should be connected
	// to a pseudoterminal.
	WithTerminal
)

// RunOptions can be used to alter how a command is run in the container.
type RunOptions struct {
	// Hostname is the hostname we set for the running container.
	Hostname string
	// Runtime is the name of the command to run.  It should accept the same arguments that runc does.
	Runtime string
	// Args adds global arguments for the runtime.
	Args []string
	// Mounts are additional mount points which we want to provide.
	Mounts []specs.Mount
	// Env is additional environment variables to set.
	Env []string
	// User is the user as whom to run the command.
	User string
	// WorkingDir is an override for the working directory.
	WorkingDir string
	// Cmd is an override for the configured default command.
	Cmd []string
	// Entrypoint is an override for the configured entry point.
	Entrypoint []string
	// NetworkDisabled puts the container into its own network namespace.
	NetworkDisabled bool
	// Terminal provides a way to specify whether or not the command should
	// be run with a pseudoterminal.  By default (DefaultTerminal), a
	// terminal is used if os.Stdout is connected to a terminal, but that
	// decision can be overridden by specifying either WithTerminal or
	// WithoutTerminal.
	Terminal int
}

func (b *Builder) setupMounts(mountPoint string, spec *specs.Spec, optionMounts []specs.Mount, bindFiles, volumes []string) error {
	// The passed-in mounts matter the most to us.
	mounts := make([]specs.Mount, len(optionMounts))
	copy(mounts, optionMounts)
	haveMount := func(destination string) bool {
		for _, mount := range mounts {
			if mount.Destination == destination {
				// Already have something to mount there.
				return true
			}
		}
		return false
	}
	// Add mounts from the generated list, unless they conflict.
	for _, specMount := range spec.Mounts {
		if haveMount(specMount.Destination) {
			// Already have something to mount there, so skip this one.
			continue
		}
		mounts = append(mounts, specMount)
	}
	// Add bind mounts for important files, unless they conflict.
	for _, boundFile := range bindFiles {
		if haveMount(boundFile) {
			// Already have something to mount there, so skip this one.
			continue
		}
		mounts = append(mounts, specs.Mount{
			Source:      boundFile,
			Destination: boundFile,
			Type:        "bind",
			Options:     []string{"rbind", "ro"},
		})
	}
	// Add temporary copies of the contents of volume locations at the
	// volume locations, unless we already have something there.
	for _, volume := range volumes {
		if haveMount(volume) {
			// Already mounting something there, no need to bother.
			continue
		}
		cdir, err := b.store.ContainerDirectory(b.ContainerID)
		if err != nil {
			return errors.Wrapf(err, "error determining work directory for container %q", b.ContainerID)
		}
		subdir := digest.Canonical.FromString(volume).Hex()
		volumePath := filepath.Join(cdir, "buildah-volumes", subdir)
		logrus.Debugf("using %q for volume at %q", volumePath, volume)
		// If we need to, initialize the volume path's initial contents.
		if _, err = os.Stat(volumePath); os.IsNotExist(err) {
			if err = os.MkdirAll(volumePath, 0755); err != nil {
				return errors.Wrapf(err, "error creating directory %q for volume %q in container %q", volumePath, volume, b.ContainerID)
			}
			srcPath := filepath.Join(mountPoint, volume)
			if err = archive.CopyWithTar(srcPath, volumePath); err != nil {
				return errors.Wrapf(err, "error populating directory %q for volume %q in container %q using contents of %q", volumePath, volume, b.ContainerID, srcPath)
			}

		}
		// Add the bind mount.
		mounts = append(mounts, specs.Mount{
			Source:      volumePath,
			Destination: volume,
			Type:        "bind",
			Options:     []string{"bind"},
		})
	}
	// Set the list in the spec.
	spec.Mounts = mounts
	return nil
}

// Run runs the specified command in the container's root filesystem.
func (b *Builder) Run(command []string, options RunOptions) error {
	var user specs.User
	path, err := ioutil.TempDir(os.TempDir(), Package)
	if err != nil {
		return err
	}
	logrus.Debugf("using %q to hold bundle data", path)
	defer func() {
		if err2 := os.RemoveAll(path); err2 != nil {
			logrus.Errorf("error removing %q: %v", path, err2)
		}
	}()
	g := generate.New()

	for _, envSpec := range append(b.Env(), options.Env...) {
		env := strings.SplitN(envSpec, "=", 2)
		if len(env) > 1 {
			g.AddProcessEnv(env[0], env[1])
		}
	}
	if len(command) > 0 {
		g.SetProcessArgs(command)
	} else {
		cmd := b.Cmd()
		if len(options.Cmd) > 0 {
			cmd = options.Cmd
		}
		ep := b.Entrypoint()
		if len(options.Entrypoint) > 0 {
			ep = options.Entrypoint
		}
		g.SetProcessArgs(append(ep, cmd...))
	}
	if options.WorkingDir != "" {
		g.SetProcessCwd(options.WorkingDir)
	} else if b.WorkDir() != "" {
		g.SetProcessCwd(b.WorkDir())
	}
	if options.Hostname != "" {
		g.SetHostname(options.Hostname)
	} else if b.Hostname() != "" {
		g.SetHostname(b.Hostname())
	}
	mountPoint, err := b.Mount("")
	if err != nil {
		return err
	}
	defer func() {
		if err2 := b.Unmount(); err2 != nil {
			logrus.Errorf("error unmounting container: %v", err2)
		}
	}()
	g.SetRootPath(mountPoint)
	switch options.Terminal {
	case DefaultTerminal:
		g.SetProcessTerminal(logrus.IsTerminal(os.Stdout))
	case WithTerminal:
		g.SetProcessTerminal(true)
	case WithoutTerminal:
		g.SetProcessTerminal(false)
	}
	if !options.NetworkDisabled {
		if err = g.RemoveLinuxNamespace("network"); err != nil {
			return errors.Wrapf(err, "error removing network namespace for run")
		}
	}
	if options.User != "" {
		user, err = getUser(mountPoint, options.User)
	} else {
		user, err = getUser(mountPoint, b.User())
	}
	if err != nil {
		return err
	}
	g.SetProcessUID(user.UID)
	g.SetProcessGID(user.GID)
	spec := g.Spec()
	if spec.Process.Cwd == "" {
		spec.Process.Cwd = DefaultWorkingDir
	}
	if err = os.MkdirAll(filepath.Join(mountPoint, b.WorkDir()), 0755); err != nil {
		return errors.Wrapf(err, "error ensuring working directory %q exists", b.WorkDir())
	}

	bindFiles := []string{"/etc/hosts", "/etc/resolv.conf"}
	err = b.setupMounts(mountPoint, spec, options.Mounts, bindFiles, b.Volumes())
	if err != nil {
		return errors.Wrapf(err, "error resolving mountpoints for container")
	}
	specbytes, err := json.Marshal(spec)
	if err != nil {
		return err
	}
	err = ioutils.AtomicWriteFile(filepath.Join(path, "config.json"), specbytes, 0600)
	if err != nil {
		return errors.Wrapf(err, "error storing runtime configuration")
	}
	logrus.Debugf("config = %v", string(specbytes))
	runtime := options.Runtime
	if runtime == "" {
		runtime = DefaultRuntime
	}
	args := append(options.Args, "run", "-b", path, Package+"-"+b.ContainerID)
	cmd := exec.Command(runtime, args...)
	cmd.Dir = mountPoint
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	err = cmd.Run()
	if err != nil {
		logrus.Debugf("error running runc %v: %v", spec.Process.Args, err)
	}
	return err
}
<|endoftext|>


<commit_before>// Copyright 2014 Hajime Hoshi
//
// 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 ebiten

import (
	"time"

	"github.com/hajimehoshi/ebiten/internal/ui"
)

type runContext struct {
	running         bool
	fps             float64
	newScreenWidth  int
	newScreenHeight int
	newScreenScale  int
	isRunningSlowly bool
}

var currentRunContext = &runContext{}

func (c *runContext) CurrentFPS() float64 {
	return c.fps
}

func (c *runContext) IsRunningSlowly() bool {
	return c.isRunningSlowly
}

func (c *runContext) Run(f func(*Image) error, width, height, scale int, title string) error {
	c.running = true
	defer func() {
		c.running = false
	}()

	if err := ui.CurrentUI().Start(width, height, scale, title); err != nil {
		return err
	}
	defer ui.CurrentUI().Terminate()

	glContext.Check()
	graphicsContext, err := newGraphicsContext(width, height, ui.CurrentUI().ActualScreenScale())
	if err != nil {
		return err
	}

	frames := 0
	now := ui.Now()
	beforeForUpdate := now
	beforeForFPS := now
	for {
		// TODO: setSize should be called after swapping buffers?
		if 0 < c.newScreenWidth || 0 < c.newScreenHeight || 0 < c.newScreenScale {
			changed := false
			if 0 < c.newScreenWidth || 0 < c.newScreenHeight {
				c := ui.CurrentUI().SetScreenSize(c.newScreenWidth, c.newScreenHeight)
				changed = changed || c
			}
			if 0 < c.newScreenScale {
				c := ui.CurrentUI().SetScreenScale(c.newScreenScale)
				changed = changed || c
			}
			if changed {
				w, h := c.newScreenWidth, c.newScreenHeight
				if err := graphicsContext.setSize(w, h, ui.CurrentUI().ActualScreenScale()); err != nil {
					return err
				}
			}
		}
		c.newScreenWidth = 0
		c.newScreenHeight = 0
		c.newScreenScale = 0

		if err := ui.CurrentUI().DoEvents(); err != nil {
			return err
		}
		if ui.CurrentUI().IsClosed() {
			return nil
		}
		now := ui.Now()
		// If beforeForUpdate is too old, we assume that screen is not shown.
		c.isRunningSlowly = false
		if int64(5*time.Second/FPS) < now-beforeForUpdate {
			beforeForUpdate = now
		} else {
			t := float64(now-beforeForUpdate) * FPS / float64(time.Second)
			c.isRunningSlowly = t >= 2.5
			for i := 0; i < int(t); i++ {
				if err := ui.CurrentUI().DoEvents(); err != nil {
					return err
				}
				if ui.CurrentUI().IsClosed() {
					return nil
				}
				if err := graphicsContext.update(f); err != nil {
					return err
				}
			}
			beforeForUpdate += int64(t) * int64(time.Second/FPS)
			ui.CurrentUI().SwapBuffers()
		}

		// Calc the current FPS.
		now = ui.Now()
		frames++
		if time.Second <= time.Duration(now-beforeForFPS) {
			c.fps = float64(frames) * float64(time.Second) / float64(now-beforeForFPS)
			beforeForFPS = now
			frames = 0
		}
	}
}

func (c *runContext) SetScreenSize(width, height int) {
	if !c.running {
		panic("ebiten: SetScreenSize must be called during Run")
	}
	if width <= 0 || height <= 0 {
		panic("ebiten: width and height must be positive")
	}
	c.newScreenWidth = width
	c.newScreenHeight = height
}

func (c *runContext) SetScreenScale(scale int) {
	if !c.running {
		panic("ebiten: SetScreenScale must be called during Run")
	}
	if scale <= 0 {
		panic("ebiten: scale must be positive")
	}
	c.newScreenScale = scale
}

// FPS represents how many times game updating happens in a second.
const FPS = 60

// CurrentFPS returns the current number of frames per second of rendering.
//
// This value represents how many times rendering happens in 1/60 second and
// NOT how many times logical game updating (a passed function to Run) happens.
// Note that logical game updating is assured to happen 60 times in a second
// as long as the screen is active.
func CurrentFPS() float64 {
	return currentRunContext.CurrentFPS()
}

// IsRunningSlowly returns true if the game is running too slowly to keep 60 FPS of rendering.
// The game screen is not updated when IsRunningSlowly is true.
// It is recommended to skip heavy processing, especially drawing, when IsRunningSlowly is true.
func IsRunningSlowly() bool {
	return currentRunContext.IsRunningSlowly()
}

// Run runs the game.
// f is a function which is called at every frame.
// The argument (*Image) is the render target that represents the screen.
//
// This function must be called from the main thread.
// Note that ebiten bounds the main goroutine to the main OS thread by runtime.LockOSThread.
//
// The given function f is guaranteed to be called 60 times a second
// even if a rendering frame is skipped.
// f is not called when the screen is not shown.
func Run(f func(*Image) error, width, height, scale int, title string) error {
	return currentRunContext.Run(f, width, height, scale, title)
}

// SetScreenSize changes the (logical) size of the screen.
// This doesn't affect the current scale of the screen.
func SetScreenSize(width, height int) {
	currentRunContext.SetScreenSize(width, height)
}

// SetScreenSize changes the scale of the screen.
func SetScreenScale(scale int) {
	currentRunContext.SetScreenScale(scale)
}

// ScreenScale returns the current screen scale.
func ScreenScale() int {
	return ui.CurrentUI().ScreenScale()
}
<commit_msg>ui: Remove running member<commit_after>// Copyright 2014 Hajime Hoshi
//
// 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 ebiten

import (
	"time"

	"github.com/hajimehoshi/ebiten/internal/ui"
)

type runContext struct {
	fps             float64
	newScreenWidth  int
	newScreenHeight int
	newScreenScale  int
	isRunningSlowly bool
}

var currentRunContext = &runContext{}

func (c *runContext) CurrentFPS() float64 {
	if c == nil {
		// TODO: Should panic here?
		return 0
	}
	return c.fps
}

func (c *runContext) IsRunningSlowly() bool {
	if c == nil {
		// TODO: Should panic here?
		return false
	}
	return c.isRunningSlowly
}

func (c *runContext) Run(f func(*Image) error, width, height, scale int, title string) error {
	if err := ui.CurrentUI().Start(width, height, scale, title); err != nil {
		return err
	}
	defer ui.CurrentUI().Terminate()

	glContext.Check()
	graphicsContext, err := newGraphicsContext(width, height, ui.CurrentUI().ActualScreenScale())
	if err != nil {
		return err
	}

	frames := 0
	now := ui.Now()
	beforeForUpdate := now
	beforeForFPS := now
	for {
		// TODO: setSize should be called after swapping buffers?
		if 0 < c.newScreenWidth || 0 < c.newScreenHeight || 0 < c.newScreenScale {
			changed := false
			if 0 < c.newScreenWidth || 0 < c.newScreenHeight {
				c := ui.CurrentUI().SetScreenSize(c.newScreenWidth, c.newScreenHeight)
				changed = changed || c
			}
			if 0 < c.newScreenScale {
				c := ui.CurrentUI().SetScreenScale(c.newScreenScale)
				changed = changed || c
			}
			if changed {
				w, h := c.newScreenWidth, c.newScreenHeight
				if err := graphicsContext.setSize(w, h, ui.CurrentUI().ActualScreenScale()); err != nil {
					return err
				}
			}
		}
		c.newScreenWidth = 0
		c.newScreenHeight = 0
		c.newScreenScale = 0

		if err := ui.CurrentUI().DoEvents(); err != nil {
			return err
		}
		if ui.CurrentUI().IsClosed() {
			return nil
		}
		now := ui.Now()
		// If beforeForUpdate is too old, we assume that screen is not shown.
		c.isRunningSlowly = false
		if int64(5*time.Second/FPS) < now-beforeForUpdate {
			beforeForUpdate = now
		} else {
			t := float64(now-beforeForUpdate) * FPS / float64(time.Second)
			c.isRunningSlowly = t >= 2.5
			for i := 0; i < int(t); i++ {
				if err := ui.CurrentUI().DoEvents(); err != nil {
					return err
				}
				if ui.CurrentUI().IsClosed() {
					return nil
				}
				if err := graphicsContext.update(f); err != nil {
					return err
				}
			}
			beforeForUpdate += int64(t) * int64(time.Second/FPS)
			ui.CurrentUI().SwapBuffers()
		}

		// Calc the current FPS.
		now = ui.Now()
		frames++
		if time.Second <= time.Duration(now-beforeForFPS) {
			c.fps = float64(frames) * float64(time.Second) / float64(now-beforeForFPS)
			beforeForFPS = now
			frames = 0
		}
	}
}

func (c *runContext) SetScreenSize(width, height int) {
	if c == nil {
		panic("ebiten: SetScreenSize must be called during Run")
	}
	if width <= 0 || height <= 0 {
		panic("ebiten: width and height must be positive")
	}
	c.newScreenWidth = width
	c.newScreenHeight = height
}

func (c *runContext) SetScreenScale(scale int) {
	if c == nil {
		panic("ebiten: SetScreenScale must be called during Run")
	}
	if scale <= 0 {
		panic("ebiten: scale must be positive")
	}
	c.newScreenScale = scale
}

// FPS represents how many times game updating happens in a second.
const FPS = 60

// CurrentFPS returns the current number of frames per second of rendering.
//
// This value represents how many times rendering happens in 1/60 second and
// NOT how many times logical game updating (a passed function to Run) happens.
// Note that logical game updating is assured to happen 60 times in a second
// as long as the screen is active.
func CurrentFPS() float64 {
	return currentRunContext.CurrentFPS()
}

// IsRunningSlowly returns true if the game is running too slowly to keep 60 FPS of rendering.
// The game screen is not updated when IsRunningSlowly is true.
// It is recommended to skip heavy processing, especially drawing, when IsRunningSlowly is true.
func IsRunningSlowly() bool {
	return currentRunContext.IsRunningSlowly()
}

// Run runs the game.
// f is a function which is called at every frame.
// The argument (*Image) is the render target that represents the screen.
//
// This function must be called from the main thread.
// Note that ebiten bounds the main goroutine to the main OS thread by runtime.LockOSThread.
//
// The given function f is guaranteed to be called 60 times a second
// even if a rendering frame is skipped.
// f is not called when the screen is not shown.
func Run(f func(*Image) error, width, height, scale int, title string) error {
	currentRunContext = &runContext{}
	defer func() {
		currentRunContext = nil
	}()
	return currentRunContext.Run(f, width, height, scale, title)
}

// SetScreenSize changes the (logical) size of the screen.
// This doesn't affect the current scale of the screen.
func SetScreenSize(width, height int) {
	currentRunContext.SetScreenSize(width, height)
}

// SetScreenSize changes the scale of the screen.
func SetScreenScale(scale int) {
	currentRunContext.SetScreenScale(scale)
}

// ScreenScale returns the current screen scale.
func ScreenScale() int {
	return ui.CurrentUI().ScreenScale()
}
<|endoftext|>


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

package main

// imports for this file should not contain "os".
import (
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	. "github.com/kardianos/govendor/context"
	"github.com/kardianos/govendor/migrate"
)

var help = `govendor: copy go packages locally and optionally re-write imports.
govendor init
govendor list [-v] [+status] [import-path-filter]
govendor {add, update, remove} [-n] [+status] [import-path-filter]
govendor migrate [auto, godep, internal]

	init
		create a vendor file if it does not exist.

	add
		copy one or more packages into the internal folder and re-write paths.

	update
		update one or more packages from GOPATH into the internal folder.

	remove
		remove one or more packages from the internal folder and re-write packages to vendor paths.

	migrate
		change from a one schema to use the vendor folder.

Expanding "..."
	A package import path may be expanded to other paths that
	show up in "govendor list" be ending the "import-path" with "...".
	NOTE: this uses the import tree from "vendor list" and NOT the file system.

Flags
	-n		print actions but do not run them

Status list:
	external - package does not share root path
	vendor - vendor folder; copied locally
	unused - the package has been copied locally, but isn't used
	local - shares the root path and is not a vendor package
	missing - referenced but not found in GOROOT or GOPATH
	std - standard library package
	program - package is a main package
	---
	all - all of the above status

Status can be referenced by their initial letters.
	"st" == "std"
	"e" == "external"

Example:
	govendor add github.com/kardianos/osext
	govendor update github.com/kardianos/...
	govendor add +external
	govendor update +ven github.com/company/project/... bitbucket.org/user/pkg
	govendor remove +vendor
	govendor list +ext +std

To opt use the standard vendor directory:
set GO15VENDOREXPERIMENT=1

When GO15VENDOREXPERIMENT=1 imports are copied to the vendor directory without
rewriting their import paths.
`

var (
	normal = []Status{StatusExternal, StatusVendor, StatusUnused, StatusMissing, StatusLocal, StatusProgram}
	all    = []Status{StatusExternal, StatusVendor, StatusUnused, StatusMissing, StatusLocal, StatusProgram, StatusStandard}
)

func parseStatus(s string) (status []Status, err error) {
	switch {
	case strings.HasPrefix("external", s):
		status = []Status{StatusExternal}
	case strings.HasPrefix("vendor", s):
		status = []Status{StatusVendor}
	case strings.HasPrefix("unused", s):
		status = []Status{StatusUnused}
	case strings.HasPrefix("missing", s):
		status = []Status{StatusMissing}
	case strings.HasPrefix("local", s):
		status = []Status{StatusLocal}
	case strings.HasPrefix("program", s):
		status = []Status{StatusProgram}
	case strings.HasPrefix("std", s):
		status = []Status{StatusStandard}
	case strings.HasPrefix("standard", s):
		status = []Status{StatusStandard}
	case strings.HasPrefix("all", s):
		status = all
	default:
		err = fmt.Errorf("unknown status %q", s)
	}
	return
}

type filter struct {
	Status []Status
	Import []string
}

func (f filter) HasStatus(item StatusItem) bool {
	for _, s := range f.Status {
		if s == item.Status {
			return true
		}
	}
	return false
}
func (f filter) HasImport(item StatusItem) bool {
	for _, imp := range f.Import {
		if imp == item.Local || imp == item.Canonical {
			return true
		}
		if strings.HasSuffix(imp, "...") {
			base := strings.TrimSuffix(imp, "...")
			if strings.HasPrefix(item.Local, base) || strings.HasPrefix(item.Canonical, base) {
				return true
			}
		}
	}
	return false
}

func parseFilter(args []string) (filter, error) {
	f := filter{
		Status: make([]Status, 0, len(args)),
		Import: make([]string, 0, len(args)),
	}
	for _, a := range args {
		if len(a) == 0 {
			continue
		}
		// Check if item is a status.
		if a[0] == '+' {
			ss, err := parseStatus(a[1:])
			if err != nil {
				return f, err
			}
			f.Status = append(f.Status, ss...)
		} else {
			f.Import = append(f.Import, a)
		}
	}
	return f, nil
}

// run is isoloated from main and os.Args to help with testing.
// Shouldn't directly print to console, just write through w.
func run(w io.Writer, appArgs []string) (bool, error) {
	if len(appArgs) == 1 {
		return true, nil
	}

	cmd := appArgs[1]
	switch cmd {
	case "init":
		ctx, err := NewContextWD(true)
		if err != nil {
			return false, err
		}
		err = ctx.WriteVendorFile()
		if err != nil {
			return false, err
		}
		err = os.MkdirAll(filepath.Join(ctx.RootDir, ctx.VendorFolder), 0777)
		if err != nil {
			return false, err
		}
	case "list":
		listFlags := flag.NewFlagSet("list", flag.ContinueOnError)
		verbose := listFlags.Bool("v", false, "verbose")
		err := listFlags.Parse(appArgs[2:])
		if err != nil {
			return true, err
		}
		args := listFlags.Args()
		f, err := parseFilter(args)
		if err != nil {
			return true, err
		}
		if len(f.Status) == 0 {
			f.Status = append(f.Status, normal...)
		}
		// Print all listed status.
		ctx, err := NewContextWD(false)
		if err != nil {
			return checkNewContextError(err)
		}
		list, err := ctx.Status()
		if err != nil {
			return false, err
		}
		for _, item := range list {
			if f.HasStatus(item) == false {
				continue
			}
			if len(f.Import) != 0 && f.HasImport(item) == false {
				continue
			}
			if item.Local == item.Canonical {
				fmt.Fprintf(w, "%v %s\n", item.Status, item.Local)
			} else {
				fmt.Fprintf(w, "%v %s [%s]\n", item.Status, item.Local, item.Canonical)
			}
			if *verbose {
				for i, imp := range item.ImportedBy {
					if i != len(item.ImportedBy)-1 {
						fmt.Fprintf(w, "  ├── %s\n", imp)
					} else {
						fmt.Fprintf(w, "  └── %s\n", imp)
					}
				}
			}
		}
	case "add", "update", "remove":
		listFlags := flag.NewFlagSet("list", flag.ContinueOnError)
		dryrun := listFlags.Bool("n", false, "dry-run")
		err := listFlags.Parse(appArgs[2:])
		if err != nil {
			return true, err
		}
		args := listFlags.Args()
		if len(args) == 0 {
			return true, errors.New("missing package or status")
		}
		f, err := parseFilter(args)
		if err != nil {
			return true, err
		}
		ctx, err := NewContextWD(false)
		if err != nil {
			return checkNewContextError(err)
		}
		list, err := ctx.Status()
		if err != nil {
			return true, err
		}

		var mod Modify
		switch cmd {
		case "add":
			mod = Add
		case "update":
			mod = Update
		case "remove":
			mod = Remove
		}

		for _, item := range list {
			if f.HasStatus(item) {
				err = ctx.ModifyImport(item.Local, mod)
				if err != nil {
					return false, err
				}
			}
			if f.HasImport(item) {
				err = ctx.ModifyImport(item.Local, mod)
				if err != nil {
					return false, err
				}
			}
		}
		for _, imp := range f.Import {
			err = ctx.ModifyImport(imp, mod)
			if err != nil {
				return false, err
			}
		}

		// Auto-resolve package conflicts.
		ctx.Reslove(ctx.Check())

		if *dryrun {
			for _, op := range ctx.Operation {
				if len(op.Dest) == 0 {
					fmt.Fprintf(w, "Remove %q\n", op.Src)
				} else {
					fmt.Fprintf(w, "Copy %q -> %q\n", op.Src, op.Dest)
				}
			}
			return false, nil
		}

		// Write out vendor file and do change.
		err = ctx.WriteVendorFile()
		if err != nil {
			return false, err
		}
		err = ctx.Alter()
		if err != nil {
			return false, err
		}
	case "migrate":
		args := appArgs[2:]
		from := migrate.Auto
		if len(args) > 0 {
			switch args[0] {
			case "auto":
				from = migrate.Auto
			case "gb":
				from = migrate.Gb
			case "godep":
				from = migrate.Godep
			case "internal":
				from = migrate.Internal
			default:
				return true, fmt.Errorf("Unknown migrate command %q", args[0])
			}
		}
		return false, migrate.MigrateWD(from)
	default:
		return true, fmt.Errorf("Unknown command %q", cmd)
	}
	return false, nil
}

func checkNewContextError(err error) (bool, error) {
	// Diagnose error, show current value of 1.5vendor, suggest alter.
	if err == nil {
		return false, nil
	}
	if _, is := err.(ErrMissingVendorFile); is {
		expValue := os.Getenv("GO15VENDOREXPERIMENT")
		err = fmt.Errorf(`%v

GO15VENDOREXPERIMENT=%q
It is possible this project requires changing the above env var
or the project is not initialized.
`, err, expValue)
		return false, err
	}
	return false, err
}
<commit_msg>govendor: do not add package if it contains "...". Already added.<commit_after>// Copyright 2015 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.

package main

// imports for this file should not contain "os".
import (
	"errors"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"

	. "github.com/kardianos/govendor/context"
	"github.com/kardianos/govendor/migrate"
)

var help = `govendor: copy go packages locally and optionally re-write imports.
govendor init
govendor list [-v] [+status] [import-path-filter]
govendor {add, update, remove} [-n] [+status] [import-path-filter]
govendor migrate [auto, godep, internal]

	init
		create a vendor file if it does not exist.

	add
		copy one or more packages into the internal folder and re-write paths.

	update
		update one or more packages from GOPATH into the internal folder.

	remove
		remove one or more packages from the internal folder and re-write packages to vendor paths.

	migrate
		change from a one schema to use the vendor folder.

Expanding "..."
	A package import path may be expanded to other paths that
	show up in "govendor list" be ending the "import-path" with "...".
	NOTE: this uses the import tree from "vendor list" and NOT the file system.

Flags
	-n		print actions but do not run them

Status list:
	external - package does not share root path
	vendor - vendor folder; copied locally
	unused - the package has been copied locally, but isn't used
	local - shares the root path and is not a vendor package
	missing - referenced but not found in GOROOT or GOPATH
	std - standard library package
	program - package is a main package
	---
	all - all of the above status

Status can be referenced by their initial letters.
	"st" == "std"
	"e" == "external"

Example:
	govendor add github.com/kardianos/osext
	govendor update github.com/kardianos/...
	govendor add +external
	govendor update +ven github.com/company/project/... bitbucket.org/user/pkg
	govendor remove +vendor
	govendor list +ext +std

To opt use the standard vendor directory:
set GO15VENDOREXPERIMENT=1

When GO15VENDOREXPERIMENT=1 imports are copied to the vendor directory without
rewriting their import paths.
`

var (
	normal = []Status{StatusExternal, StatusVendor, StatusUnused, StatusMissing, StatusLocal, StatusProgram}
	all    = []Status{StatusExternal, StatusVendor, StatusUnused, StatusMissing, StatusLocal, StatusProgram, StatusStandard}
)

func parseStatus(s string) (status []Status, err error) {
	switch {
	case strings.HasPrefix("external", s):
		status = []Status{StatusExternal}
	case strings.HasPrefix("vendor", s):
		status = []Status{StatusVendor}
	case strings.HasPrefix("unused", s):
		status = []Status{StatusUnused}
	case strings.HasPrefix("missing", s):
		status = []Status{StatusMissing}
	case strings.HasPrefix("local", s):
		status = []Status{StatusLocal}
	case strings.HasPrefix("program", s):
		status = []Status{StatusProgram}
	case strings.HasPrefix("std", s):
		status = []Status{StatusStandard}
	case strings.HasPrefix("standard", s):
		status = []Status{StatusStandard}
	case strings.HasPrefix("all", s):
		status = all
	default:
		err = fmt.Errorf("unknown status %q", s)
	}
	return
}

type filter struct {
	Status []Status
	Import []string
}

func (f filter) HasStatus(item StatusItem) bool {
	for _, s := range f.Status {
		if s == item.Status {
			return true
		}
	}
	return false
}
func (f filter) HasImport(item StatusItem) bool {
	for _, imp := range f.Import {
		if imp == item.Local || imp == item.Canonical {
			return true
		}
		if strings.HasSuffix(imp, "...") {
			base := strings.TrimSuffix(imp, "...")
			if strings.HasPrefix(item.Local, base) || strings.HasPrefix(item.Canonical, base) {
				return true
			}
		}
	}
	return false
}

func parseFilter(args []string) (filter, error) {
	f := filter{
		Status: make([]Status, 0, len(args)),
		Import: make([]string, 0, len(args)),
	}
	for _, a := range args {
		if len(a) == 0 {
			continue
		}
		// Check if item is a status.
		if a[0] == '+' {
			ss, err := parseStatus(a[1:])
			if err != nil {
				return f, err
			}
			f.Status = append(f.Status, ss...)
		} else {
			f.Import = append(f.Import, a)
		}
	}
	return f, nil
}

// run is isoloated from main and os.Args to help with testing.
// Shouldn't directly print to console, just write through w.
func run(w io.Writer, appArgs []string) (bool, error) {
	if len(appArgs) == 1 {
		return true, nil
	}

	cmd := appArgs[1]
	switch cmd {
	case "init":
		ctx, err := NewContextWD(true)
		if err != nil {
			return false, err
		}
		err = ctx.WriteVendorFile()
		if err != nil {
			return false, err
		}
		err = os.MkdirAll(filepath.Join(ctx.RootDir, ctx.VendorFolder), 0777)
		if err != nil {
			return false, err
		}
	case "list":
		listFlags := flag.NewFlagSet("list", flag.ContinueOnError)
		verbose := listFlags.Bool("v", false, "verbose")
		err := listFlags.Parse(appArgs[2:])
		if err != nil {
			return true, err
		}
		args := listFlags.Args()
		f, err := parseFilter(args)
		if err != nil {
			return true, err
		}
		if len(f.Status) == 0 {
			f.Status = append(f.Status, normal...)
		}
		// Print all listed status.
		ctx, err := NewContextWD(false)
		if err != nil {
			return checkNewContextError(err)
		}
		list, err := ctx.Status()
		if err != nil {
			return false, err
		}
		for _, item := range list {
			if f.HasStatus(item) == false {
				continue
			}
			if len(f.Import) != 0 && f.HasImport(item) == false {
				continue
			}
			if item.Local == item.Canonical {
				fmt.Fprintf(w, "%v %s\n", item.Status, item.Local)
			} else {
				fmt.Fprintf(w, "%v %s [%s]\n", item.Status, item.Local, item.Canonical)
			}
			if *verbose {
				for i, imp := range item.ImportedBy {
					if i != len(item.ImportedBy)-1 {
						fmt.Fprintf(w, "  ├── %s\n", imp)
					} else {
						fmt.Fprintf(w, "  └── %s\n", imp)
					}
				}
			}
		}
	case "add", "update", "remove":
		listFlags := flag.NewFlagSet("list", flag.ContinueOnError)
		dryrun := listFlags.Bool("n", false, "dry-run")
		err := listFlags.Parse(appArgs[2:])
		if err != nil {
			return true, err
		}
		args := listFlags.Args()
		if len(args) == 0 {
			return true, errors.New("missing package or status")
		}
		f, err := parseFilter(args)
		if err != nil {
			return true, err
		}
		ctx, err := NewContextWD(false)
		if err != nil {
			return checkNewContextError(err)
		}
		list, err := ctx.Status()
		if err != nil {
			return true, err
		}

		var mod Modify
		switch cmd {
		case "add":
			mod = Add
		case "update":
			mod = Update
		case "remove":
			mod = Remove
		}

		for _, item := range list {
			if f.HasStatus(item) {
				err = ctx.ModifyImport(item.Local, mod)
				if err != nil {
					return false, err
				}
			}
			if f.HasImport(item) {
				err = ctx.ModifyImport(item.Local, mod)
				if err != nil {
					return false, err
				}
			}
		}
		for _, imp := range f.Import {
			if strings.HasSuffix(imp, "...") {
				continue
			}
			err = ctx.ModifyImport(imp, mod)
			if err != nil {
				return false, err
			}
		}

		// Auto-resolve package conflicts.
		ctx.Reslove(ctx.Check())

		if *dryrun {
			for _, op := range ctx.Operation {
				if len(op.Dest) == 0 {
					fmt.Fprintf(w, "Remove %q\n", op.Src)
				} else {
					fmt.Fprintf(w, "Copy %q -> %q\n", op.Src, op.Dest)
				}
			}
			return false, nil
		}

		// Write out vendor file and do change.
		err = ctx.WriteVendorFile()
		if err != nil {
			return false, err
		}
		err = ctx.Alter()
		if err != nil {
			return false, err
		}
	case "migrate":
		args := appArgs[2:]
		from := migrate.Auto
		if len(args) > 0 {
			switch args[0] {
			case "auto":
				from = migrate.Auto
			case "gb":
				from = migrate.Gb
			case "godep":
				from = migrate.Godep
			case "internal":
				from = migrate.Internal
			default:
				return true, fmt.Errorf("Unknown migrate command %q", args[0])
			}
		}
		return false, migrate.MigrateWD(from)
	default:
		return true, fmt.Errorf("Unknown command %q", cmd)
	}
	return false, nil
}

func checkNewContextError(err error) (bool, error) {
	// Diagnose error, show current value of 1.5vendor, suggest alter.
	if err == nil {
		return false, nil
	}
	if _, is := err.(ErrMissingVendorFile); is {
		expValue := os.Getenv("GO15VENDOREXPERIMENT")
		err = fmt.Errorf(`%v

GO15VENDOREXPERIMENT=%q
It is possible this project requires changing the above env var
or the project is not initialized.
`, err, expValue)
		return false, err
	}
	return false, err
}
<|endoftext|>


<commit_before>// +build linux

package main

import (
	"fmt"
	"os"
	"runtime"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/opencontainers/runc/libcontainer"
	"github.com/opencontainers/specs"
)

func init() {
	if len(os.Args) > 1 && os.Args[1] == "init" {
		runtime.GOMAXPROCS(1)
		runtime.LockOSThread()
		factory, _ := libcontainer.New("")
		if err := factory.StartInitialization(); err != nil {
			fatal(err)
		}
		panic("--this line should never been executed, congratulations--")
	}
}

func execContainer(context *cli.Context, spec *specs.LinuxSpec) (int, error) {
	config, err := createLibcontainerConfig(spec)
	if err != nil {
		return -1, err
	}
	if _, err := os.Stat(config.Rootfs); err != nil {
		if os.IsNotExist(err) {
			return -1, fmt.Errorf("Rootfs (%q) does not exist", config.Rootfs)
		}
		return -1, err
	}
	rootuid, err := config.HostUID()
	if err != nil {
		return -1, err
	}
	factory, err := loadFactory(context)
	if err != nil {
		return -1, err
	}
	container, err := factory.Create(context.GlobalString("id"), config)
	if err != nil {
		return -1, err
	}
	// ensure that the container is always removed if we were the process
	// that created it.
	defer destroy(container)
	process := newProcess(spec.Process)
	tty, err := newTty(spec.Process.Terminal, process, rootuid)
	if err != nil {
		return -1, err
	}
	handler := newSignalHandler(tty)
	defer handler.Close()
	if err := container.Start(process); err != nil {
		return -1, err
	}
	return handler.forward(process)
}

// default action is to execute a container
func runAction(context *cli.Context) {
	spec, err := loadSpec(context.Args().First())
	if err != nil {
		fatal(err)
	}
	if os.Geteuid() != 0 {
		logrus.Fatal("runc should be run as root")
	}
	status, err := execContainer(context, spec)
	if err != nil {
		logrus.Fatalf("Container start failed: %v", err)
	}
	// exit with the container's exit status so any external supervisor is
	// notified of the exit with the correct exit status.
	os.Exit(status)
}

func destroy(container libcontainer.Container) {
	status, err := container.Status()
	if err != nil {
		logrus.Error(err)
	}
	if status != libcontainer.Checkpointed {
		if err := container.Destroy(); err != nil {
			logrus.Error(err)
		}
	}
}
<commit_msg>wrong grammar: should never been --> should have never been<commit_after>// +build linux

package main

import (
	"fmt"
	"os"
	"runtime"

	"github.com/Sirupsen/logrus"
	"github.com/codegangsta/cli"
	"github.com/opencontainers/runc/libcontainer"
	"github.com/opencontainers/specs"
)

func init() {
	if len(os.Args) > 1 && os.Args[1] == "init" {
		runtime.GOMAXPROCS(1)
		runtime.LockOSThread()
		factory, _ := libcontainer.New("")
		if err := factory.StartInitialization(); err != nil {
			fatal(err)
		}
		panic("--this line should have never been executed, congratulations--")
	}
}

func execContainer(context *cli.Context, spec *specs.LinuxSpec) (int, error) {
	config, err := createLibcontainerConfig(spec)
	if err != nil {
		return -1, err
	}
	if _, err := os.Stat(config.Rootfs); err != nil {
		if os.IsNotExist(err) {
			return -1, fmt.Errorf("Rootfs (%q) does not exist", config.Rootfs)
		}
		return -1, err
	}
	rootuid, err := config.HostUID()
	if err != nil {
		return -1, err
	}
	factory, err := loadFactory(context)
	if err != nil {
		return -1, err
	}
	container, err := factory.Create(context.GlobalString("id"), config)
	if err != nil {
		return -1, err
	}
	// ensure that the container is always removed if we were the process
	// that created it.
	defer destroy(container)
	process := newProcess(spec.Process)
	tty, err := newTty(spec.Process.Terminal, process, rootuid)
	if err != nil {
		return -1, err
	}
	handler := newSignalHandler(tty)
	defer handler.Close()
	if err := container.Start(process); err != nil {
		return -1, err
	}
	return handler.forward(process)
}

// default action is to execute a container
func runAction(context *cli.Context) {
	spec, err := loadSpec(context.Args().First())
	if err != nil {
		fatal(err)
	}
	if os.Geteuid() != 0 {
		logrus.Fatal("runc should be run as root")
	}
	status, err := execContainer(context, spec)
	if err != nil {
		logrus.Fatalf("Container start failed: %v", err)
	}
	// exit with the container's exit status so any external supervisor is
	// notified of the exit with the correct exit status.
	os.Exit(status)
}

func destroy(container libcontainer.Container) {
	status, err := container.Status()
	if err != nil {
		logrus.Error(err)
	}
	if status != libcontainer.Checkpointed {
		if err := container.Destroy(); err != nil {
			logrus.Error(err)
		}
	}
}
<|endoftext|>


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

package main

import (
	"./subtitle"
	"errors"
	"fmt"
	"github.com/0xe2-0x9a-0x9b/Go-SDL/sdl"
	"github.com/0xe2-0x9a-0x9b/Go-SDL/ttf"
	"log"
	"sort"
	"strings"
	"time"
)

const (
	DEFAULT_FONT_PATH = "/usr/share/fonts/truetype/nanum/NanumGothicBold.ttf"
	DEFAULT_FONT_SIZE = 60
)

var (
	BG_COLOR    = sdl.Color{0, 0, 0, 0}
	TEXT_COLOR  = sdl.Color{255, 255, 255, 0}
	waitFinishC = make(chan bool)
)

type sdlCtx struct {
	surface *sdl.Surface
	w, h    int

	currScript *subtitle.Script
	font       *ttf.Font
	lineHeight int

	fontSize int
	fontPath string
}

func NewSdlContext(w, h int) *sdlCtx {
	if sdl.Init(sdl.INIT_EVERYTHING) != 0 {
		log.Fatal("failed to init sdl", sdl.GetError())
		return nil
	}

	if ttf.Init() != 0 {
		log.Fatal("failed to init ttf", sdl.GetError())
		return nil
	}

	var ctx sdlCtx
	if err := ctx.setSurface(w, h); err != nil {
		log.Fatal(err)
	}

	var vInfo = sdl.GetVideoInfo()
	log.Println("HW_available = ", vInfo.HW_available)
	log.Println("WM_available = ", vInfo.WM_available)
	log.Println("Video_mem = ", vInfo.Video_mem, "kb")

	title := "Subtitle Player"
	icon := "" // path/to/icon
	sdl.WM_SetCaption(title, icon)

	sdl.EnableUNICODE(1)

	go func() {
	EVENT_LOOP:
		for {
			err := ctx.handelEvent()
			if err != nil {
				fmt.Println(err)
				break EVENT_LOOP
			}
		}
		log.Println("sdl: exit event loop")
		quitC <- true
	}()

	return &ctx
}

func (c *sdlCtx) Release() {
	if c.font != nil {
		c.font.Close()
	}
	if c.surface != nil {
		c.surface.Free()
	}
	ttf.Quit()
	sdl.Quit()

	/* log.Printf("sdl Released...") */
}

func (c *sdlCtx) DisplayScript(script *subtitle.Script) {
	c.displayScript(script, true, false)
}

func (c *sdlCtx) Clear() {
	if c.currScript == nil {
		return
	}
	log.Println("clear")
	c.surface.FillRect(nil, 0 /* BG_COLOR */)
	c.surface.Flip()
	c.currScript = nil
}

func (c *sdlCtx) setFont(path string, size int) error {
	if size < 10 {
		log.Println("set font size to minimum, 10")
		size = 10
	}

	c.font = ttf.OpenFont(path, size)
	if c.font == nil {
		errMsg := fmt.Sprintf("failed to open font from %s: %s",
			path, sdl.GetError())
		return errors.New(errMsg)
	}

	c.fontSize = size
	c.fontPath = path
	c.lineHeight = c.font.LineSkip()

	log.Println(c.fontSize, c.lineHeight)
	/* ctx.font.SetStyle(ttf.STYLE_UNDERLINE) */
	return nil
}

func (c *sdlCtx) changeFontSize(by int) {
	if c.font == nil {
		return
	}
	c.setFont(c.fontPath, c.fontSize+by)
	c.displayScript(c.currScript, false, true)
}

func (c *sdlCtx) setSurface(w, h int) error {
	log.Printf("setSurface to %dx%d", w, h)
	c.surface = sdl.SetVideoMode(w, h, 32, sdl.RESIZABLE) /* sdl.FULLSCREEN */
	if c.surface == nil {
		errMsg := fmt.Sprintf("sdl: failed to set video to %dx%d: %s",
			w, h, sdl.GetError())
		return errors.New(errMsg)
	}

	c.w, c.h = w, h
	if c.currScript != nil {
		c.displayScript(c.currScript, false, true)
	}

	return nil
}

func (c *sdlCtx) handelEvent() error {
	// KeySym to time.Duration mapping
	kmVias := map[uint32]time.Duration{
		sdl.K_z:     -100 * time.Microsecond,
		sdl.K_x:     +100 * time.Microsecond,
		sdl.K_LEFT:  -1 * time.Second,
		sdl.K_RIGHT: +1 * time.Second,
		sdl.K_DOWN:  -10 * time.Second,
		sdl.K_UP:    +10 * time.Second,
	}

	kmFontSize := map[uint32]int{
		sdl.K_PLUS:     +5,
		sdl.K_KP_PLUS:  +5,
		sdl.K_MINUS:    -5,
		sdl.K_KP_MINUS: -5,
	}

	kmNavScript := map[uint32]int{
		sdl.K_SPACE:  0,
		sdl.K_COMMA:  -1, // <
		sdl.K_PERIOD: +1, // >
		// sdl. : -1,
		// sdl. : +1,
	}

	select {
	case event := <-sdl.Events:
		/* log.Printf("%#v\n", event) */
		switch e := event.(type) {
		case sdl.QuitEvent:
			return errors.New("sdl: received QuitEvent")

		case sdl.ResizeEvent:
			if err := c.setSurface(int(e.W), int(e.H)); err != nil {
				log.Fatal(err)
			}

		case sdl.KeyboardEvent:
			// Ignore release key
			if e.State == 0 {
				return nil
			}

			keysym := e.Keysym.Sym
			// tune timestamp
			if vias, ok := kmVias[keysym]; ok {
				viasC <- vias
				break
			}
			// tune font size
			if vias, ok := kmFontSize[keysym]; ok {
				c.changeFontSize(vias)
				break
			}

			// pause/resume
			if vias, ok := kmNavScript[keysym]; ok {
				log.Println("TODO: nav vias=", vias)
				navC <- vias
				break
			}
			log.Printf("Sim:%08x, Mod:%04x, Unicode:%02x, %t\n",
				e.Keysym.Sym, e.Keysym.Mod, e.Keysym.Unicode,
				e.Keysym.Unicode)
		}
	}
	return nil
}

func (c *sdlCtx) displayScript(script *subtitle.Script,
	andClear bool, forceUpdate bool) {
	if forceUpdate == false && c.currScript == script {
		return
	}
	c.currScript = script

	log.Printf("display %s", script.Text)

	if c.font == nil {
		log.Println("set default font")
		err := c.setFont(DEFAULT_FONT_PATH, DEFAULT_FONT_SIZE)
		if err != nil {
			log.Fatal("failed to set default font")
			return
		}
	}

	c.surface.FillRect(nil, 0 /* BG_COLOR */)
	offsetX := 10
	offsetY := 10

	for _, line := range strings.Split(script.TextWithoutMarkup(), "\n") {
		runeLine := []rune(line)
		runeLineLen := len(runeLine)
		runeLineStart := 0

		for runeLineStart != runeLineLen {
			/* log.Println("start =", runeLineStart, "len =", runeLineLen) */
			runeSubLine := runeLine[runeLineStart:]
			i := sort.Search(len(runeSubLine), func(i int) bool {
				w, _, _ := c.font.SizeUTF8(string(runeSubLine[:i]))
				return (w - 20) >= c.w
			})
			/* log.Println("runeSubLine=", string(runeSubLine)) */

			if i != len(runeSubLine) && i > 1 {
				i -= 1
			}
			if i > runeLineLen {
				i = runeLineLen
			}
			/* log.Println("returned i=", i) */

			subline := string(runeLine[runeLineStart : runeLineStart+i])
			subline = strings.TrimSpace(subline)
			/* log.Println("subline=", subline) */
			runeLineStart += i
			if runeLineStart > runeLineLen {
				runeLineStart = runeLineLen
			}

			w, _, err := c.font.SizeUTF8(subline)
			if err != 0 {
				log.Fatal("Failed to get size of the font")
			}
			offsetX = (c.w - w) / 2

			glypse := ttf.RenderUTF8_Blended(c.font, subline, TEXT_COLOR)
			lt := sdl.Rect{int16(offsetX), int16(offsetY), 0, 0}
			c.surface.Blit(&lt, glypse, nil)
			offsetY += c.lineHeight
		}

	}
	c.surface.Flip()

	if andClear == false {
		return
	}

	go func() {
		<-time.After(script.Duration())
		if c.currScript != nil && c.currScript == script {
			c.surface.FillRect(nil, 0 /* BG_COLOR */)
			c.surface.Flip()
		}
	}()
}
<commit_msg>set max fps of surface to 30<commit_after>// Copyright 2013, Homin Lee. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"./subtitle"
	"errors"
	"fmt"
	"github.com/0xe2-0x9a-0x9b/Go-SDL/sdl"
	"github.com/0xe2-0x9a-0x9b/Go-SDL/ttf"
	"log"
	"sort"
	"strings"
	"time"
)

const (
	DEFAULT_FONT_PATH = "/usr/share/fonts/truetype/nanum/NanumGothicBold.ttf"
	DEFAULT_FONT_SIZE = 60
)

var (
	BG_COLOR    = sdl.Color{0, 0, 0, 0}
	TEXT_COLOR  = sdl.Color{255, 255, 255, 0}
	waitFinishC = make(chan bool)
)

type sdlCtx struct {
	surface      *sdl.Surface
	dirtySurface bool
	fps          int
	w, h         int

	currScript *subtitle.Script
	font       *ttf.Font
	lineHeight int

	fontSize int
	fontPath string
}

func NewSdlContext(w, h int) *sdlCtx {
	if sdl.Init(sdl.INIT_EVERYTHING) != 0 {
		log.Fatal("failed to init sdl", sdl.GetError())
		return nil
	}

	if ttf.Init() != 0 {
		log.Fatal("failed to init ttf", sdl.GetError())
		return nil
	}

	var ctx sdlCtx
	if err := ctx.setSurface(w, h); err != nil {
		log.Fatal(err)
	}

	var vInfo = sdl.GetVideoInfo()
	log.Println("HW_available = ", vInfo.HW_available)
	log.Println("WM_available = ", vInfo.WM_available)
	log.Println("Video_mem = ", vInfo.Video_mem, "kb")

	title := "Subtitle Player"
	icon := "" // path/to/icon
	sdl.WM_SetCaption(title, icon)

	sdl.EnableUNICODE(1)

	// XXX: fix it to set from argument
	ctx.fps = 30

	go func() {
	EVENT_LOOP:
		for {
			err := ctx.handelEvent()
			if err != nil {
				fmt.Println(err)
				break EVENT_LOOP
			}
		}
		log.Println("sdl: exit event loop")
		quitC <- true
	}()

	return &ctx
}

func (c *sdlCtx) Release() {
	if c.font != nil {
		c.font.Close()
	}
	if c.surface != nil {
		c.surface.Free()
	}
	ttf.Quit()
	sdl.Quit()

	/* log.Printf("sdl Released...") */
}

func (c *sdlCtx) DisplayScript(script *subtitle.Script) {
	c.displayScript(script, true, false)
}

func (c *sdlCtx) Clear() {
	if c.currScript == nil {
		return
	}
	log.Println("clear")
	c.surface.FillRect(nil, 0 /* BG_COLOR */)
	c.dirtySurface = true
	/* c.surface.Flip() */
	c.currScript = nil
}

func (c *sdlCtx) setFont(path string, size int) error {
	if size < 10 {
		log.Println("set font size to minimum, 10")
		size = 10
	}

	c.font = ttf.OpenFont(path, size)
	if c.font == nil {
		errMsg := fmt.Sprintf("failed to open font from %s: %s",
			path, sdl.GetError())
		return errors.New(errMsg)
	}

	c.fontSize = size
	c.fontPath = path
	c.lineHeight = c.font.LineSkip()

	log.Println(c.fontSize, c.lineHeight)
	/* ctx.font.SetStyle(ttf.STYLE_UNDERLINE) */
	return nil
}

func (c *sdlCtx) changeFontSize(by int) {
	if c.font == nil {
		return
	}
	c.setFont(c.fontPath, c.fontSize+by)
	c.displayScript(c.currScript, false, true)
}

func (c *sdlCtx) setSurface(w, h int) error {
	log.Printf("setSurface to %dx%d", w, h)
	c.surface = sdl.SetVideoMode(w, h, 32, sdl.RESIZABLE) /* sdl.FULLSCREEN */
	if c.surface == nil {
		errMsg := fmt.Sprintf("sdl: failed to set video to %dx%d: %s",
			w, h, sdl.GetError())
		return errors.New(errMsg)
	}

	c.w, c.h = w, h
	if c.currScript != nil {
		c.displayScript(c.currScript, false, true)
	}

	return nil
}

func (c *sdlCtx) handelEvent() error {
	// KeySym to time.Duration mapping
	kmVias := map[uint32]time.Duration{
		sdl.K_z:     -100 * time.Microsecond,
		sdl.K_x:     +100 * time.Microsecond,
		sdl.K_LEFT:  -1 * time.Second,
		sdl.K_RIGHT: +1 * time.Second,
		sdl.K_DOWN:  -10 * time.Second,
		sdl.K_UP:    +10 * time.Second,
	}

	kmFontSize := map[uint32]int{
		sdl.K_PLUS:     +5,
		sdl.K_KP_PLUS:  +5,
		sdl.K_MINUS:    -5,
		sdl.K_KP_MINUS: -5,
	}

	kmNavScript := map[uint32]int{
		sdl.K_SPACE:  0,
		sdl.K_COMMA:  -1, // <
		sdl.K_PERIOD: +1, // >
	}

	fpsTicker := time.NewTicker(time.Second / time.Duration(c.fps)) // 30fps

	select {
	case <-fpsTicker.C:
		if c.dirtySurface {
			c.surface.Flip()
			c.dirtySurface = false
		}

	case event := <-sdl.Events:
		/* log.Printf("%#v\n", event) */
		switch e := event.(type) {
		case sdl.QuitEvent:
			return errors.New("sdl: received QuitEvent")

		case sdl.ResizeEvent:
			if err := c.setSurface(int(e.W), int(e.H)); err != nil {
				log.Fatal(err)
			}

		case sdl.KeyboardEvent:
			// Ignore release key
			if e.State == 0 {
				return nil
			}

			keysym := e.Keysym.Sym
			// tune timestamp
			if vias, ok := kmVias[keysym]; ok {
				viasC <- vias
				break
			}
			// tune font size
			if vias, ok := kmFontSize[keysym]; ok {
				c.changeFontSize(vias)
				break
			}

			// pause/resume
			if vias, ok := kmNavScript[keysym]; ok {
				log.Println("TODO: nav vias=", vias)
				navC <- vias
				break
			}
			log.Printf("Sim:%08x, Mod:%04x, Unicode:%02x, %t\n",
				e.Keysym.Sym, e.Keysym.Mod, e.Keysym.Unicode,
				e.Keysym.Unicode)
		}
	}
	return nil
}

func (c *sdlCtx) displayScript(script *subtitle.Script,
	andClear bool, forceUpdate bool) {
	if forceUpdate == false && c.currScript == script {
		return
	}
	c.currScript = script

	log.Printf("display %s", script.Text)

	if c.font == nil {
		log.Println("set default font")
		err := c.setFont(DEFAULT_FONT_PATH, DEFAULT_FONT_SIZE)
		if err != nil {
			log.Fatal("failed to set default font")
			return
		}
	}

	c.surface.FillRect(nil, 0 /* BG_COLOR */)
	offsetX := 10
	offsetY := 10

	for _, line := range strings.Split(script.TextWithoutMarkup(), "\n") {
		runeLine := []rune(line)
		runeLineLen := len(runeLine)
		runeLineStart := 0

		for runeLineStart != runeLineLen {
			/* log.Println("start =", runeLineStart, "len =", runeLineLen) */
			runeSubLine := runeLine[runeLineStart:]
			i := sort.Search(len(runeSubLine), func(i int) bool {
				w, _, _ := c.font.SizeUTF8(string(runeSubLine[:i]))
				return (w - 20) >= c.w
			})
			/* log.Println("runeSubLine=", string(runeSubLine)) */

			if i != len(runeSubLine) && i > 1 {
				i -= 1
			}
			if i > runeLineLen {
				i = runeLineLen
			}
			/* log.Println("returned i=", i) */

			subline := string(runeLine[runeLineStart : runeLineStart+i])
			subline = strings.TrimSpace(subline)
			/* log.Println("subline=", subline) */
			runeLineStart += i
			if runeLineStart > runeLineLen {
				runeLineStart = runeLineLen
			}

			w, _, err := c.font.SizeUTF8(subline)
			if err != 0 {
				log.Fatal("Failed to get size of the font")
			}
			offsetX = (c.w - w) / 2

			glypse := ttf.RenderUTF8_Blended(c.font, subline, TEXT_COLOR)
			lt := sdl.Rect{int16(offsetX), int16(offsetY), 0, 0}
			c.surface.Blit(&lt, glypse, nil)
			offsetY += c.lineHeight
		}

	}
	c.dirtySurface = true
	/* c.surface.Flip() */

	if andClear == false {
		return
	}

	go func() {
		<-time.After(script.Duration())
		if c.currScript != nil && c.currScript == script {
			c.surface.FillRect(nil, 0 /* BG_COLOR */)
			c.surface.Flip()
		}
	}()
}
<|endoftext|>