<commit_before>//  Copyright (c) 2016 Couchbase, 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 moss

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

	"github.com/edsrzf/mmap-go"
)

func (s *Store) persistFooter(file File, footer *Footer,
	options StorePersistOptions) error {
	startTime := time.Now()

	if !options.NoSync {
		err := file.Sync()
		if err != nil {
			return err
		}
	}

	err := s.persistFooterUnsynced(file, footer)
	if err != nil {
		return err
	}

	if !options.NoSync {
		err = file.Sync()
	}

	if err == nil {
		s.histograms["PersistFooterUsecs"].Add(
			uint64(time.Since(startTime).Nanoseconds()/1000), 1)
	}

	return err
}

func (s *Store) persistFooterUnsynced(file File, footer *Footer) error {
	jBuf, err := json.Marshal(footer)
	if err != nil {
		return err
	}

	finfo, err := file.Stat()
	if err != nil {
		return err
	}

	footerPos := pageAlignCeil(finfo.Size())
	footerLen := footerBegLen + len(jBuf) + footerEndLen

	footerBuf := bytes.NewBuffer(make([]byte, 0, footerLen))
	footerBuf.Write(StoreMagicBeg)
	footerBuf.Write(StoreMagicBeg)
	binary.Write(footerBuf, StoreEndian, uint32(StoreVersion))
	binary.Write(footerBuf, StoreEndian, uint32(footerLen))
	footerBuf.Write(jBuf)
	binary.Write(footerBuf, StoreEndian, footerPos)
	binary.Write(footerBuf, StoreEndian, uint32(footerLen))
	footerBuf.Write(StoreMagicEnd)
	footerBuf.Write(StoreMagicEnd)

	footerWritten, err := file.WriteAt(footerBuf.Bytes(), footerPos)
	if err != nil {
		return err
	}
	if footerWritten != len(footerBuf.Bytes()) {
		return fmt.Errorf("store: persistFooter error writing all footerBuf")
	}

	footer.fileName = finfo.Name()
	footer.filePos = footerPos

	return nil
}

// --------------------------------------------------------

// ReadFooter reads the last valid Footer from a file.
func ReadFooter(options *StoreOptions, file File) (*Footer, error) {
	finfo, err := file.Stat()
	if err != nil {
		return nil, err
	}

	fref := &FileRef{file: file, refs: 1}

	// To avoid an EOF while reading, start scanning the footer from
	// the last byte. This is under the assumption that the footer is
	// at least 2 bytes long.
	f, err := ScanFooter(options, fref, finfo.Name(), finfo.Size()-1)
	if err != nil {
		return nil, err
	}

	fref.DecRef() // ScanFooter added its own ref-counts on success.

	return f, err
}

// --------------------------------------------------------

// ScanFooter scans a file backwards from the given pos for a valid
// Footer, adding ref-counts to fref on success.
func ScanFooter(options *StoreOptions, fref *FileRef, fileName string,
	pos int64) (*Footer, error) {
	footerBeg := make([]byte, footerBegLen)

	// Align pos to the start of a page (floor).
	pos = pageAlignFloor(pos)

	for {
		for { // Scan for StoreMagicBeg, which may be a potential footer.
			if pos <= 0 {
				return nil, ErrNoValidFooter
			}

			n, err := fref.file.ReadAt(footerBeg, pos)
			if err != nil {
				return nil, err
			}

			if n == footerBegLen &&
				bytes.Equal(StoreMagicBeg, footerBeg[:lenMagicBeg]) &&
				bytes.Equal(StoreMagicBeg, footerBeg[lenMagicBeg:2*lenMagicBeg]) {
				break
			}

			// Move pos back by page size.
			pos -= int64(StorePageSize)
		}

		// Read and check the potential footer.
		footerBegBuf := bytes.NewBuffer(footerBeg[2*lenMagicBeg:])

		var version uint32
		if err := binary.Read(footerBegBuf, StoreEndian, &version); err != nil {
			return nil, err
		}
		if version != StoreVersion {
			return nil, fmt.Errorf("store: version mismatch, "+
				"current: %v != found: %v", StoreVersion, version)
		}

		var length uint32
		if err := binary.Read(footerBegBuf, StoreEndian, &length); err != nil {
			return nil, err
		}

		data := make([]byte, int64(length)-int64(footerBegLen))

		n, err := fref.file.ReadAt(data, pos+int64(footerBegLen))
		if err != nil {
			return nil, err
		}

		if n == len(data) &&
			bytes.Equal(StoreMagicEnd, data[n-lenMagicEnd*2:n-lenMagicEnd]) &&
			bytes.Equal(StoreMagicEnd, data[n-lenMagicEnd:]) {

			content := int(length) - footerBegLen - footerEndLen
			b := bytes.NewBuffer(data[content:])

			var offset int64
			if err = binary.Read(b, StoreEndian, &offset); err != nil {
				return nil, err
			}
			if offset != pos {
				return nil, fmt.Errorf("store: offset mismatch, "+
					"wanted: %v != found: %v", offset, pos)
			}

			var length1 uint32
			if err = binary.Read(b, StoreEndian, &length1); err != nil {
				return nil, err
			}
			if length1 != length {
				return nil, fmt.Errorf("store: length mismatch, "+
					"wanted: %v != found: %v", length1, length)
			}

			f := &Footer{refs: 1, fileName: fileName, filePos: offset}

			err = json.Unmarshal(data[:content], f)
			if err != nil {
				return nil, err
			}

			// json.Unmarshal would have just loaded the map.
			// We now need to load each segment into the map.
			// Also recursively load child footer segment stacks.
			err = f.loadSegments(options, fref)
			if err != nil {
				return nil, err
			}

			return f, nil
		}
		// Else, invalid footer - StoreMagicEnd missing and/or file
		// pos out of bounds.

		// Footer was invalid, so keep scanning.
		pos -= int64(StorePageSize)
	}
}

// --------------------------------------------------------

// loadSegments() loads the segments of a footer.  Adds new ref-counts
// to the fref on success.  The footer will be in an already closed
// state on error.
func (f *Footer) loadSegments(options *StoreOptions, fref *FileRef) (err error) {
	// Track mrefs that we need to DecRef() if there's an error.
	mrefs := make([]*mmapRef, 0, len(f.SegmentLocs))
	mrefs, err = f.doLoadSegments(options, fref, mrefs)
	if err != nil {
		for _, mref := range mrefs {
			mref.DecRef()
		}
		return err
	}

	return nil
}

func (f *Footer) doLoadSegments(options *StoreOptions, fref *FileRef,
	mrefs []*mmapRef) (mrefsSoFar []*mmapRef, err error) {
	// Recursively load the childFooters first.
	for _, childFooter := range f.ChildFooters {
		mrefs, err = childFooter.doLoadSegments(options, fref, mrefs)
		if err != nil {
			return mrefs, err
		}
	}

	if f.ss != nil && f.ss.a != nil {
		return mrefs, nil
	}

	osFile := ToOsFile(fref.file)
	if osFile == nil {
		return mrefs, fmt.Errorf("store: doLoadSegments convert to os.File error")
	}

	a := make([]Segment, len(f.SegmentLocs))

	for i := range f.SegmentLocs {
		sloc := &f.SegmentLocs[i]

		mref := sloc.mref
		if mref != nil {
			if mref.fref != fref {
				return mrefs, fmt.Errorf("store: doLoadSegments fref mismatch")
			}

			mref.AddRef()
		} else {
			// We persist kvs before buf, so KvsOffset < BufOffset.
			begOffset := int64(sloc.KvsOffset)
			endOffset := int64(sloc.BufOffset + sloc.BufBytes)

			nbytes := int(endOffset - begOffset)

			// Some platforms (windows) only support mmap()'ing at an
			// allocation granularity that's != to a page size, so
			// calculate the actual offset/nbytes to use.
			begOffsetActual := pageOffset(begOffset, int64(AllocationGranularity))
			begOffsetDelta := int(begOffset - begOffsetActual)
			nbytesActual := nbytes + begOffsetDelta

			mm, err := mmap.MapRegion(osFile, nbytesActual, mmap.RDONLY, 0, begOffsetActual)
			if err != nil {
				return mrefs,
					fmt.Errorf("store: doLoadSegments mmap.Map(), nbytesActual = %v, sloc = %v, err: %v",
						nbytesActual, sloc, err)
			}

			fref.AddRef() // New mref owns 1 fref ref-count.

			buf := mm[begOffsetDelta : begOffsetDelta+nbytes]

			sloc.mref = &mmapRef{fref: fref, mm: mm, buf: buf, refs: 1}

			mref = sloc.mref
		}

		mrefs = append(mrefs, mref)

		segmentLoader, exists := SegmentLoaders[sloc.Kind]
		if !exists || segmentLoader == nil {
			return mrefs, fmt.Errorf("store: unknown SegmentLoc kind, sloc: %+v", sloc)
		}

		seg, err := segmentLoader(sloc)
		if err != nil {
			return mrefs, fmt.Errorf("store: segmentLoader failed, footer: %+v,"+
				" f.SegmentLocs: %+v, i: %d, options: %v err: %+v",
				f, f.SegmentLocs, i, options, err)
		}

		a[i] = seg
	}

	f.ss = &segmentStack{
		options: &options.CollectionOptions,
		a:       a,
		refs:    1,
	}

	return mrefs, nil
}

// --------------------------------------------------------

// ChildCollectionNames returns an array of child collection name strings.
func (f *Footer) ChildCollectionNames() ([]string, error) {
	var childNames = make([]string, len(f.ChildFooters))
	idx := 0
	for name := range f.ChildFooters {
		childNames[idx] = name
		idx++
	}
	return childNames, nil
}

// ChildCollectionSnapshot returns a Snapshot on a given child
// collection by its name.
func (f *Footer) ChildCollectionSnapshot(childCollectionName string) (
	Snapshot, error) {
	childFooter, exists := f.ChildFooters[childCollectionName]
	if !exists {
		return nil, nil
	}
	childFooter.AddRef()
	return childFooter, nil
}

// Close decrements the ref count on this footer
func (f *Footer) Close() error {
	f.DecRef()
	return nil
}

// AddRef increases the ref count on this footer
func (f *Footer) AddRef() {
	f.m.Lock()
	f.refs++
	f.m.Unlock()
}

// DecRef decreases the ref count on this footer
func (f *Footer) DecRef() {
	f.m.Lock()
	f.refs--
	if f.refs <= 0 {
		f.SegmentLocs.DecRef()
		f.SegmentLocs = nil
		f.ss = nil
	}
	f.m.Unlock()
}

// Length returns the length of this footer
func (f *Footer) Length() uint64 {
	jBuf, err := json.Marshal(f)
	if err != nil {
		return 0
	}

	footerLen := footerBegLen + len(jBuf) + footerEndLen
	return uint64(footerLen)
}

// --------------------------------------------------------

// segmentLocs returns the current SegmentLocs and segmentStack for
// a footer, while also incrementing the ref-count on the footer.  The
// caller must DecRef() the footer when done.
func (f *Footer) segmentLocs() (SegmentLocs, *segmentStack) {
	f.m.Lock()

	f.refs++

	slocs, ss := f.SegmentLocs, f.ss

	f.m.Unlock()

	return slocs, ss
}

// --------------------------------------------------------

// Get retrieves a val from the footer, and will return nil val
// if the entry does not exist in the footer.
func (f *Footer) Get(key []byte, readOptions ReadOptions) ([]byte, error) {
	_, ss := f.segmentLocs()
	if ss == nil {
		f.DecRef()
		return nil, nil
	}

	rv, err := ss.Get(key, readOptions)
	if err == nil && rv != nil && !readOptions.NoCopyValue {
		rv = append(make([]byte, 0, len(rv)), rv...) // Copy.
	}

	f.DecRef()

	return rv, err
}

// StartIterator returns a new Iterator instance on this footer.
//
// On success, the returned Iterator will be positioned so that
// Iterator.Current() will either provide the first entry in the
// range or ErrIteratorDone.
//
// A startKeyIncl of nil means the logical "bottom-most" possible key
// and an endKeyExcl of nil means the logical "top-most" possible key.
func (f *Footer) StartIterator(startKeyIncl, endKeyExcl []byte,
	iteratorOptions IteratorOptions) (Iterator, error) {
	_, ss := f.segmentLocs()
	if ss == nil {
		f.DecRef()
		return nil, nil
	}

	iter, err := ss.StartIterator(startKeyIncl, endKeyExcl, iteratorOptions)
	if err != nil || iter == nil {
		f.DecRef()
		return nil, err
	}

	initCloser, ok := iter.(InitCloser)
	if !ok || initCloser == nil {
		iter.Close()
		f.DecRef()
		return nil, ErrUnexpected
	}

	err = initCloser.InitCloser(f)
	if err != nil {
		iter.Close()
		f.DecRef()
		return nil, err
	}

	return iter, nil
}
<commit_msg>MB-25330: Pad up file to page boundary on windows<commit_after>//  Copyright (c) 2016 Couchbase, 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 moss

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

	"github.com/edsrzf/mmap-go"
)

func (s *Store) persistFooter(file File, footer *Footer,
	options StorePersistOptions) error {
	startTime := time.Now()

	if !options.NoSync {
		err := file.Sync()
		if err != nil {
			return err
		}
	}

	err := s.persistFooterUnsynced(file, footer)
	if err != nil {
		return err
	}

	if !options.NoSync {
		err = file.Sync()
	}

	if err == nil {
		s.histograms["PersistFooterUsecs"].Add(
			uint64(time.Since(startTime).Nanoseconds()/1000), 1)
	}

	return err
}

func (s *Store) persistFooterUnsynced(file File, footer *Footer) error {
	jBuf, err := json.Marshal(footer)
	if err != nil {
		return err
	}

	finfo, err := file.Stat()
	if err != nil {
		return err
	}

	footerPos := pageAlignCeil(finfo.Size())
	footerLen := footerBegLen + len(jBuf) + footerEndLen

	footerBuf := bytes.NewBuffer(make([]byte, 0, footerLen))
	footerBuf.Write(StoreMagicBeg)
	footerBuf.Write(StoreMagicBeg)
	binary.Write(footerBuf, StoreEndian, uint32(StoreVersion))
	binary.Write(footerBuf, StoreEndian, uint32(footerLen))
	footerBuf.Write(jBuf)
	binary.Write(footerBuf, StoreEndian, footerPos)
	binary.Write(footerBuf, StoreEndian, uint32(footerLen))
	footerBuf.Write(StoreMagicEnd)
	footerBuf.Write(StoreMagicEnd)

	footerWritten, err := file.WriteAt(footerBuf.Bytes(), footerPos)
	if err != nil {
		return err
	}
	if footerWritten != len(footerBuf.Bytes()) {
		return fmt.Errorf("store: persistFooter error writing all footerBuf")
	}

	if AllocationGranularity != StorePageSize {
		// Some platforms (windows) only support mmap()'ing at an
		// allocation granularity that's != to a page size. However if on such
		// platforms there are empty segments, then due to the extra space
		// imposed by the above granularity requirement, mmap() can fail
		// complaining about insufficient file space.
		// To avoid this error, simply pad up the file upto a page boundary.
		// This pad of zeroes will not interfere with file recovery.
		padding := make([]byte, int(pageAlignCeil(int64(footerWritten)))-footerWritten)
		_, err = file.WriteAt(padding, footerPos+int64(footerWritten))
		if err != nil {
			return err
		}
	}

	footer.fileName = finfo.Name()
	footer.filePos = footerPos

	return nil
}

// --------------------------------------------------------

// ReadFooter reads the last valid Footer from a file.
func ReadFooter(options *StoreOptions, file File) (*Footer, error) {
	finfo, err := file.Stat()
	if err != nil {
		return nil, err
	}

	fref := &FileRef{file: file, refs: 1}

	// To avoid an EOF while reading, start scanning the footer from
	// the last byte. This is under the assumption that the footer is
	// at least 2 bytes long.
	f, err := ScanFooter(options, fref, finfo.Name(), finfo.Size()-1)
	if err != nil {
		return nil, err
	}

	fref.DecRef() // ScanFooter added its own ref-counts on success.

	return f, err
}

// --------------------------------------------------------

// ScanFooter scans a file backwards from the given pos for a valid
// Footer, adding ref-counts to fref on success.
func ScanFooter(options *StoreOptions, fref *FileRef, fileName string,
	pos int64) (*Footer, error) {
	footerBeg := make([]byte, footerBegLen)

	// Align pos to the start of a page (floor).
	pos = pageAlignFloor(pos)

	for {
		for { // Scan for StoreMagicBeg, which may be a potential footer.
			if pos <= 0 {
				return nil, ErrNoValidFooter
			}

			n, err := fref.file.ReadAt(footerBeg, pos)
			if err != nil {
				return nil, err
			}

			if n == footerBegLen &&
				bytes.Equal(StoreMagicBeg, footerBeg[:lenMagicBeg]) &&
				bytes.Equal(StoreMagicBeg, footerBeg[lenMagicBeg:2*lenMagicBeg]) {
				break
			}

			// Move pos back by page size.
			pos -= int64(StorePageSize)
		}

		// Read and check the potential footer.
		footerBegBuf := bytes.NewBuffer(footerBeg[2*lenMagicBeg:])

		var version uint32
		if err := binary.Read(footerBegBuf, StoreEndian, &version); err != nil {
			return nil, err
		}
		if version != StoreVersion {
			return nil, fmt.Errorf("store: version mismatch, "+
				"current: %v != found: %v", StoreVersion, version)
		}

		var length uint32
		if err := binary.Read(footerBegBuf, StoreEndian, &length); err != nil {
			return nil, err
		}

		data := make([]byte, int64(length)-int64(footerBegLen))

		n, err := fref.file.ReadAt(data, pos+int64(footerBegLen))
		if err != nil {
			return nil, err
		}

		if n == len(data) &&
			bytes.Equal(StoreMagicEnd, data[n-lenMagicEnd*2:n-lenMagicEnd]) &&
			bytes.Equal(StoreMagicEnd, data[n-lenMagicEnd:]) {

			content := int(length) - footerBegLen - footerEndLen
			b := bytes.NewBuffer(data[content:])

			var offset int64
			if err = binary.Read(b, StoreEndian, &offset); err != nil {
				return nil, err
			}
			if offset != pos {
				return nil, fmt.Errorf("store: offset mismatch, "+
					"wanted: %v != found: %v", offset, pos)
			}

			var length1 uint32
			if err = binary.Read(b, StoreEndian, &length1); err != nil {
				return nil, err
			}
			if length1 != length {
				return nil, fmt.Errorf("store: length mismatch, "+
					"wanted: %v != found: %v", length1, length)
			}

			f := &Footer{refs: 1, fileName: fileName, filePos: offset}

			err = json.Unmarshal(data[:content], f)
			if err != nil {
				return nil, err
			}

			// json.Unmarshal would have just loaded the map.
			// We now need to load each segment into the map.
			// Also recursively load child footer segment stacks.
			err = f.loadSegments(options, fref)
			if err != nil {
				return nil, err
			}

			return f, nil
		}
		// Else, invalid footer - StoreMagicEnd missing and/or file
		// pos out of bounds.

		// Footer was invalid, so keep scanning.
		pos -= int64(StorePageSize)
	}
}

// --------------------------------------------------------

// loadSegments() loads the segments of a footer.  Adds new ref-counts
// to the fref on success.  The footer will be in an already closed
// state on error.
func (f *Footer) loadSegments(options *StoreOptions, fref *FileRef) (err error) {
	// Track mrefs that we need to DecRef() if there's an error.
	mrefs := make([]*mmapRef, 0, len(f.SegmentLocs))
	mrefs, err = f.doLoadSegments(options, fref, mrefs)
	if err != nil {
		for _, mref := range mrefs {
			mref.DecRef()
		}
		return err
	}

	return nil
}

func (f *Footer) doLoadSegments(options *StoreOptions, fref *FileRef,
	mrefs []*mmapRef) (mrefsSoFar []*mmapRef, err error) {
	// Recursively load the childFooters first.
	for _, childFooter := range f.ChildFooters {
		mrefs, err = childFooter.doLoadSegments(options, fref, mrefs)
		if err != nil {
			return mrefs, err
		}
	}

	if f.ss != nil && f.ss.a != nil {
		return mrefs, nil
	}

	osFile := ToOsFile(fref.file)
	if osFile == nil {
		return mrefs, fmt.Errorf("store: doLoadSegments convert to os.File error")
	}

	a := make([]Segment, len(f.SegmentLocs))

	for i := range f.SegmentLocs {
		sloc := &f.SegmentLocs[i]

		mref := sloc.mref
		if mref != nil {
			if mref.fref != fref {
				return mrefs, fmt.Errorf("store: doLoadSegments fref mismatch")
			}

			mref.AddRef()
		} else {
			// We persist kvs before buf, so KvsOffset < BufOffset.
			begOffset := int64(sloc.KvsOffset)
			endOffset := int64(sloc.BufOffset + sloc.BufBytes)

			nbytes := int(endOffset - begOffset)

			// Some platforms (windows) only support mmap()'ing at an
			// allocation granularity that's != to a page size, so
			// calculate the actual offset/nbytes to use.
			begOffsetActual := pageOffset(begOffset, int64(AllocationGranularity))
			begOffsetDelta := int(begOffset - begOffsetActual)
			nbytesActual := nbytes + begOffsetDelta

			mm, err := mmap.MapRegion(osFile, nbytesActual, mmap.RDONLY, 0, begOffsetActual)
			if err != nil {
				return mrefs,
					fmt.Errorf("store: doLoadSegments mmap.Map(), "+
						"begOffsetActual = %v,"+
						"nbytesActual = %v, sloc = %v, err: %v",
						begOffsetActual, nbytesActual, sloc, err)
			}

			fref.AddRef() // New mref owns 1 fref ref-count.

			buf := mm[begOffsetDelta : begOffsetDelta+nbytes]

			sloc.mref = &mmapRef{fref: fref, mm: mm, buf: buf, refs: 1}

			mref = sloc.mref
		}

		mrefs = append(mrefs, mref)

		segmentLoader, exists := SegmentLoaders[sloc.Kind]
		if !exists || segmentLoader == nil {
			return mrefs, fmt.Errorf("store: unknown SegmentLoc kind, sloc: %+v", sloc)
		}

		seg, err := segmentLoader(sloc)
		if err != nil {
			return mrefs, fmt.Errorf("store: segmentLoader failed, footer: %+v,"+
				" f.SegmentLocs: %+v, i: %d, options: %v err: %+v",
				f, f.SegmentLocs, i, options, err)
		}

		a[i] = seg
	}

	f.ss = &segmentStack{
		options: &options.CollectionOptions,
		a:       a,
		refs:    1,
	}

	return mrefs, nil
}

// --------------------------------------------------------

// ChildCollectionNames returns an array of child collection name strings.
func (f *Footer) ChildCollectionNames() ([]string, error) {
	var childNames = make([]string, len(f.ChildFooters))
	idx := 0
	for name := range f.ChildFooters {
		childNames[idx] = name
		idx++
	}
	return childNames, nil
}

// ChildCollectionSnapshot returns a Snapshot on a given child
// collection by its name.
func (f *Footer) ChildCollectionSnapshot(childCollectionName string) (
	Snapshot, error) {
	childFooter, exists := f.ChildFooters[childCollectionName]
	if !exists {
		return nil, nil
	}
	childFooter.AddRef()
	return childFooter, nil
}

// Close decrements the ref count on this footer
func (f *Footer) Close() error {
	f.DecRef()
	return nil
}

// AddRef increases the ref count on this footer
func (f *Footer) AddRef() {
	f.m.Lock()
	f.refs++
	f.m.Unlock()
}

// DecRef decreases the ref count on this footer
func (f *Footer) DecRef() {
	f.m.Lock()
	f.refs--
	if f.refs <= 0 {
		f.SegmentLocs.DecRef()
		f.SegmentLocs = nil
		f.ss = nil
	}
	f.m.Unlock()
}

// Length returns the length of this footer
func (f *Footer) Length() uint64 {
	jBuf, err := json.Marshal(f)
	if err != nil {
		return 0
	}

	footerLen := footerBegLen + len(jBuf) + footerEndLen
	return uint64(footerLen)
}

// --------------------------------------------------------

// segmentLocs returns the current SegmentLocs and segmentStack for
// a footer, while also incrementing the ref-count on the footer.  The
// caller must DecRef() the footer when done.
func (f *Footer) segmentLocs() (SegmentLocs, *segmentStack) {
	f.m.Lock()

	f.refs++

	slocs, ss := f.SegmentLocs, f.ss

	f.m.Unlock()

	return slocs, ss
}

// --------------------------------------------------------

// Get retrieves a val from the footer, and will return nil val
// if the entry does not exist in the footer.
func (f *Footer) Get(key []byte, readOptions ReadOptions) ([]byte, error) {
	_, ss := f.segmentLocs()
	if ss == nil {
		f.DecRef()
		return nil, nil
	}

	rv, err := ss.Get(key, readOptions)
	if err == nil && rv != nil && !readOptions.NoCopyValue {
		rv = append(make([]byte, 0, len(rv)), rv...) // Copy.
	}

	f.DecRef()

	return rv, err
}

// StartIterator returns a new Iterator instance on this footer.
//
// On success, the returned Iterator will be positioned so that
// Iterator.Current() will either provide the first entry in the
// range or ErrIteratorDone.
//
// A startKeyIncl of nil means the logical "bottom-most" possible key
// and an endKeyExcl of nil means the logical "top-most" possible key.
func (f *Footer) StartIterator(startKeyIncl, endKeyExcl []byte,
	iteratorOptions IteratorOptions) (Iterator, error) {
	_, ss := f.segmentLocs()
	if ss == nil {
		f.DecRef()
		return nil, nil
	}

	iter, err := ss.StartIterator(startKeyIncl, endKeyExcl, iteratorOptions)
	if err != nil || iter == nil {
		f.DecRef()
		return nil, err
	}

	initCloser, ok := iter.(InitCloser)
	if !ok || initCloser == nil {
		iter.Close()
		f.DecRef()
		return nil, ErrUnexpected
	}

	err = initCloser.InitCloser(f)
	if err != nil {
		iter.Close()
		f.DecRef()
		return nil, err
	}

	return iter, nil
}
<|endoftext|>


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

// +build openbsd
// +build !nomeminfo

package collector

import (
	"fmt"
)

/*
#include <sys/param.h>
#include <sys/types.h>
#include <sys/sysctl.h>

int
sysctl_uvmexp(struct uvmexp *uvmexp)
{
        static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
        size_t sz = sizeof(struct uvmexp);

        if(sysctl(uvmexp_mib, 2, uvmexp, &sz, NULL, 0) < 0)
                return -1;

        return 0;
}

*/
import "C"

func (c *meminfoCollector) getMemInfo() (map[string]float64, error) {
	var uvmexp C.struct_uvmexp

	if _, err := C.sysctl_uvmexp(&uvmexp); err != nil {
		return nil, fmt.Errorf("sysctl CTL_VM VM_UVMEXP failed: %v", err)
	}

	ps := float64(uvmexp.pagesize)

	// see uvm(9)
	return map[string]float64{
		"active_bytes":                  ps * float64(uvmexp.active),
		"cache_bytes":                   ps * float64(uvmexp.vnodepages),
		"free_bytes":                    ps * float64(uvmexp.free),
		"inactive_bytes":                ps * float64(uvmexp.inactive),
		"size_bytes":                    ps * float64(uvmexp.npages),
		"swap_size_bytes":               ps * float64(uvmexp.swpages),
		"swap_used_bytes":               ps * float64(uvmexp.swpgonly),
		"swapped_in_pages_bytes_total":  ps * float64(uvmexp.pgswapin),
		"swapped_out_pages_bytes_total": ps * float64(uvmexp.pgswapout),
		"wired_bytes":                   ps * float64(uvmexp.wired),
	}, nil
}
<commit_msg>Use swpginuse instead of swpgonly in meminfo_openbsd (#813)<commit_after>// Copyright 2015 The Prometheus 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.

// +build openbsd
// +build !nomeminfo

package collector

import (
	"fmt"
)

/*
#include <sys/param.h>
#include <sys/types.h>
#include <sys/sysctl.h>

int
sysctl_uvmexp(struct uvmexp *uvmexp)
{
        static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP};
        size_t sz = sizeof(struct uvmexp);

        if(sysctl(uvmexp_mib, 2, uvmexp, &sz, NULL, 0) < 0)
                return -1;

        return 0;
}

*/
import "C"

func (c *meminfoCollector) getMemInfo() (map[string]float64, error) {
	var uvmexp C.struct_uvmexp

	if _, err := C.sysctl_uvmexp(&uvmexp); err != nil {
		return nil, fmt.Errorf("sysctl CTL_VM VM_UVMEXP failed: %v", err)
	}

	ps := float64(uvmexp.pagesize)

	// see uvm(9)
	return map[string]float64{
		"active_bytes":                  ps * float64(uvmexp.active),
		"cache_bytes":                   ps * float64(uvmexp.vnodepages),
		"free_bytes":                    ps * float64(uvmexp.free),
		"inactive_bytes":                ps * float64(uvmexp.inactive),
		"size_bytes":                    ps * float64(uvmexp.npages),
		"swap_size_bytes":               ps * float64(uvmexp.swpages),
		"swap_used_bytes":               ps * float64(uvmexp.swpginuse),
		"swapped_in_pages_bytes_total":  ps * float64(uvmexp.pgswapin),
		"swapped_out_pages_bytes_total": ps * float64(uvmexp.pgswapout),
		"wired_bytes":                   ps * float64(uvmexp.wired),
	}, nil
}
<|endoftext|>


<commit_before>// This is free and unencumbered software released into the public
// domain.  For more information, see <http://unlicense.org> or the
// accompanying UNLICENSE file.

package commands

import "github.com/nelsam/vidar/commander/bind"

type ShowSuggestions struct {
}

func NewShowSuggestions() *ShowSuggestions {
	return &ShowSuggestions{}
}

func (s *ShowSuggestions) Name() string {
	return "show-suggestions"
}

func (s *ShowSuggestions) Menu() string {
	return "Edit"
}

func (s *ShowSuggestions) Exec(target interface{}) bind.Status {
	finder, ok := target.(EditorFinder)
	if !ok {
		return bind.Waiting
	}
	editor := finder.CurrentEditor()
	if editor == nil {
		return bind.Done
	}
	editor.ShowSuggestionList()
	return bind.Done
}
<commit_msg>Remove old suggestions showing plugin<commit_after><|endoftext|>


<commit_before>package compute

import (
	"fmt"
	"log"
	"time"
)

// WaitForDeploy waits for a resource's pending deployment operation to complete.
func (client *Client) WaitForDeploy(resourceType ResourceType, id string, timeout time.Duration) (resource Resource, err error) {
	return client.waitForPendingOperation(resourceType, id, "Deploy", ResourceStatusPendingAdd, timeout)
}

// WaitForEdit waits for a resource's pending edit operation to complete.
func (client *Client) WaitForEdit(resourceType ResourceType, id string, timeout time.Duration) (resource Resource, err error) {
	return client.WaitForChange(resourceType, id, "Edit", timeout)
}

// WaitForChange waits for a resource's pending change operation to complete.
func (client *Client) WaitForChange(resourceType ResourceType, id string, actionDescription string, timeout time.Duration) (resource Resource, err error) {
	return client.waitForPendingOperation(resourceType, id, actionDescription, ResourceStatusPendingChange, timeout)
}

// WaitForDelete waits for a resource's pending deletion to complete.
func (client *Client) WaitForDelete(resourceType ResourceType, id string, timeout time.Duration) error {
	_, err := client.waitForPendingOperation(resourceType, id, "Delete", ResourceStatusPendingDelete, timeout)

	return err
}

// waitForPendingOperation waits for a resource's pending operation to complete (i.e. for its status to become ResourceStatusNormal or the resource to disappear if expectedStatus is ResourceStatusPendingDelete).
func (client *Client) waitForPendingOperation(resourceType ResourceType, id string, actionDescription string, expectedStatus string, timeout time.Duration) (resource Resource, err error) {
	return client.waitForResourceStatus(resourceType, id, actionDescription, expectedStatus, ResourceStatusNormal, timeout)
}

// waitForResourceStatus polls a resource for its status (which is expected to initially be expectedStatus) until it becomes expectedStatus.
// getResource is a function that, given the resource Id, will retrieve the resource.
// timeout is the length of time before the wait times out.
func (client *Client) waitForResourceStatus(resourceType ResourceType, id string, actionDescription string, expectedStatus string, targetStatus string, timeout time.Duration) (resource Resource, err error) {
	waitTimeout := time.NewTimer(timeout)
	defer waitTimeout.Stop()

	pollTicker := time.NewTicker(5 * time.Second)
	defer pollTicker.Stop()

	resourceDescription, err := GetResourceDescription(resourceType)
	if err != nil {
		return nil, err
	}

	for {
		select {
		case <-waitTimeout.C:
			return nil, fmt.Errorf("Timed out after waiting %d seconds for %s of %s '%s' to complete", timeout/time.Second, actionDescription, resourceDescription, id)

		case <-pollTicker.C:
			log.Printf("Polling status for %s '%s'...", resourceDescription, id)
			resource, err := client.GetResource(id, resourceType)
			if err != nil {
				return nil, err
			}
			if err != nil {
				return nil, err
			}

			if resource.IsDeleted() {
				if expectedStatus == ResourceStatusPendingDelete {
					log.Printf("%s '%s' has been successfully deleted.", resourceDescription, id)

					return nil, nil
				}

				return nil, fmt.Errorf("No %s was found with Id '%s'", resourceDescription, id)
			}

			switch resource.GetState() {
			case ResourceStatusNormal:
				log.Printf("%s of %s '%s' has successfully completed.", actionDescription, resourceDescription, id)

				return resource, nil

			case ResourceStatusPendingAdd:
				log.Printf("%s of %s '%s' is still in progress...", actionDescription, resourceDescription, id)

				continue
			case ResourceStatusPendingChange:
				log.Printf("%s of %s '%s' is still in progress...", actionDescription, resourceDescription, id)

				continue
			case ResourceStatusPendingDelete:
				log.Printf("%s of %s '%s' is still in progress...", actionDescription, resourceDescription, id)

				continue
			default:
				log.Printf("Unexpected status for %s '%s' ('%s').", resourceDescription, id, resource.GetState())

				return nil, fmt.Errorf("%s failed for %s '%s' ('%s'): encountered unexpected state '%s'", actionDescription, resourceDescription, id, resource.GetName(), resource.GetState())
			}
		}
	}
}
<commit_msg>Add support for waiting on resource with 'PENDING_ADD' status.<commit_after>package compute

import (
	"fmt"
	"log"
	"time"
)

// WaitForDeploy waits for a resource's pending deployment operation to complete.
func (client *Client) WaitForDeploy(resourceType ResourceType, id string, timeout time.Duration) (resource Resource, err error) {
	return client.waitForPendingOperation(resourceType, id, "Deploy", ResourceStatusPendingAdd, timeout)
}

// WaitForEdit waits for a resource's pending edit operation to complete.
func (client *Client) WaitForEdit(resourceType ResourceType, id string, timeout time.Duration) (resource Resource, err error) {
	return client.WaitForChange(resourceType, id, "Edit", timeout)
}

// WaitForAdd waits for a resource's pending add operation to complete.
func (client *Client) WaitForAdd(resourceType ResourceType, id string, actionDescription string, timeout time.Duration) (resource Resource, err error) {
	return client.waitForPendingOperation(resourceType, id, actionDescription, ResourceStatusPendingAdd, timeout)
}

// WaitForChange waits for a resource's pending change operation to complete.
func (client *Client) WaitForChange(resourceType ResourceType, id string, actionDescription string, timeout time.Duration) (resource Resource, err error) {
	return client.waitForPendingOperation(resourceType, id, actionDescription, ResourceStatusPendingChange, timeout)
}

// WaitForDelete waits for a resource's pending deletion to complete.
func (client *Client) WaitForDelete(resourceType ResourceType, id string, timeout time.Duration) error {
	_, err := client.waitForPendingOperation(resourceType, id, "Delete", ResourceStatusPendingDelete, timeout)

	return err
}

// waitForPendingOperation waits for a resource's pending operation to complete (i.e. for its status to become ResourceStatusNormal or the resource to disappear if expectedStatus is ResourceStatusPendingDelete).
func (client *Client) waitForPendingOperation(resourceType ResourceType, id string, actionDescription string, expectedStatus string, timeout time.Duration) (resource Resource, err error) {
	return client.waitForResourceStatus(resourceType, id, actionDescription, expectedStatus, ResourceStatusNormal, timeout)
}

// waitForResourceStatus polls a resource for its status (which is expected to initially be expectedStatus) until it becomes expectedStatus.
// getResource is a function that, given the resource Id, will retrieve the resource.
// timeout is the length of time before the wait times out.
func (client *Client) waitForResourceStatus(resourceType ResourceType, id string, actionDescription string, expectedStatus string, targetStatus string, timeout time.Duration) (resource Resource, err error) {
	waitTimeout := time.NewTimer(timeout)
	defer waitTimeout.Stop()

	pollTicker := time.NewTicker(5 * time.Second)
	defer pollTicker.Stop()

	resourceDescription, err := GetResourceDescription(resourceType)
	if err != nil {
		return nil, err
	}

	for {
		select {
		case <-waitTimeout.C:
			return nil, fmt.Errorf("Timed out after waiting %d seconds for %s of %s '%s' to complete", timeout/time.Second, actionDescription, resourceDescription, id)

		case <-pollTicker.C:
			log.Printf("Polling status for %s '%s'...", resourceDescription, id)
			resource, err := client.GetResource(id, resourceType)
			if err != nil {
				return nil, err
			}
			if err != nil {
				return nil, err
			}

			if resource.IsDeleted() {
				if expectedStatus == ResourceStatusPendingDelete {
					log.Printf("%s '%s' has been successfully deleted.", resourceDescription, id)

					return nil, nil
				}

				return nil, fmt.Errorf("No %s was found with Id '%s'", resourceDescription, id)
			}

			switch resource.GetState() {
			case ResourceStatusNormal:
				log.Printf("%s of %s '%s' has successfully completed.", actionDescription, resourceDescription, id)

				return resource, nil

			case ResourceStatusPendingAdd:
				log.Printf("%s of %s '%s' is still in progress...", actionDescription, resourceDescription, id)

				continue
			case ResourceStatusPendingChange:
				log.Printf("%s of %s '%s' is still in progress...", actionDescription, resourceDescription, id)

				continue
			case ResourceStatusPendingDelete:
				log.Printf("%s of %s '%s' is still in progress...", actionDescription, resourceDescription, id)

				continue
			default:
				log.Printf("Unexpected status for %s '%s' ('%s').", resourceDescription, id, resource.GetState())

				return nil, fmt.Errorf("%s failed for %s '%s' ('%s'): encountered unexpected state '%s'", actionDescription, resourceDescription, id, resource.GetName(), resource.GetState())
			}
		}
	}
}
<|endoftext|>


<commit_before>package decor

import (
	"fmt"
)

const (
	_ = iota
	UnitKiB
	UnitKB
)

// CountersNoUnit is a wrapper around Counters with no unit param.
func CountersNoUnit(pairFmt string, wcc ...WC) Decorator {
	return Counters(0, pairFmt, wcc...)
}

// CountersKibiByte is a wrapper around Counters with predefined unit
// UnitKiB (bytes/1024).
func CountersKibiByte(pairFmt string, wcc ...WC) Decorator {
	return Counters(UnitKiB, pairFmt, wcc...)
}

// CountersKiloByte is a wrapper around Counters with predefined unit
// UnitKB (bytes/1000).
func CountersKiloByte(pairFmt string, wcc ...WC) Decorator {
	return Counters(UnitKB, pairFmt, wcc...)
}

// Counters decorator with dynamic unit measure adjustment.
//
//	`unit` one of [0|UnitKiB|UnitKB] zero for no unit
//
//	`pairFmt` printf compatible verbs for current and total, like "%f" or "%d"
//
//	`wcc` optional WC config
//
// pairFmt example if unit=UnitKB:
//
//	pairFmt="%.1f / %.1f"   output: "1.0MB / 12.0MB"
//	pairFmt="% .1f / % .1f" output: "1.0 MB / 12.0 MB"
//	pairFmt="%d / %d"       output: "1MB / 12MB"
//	pairFmt="% d / % d"     output: "1 MB / 12 MB"
//
func Counters(unit int, pairFmt string, wcc ...WC) Decorator {
	var wc WC
	for _, widthConf := range wcc {
		wc = widthConf
	}
	d := &countersDecorator{
		WC:       wc.Init(),
		producer: chooseSizeProducer(unit, pairFmt),
	}
	return d
}

type countersDecorator struct {
	WC
	producer func(*Statistics) string
}

func (d *countersDecorator) Decor(st *Statistics) string {
	return d.producer(st)
}

func chooseSizeProducer(unit int, format string) func(*Statistics) string {
	if format == "" {
		format = "%d / %d"
	}
	switch unit {
	case UnitKiB:
		return func(st *Statistics) string {
			return fmt.Sprintf(format, SizeB1024(st.Current), SizeB1024(st.Total))
		}
	case UnitKB:
		return func(st *Statistics) string {
			return fmt.Sprintf(format, SizeB1000(st.Current), SizeB1000(st.Total))
		}
	default:
		return func(st *Statistics) string {
			return fmt.Sprintf(format, st.Current, st.Total)
		}
	}
}
<commit_msg>fix: FormatMsg<commit_after>package decor

import (
	"fmt"
)

const (
	_ = iota
	UnitKiB
	UnitKB
)

// CountersNoUnit is a wrapper around Counters with no unit param.
func CountersNoUnit(pairFmt string, wcc ...WC) Decorator {
	return Counters(0, pairFmt, wcc...)
}

// CountersKibiByte is a wrapper around Counters with predefined unit
// UnitKiB (bytes/1024).
func CountersKibiByte(pairFmt string, wcc ...WC) Decorator {
	return Counters(UnitKiB, pairFmt, wcc...)
}

// CountersKiloByte is a wrapper around Counters with predefined unit
// UnitKB (bytes/1000).
func CountersKiloByte(pairFmt string, wcc ...WC) Decorator {
	return Counters(UnitKB, pairFmt, wcc...)
}

// Counters decorator with dynamic unit measure adjustment.
//
//	`unit` one of [0|UnitKiB|UnitKB] zero for no unit
//
//	`pairFmt` printf compatible verbs for current and total, like "%f" or "%d"
//
//	`wcc` optional WC config
//
// pairFmt example if unit=UnitKB:
//
//	pairFmt="%.1f / %.1f"   output: "1.0MB / 12.0MB"
//	pairFmt="% .1f / % .1f" output: "1.0 MB / 12.0 MB"
//	pairFmt="%d / %d"       output: "1MB / 12MB"
//	pairFmt="% d / % d"     output: "1 MB / 12 MB"
//
func Counters(unit int, pairFmt string, wcc ...WC) Decorator {
	var wc WC
	for _, widthConf := range wcc {
		wc = widthConf
	}
	d := &countersDecorator{
		WC:       wc.Init(),
		producer: chooseSizeProducer(unit, pairFmt),
	}
	return d
}

type countersDecorator struct {
	WC
	producer func(*Statistics) string
}

func (d *countersDecorator) Decor(st *Statistics) string {
	return d.FormatMsg(d.producer(st))
}

func chooseSizeProducer(unit int, format string) func(*Statistics) string {
	if format == "" {
		format = "%d / %d"
	}
	switch unit {
	case UnitKiB:
		return func(st *Statistics) string {
			return fmt.Sprintf(format, SizeB1024(st.Current), SizeB1024(st.Total))
		}
	case UnitKB:
		return func(st *Statistics) string {
			return fmt.Sprintf(format, SizeB1000(st.Current), SizeB1000(st.Total))
		}
	default:
		return func(st *Statistics) string {
			return fmt.Sprintf(format, st.Current, st.Total)
		}
	}
}
<|endoftext|>


<commit_before>package azurerm

import (
	"fmt"
	"net/http"

	"github.com/Azure/azure-sdk-for-go/arm/network"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceArmLocalNetworkGateway() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmLocalNetworkGatewayCreate,
		Read:   resourceArmLocalNetworkGatewayRead,
		Update: resourceArmLocalNetworkGatewayCreate,
		Delete: resourceArmLocalNetworkGatewayDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"location": locationSchema(),

			"resource_group_name": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"gateway_address": {
				Type:     schema.TypeString,
				Required: true,
			},

			"address_space": {
				Type:     schema.TypeList,
				Required: true,
				Elem: &schema.Schema{
					Type: schema.TypeString,
				},
			},
		},
	}
}

func resourceArmLocalNetworkGatewayCreate(d *schema.ResourceData, meta interface{}) error {
	lnetClient := meta.(*ArmClient).localNetConnClient

	name := d.Get("name").(string)
	location := d.Get("location").(string)
	resGroup := d.Get("resource_group_name").(string)
	ipAddress := d.Get("gateway_address").(string)

	// fetch the 'address_space_prefixes:
	prefixes := []string{}
	for _, pref := range d.Get("address_space").([]interface{}) {
		prefixes = append(prefixes, pref.(string))
	}

	gateway := network.LocalNetworkGateway{
		Name:     &name,
		Location: &location,
		LocalNetworkGatewayPropertiesFormat: &network.LocalNetworkGatewayPropertiesFormat{
			LocalNetworkAddressSpace: &network.AddressSpace{
				AddressPrefixes: &prefixes,
			},
			GatewayIPAddress: &ipAddress,
		},
	}

	_, err := lnetClient.CreateOrUpdate(resGroup, name, gateway, make(chan struct{}))
	if err != nil {
		return fmt.Errorf("Error creating Azure ARM Local Network Gateway '%s': %s", name, err)
	}

	read, err := lnetClient.Get(resGroup, name)
	if err != nil {
		return err
	}
	if read.ID == nil {
		return fmt.Errorf("Cannot read Virtual Network %s (resource group %s) ID", name, resGroup)
	}

	d.SetId(*read.ID)

	return resourceArmLocalNetworkGatewayRead(d, meta)
}

// resourceArmLocalNetworkGatewayRead goes ahead and reads the state of the corresponding ARM local network gateway.
func resourceArmLocalNetworkGatewayRead(d *schema.ResourceData, meta interface{}) error {
	lnetClient := meta.(*ArmClient).localNetConnClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	name := id.Path["localNetworkGateways"]
	resGroup := id.ResourceGroup

	resp, err := lnetClient.Get(resGroup, name)
	if err != nil {
		if resp.StatusCode == http.StatusNotFound {
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error reading the state of Azure ARM local network gateway '%s': %s", name, err)
	}

	d.Set("resource_group_name", resGroup)
	d.Set("name", resp.Name)
	d.Set("location", resp.Location)
	d.Set("gateway_address", resp.LocalNetworkGatewayPropertiesFormat.GatewayIPAddress)

	prefs := []string{}
	if ps := *resp.LocalNetworkGatewayPropertiesFormat.LocalNetworkAddressSpace.AddressPrefixes; ps != nil {
		prefs = ps
	}
	d.Set("address_space", prefs)

	return nil
}

// resourceArmLocalNetworkGatewayDelete deletes the specified ARM local network gateway.
func resourceArmLocalNetworkGatewayDelete(d *schema.ResourceData, meta interface{}) error {
	lnetClient := meta.(*ArmClient).localNetConnClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	name := id.Path["localNetworkGateways"]
	resGroup := id.ResourceGroup

	_, err = lnetClient.Delete(resGroup, name, make(chan struct{}))
	if err != nil {
		return fmt.Errorf("Error issuing Azure ARM delete request of local network gateway '%s': %s", name, err)
	}

	return nil
}
<commit_msg>Fix crash in import azurerm_local_network_gateway<commit_after>package azurerm

import (
	"fmt"
	"net/http"

	"github.com/Azure/azure-sdk-for-go/arm/network"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceArmLocalNetworkGateway() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmLocalNetworkGatewayCreate,
		Read:   resourceArmLocalNetworkGatewayRead,
		Update: resourceArmLocalNetworkGatewayCreate,
		Delete: resourceArmLocalNetworkGatewayDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"location": locationSchema(),

			"resource_group_name": {
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},

			"gateway_address": {
				Type:     schema.TypeString,
				Required: true,
			},

			"address_space": {
				Type:     schema.TypeList,
				Required: true,
				Elem: &schema.Schema{
					Type: schema.TypeString,
				},
			},
		},
	}
}

func resourceArmLocalNetworkGatewayCreate(d *schema.ResourceData, meta interface{}) error {
	lnetClient := meta.(*ArmClient).localNetConnClient

	name := d.Get("name").(string)
	location := d.Get("location").(string)
	resGroup := d.Get("resource_group_name").(string)
	ipAddress := d.Get("gateway_address").(string)

	// fetch the 'address_space_prefixes:
	prefixes := []string{}
	for _, pref := range d.Get("address_space").([]interface{}) {
		prefixes = append(prefixes, pref.(string))
	}

	gateway := network.LocalNetworkGateway{
		Name:     &name,
		Location: &location,
		LocalNetworkGatewayPropertiesFormat: &network.LocalNetworkGatewayPropertiesFormat{
			LocalNetworkAddressSpace: &network.AddressSpace{
				AddressPrefixes: &prefixes,
			},
			GatewayIPAddress: &ipAddress,
		},
	}

	_, err := lnetClient.CreateOrUpdate(resGroup, name, gateway, make(chan struct{}))
	if err != nil {
		return fmt.Errorf("Error creating Azure ARM Local Network Gateway '%s': %s", name, err)
	}

	read, err := lnetClient.Get(resGroup, name)
	if err != nil {
		return err
	}
	if read.ID == nil {
		return fmt.Errorf("Cannot read Virtual Network %s (resource group %s) ID", name, resGroup)
	}

	d.SetId(*read.ID)

	return resourceArmLocalNetworkGatewayRead(d, meta)
}

// resourceArmLocalNetworkGatewayRead goes ahead and reads the state of the corresponding ARM local network gateway.
func resourceArmLocalNetworkGatewayRead(d *schema.ResourceData, meta interface{}) error {
	lnetClient := meta.(*ArmClient).localNetConnClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	name := id.Path["localNetworkGateways"]
	if name == "" {
		return fmt.Errorf("Cannot find parameter 'localNetworkGateways' from '%s'", id.Path)
	}
	resGroup := id.ResourceGroup

	resp, err := lnetClient.Get(resGroup, name)
	if err != nil {
		if resp.StatusCode == http.StatusNotFound {
			d.SetId("")
			return nil
		}
		return fmt.Errorf("Error reading the state of Azure ARM local network gateway '%s': %s", name, err)
	}

	d.Set("resource_group_name", resGroup)
	d.Set("name", resp.Name)
	d.Set("location", resp.Location)
	d.Set("gateway_address", resp.LocalNetworkGatewayPropertiesFormat.GatewayIPAddress)

	prefs := []string{}
	if ps := *resp.LocalNetworkGatewayPropertiesFormat.LocalNetworkAddressSpace.AddressPrefixes; ps != nil {
		prefs = ps
	}
	d.Set("address_space", prefs)

	return nil
}

// resourceArmLocalNetworkGatewayDelete deletes the specified ARM local network gateway.
func resourceArmLocalNetworkGatewayDelete(d *schema.ResourceData, meta interface{}) error {
	lnetClient := meta.(*ArmClient).localNetConnClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	name := id.Path["localNetworkGateways"]
	resGroup := id.ResourceGroup

	_, err = lnetClient.Delete(resGroup, name, make(chan struct{}))
	if err != nil {
		return fmt.Errorf("Error issuing Azure ARM delete request of local network gateway '%s': %s", name, err)
	}

	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"net"
	"strconv"
	"sync"
	"time"
)

func main() {
	flagMaxConn := flag.Int("max_con", 5, "The maximum number of simultanious connection attempts to make.")
	flagHost := flag.String("host", "localhost", "The hostname/IP address to scan.")
	flagPortMin := flag.Uint("min", 1, "The scanning starting port.")
	flagPortMax := flag.Uint("max", 1024, "The scanning end port.")
	flagTimeout := flag.Int("timeout", 5, "Time in seconds to wait for a port probe before giving up.")
	flag.Parse()

	if *flagHost == "" {
		flag.Usage()
		return
	}

	fmt.Printf("Scanning ports %d-%d on %s...\n", *flagPortMin, *flagPortMax, *flagHost)
	ports := feedPorts(*flagPortMin, *flagPortMax)

	var wg sync.WaitGroup
	for i := 0; i < *flagMaxConn; i++ {
		wg.Add(1)
		go checker(*flagHost, ports, &wg, time.Duration(*flagTimeout)*time.Second)
	}

	wg.Wait()

	fmt.Println("Done.")
}

func feedPorts(start, end uint) chan uint {
	portCh := make(chan uint)

	go func() {
		for i := start; i < end; i++ {
			portCh <- i
		}
		close(portCh)
	}()

	return portCh
}

func checker(host string, ports chan uint, wg *sync.WaitGroup, timeout time.Duration) {
	for port := range ports {
		conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, strconv.Itoa(int(port))), timeout)
		if err != nil {
			continue
		}
		conn.Close()

		fmt.Printf("%d\n", port)
	}

	wg.Done()
}
<commit_msg>use flag.Duration instead of int<commit_after>package main

import (
	"flag"
	"fmt"
	"net"
	"strconv"
	"sync"
	"time"
)

func main() {
	flagMaxConn := flag.Int("max_con", 5, "The maximum number of simultanious connection attempts to make.")
	flagHost := flag.String("host", "localhost", "The hostname/IP address to scan.")
	flagPortMin := flag.Uint("min", 1, "The scanning starting port.")
	flagPortMax := flag.Uint("max", 1024, "The scanning end port.")
	flagTimeout := flag.Duration("timeout", 5, "Time in seconds to wait for a port probe before giving up.")
	flag.Parse()

	if *flagHost == "" {
		flag.Usage()
		return
	}

	fmt.Printf("Scanning ports %d-%d on %s...\n", *flagPortMin, *flagPortMax, *flagHost)
	ports := feedPorts(*flagPortMin, *flagPortMax)

	var wg sync.WaitGroup
	for i := 0; i < *flagMaxConn; i++ {
		wg.Add(1)
		go checker(*flagHost, ports, &wg, *flagTimeout*time.Second)
	}

	wg.Wait()

	fmt.Println("Done.")
}

func feedPorts(start, end uint) chan uint {
	portCh := make(chan uint)

	go func() {
		for i := start; i < end; i++ {
			portCh <- i
		}
		close(portCh)
	}()

	return portCh
}

func checker(host string, ports chan uint, wg *sync.WaitGroup, timeout time.Duration) {
	for port := range ports {
		conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, strconv.Itoa(int(port))), timeout)
		if err != nil {
			continue
		}
		conn.Close()

		fmt.Printf("%d\n", port)
	}

	wg.Done()
}
<|endoftext|>


<commit_before>package term

import (
	"io"
	"os"
	"os/signal"

	windowsconsole "github.com/moby/term/windows"
	"golang.org/x/sys/windows"
)

// State holds the console mode for the terminal.
type State struct {
	mode uint32
}

// Winsize is used for window size.
type Winsize struct {
	Height uint16
	Width  uint16
}

// vtInputSupported is true if winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported by the console
var vtInputSupported bool

// StdStreams returns the standard streams (stdin, stdout, stderr).
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
	// Turn on VT handling on all std handles, if possible. This might
	// fail, in which case we will fall back to terminal emulation.
	var (
		emulateStdin, emulateStdout, emulateStderr bool

		mode uint32
	)

	fd := windows.Handle(os.Stdin.Fd())
	if err := windows.GetConsoleMode(fd, &mode); err == nil {
		// Validate that winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil {
			emulateStdin = true
		} else {
			vtInputSupported = true
		}
		// Unconditionally set the console mode back even on failure because SetConsoleMode
		// remembers invalid bits on input handles.
		_ = windows.SetConsoleMode(fd, mode)
	}

	fd = windows.Handle(os.Stdout.Fd())
	if err := windows.GetConsoleMode(fd, &mode); err == nil {
		// Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it.
		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|windows.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
			emulateStdout = true
		} else {
			_ = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
		}
	}

	fd = windows.Handle(os.Stderr.Fd())
	if err := windows.GetConsoleMode(fd, &mode); err == nil {
		// Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it.
		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|windows.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
			emulateStderr = true
		} else {
			_ = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
		}
	}

	// Temporarily use STD_INPUT_HANDLE, STD_OUTPUT_HANDLE and
	// STD_ERROR_HANDLE from syscall rather than x/sys/windows as long as
	// go-ansiterm hasn't switch to x/sys/windows.
	// TODO: switch back to x/sys/windows once go-ansiterm has switched
	if emulateStdin {
		stdIn = windowsconsole.NewAnsiReader(windows.STD_INPUT_HANDLE)
	} else {
		stdIn = os.Stdin
	}

	if emulateStdout {
		stdOut = windowsconsole.NewAnsiWriter(windows.STD_OUTPUT_HANDLE)
	} else {
		stdOut = os.Stdout
	}

	if emulateStderr {
		stdErr = windowsconsole.NewAnsiWriter(windows.STD_ERROR_HANDLE)
	} else {
		stdErr = os.Stderr
	}

	return
}

// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
func GetFdInfo(in interface{}) (uintptr, bool) {
	return windowsconsole.GetHandleInfo(in)
}

// GetWinsize returns the window size based on the specified file descriptor.
func GetWinsize(fd uintptr) (*Winsize, error) {
	var info windows.ConsoleScreenBufferInfo
	if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
		return nil, err
	}

	winsize := &Winsize{
		Width:  uint16(info.Window.Right - info.Window.Left + 1),
		Height: uint16(info.Window.Bottom - info.Window.Top + 1),
	}

	return winsize, nil
}

// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
	var mode uint32
	err := windows.GetConsoleMode(windows.Handle(fd), &mode)
	return err == nil
}

// RestoreTerminal restores the terminal connected to the given file descriptor
// to a previous state.
func RestoreTerminal(fd uintptr, state *State) error {
	return windows.SetConsoleMode(windows.Handle(fd), state.mode)
}

// SaveState saves the state of the terminal connected to the given file descriptor.
func SaveState(fd uintptr) (*State, error) {
	var mode uint32

	if err := windows.GetConsoleMode(windows.Handle(fd), &mode); err != nil {
		return nil, err
	}

	return &State{mode: mode}, nil
}

// DisableEcho disables echo for the terminal connected to the given file descriptor.
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
func DisableEcho(fd uintptr, state *State) error {
	mode := state.mode
	mode &^= windows.ENABLE_ECHO_INPUT
	mode |= windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT
	err := windows.SetConsoleMode(windows.Handle(fd), mode)
	if err != nil {
		return err
	}

	// Register an interrupt handler to catch and restore prior state
	restoreAtInterrupt(fd, state)
	return nil
}

// SetRawTerminal puts the terminal connected to the given file descriptor into
// raw mode and returns the previous state. On UNIX, this puts both the input
// and output into raw mode. On Windows, it only puts the input into raw mode.
func SetRawTerminal(fd uintptr) (*State, error) {
	state, err := MakeRaw(fd)
	if err != nil {
		return nil, err
	}

	// Register an interrupt handler to catch and restore prior state
	restoreAtInterrupt(fd, state)
	return state, err
}

// SetRawTerminalOutput puts the output of terminal connected to the given file
// descriptor into raw mode. On UNIX, this does nothing and returns nil for the
// state. On Windows, it disables LF -> CRLF translation.
func SetRawTerminalOutput(fd uintptr) (*State, error) {
	state, err := SaveState(fd)
	if err != nil {
		return nil, err
	}

	// Ignore failures, since winterm.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this
	// version of Windows.
	_ = windows.SetConsoleMode(windows.Handle(fd), state.mode|windows.DISABLE_NEWLINE_AUTO_RETURN)
	return state, err
}

// MakeRaw puts the terminal (Windows Console) connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be restored.
func MakeRaw(fd uintptr) (*State, error) {
	state, err := SaveState(fd)
	if err != nil {
		return nil, err
	}

	mode := state.mode

	// See
	// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
	// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx

	// Disable these modes
	mode &^= windows.ENABLE_ECHO_INPUT
	mode &^= windows.ENABLE_LINE_INPUT
	mode &^= windows.ENABLE_MOUSE_INPUT
	mode &^= windows.ENABLE_WINDOW_INPUT
	mode &^= windows.ENABLE_PROCESSED_INPUT

	// Enable these modes
	mode |= windows.ENABLE_EXTENDED_FLAGS
	mode |= windows.ENABLE_INSERT_MODE
	mode |= windows.ENABLE_QUICK_EDIT_MODE
	if vtInputSupported {
		mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
	}

	err = windows.SetConsoleMode(windows.Handle(fd), mode)
	if err != nil {
		return nil, err
	}
	return state, nil
}

func restoreAtInterrupt(fd uintptr, state *State) {
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt)

	go func() {
		_ = <-sigchan
		_ = RestoreTerminal(fd, state)
		os.Exit(0)
	}()
}
<commit_msg>Fix windows integer overflow<commit_after>package term

import (
	"io"
	"os"
	"os/signal"

	windowsconsole "github.com/moby/term/windows"
	"golang.org/x/sys/windows"
)

// State holds the console mode for the terminal.
type State struct {
	mode uint32
}

// Winsize is used for window size.
type Winsize struct {
	Height uint16
	Width  uint16
}

// vtInputSupported is true if winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported by the console
var vtInputSupported bool

// StdStreams returns the standard streams (stdin, stdout, stderr).
func StdStreams() (stdIn io.ReadCloser, stdOut, stdErr io.Writer) {
	// Turn on VT handling on all std handles, if possible. This might
	// fail, in which case we will fall back to terminal emulation.
	var (
		emulateStdin, emulateStdout, emulateStderr bool

		mode uint32
	)

	fd := windows.Handle(os.Stdin.Fd())
	if err := windows.GetConsoleMode(fd, &mode); err == nil {
		// Validate that winterm.ENABLE_VIRTUAL_TERMINAL_INPUT is supported, but do not set it.
		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_INPUT); err != nil {
			emulateStdin = true
		} else {
			vtInputSupported = true
		}
		// Unconditionally set the console mode back even on failure because SetConsoleMode
		// remembers invalid bits on input handles.
		_ = windows.SetConsoleMode(fd, mode)
	}

	fd = windows.Handle(os.Stdout.Fd())
	if err := windows.GetConsoleMode(fd, &mode); err == nil {
		// Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it.
		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|windows.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
			emulateStdout = true
		} else {
			_ = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
		}
	}

	fd = windows.Handle(os.Stderr.Fd())
	if err := windows.GetConsoleMode(fd, &mode); err == nil {
		// Validate winterm.DISABLE_NEWLINE_AUTO_RETURN is supported, but do not set it.
		if err = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING|windows.DISABLE_NEWLINE_AUTO_RETURN); err != nil {
			emulateStderr = true
		} else {
			_ = windows.SetConsoleMode(fd, mode|windows.ENABLE_VIRTUAL_TERMINAL_PROCESSING)
		}
	}

	// Temporarily use STD_INPUT_HANDLE, STD_OUTPUT_HANDLE and
	// STD_ERROR_HANDLE from syscall rather than x/sys/windows as long as
	// go-ansiterm hasn't switch to x/sys/windows.
	// TODO: switch back to x/sys/windows once go-ansiterm has switched
	if emulateStdin {
		h := uint32(windows.STD_INPUT_HANDLE)
		stdIn = windowsconsole.NewAnsiReader(int(h))
	} else {
		stdIn = os.Stdin
	}

	if emulateStdout {
		h := uint32(windows.STD_OUTPUT_HANDLE)
		stdOut = windowsconsole.NewAnsiWriter(int(h))
	} else {
		stdOut = os.Stdout
	}

	if emulateStderr {
		h := uint32(windows.STD_ERROR_HANDLE)
		stdErr = windowsconsole.NewAnsiWriter(int(h))
	} else {
		stdErr = os.Stderr
	}

	return
}

// GetFdInfo returns the file descriptor for an os.File and indicates whether the file represents a terminal.
func GetFdInfo(in interface{}) (uintptr, bool) {
	return windowsconsole.GetHandleInfo(in)
}

// GetWinsize returns the window size based on the specified file descriptor.
func GetWinsize(fd uintptr) (*Winsize, error) {
	var info windows.ConsoleScreenBufferInfo
	if err := windows.GetConsoleScreenBufferInfo(windows.Handle(fd), &info); err != nil {
		return nil, err
	}

	winsize := &Winsize{
		Width:  uint16(info.Window.Right - info.Window.Left + 1),
		Height: uint16(info.Window.Bottom - info.Window.Top + 1),
	}

	return winsize, nil
}

// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
	var mode uint32
	err := windows.GetConsoleMode(windows.Handle(fd), &mode)
	return err == nil
}

// RestoreTerminal restores the terminal connected to the given file descriptor
// to a previous state.
func RestoreTerminal(fd uintptr, state *State) error {
	return windows.SetConsoleMode(windows.Handle(fd), state.mode)
}

// SaveState saves the state of the terminal connected to the given file descriptor.
func SaveState(fd uintptr) (*State, error) {
	var mode uint32

	if err := windows.GetConsoleMode(windows.Handle(fd), &mode); err != nil {
		return nil, err
	}

	return &State{mode: mode}, nil
}

// DisableEcho disables echo for the terminal connected to the given file descriptor.
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx
func DisableEcho(fd uintptr, state *State) error {
	mode := state.mode
	mode &^= windows.ENABLE_ECHO_INPUT
	mode |= windows.ENABLE_PROCESSED_INPUT | windows.ENABLE_LINE_INPUT
	err := windows.SetConsoleMode(windows.Handle(fd), mode)
	if err != nil {
		return err
	}

	// Register an interrupt handler to catch and restore prior state
	restoreAtInterrupt(fd, state)
	return nil
}

// SetRawTerminal puts the terminal connected to the given file descriptor into
// raw mode and returns the previous state. On UNIX, this puts both the input
// and output into raw mode. On Windows, it only puts the input into raw mode.
func SetRawTerminal(fd uintptr) (*State, error) {
	state, err := MakeRaw(fd)
	if err != nil {
		return nil, err
	}

	// Register an interrupt handler to catch and restore prior state
	restoreAtInterrupt(fd, state)
	return state, err
}

// SetRawTerminalOutput puts the output of terminal connected to the given file
// descriptor into raw mode. On UNIX, this does nothing and returns nil for the
// state. On Windows, it disables LF -> CRLF translation.
func SetRawTerminalOutput(fd uintptr) (*State, error) {
	state, err := SaveState(fd)
	if err != nil {
		return nil, err
	}

	// Ignore failures, since winterm.DISABLE_NEWLINE_AUTO_RETURN might not be supported on this
	// version of Windows.
	_ = windows.SetConsoleMode(windows.Handle(fd), state.mode|windows.DISABLE_NEWLINE_AUTO_RETURN)
	return state, err
}

// MakeRaw puts the terminal (Windows Console) connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be restored.
func MakeRaw(fd uintptr) (*State, error) {
	state, err := SaveState(fd)
	if err != nil {
		return nil, err
	}

	mode := state.mode

	// See
	// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
	// -- https://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx

	// Disable these modes
	mode &^= windows.ENABLE_ECHO_INPUT
	mode &^= windows.ENABLE_LINE_INPUT
	mode &^= windows.ENABLE_MOUSE_INPUT
	mode &^= windows.ENABLE_WINDOW_INPUT
	mode &^= windows.ENABLE_PROCESSED_INPUT

	// Enable these modes
	mode |= windows.ENABLE_EXTENDED_FLAGS
	mode |= windows.ENABLE_INSERT_MODE
	mode |= windows.ENABLE_QUICK_EDIT_MODE
	if vtInputSupported {
		mode |= windows.ENABLE_VIRTUAL_TERMINAL_INPUT
	}

	err = windows.SetConsoleMode(windows.Handle(fd), mode)
	if err != nil {
		return nil, err
	}
	return state, nil
}

func restoreAtInterrupt(fd uintptr, state *State) {
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, os.Interrupt)

	go func() {
		_ = <-sigchan
		_ = RestoreTerminal(fd, state)
		os.Exit(0)
	}()
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"io"
	"fmt"
	"database/sql"
	_ "github.com/ziutek/mymysql/godrv"
	"io/ioutil"
	"os"
	"strings"
)

const (
	nil_timestamp = "0000-00-00 00:00:00"
	mysql_datetime_format = "2006-01-02 15:04:05"
)

var (
	db *sql.DB
	db_connected = false
)

// escapeString and escapeQuotes copied from github.com/ziutek/mymysql/native/codecs.go
func escapeString(txt string) string {
	var (
		esc string
		buf bytes.Buffer
	)
	last := 0
	for ii, bb := range txt {
		switch bb {
		case 0:
			esc = `\0`
		case '\n':
			esc = `\n`
		case '\r':
			esc = `\r`
		case '\\':
			esc = `\\`
		case '\'':
			esc = `\'`
		case '"':
			esc = `\"`
		case '\032':
			esc = `\Z`
		default:
			continue
		}
		io.WriteString(&buf, txt[last:ii])
		io.WriteString(&buf, esc)
		last = ii + 1
	}
	io.WriteString(&buf, txt[last:])
	return buf.String()
}

func escapeQuotes(txt string) string {
	var buf bytes.Buffer
	last := 0
	for ii, bb := range txt {
		if bb == '\'' {
			io.WriteString(&buf, txt[last:ii])
			io.WriteString(&buf, `''`)
			last = ii + 1
		}
	}
	io.WriteString(&buf, txt[last:])
	return buf.String()
}

func connectToSQLServer() {
	// does the original initialsetupdb.sql (as opposed to .bak.sql) exist?
	var err error
	_, err1 := os.Stat("initialsetupdb.sql")
	_, err2 := os.Stat("initialsetupdb.bak.sql")
	if err2 == nil {
		// the .bak.sql file exists
		os.Remove("initialsetupdb.sql")
		fmt.Println("complete.")
		needs_initial_setup = false
		return
	} else {
		if err1 != nil {
			// neither one exists
			fmt.Println("failed...initial setup file doesn't exist, please reinstall gochan.")
			error_log.Fatal("Initial setup file doesn't exist, exiting.")
			return
		}
	}
	err1 = nil
	err2 = nil

	db, err = sql.Open("mymysql", config.DBhost + "*" + config.DBname + "/"+config.DBusername+"/"+config.DBpassword)
	if err != nil {
		fmt.Println("Failed to connect to the database, see log for details.")
		error_log.Fatal(err.Error())
	}
	// read the initial setup sql file into a string
	initial_sql_bytes,err := ioutil.ReadFile("initialsetupdb.sql")
	if err != nil {
		fmt.Println("failed.")
		error_log.Fatal(err.Error())
	}
	initial_sql_str := string(initial_sql_bytes)
	initial_sql_bytes = nil
	fmt.Printf("Starting initial setup...")
	initial_sql_str = strings.Replace(initial_sql_str,"DBNAME",config.DBname, -1)
	initial_sql_str = strings.Replace(initial_sql_str,"DBPREFIX",config.DBprefix, -1)
	initial_sql_str += "\nINSERT INTO `"+config.DBname+"`.`"+config.DBprefix+"staff` (`username`, `password_checksum`, `salt`, `rank`) VALUES ('admin', '"+bcrypt_sum("password")+"', 'abc', 3);"
	initial_sql_arr := strings.Split(initial_sql_str, ";")
	initial_sql_str = ""

	for _,statement := range initial_sql_arr {
		if statement != "" {
			_,err := db.Exec(statement+";")
			if err != nil {
				fmt.Println("failed.")
				error_log.Fatal(err.Error())
				return
			}
		}
	}
	initial_sql_arr = nil
	// rename initialsetupdb.sql to initialsetup.bak.sql
	err = ioutil.WriteFile("initialsetupdb.bak.sql", initial_sql_bytes, 0777)
	if err != nil {
		fmt.Println("failed")
		error_log.Fatal(err.Error())
		return
	}

	err = os.Remove("initialsetupdb.bak.sql")
	if err != nil {
		fmt.Println("failed.")
		error_log.Fatal(err.Error())
		return
	}
	fmt.Println("complete.")

	needs_initial_setup = false
	db_connected = true
}<commit_msg>connect to db if the initial setup file has already been used (fixes nil db error)<commit_after>package main

import (
	"bytes"
	"io"
	"fmt"
	"database/sql"
	_ "github.com/ziutek/mymysql/godrv"
	"io/ioutil"
	"os"
	"strings"
)

const (
	nil_timestamp = "0000-00-00 00:00:00"
	mysql_datetime_format = "2006-01-02 15:04:05"
)

var (
	db *sql.DB
	db_connected = false
)

// escapeString and escapeQuotes copied from github.com/ziutek/mymysql/native/codecs.go
func escapeString(txt string) string {
	var (
		esc string
		buf bytes.Buffer
	)
	last := 0
	for ii, bb := range txt {
		switch bb {
		case 0:
			esc = `\0`
		case '\n':
			esc = `\n`
		case '\r':
			esc = `\r`
		case '\\':
			esc = `\\`
		case '\'':
			esc = `\'`
		case '"':
			esc = `\"`
		case '\032':
			esc = `\Z`
		default:
			continue
		}
		io.WriteString(&buf, txt[last:ii])
		io.WriteString(&buf, esc)
		last = ii + 1
	}
	io.WriteString(&buf, txt[last:])
	return buf.String()
}

func escapeQuotes(txt string) string {
	var buf bytes.Buffer
	last := 0
	for ii, bb := range txt {
		if bb == '\'' {
			io.WriteString(&buf, txt[last:ii])
			io.WriteString(&buf, `''`)
			last = ii + 1
		}
	}
	io.WriteString(&buf, txt[last:])
	return buf.String()
}

func connectToSQLServer() {
	// does the original initialsetupdb.sql (as opposed to .bak.sql) exist?
	var err error
	_, err1 := os.Stat("initialsetupdb.sql")
	_, err2 := os.Stat("initialsetupdb.bak.sql")
	if err2 == nil {
		// the .bak.sql file exists
		os.Remove("initialsetupdb.sql")
		fmt.Println("complete.")
		needs_initial_setup = false
		db, err = sql.Open("mymysql", config.DBhost + "*" + config.DBname + "/"+config.DBusername+"/"+config.DBpassword)
		if err != nil {
			fmt.Println("Failed to connect to the database, see log for details.")
			error_log.Fatal(err.Error())
		}
		return
	} else {
		if err1 != nil {
			// neither one exists
			fmt.Println("failed...initial setup file doesn't exist, please reinstall gochan.")
			error_log.Fatal("Initial setup file doesn't exist, exiting.")
			return
		}
	}
	err1 = nil
	err2 = nil

	db, err = sql.Open("mymysql", config.DBhost + "*" + config.DBname + "/"+config.DBusername+"/"+config.DBpassword)
	fmt.Println("jweiofjeaioewhfeiwoaaehfaouifheuiofeagfhuoagfuogfuo")
	fmt.Println(db)
	if err != nil {
		fmt.Println("Failed to connect to the database, see log for details.")
		error_log.Fatal(err.Error())
	}
	// read the initial setup sql file into a string
	initial_sql_bytes,err := ioutil.ReadFile("initialsetupdb.sql")
	if err != nil {
		fmt.Println("failed.")
		error_log.Fatal(err.Error())
	}
	initial_sql_str := string(initial_sql_bytes)
	initial_sql_bytes = nil
	fmt.Printf("Starting initial setup...")
	initial_sql_str = strings.Replace(initial_sql_str,"DBNAME",config.DBname, -1)
	initial_sql_str = strings.Replace(initial_sql_str,"DBPREFIX",config.DBprefix, -1)
	initial_sql_str += "\nINSERT INTO `"+config.DBname+"`.`"+config.DBprefix+"staff` (`username`, `password_checksum`, `salt`, `rank`) VALUES ('admin', '"+bcrypt_sum("password")+"', 'abc', 3);"
	initial_sql_arr := strings.Split(initial_sql_str, ";")
	initial_sql_str = ""

	for _,statement := range initial_sql_arr {
		if statement != "" {
			_,err := db.Exec(statement+";")
			if err != nil {
				fmt.Println("failed.")
				error_log.Fatal(err.Error())
				return
			}
		}
	}
	initial_sql_arr = nil
	// rename initialsetupdb.sql to initialsetup.bak.sql
	err = ioutil.WriteFile("initialsetupdb.bak.sql", initial_sql_bytes, 0777)
	if err != nil {
		fmt.Println("failed")
		error_log.Fatal(err.Error())
		return
	}

	err = os.Remove("initialsetupdb.bak.sql")
	if err != nil {
		fmt.Println("failed.")
		error_log.Fatal(err.Error())
		return
	}
	fmt.Println("complete.")

	needs_initial_setup = false
	db_connected = true
}<|endoftext|>


<commit_before>/*
Copyright 2016 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 yamlcfg

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

	cfgutil "github.com/GoogleCloudPlatform/testgrid/config"
	"github.com/GoogleCloudPlatform/testgrid/pb/config"
	"sigs.k8s.io/yaml"
)

// Takes multiple source paths of the following form:
//   If path is a local file, then the file will be parsed as YAML
//   If path is a directory, then all files and directories within it will be parsed.
// Optionally, defaultPath points to default setting YAML
// Returns a configuration proto containing the data from all of those sources
func ReadConfig(paths []string, defaultpath string) (config.Configuration, error) {

	var result config.Configuration

	var defaults DefaultConfiguration
	if defaultpath != "" {
		b, err := ioutil.ReadFile(defaultpath)
		if err != nil {
			return result, fmt.Errorf("failed to read default at %s: %v", defaultpath, err)
		}
		defaults, err = LoadDefaults(b)
		if err != nil {
			return result, fmt.Errorf("failed to deserialize default at %s: %v", defaultpath, err)
		}
	}

	err := SeekYAMLFiles(paths, func(path string, info os.FileInfo) error {
		// Read YAML file and Update config
		b, err := ioutil.ReadFile(path)
		if err != nil {
			return fmt.Errorf("failed to read %s: %v", path, err)
		}
		if err = Update(&result, b, &defaults); err != nil {
			return fmt.Errorf("failed to merge %s into config: %v", path, err)
		}

		return nil
	})

	return result, err
}

// Update reads the config in yamlData and updates the config in c.
// If reconcile is non-nil, it will pad out new entries with those default settings
func Update(cfg *config.Configuration, yamlData []byte, reconcile *DefaultConfiguration) error {

	newConfig := &config.Configuration{}
	if err := yaml.Unmarshal(yamlData, newConfig); err != nil {
		return err
	}

	if cfg == nil {
		cfg = &config.Configuration{}
	}

	for _, testgroup := range newConfig.TestGroups {
		if reconcile != nil {
			ReconcileTestGroup(testgroup, reconcile.DefaultTestGroup)
		}
		cfg.TestGroups = append(cfg.TestGroups, testgroup)
	}

	for _, dashboard := range newConfig.Dashboards {
		if reconcile != nil {
			for _, dashboardtab := range dashboard.DashboardTab {
				ReconcileDashboardTab(dashboardtab, reconcile.DefaultDashboardTab)
			}
		}
		cfg.Dashboards = append(cfg.Dashboards, dashboard)
	}

	for _, dashboardGroup := range newConfig.DashboardGroups {
		cfg.DashboardGroups = append(cfg.DashboardGroups, dashboardGroup)
	}

	return nil
}

// MarshalYAML returns a YAML file representing the parsed configuration.
// Returns an error if config is invalid or encoding failed.
func MarshalYAML(c config.Configuration) ([]byte, error) {
	if err := cfgutil.Validate(c); err != nil {
		return nil, err
	}
	bytes, err := yaml.Marshal(c)
	if err != nil {
		return nil, fmt.Errorf("could not write config to yaml: %v", err)
	}
	return bytes, nil
}

type DefaultConfiguration struct {
	// A default testgroup with default initialization data
	DefaultTestGroup *config.TestGroup `json:"default_test_group,omitempty"`
	// A default dashboard tab with default initialization data
	DefaultDashboardTab *config.DashboardTab `json:"default_dashboard_tab,omitempty"`
}

// MissingFieldError is an error that includes the missing field.
type MissingFieldError struct {
	Field string
}

func (e MissingFieldError) Error() string {
	return fmt.Sprintf("field missing or unset: %s", e.Field)
}

// ReconcileTestGroup sets unfilled currentTestGroup fields to the corresponding defaultTestGroup value, if present
func ReconcileTestGroup(currentTestGroup *config.TestGroup, defaultTestGroup *config.TestGroup) {
	if currentTestGroup.DaysOfResults == 0 {
		currentTestGroup.DaysOfResults = defaultTestGroup.DaysOfResults
	}

	if currentTestGroup.TestsNamePolicy == config.TestGroup_TESTS_NAME_MIN {
		currentTestGroup.TestsNamePolicy = defaultTestGroup.TestsNamePolicy
	}

	if currentTestGroup.IgnorePending == false {
		currentTestGroup.IgnorePending = defaultTestGroup.IgnorePending
	}

	if currentTestGroup.ColumnHeader == nil {
		currentTestGroup.ColumnHeader = defaultTestGroup.ColumnHeader
	}

	if currentTestGroup.NumColumnsRecent == 0 {
		currentTestGroup.NumColumnsRecent = defaultTestGroup.NumColumnsRecent
	}

	if currentTestGroup.AlertStaleResultsHours == 0 {
		currentTestGroup.AlertStaleResultsHours = defaultTestGroup.AlertStaleResultsHours
	}

	if currentTestGroup.NumFailuresToAlert == 0 {
		currentTestGroup.NumFailuresToAlert = defaultTestGroup.NumFailuresToAlert
	}
	if currentTestGroup.CodeSearchPath == "" {
		currentTestGroup.CodeSearchPath = defaultTestGroup.CodeSearchPath
	}
	if currentTestGroup.NumPassesToDisableAlert == 0 {
		currentTestGroup.NumPassesToDisableAlert = defaultTestGroup.NumPassesToDisableAlert
	}
	// is_external and user_kubernetes_client should always be true
	currentTestGroup.IsExternal = true
	currentTestGroup.UseKubernetesClient = true
}

// ReconcileDashboardTab sets unfilled currentTab fields to the corresponding defaultTab value, if present
func ReconcileDashboardTab(currentTab *config.DashboardTab, defaultTab *config.DashboardTab) {
	if currentTab.BugComponent == 0 {
		currentTab.BugComponent = defaultTab.BugComponent
	}

	if currentTab.CodeSearchPath == "" {
		currentTab.CodeSearchPath = defaultTab.CodeSearchPath
	}

	if currentTab.NumColumnsRecent == 0 {
		currentTab.NumColumnsRecent = defaultTab.NumColumnsRecent
	}

	if currentTab.OpenTestTemplate == nil {
		currentTab.OpenTestTemplate = defaultTab.OpenTestTemplate
	}

	if currentTab.FileBugTemplate == nil {
		currentTab.FileBugTemplate = defaultTab.FileBugTemplate
	}

	if currentTab.AttachBugTemplate == nil {
		currentTab.AttachBugTemplate = defaultTab.AttachBugTemplate
	}

	if currentTab.ResultsText == "" {
		currentTab.ResultsText = defaultTab.ResultsText
	}

	if currentTab.ResultsUrlTemplate == nil {
		currentTab.ResultsUrlTemplate = defaultTab.ResultsUrlTemplate
	}

	if currentTab.CodeSearchUrlTemplate == nil {
		currentTab.CodeSearchUrlTemplate = defaultTab.CodeSearchUrlTemplate
	}

	if currentTab.AlertOptions == nil {
		currentTab.AlertOptions = defaultTab.AlertOptions
	}

	if currentTab.OpenBugTemplate == nil {
		currentTab.OpenBugTemplate = defaultTab.OpenBugTemplate
	}
}

// UpdateDefaults reads and validates default settings from YAML
// Returns an error if the defaultConfig is partially or completely missing.
func LoadDefaults(yamlData []byte) (DefaultConfiguration, error) {

	var result DefaultConfiguration
	err := yaml.Unmarshal(yamlData, &result)
	if err != nil {
		return result, err
	}

	if result.DefaultTestGroup == nil {
		return result, MissingFieldError{"DefaultTestGroup"}
	}
	if result.DefaultDashboardTab == nil {
		return result, MissingFieldError{"DefaultDashboardTab"}
	}
	return result, nil
}

// walks through paths and directories, calling the passed function on each YAML file
// future modifications to what Configurator sees as a "config file" can be made here
//TODO(chases2) Rewrite so that it walks recursively, not lexically.
func SeekYAMLFiles(paths []string, callFunc func(path string, info os.FileInfo) error) error {
	for _, path := range paths {
		_, err := os.Stat(path)
		if err != nil {
			return fmt.Errorf("Failed status call on %s: %v", path, err)
		}

		err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {

			// A bad file should not stop us from parsing the directory
			if err != nil {
				return nil
			}

			// Only YAML files will be
			if filepath.Ext(path) != ".yaml" && filepath.Ext(path) != ".yml" {
				return nil
			}

			if info.IsDir() {
				return nil
			}

			return callFunc(path, info)
		})

		if err != nil {
			return fmt.Errorf("Failed to walk through %s: %v", path, err)
		}
	}
	return nil
}
<commit_msg>Actually reconcile ignore_skip in default.yaml.<commit_after>/*
Copyright 2016 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 yamlcfg

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

	cfgutil "github.com/GoogleCloudPlatform/testgrid/config"
	"github.com/GoogleCloudPlatform/testgrid/pb/config"
	"sigs.k8s.io/yaml"
)

// Takes multiple source paths of the following form:
//   If path is a local file, then the file will be parsed as YAML
//   If path is a directory, then all files and directories within it will be parsed.
// Optionally, defaultPath points to default setting YAML
// Returns a configuration proto containing the data from all of those sources
func ReadConfig(paths []string, defaultpath string) (config.Configuration, error) {

	var result config.Configuration

	var defaults DefaultConfiguration
	if defaultpath != "" {
		b, err := ioutil.ReadFile(defaultpath)
		if err != nil {
			return result, fmt.Errorf("failed to read default at %s: %v", defaultpath, err)
		}
		defaults, err = LoadDefaults(b)
		if err != nil {
			return result, fmt.Errorf("failed to deserialize default at %s: %v", defaultpath, err)
		}
	}

	err := SeekYAMLFiles(paths, func(path string, info os.FileInfo) error {
		// Read YAML file and Update config
		b, err := ioutil.ReadFile(path)
		if err != nil {
			return fmt.Errorf("failed to read %s: %v", path, err)
		}
		if err = Update(&result, b, &defaults); err != nil {
			return fmt.Errorf("failed to merge %s into config: %v", path, err)
		}

		return nil
	})

	return result, err
}

// Update reads the config in yamlData and updates the config in c.
// If reconcile is non-nil, it will pad out new entries with those default settings
func Update(cfg *config.Configuration, yamlData []byte, reconcile *DefaultConfiguration) error {

	newConfig := &config.Configuration{}
	if err := yaml.Unmarshal(yamlData, newConfig); err != nil {
		return err
	}

	if cfg == nil {
		cfg = &config.Configuration{}
	}

	for _, testgroup := range newConfig.TestGroups {
		if reconcile != nil {
			ReconcileTestGroup(testgroup, reconcile.DefaultTestGroup)
		}
		cfg.TestGroups = append(cfg.TestGroups, testgroup)
	}

	for _, dashboard := range newConfig.Dashboards {
		if reconcile != nil {
			for _, dashboardtab := range dashboard.DashboardTab {
				ReconcileDashboardTab(dashboardtab, reconcile.DefaultDashboardTab)
			}
		}
		cfg.Dashboards = append(cfg.Dashboards, dashboard)
	}

	for _, dashboardGroup := range newConfig.DashboardGroups {
		cfg.DashboardGroups = append(cfg.DashboardGroups, dashboardGroup)
	}

	return nil
}

// MarshalYAML returns a YAML file representing the parsed configuration.
// Returns an error if config is invalid or encoding failed.
func MarshalYAML(c config.Configuration) ([]byte, error) {
	if err := cfgutil.Validate(c); err != nil {
		return nil, err
	}
	bytes, err := yaml.Marshal(c)
	if err != nil {
		return nil, fmt.Errorf("could not write config to yaml: %v", err)
	}
	return bytes, nil
}

type DefaultConfiguration struct {
	// A default testgroup with default initialization data
	DefaultTestGroup *config.TestGroup `json:"default_test_group,omitempty"`
	// A default dashboard tab with default initialization data
	DefaultDashboardTab *config.DashboardTab `json:"default_dashboard_tab,omitempty"`
}

// MissingFieldError is an error that includes the missing field.
type MissingFieldError struct {
	Field string
}

func (e MissingFieldError) Error() string {
	return fmt.Sprintf("field missing or unset: %s", e.Field)
}

// ReconcileTestGroup sets unfilled currentTestGroup fields to the corresponding defaultTestGroup value, if present
func ReconcileTestGroup(currentTestGroup *config.TestGroup, defaultTestGroup *config.TestGroup) {
	if currentTestGroup.DaysOfResults == 0 {
		currentTestGroup.DaysOfResults = defaultTestGroup.DaysOfResults
	}

	if currentTestGroup.TestsNamePolicy == config.TestGroup_TESTS_NAME_MIN {
		currentTestGroup.TestsNamePolicy = defaultTestGroup.TestsNamePolicy
	}

	if currentTestGroup.IgnorePending == false {
		currentTestGroup.IgnorePending = defaultTestGroup.IgnorePending
	}

	if currentTestGroup.IgnoreSkip == false {
		currentTestGroup.IgnoreSkip = defaultTestGroup.IgnoreSkip
	}

	if currentTestGroup.ColumnHeader == nil {
		currentTestGroup.ColumnHeader = defaultTestGroup.ColumnHeader
	}

	if currentTestGroup.NumColumnsRecent == 0 {
		currentTestGroup.NumColumnsRecent = defaultTestGroup.NumColumnsRecent
	}

	if currentTestGroup.AlertStaleResultsHours == 0 {
		currentTestGroup.AlertStaleResultsHours = defaultTestGroup.AlertStaleResultsHours
	}

	if currentTestGroup.NumFailuresToAlert == 0 {
		currentTestGroup.NumFailuresToAlert = defaultTestGroup.NumFailuresToAlert
	}
	if currentTestGroup.CodeSearchPath == "" {
		currentTestGroup.CodeSearchPath = defaultTestGroup.CodeSearchPath
	}
	if currentTestGroup.NumPassesToDisableAlert == 0 {
		currentTestGroup.NumPassesToDisableAlert = defaultTestGroup.NumPassesToDisableAlert
	}
	// is_external and user_kubernetes_client should always be true
	currentTestGroup.IsExternal = true
	currentTestGroup.UseKubernetesClient = true
}

// ReconcileDashboardTab sets unfilled currentTab fields to the corresponding defaultTab value, if present
func ReconcileDashboardTab(currentTab *config.DashboardTab, defaultTab *config.DashboardTab) {
	if currentTab.BugComponent == 0 {
		currentTab.BugComponent = defaultTab.BugComponent
	}

	if currentTab.CodeSearchPath == "" {
		currentTab.CodeSearchPath = defaultTab.CodeSearchPath
	}

	if currentTab.NumColumnsRecent == 0 {
		currentTab.NumColumnsRecent = defaultTab.NumColumnsRecent
	}

	if currentTab.OpenTestTemplate == nil {
		currentTab.OpenTestTemplate = defaultTab.OpenTestTemplate
	}

	if currentTab.FileBugTemplate == nil {
		currentTab.FileBugTemplate = defaultTab.FileBugTemplate
	}

	if currentTab.AttachBugTemplate == nil {
		currentTab.AttachBugTemplate = defaultTab.AttachBugTemplate
	}

	if currentTab.ResultsText == "" {
		currentTab.ResultsText = defaultTab.ResultsText
	}

	if currentTab.ResultsUrlTemplate == nil {
		currentTab.ResultsUrlTemplate = defaultTab.ResultsUrlTemplate
	}

	if currentTab.CodeSearchUrlTemplate == nil {
		currentTab.CodeSearchUrlTemplate = defaultTab.CodeSearchUrlTemplate
	}

	if currentTab.AlertOptions == nil {
		currentTab.AlertOptions = defaultTab.AlertOptions
	}

	if currentTab.OpenBugTemplate == nil {
		currentTab.OpenBugTemplate = defaultTab.OpenBugTemplate
	}
}

// UpdateDefaults reads and validates default settings from YAML
// Returns an error if the defaultConfig is partially or completely missing.
func LoadDefaults(yamlData []byte) (DefaultConfiguration, error) {

	var result DefaultConfiguration
	err := yaml.Unmarshal(yamlData, &result)
	if err != nil {
		return result, err
	}

	if result.DefaultTestGroup == nil {
		return result, MissingFieldError{"DefaultTestGroup"}
	}
	if result.DefaultDashboardTab == nil {
		return result, MissingFieldError{"DefaultDashboardTab"}
	}
	return result, nil
}

// walks through paths and directories, calling the passed function on each YAML file
// future modifications to what Configurator sees as a "config file" can be made here
//TODO(chases2) Rewrite so that it walks recursively, not lexically.
func SeekYAMLFiles(paths []string, callFunc func(path string, info os.FileInfo) error) error {
	for _, path := range paths {
		_, err := os.Stat(path)
		if err != nil {
			return fmt.Errorf("Failed status call on %s: %v", path, err)
		}

		err = filepath.Walk(path, func(path string, info os.FileInfo, err error) error {

			// A bad file should not stop us from parsing the directory
			if err != nil {
				return nil
			}

			// Only YAML files will be
			if filepath.Ext(path) != ".yaml" && filepath.Ext(path) != ".yml" {
				return nil
			}

			if info.IsDir() {
				return nil
			}

			return callFunc(path, info)
		})

		if err != nil {
			return fmt.Errorf("Failed to walk through %s: %v", path, err)
		}
	}
	return nil
}
<|endoftext|>