<commit_before>package reactor

import (
    mg "mingle"
    "bitgirder/stack"
    "bitgirder/pipeline"
//    "log"
)

type ValueBuilder struct {
    acc *valueAccumulator
}

func NewValueBuilder() *ValueBuilder {
    return &ValueBuilder{ acc: newValueAccumulator() }
}

func ( vb *ValueBuilder ) InitializePipeline( p *pipeline.Pipeline ) {
    EnsureStructuralReactor( p )
    EnsurePointerCheckReactor( p )
}

func ( vb *ValueBuilder ) GetValue() mg.Value { return vb.acc.getValue() }

type valPtrAcc struct {
    id mg.PointerId
    val *mg.HeapValue
}

func ( vp *valPtrAcc ) mustValue() *mg.HeapValue {
    if vp.val == nil {
        panic( libErrorf( "no val for ptr acc with id %s", vp.id ) )
    }
    return vp.val
}

type mapAcc struct {
    id mg.PointerId
    m *mg.SymbolMap
    curFld *mg.Identifier
}

func newMapAcc() *mapAcc { return &mapAcc{ m: mg.NewSymbolMap() } }

func newMapAccWithId( id mg.PointerId ) *mapAcc {
    res := newMapAcc()
    res.id = id
    return res
}

// asserts that ma.curFld is non-nil, clears it, and returns it
func ( ma *mapAcc ) clearField() *mg.Identifier {
    if ma.curFld == nil { panic( libError( "no current field" ) ) }
    res := ma.curFld
    ma.curFld = nil
    return res
}

func ( ma *mapAcc ) setValue( val mg.Value ) { ma.m.Put( ma.clearField(), val ) }

func ( ma *mapAcc ) startField( fld *mg.Identifier ) {
    if cur := ma.curFld; cur != nil {
        panic( libErrorf( "saw start of field %s while cur is %s", fld, cur ) )
    }
    ma.curFld = fld
}

type structAcc struct {
    flds *mapAcc
    s *mg.Struct
}

func newStructAcc( typ *mg.QualifiedTypeName ) *structAcc {
    res := &structAcc{ flds: newMapAcc() }
    res.s = &mg.Struct{ Type: typ, Fields: res.flds.m }
    return res
}

type listAcc struct {
    id mg.PointerId
    l *mg.List
}

func newListAcc( id mg.PointerId ) *listAcc {
    return &listAcc{ id: id, l: mg.NewList( mg.TypeOpaqueList ) }
}

type valueBuildResolution struct {
    id mg.PointerId
    f func( mg.Value )
}

// Can make this public if needed
type valueAccumulator struct {
    val mg.Value
    accs *stack.Stack
    refs map[ mg.PointerId ] interface{}
    resolutions []valueBuildResolution
}

func newValueAccumulator() *valueAccumulator {
    return &valueAccumulator{
        accs: stack.NewStack(),
        refs: make( map[ mg.PointerId ] interface{} ),
        resolutions: make( []valueBuildResolution, 0, 4 ),
    }
}

func ( va *valueAccumulator ) addResolver( id mg.PointerId, f func( mg.Value ) ) {
    res := valueBuildResolution{ id: id, f: f }
    va.resolutions = append( va.resolutions, res )
}

func ( va *valueAccumulator ) pushAcc( acc interface{} ) { va.accs.Push( acc ) }

func ( va *valueAccumulator ) idForAcc( acc interface{} ) mg.PointerId {
    switch v := acc.( type ) {
    case *valPtrAcc: return v.id
    case *listAcc: return v.id
    case *mapAcc: return v.id
    }
    panic( libErrorf( "not a addressable acc: %T", acc ) )
}

func ( va *valueAccumulator ) pushReferenceAcc( acc interface{} ) {
    if id := va.idForAcc( acc ); id != mg.PointerIdNull { va.refs[ id ] = acc }
    va.pushAcc( acc )
}

func ( va *valueAccumulator ) peekAcc() ( interface{}, bool ) {
    return va.accs.Peek(), ! va.accs.IsEmpty()
}

func ( va *valueAccumulator ) mustPeekAcc() interface{} {
    if res, ok := va.peekAcc(); ok { return res }
    panic( libError( "acc stack is empty" ) )
}

func ( va *valueAccumulator ) setForwardFieldValue( ma *mapAcc, id mg.PointerId ) {
    fld := ma.clearField()
    va.addResolver( id, func( val mg.Value ) { ma.m.Put( fld, val ) } )
}

func ( va *valueAccumulator ) forwardValueReferenced( id mg.PointerId ) {
    switch v := va.mustPeekAcc().( type ) {
    case *structAcc: va.setForwardFieldValue( v.flds, id )
    case *mapAcc: va.setForwardFieldValue( v, id )
    default: panic( libErrorf( "unhandled acc: %T", v ) )
    }
}

func ( va *valueAccumulator ) acceptValue( acc interface{}, val mg.Value ) bool {
    switch v := acc.( type ) {
    case *valPtrAcc: v.val = mg.NewHeapValue( val ); return true
    case *mapAcc: v.setValue( val ); return false
    case *structAcc: v.flds.setValue( val ); return false
    case *listAcc: v.l.Add( val ); return false
    }
    panic( libErrorf( "unhandled acc: %T", acc ) )
}

func ( va *valueAccumulator ) valueForAcc( acc interface{} ) mg.Value {
    switch v := acc.( type ) {
    case *valPtrAcc: return v.mustValue()
    case *mapAcc: return v.m
    case *structAcc: return v.s
    case *listAcc: return v.l
    }
    panic( libErrorf( "unhandled acc: %T", acc ) )
}

func ( va *valueAccumulator ) popAccValue() {
    va.valueReady( va.valueForAcc( va.accs.Pop() ) )
}

func ( va *valueAccumulator ) resolve() {
    for _, rs := range va.resolutions {
        acc := va.refs[ rs.id ]
        rs.f( va.valueForAcc( acc ) )
    }
}

func ( va *valueAccumulator ) valueReady( val mg.Value ) {
    if acc, ok := va.peekAcc(); ok {
        if va.acceptValue( acc, val ) { va.popAccValue() }
    } else {
        va.resolve()
        va.val = val
    }
}

// Panics if result of val is not ready
func ( va *valueAccumulator ) getValue() mg.Value {
    if va.val == nil { panic( rctErrorf( nil, "Value is not yet built" ) ) }
    return va.val
}

func ( va *valueAccumulator ) startField( fld *mg.Identifier ) {
    acc, ok := va.peekAcc()
    if ! ok { panic( libErrorf( "got field start %s with empty stack", fld ) ) }
    switch v := acc.( type ) {
    case *mapAcc: v.startField( fld )
    case *structAcc: v.flds.startField( fld )
    default:
        panic( libErrorf( "unexpected acc for start of field %s: %T", fld, v ) )
    }
}

func ( va *valueAccumulator ) end() { va.popAccValue() }

func ( va *valueAccumulator ) isForwardRef( acc interface{} ) bool {
    if vp, ok := acc.( *valPtrAcc ); ok { return vp.val == nil }
    return false
}

func ( va *valueAccumulator ) valueReferenced( vr *ValueReferenceEvent ) error {
    if acc, ok := va.refs[ vr.Id ]; ok {
        if va.isForwardRef( acc ) {
            va.forwardValueReferenced( vr.Id )
        } else {
            va.valueReady( va.valueForAcc( acc ) )
        }
        return nil
    }
    return rctErrorf( vr.GetPath(), "unhandled value pointer ref: %s", vr.Id )
}

func ( va *valueAccumulator ) ProcessEvent( ev ReactorEvent ) error {
    switch v := ev.( type ) {
    case *ValueEvent: va.valueReady( v.Val )
    case *ListStartEvent: va.pushReferenceAcc( newListAcc( v.Id ) )
    case *MapStartEvent: va.pushReferenceAcc( newMapAccWithId( v.Id ) )
    case *StructStartEvent: va.pushAcc( newStructAcc( v.Type ) )
    case *FieldStartEvent: va.startField( v.Field )
    case *EndEvent: va.end()
    case *ValueAllocationEvent: va.pushReferenceAcc( &valPtrAcc{ id: v.Id } )
    case *ValueReferenceEvent: return va.valueReferenced( v )
    default: panic( libErrorf( "Unhandled event: %T", ev ) )
    }
    return nil
}

func ( vb *ValueBuilder ) ProcessEvent( ev ReactorEvent ) error {
    return vb.acc.ProcessEvent( ev )
}
<commit_msg>removing forward-ref/cycle handling form value builder<commit_after>package reactor

import (
    mg "mingle"
    "bitgirder/stack"
    "bitgirder/pipeline"
//    "log"
)

type ValueBuilder struct {
    acc *valueAccumulator
}

func NewValueBuilder() *ValueBuilder {
    return &ValueBuilder{ acc: newValueAccumulator() }
}

func ( vb *ValueBuilder ) InitializePipeline( p *pipeline.Pipeline ) {
    EnsureStructuralReactor( p )
    EnsurePointerCheckReactor( p )
}

func ( vb *ValueBuilder ) GetValue() mg.Value { return vb.acc.getValue() }

type valPtrAcc struct {
    id mg.PointerId
    val *mg.HeapValue
}

func ( vp *valPtrAcc ) mustValue() *mg.HeapValue {
    if vp.val == nil {
        panic( libErrorf( "no val for ptr acc with id %s", vp.id ) )
    }
    return vp.val
}

type mapAcc struct {
    id mg.PointerId
    m *mg.SymbolMap
    curFld *mg.Identifier
}

func newMapAcc() *mapAcc { return &mapAcc{ m: mg.NewSymbolMap() } }

func newMapAccWithId( id mg.PointerId ) *mapAcc {
    res := newMapAcc()
    res.id = id
    return res
}

// asserts that ma.curFld is non-nil, clears it, and returns it
func ( ma *mapAcc ) clearField() *mg.Identifier {
    if ma.curFld == nil { panic( libError( "no current field" ) ) }
    res := ma.curFld
    ma.curFld = nil
    return res
}

func ( ma *mapAcc ) setValue( val mg.Value ) { ma.m.Put( ma.clearField(), val ) }

func ( ma *mapAcc ) startField( fld *mg.Identifier ) {
    if cur := ma.curFld; cur != nil {
        panic( libErrorf( "saw start of field %s while cur is %s", fld, cur ) )
    }
    ma.curFld = fld
}

type structAcc struct {
    flds *mapAcc
    s *mg.Struct
}

func newStructAcc( typ *mg.QualifiedTypeName ) *structAcc {
    res := &structAcc{ flds: newMapAcc() }
    res.s = &mg.Struct{ Type: typ, Fields: res.flds.m }
    return res
}

type listAcc struct {
    id mg.PointerId
    l *mg.List
}

func newListAcc( id mg.PointerId ) *listAcc {
    return &listAcc{ id: id, l: mg.NewList( mg.TypeOpaqueList ) }
}

// Can make this public if needed
type valueAccumulator struct {
    val mg.Value
    accs *stack.Stack
    refs map[ mg.PointerId ] interface{}
}

func newValueAccumulator() *valueAccumulator {
    return &valueAccumulator{
        accs: stack.NewStack(),
        refs: make( map[ mg.PointerId ] interface{} ),
    }
}

func ( va *valueAccumulator ) pushAcc( acc interface{} ) { va.accs.Push( acc ) }

func ( va *valueAccumulator ) idForAcc( acc interface{} ) mg.PointerId {
    switch v := acc.( type ) {
    case *valPtrAcc: return v.id
    case *listAcc: return v.id
    case *mapAcc: return v.id
    }
    panic( libErrorf( "not a addressable acc: %T", acc ) )
}

func ( va *valueAccumulator ) pushReferenceAcc( acc interface{} ) {
    if id := va.idForAcc( acc ); id != mg.PointerIdNull { va.refs[ id ] = acc }
    va.pushAcc( acc )
}

func ( va *valueAccumulator ) peekAcc() ( interface{}, bool ) {
    return va.accs.Peek(), ! va.accs.IsEmpty()
}

func ( va *valueAccumulator ) mustPeekAcc() interface{} {
    if res, ok := va.peekAcc(); ok { return res }
    panic( libError( "acc stack is empty" ) )
}

func ( va *valueAccumulator ) acceptValue( acc interface{}, val mg.Value ) bool {
    switch v := acc.( type ) {
    case *valPtrAcc: v.val = mg.NewHeapValue( val ); return true
    case *mapAcc: v.setValue( val ); return false
    case *structAcc: v.flds.setValue( val ); return false
    case *listAcc: v.l.Add( val ); return false
    }
    panic( libErrorf( "unhandled acc: %T", acc ) )
}

func ( va *valueAccumulator ) valueForAcc( acc interface{} ) mg.Value {
    switch v := acc.( type ) {
    case *valPtrAcc: return v.mustValue()
    case *mapAcc: return v.m
    case *structAcc: return v.s
    case *listAcc: return v.l
    }
    panic( libErrorf( "unhandled acc: %T", acc ) )
}

func ( va *valueAccumulator ) popAccValue() {
    va.valueReady( va.valueForAcc( va.accs.Pop() ) )
}

func ( va *valueAccumulator ) valueReady( val mg.Value ) {
    if acc, ok := va.peekAcc(); ok {
        if va.acceptValue( acc, val ) { va.popAccValue() }
    } else {
        va.val = val
    }
}

// Panics if result of val is not ready
func ( va *valueAccumulator ) getValue() mg.Value {
    if va.val == nil { panic( rctErrorf( nil, "Value is not yet built" ) ) }
    return va.val
}

func ( va *valueAccumulator ) startField( fld *mg.Identifier ) {
    acc, ok := va.peekAcc()
    if ! ok { panic( libErrorf( "got field start %s with empty stack", fld ) ) }
    switch v := acc.( type ) {
    case *mapAcc: v.startField( fld )
    case *structAcc: v.flds.startField( fld )
    default:
        panic( libErrorf( "unexpected acc for start of field %s: %T", fld, v ) )
    }
}

func ( va *valueAccumulator ) end() { va.popAccValue() }

func ( va *valueAccumulator ) valueReferenced( vr *ValueReferenceEvent ) error {
    if acc, ok := va.refs[ vr.Id ]; ok {
        va.valueReady( va.valueForAcc( acc ) )
        return nil
    }
    return rctErrorf( vr.GetPath(), "unhandled value pointer ref: %s", vr.Id )
}

func ( va *valueAccumulator ) ProcessEvent( ev ReactorEvent ) error {
    switch v := ev.( type ) {
    case *ValueEvent: va.valueReady( v.Val )
    case *ListStartEvent: va.pushReferenceAcc( newListAcc( v.Id ) )
    case *MapStartEvent: va.pushReferenceAcc( newMapAccWithId( v.Id ) )
    case *StructStartEvent: va.pushAcc( newStructAcc( v.Type ) )
    case *FieldStartEvent: va.startField( v.Field )
    case *EndEvent: va.end()
    case *ValueAllocationEvent: va.pushReferenceAcc( &valPtrAcc{ id: v.Id } )
    case *ValueReferenceEvent: return va.valueReferenced( v )
    default: panic( libErrorf( "Unhandled event: %T", ev ) )
    }
    return nil
}

func ( vb *ValueBuilder ) ProcessEvent( ev ReactorEvent ) error {
    return vb.acc.ProcessEvent( ev )
}
<|endoftext|>


<commit_before>// Copyright (c) 2013 Ostap Cherkashin. You can use this source code
// under the terms of the MIT License found in the LICENSE file.

package main

import (
	"fmt"
	"io"
	"math"
	"strconv"
)

type Bool bool
type Number float64
type String string
type List []Value
type Object []Value

var True Value = Bool(true)
var False Value = Bool(false)

type Value interface {
	Bool() Bool
	String() String
	Number() Number
	List() List
	Object() Object

	Quote(w io.Writer, t Type) error
	Equals(v Value) Bool
}

func (b Bool) Bool() Bool {
	return b
}

func (b Bool) String() String {
	if b {
		return String("true")
	}

	return String("")
}

func (b Bool) Number() Number {
	if b {
		return 1.0
	}

	return 0.0
}

func (b Bool) List() List {
	return List{b}
}

func (b Bool) Object() Object {
	return Object{b}
}

func (b Bool) Quote(w io.Writer, t Type) error {
	var err error
	if b {
		_, err = io.WriteString(w, "true")
	} else {
		_, err = io.WriteString(w, "false")
	}

	return err
}

func (b Bool) Equals(v Value) Bool {
	return b == v.Bool()
}

func (n Number) Bool() Bool {
	if math.IsNaN(float64(n)) {
		return Bool(false)
	}

	return Bool(n != 0)
}

func (n Number) Number() Number {
	return n
}

func (n Number) String() String {
	return String(fmt.Sprintf("%v", n))
}

func (n Number) List() List {
	return List{n}
}

func (n Number) Object() Object {
	return Object{n}
}

func (n Number) Quote(w io.Writer, t Type) error {
	var err error
	if math.IsInf(float64(n), 0) || math.IsNaN(float64(n)) {
		_, err = fmt.Fprintf(w, `"%v"`, n)
	} else {
		_, err = fmt.Fprintf(w, "%v", n)
	}

	return err
}

func (n Number) Equals(v Value) Bool {
	return n == v.Number()
}

func (s String) Bool() Bool {
	return s != ""
}

func (s String) Number() Number {
	res, _ := strconv.ParseFloat(string(s), 64)
	return Number(res)
}

func (s String) String() String {
	return s
}

func (s String) List() List {
	return List{s}
}

func (s String) Object() Object {
	return Object{s}
}

func (s String) Quote(w io.Writer, t Type) error {
	_, err := io.WriteString(w, strconv.Quote(string(s)))
	return err
}

func (s String) Equals(v Value) Bool {
	return s == v.String()
}

func (l List) Bool() Bool {
	return len(l) > 0
}

func (l List) Number() Number {
	return Number(math.NaN())
}

func (l List) String() String {
	return ""
}

func (l List) List() List {
	return l
}

func (l List) Object() Object {
	return nil
}

func (l List) Quote(w io.Writer, t Type) error {
	_, err := io.WriteString(w, "[ ")
	if err != nil {
		return err
	}

	lt, isList := t.(ListType)
	if !isList {
		return fmt.Errorf("internal error: %v is not a list", t.Name())
	}

	for i, v := range l {
		if i != 0 {
			_, err = io.WriteString(w, ", ")
			if err != nil {
				return err
			}
		}

		if err := v.Quote(w, lt.Elem); err != nil {
			return err
		}
	}

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

func (l List) Equals(v Value) Bool {
	r := v.List()
	if len(l) != len(r) {
		return false
	}

	for i := 0; i < len(l); i++ {
		if !l[i].Equals(r[i]) {
			return false
		}
	}

	return true
}

func (o Object) Bool() Bool {
	return len(o) > 0
}

func (o Object) Number() Number {
	return Number(math.NaN())
}

func (o Object) String() String {
	return ""
}

func (o Object) List() List {
	return nil
}

func (o Object) Object() Object {
	return o
}

func (o Object) Quote(w io.Writer, t Type) error {
	_, err := io.WriteString(w, "{ ")
	if err != nil {
		return err
	}

	ot, isObject := t.(ObjectType)
	if !isObject {
		return fmt.Errorf("internal error: %v is not an object", t.Name())
	}

	for i, v := range o {
		if i != 0 {
			_, err = io.WriteString(w, ", ")
			if err != nil {
				return err
			}
		}

		_, err = fmt.Fprintf(w, `%v: `, strconv.Quote(ot[i].Name))
		if err != nil {
			return err
		}

		if err := v.Quote(w, ot[i].Type); err != nil {
			return err
		}
	}

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

func (o Object) Equals(v Value) Bool {
	// FIXME: algorithm assumes the same field ordering for both objects
	r := v.Object()
	if len(o) != len(r) {
		return false
	}

	for i := 0; i < len(o); i++ {
		if !bool(o[i].Equals(r[i])) {
			return false
		}
	}

	return true
}
<commit_msg>fixing invalid JSON response for control and non-printable characters<commit_after>// Copyright (c) 2013 Ostap Cherkashin. You can use this source code
// under the terms of the MIT License found in the LICENSE file.

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"math"
	"strconv"
)

type Bool bool
type Number float64
type String string
type List []Value
type Object []Value

var True Value = Bool(true)
var False Value = Bool(false)

type Value interface {
	Bool() Bool
	String() String
	Number() Number
	List() List
	Object() Object

	Quote(w io.Writer, t Type) error
	Equals(v Value) Bool
}

func marshal(w io.Writer, v interface{}) error {
	data, err := json.Marshal(v)
	if err != nil {
		return err
	}

	_, err = w.Write(data)
	return err
}

func (b Bool) Bool() Bool {
	return b
}

func (b Bool) String() String {
	if b {
		return String("true")
	}

	return String("")
}

func (b Bool) Number() Number {
	if b {
		return 1.0
	}

	return 0.0
}

func (b Bool) List() List {
	return List{b}
}

func (b Bool) Object() Object {
	return Object{b}
}

func (b Bool) Quote(w io.Writer, t Type) error {
	return marshal(w, bool(b))
}

func (b Bool) Equals(v Value) Bool {
	return b == v.Bool()
}

func (n Number) Bool() Bool {
	if math.IsNaN(float64(n)) {
		return Bool(false)
	}

	return Bool(n != 0)
}

func (n Number) Number() Number {
	return n
}

func (n Number) String() String {
	return String(fmt.Sprintf("%v", n))
}

func (n Number) List() List {
	return List{n}
}

func (n Number) Object() Object {
	return Object{n}
}

func (n Number) Quote(w io.Writer, t Type) error {
	var v interface{}
	if math.IsInf(float64(n), 0) || math.IsNaN(float64(n)) {
		v = fmt.Sprintf(`%v`, n)
	} else {
		v = float64(n)
	}

	return marshal(w, v)
}

func (n Number) Equals(v Value) Bool {
	return n == v.Number()
}

func (s String) Bool() Bool {
	return s != ""
}

func (s String) Number() Number {
	res, _ := strconv.ParseFloat(string(s), 64)
	return Number(res)
}

func (s String) String() String {
	return s
}

func (s String) List() List {
	return List{s}
}

func (s String) Object() Object {
	return Object{s}
}

func (s String) Quote(w io.Writer, t Type) error {
	return marshal(w, string(s))
}

func (s String) Equals(v Value) Bool {
	return s == v.String()
}

func (l List) Bool() Bool {
	return len(l) > 0
}

func (l List) Number() Number {
	return Number(math.NaN())
}

func (l List) String() String {
	return ""
}

func (l List) List() List {
	return l
}

func (l List) Object() Object {
	return nil
}

func (l List) Quote(w io.Writer, t Type) error {
	_, err := io.WriteString(w, "[ ")
	if err != nil {
		return err
	}

	lt, isList := t.(ListType)
	if !isList {
		return fmt.Errorf("internal error: %v is not a list", t.Name())
	}

	for i, v := range l {
		if i != 0 {
			_, err = io.WriteString(w, ", ")
			if err != nil {
				return err
			}
		}

		if err := v.Quote(w, lt.Elem); err != nil {
			return err
		}
	}

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

func (l List) Equals(v Value) Bool {
	r := v.List()
	if len(l) != len(r) {
		return false
	}

	for i := 0; i < len(l); i++ {
		if !l[i].Equals(r[i]) {
			return false
		}
	}

	return true
}

func (o Object) Bool() Bool {
	return len(o) > 0
}

func (o Object) Number() Number {
	return Number(math.NaN())
}

func (o Object) String() String {
	return ""
}

func (o Object) List() List {
	return nil
}

func (o Object) Object() Object {
	return o
}

func (o Object) Quote(w io.Writer, t Type) error {
	_, err := io.WriteString(w, "{ ")
	if err != nil {
		return err
	}

	ot, isObject := t.(ObjectType)
	if !isObject {
		return fmt.Errorf("internal error: %v is not an object", t.Name())
	}

	for i, v := range o {
		if i != 0 {
			_, err = io.WriteString(w, ", ")
			if err != nil {
				return err
			}
		}

		_, err = fmt.Fprintf(w, `%v: `, strconv.Quote(ot[i].Name))
		if err != nil {
			return err
		}

		if err := v.Quote(w, ot[i].Type); err != nil {
			return err
		}
	}

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

func (o Object) Equals(v Value) Bool {
	// FIXME: algorithm assumes the same field ordering for both objects
	r := v.Object()
	if len(o) != len(r) {
		return false
	}

	for i := 0; i < len(o); i++ {
		if !bool(o[i].Equals(r[i])) {
			return false
		}
	}

	return true
}
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package api

import (
	"fmt"
	"os"
	"strconv"
	"strings"
	"testing"
	"time"

	info "github.com/google/cadvisor/info/v1"
	"github.com/google/cadvisor/integration/framework"
	"github.com/stretchr/testify/require"
)

func TestStreamingEventInformationIsReturned(t *testing.T) {
	fm := framework.New(t)
	defer fm.Cleanup()

	einfo := make(chan *info.Event)
	go func() {
		err := fm.Cadvisor().Client().EventStreamingInfo("?oom_events=true&stream=true", einfo)
		t.Logf("tried to stream events but got error %v", err)
		require.NoError(t, err)
	}()

	containerName := fmt.Sprintf("test-basic-docker-container-%d", os.Getpid())
	containerId := fm.Docker().RunStress(framework.DockerRunArgs{
		Image: "bernardo/stress",
		Args:  []string{"--name", containerName},
		InnerArgs: []string{
			"--vm", strconv.FormatUint(4, 10),
			"--vm-keep",
			"-q",
			"-m", strconv.FormatUint(1000, 10),
			"--timeout", strconv.FormatUint(10, 10),
		},
	})

	waitForStreamingEvent(containerId, "?deletion_events=true&stream=true", t, fm, info.EventContainerDeletion)
	waitForStaticEvent(containerId, "?creation_events=true", t, fm, info.EventContainerCreation)
	//TODO: test for oom events
	//waitForStaticEvent(containerId, "?oom_events=true", t, fm, info.EventOom)
}

func waitForStreamingEvent(containerId string, urlRequest string, t *testing.T, fm framework.Framework, typeEvent info.EventType) {
	timeout := make(chan bool, 1)
	go func() {
		time.Sleep(60 * time.Second)
		timeout <- true
	}()

	einfo := make(chan *info.Event)
	go func() {
		err := fm.Cadvisor().Client().EventStreamingInfo(urlRequest, einfo)
		require.NoError(t, err)
	}()
	for {
		select {
		case ev := <-einfo:
			if ev.EventType == typeEvent {
				if strings.Contains(strings.Trim(ev.ContainerName, "/ "), strings.Trim(containerId, "/ ")) {
					return
				}
			}
		case <-timeout:
			t.Fatal(
				"timeout happened before destruction event was detected")
		}
	}
}

func waitForStaticEvent(containerId string, urlRequest string, t *testing.T, fm framework.Framework, typeEvent info.EventType) {
	einfo, err := fm.Cadvisor().Client().EventStaticInfo(urlRequest)
	require.NoError(t, err)

	found := false
	for _, ev := range einfo {
		if ev.EventType == typeEvent {
			if strings.Contains(strings.Trim(ev.ContainerName, "/ "), strings.Trim(containerId, "/ ")) {
				found = true
				break
			}
		}
	}
	require.True(t, found)
}
<commit_msg>Watch for deletion event before the container runs.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package api

import (
	"strings"
	"testing"
	"time"

	info "github.com/google/cadvisor/info/v1"
	"github.com/google/cadvisor/integration/framework"
	"github.com/stretchr/testify/require"
)

func TestStreamingEventInformationIsReturned(t *testing.T) {
	fm := framework.New(t)
	defer fm.Cleanup()

	// Watch for container deletions
	einfo := make(chan *info.Event)
	go func() {
		err := fm.Cadvisor().Client().EventStreamingInfo("?deletion_events=true&stream=true&subcontainers=true", einfo)
		require.NoError(t, err)
	}()

	// Create a short-lived container.
	containerId := fm.Docker().RunBusybox("sleep", "2")

	// Wait for the deletion event.
	timeout := time.After(30 * time.Second)
	done := false
	for !done {
		select {
		case ev := <-einfo:
			if ev.EventType == info.EventContainerDeletion {
				if strings.Contains(ev.ContainerName, containerId) {
					done = true
				}
			}
		case <-timeout:
			t.Errorf(
				"timeout happened before destruction event was detected for container %q", containerId)
			done = true
		}
	}

	// We should have already received a creation event.
	waitForStaticEvent(containerId, "?creation_events=true&subcontainers=true", t, fm, info.EventContainerCreation)
}

func waitForStaticEvent(containerId string, urlRequest string, t *testing.T, fm framework.Framework, typeEvent info.EventType) {
	einfo, err := fm.Cadvisor().Client().EventStaticInfo(urlRequest)
	require.NoError(t, err)
	found := false
	for _, ev := range einfo {
		if ev.EventType == typeEvent {
			if strings.Contains(ev.ContainerName, containerId) {
				found = true
				break
			}
		}
	}
	require.True(t, found)
}
<|endoftext|>


<commit_before>package nametransform

import (
	"crypto/sha256"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/rfjakob/gocryptfs/internal/syscallcompat"
	"github.com/rfjakob/gocryptfs/internal/tlog"
)

const (
	// LongNameSuffix is the suffix used for files with long names.
	// Files with long names are stored in two files:
	// gocryptfs.longname.[sha256]       <--- File content, prefix = gocryptfs.longname.
	// gocryptfs.longname.[sha256].name  <--- File name, suffix = .name
	LongNameSuffix = ".name"
	longNamePrefix = "gocryptfs.longname."
)

// HashLongName - take the hash of a long string "name" and return
// "gocryptfs.longname.[sha256]"
//
// This function does not do any I/O.
func (n *NameTransform) HashLongName(name string) string {
	hashBin := sha256.Sum256([]byte(name))
	hashBase64 := n.B64.EncodeToString(hashBin[:])
	return longNamePrefix + hashBase64
}

// Values returned by IsLongName
const (
	// LongNameContent is the file that stores the file content.
	// Example: gocryptfs.longname.URrM8kgxTKYMgCk4hKk7RO9Lcfr30XQof4L_5bD9Iro=
	LongNameContent = iota
	// LongNameFilename is the file that stores the full encrypted filename.
	// Example: gocryptfs.longname.URrM8kgxTKYMgCk4hKk7RO9Lcfr30XQof4L_5bD9Iro=.name
	LongNameFilename = iota
	// LongNameNone is used when the file does not have a long name.
	// Example: i1bpTaVLZq7sRNA9mL_2Ig==
	LongNameNone = iota
)

// NameType - detect if cName is
// gocryptfs.longname.[sha256]  ........ LongNameContent (content of a long name file)
// gocryptfs.longname.[sha256].name .... LongNameFilename (full file name of a long name file)
// else ................................ LongNameNone (normal file)
//
// This function does not do any I/O.
func NameType(cName string) int {
	if !strings.HasPrefix(cName, longNamePrefix) {
		return LongNameNone
	}
	if strings.HasSuffix(cName, LongNameSuffix) {
		return LongNameFilename
	}
	return LongNameContent
}

// IsLongContent returns true if "cName" is the content store of a long name
// file (looks like "gocryptfs.longname.[sha256]").
//
// This function does not do any I/O.
func IsLongContent(cName string) bool {
	return NameType(cName) == LongNameContent
}

// ReadLongName - read cName + ".name" from the directory opened as dirfd.
//
// Symlink-safe through Openat().
func ReadLongNameAt(dirfd int, cName string) (string, error) {
	cName += LongNameSuffix
	fd, err := syscallcompat.Openat(dirfd, cName, syscall.O_NOFOLLOW, 0)
	if err != nil {
		return "", err
	}
	defer syscall.Close(fd)
	// 256 (=255 padded to 16) bytes base64-encoded take 344 bytes: "AAAAAAA...AAA=="
	lim := 344
	// Allocate a bigger buffer so we see whether the file is too big
	buf := make([]byte, lim+1)
	n, err := syscall.Pread(fd, buf, 0)
	if err != nil && err != io.EOF {
		return "", err
	}
	if n == 0 {
		return "", fmt.Errorf("ReadLongName: empty file")
	}
	if n > lim {
		return "", fmt.Errorf("ReadLongName: size=%d > limit=%d", n, lim)
	}
	return string(buf[0:n]), nil
}

// DeleteLongName deletes "hashName.name" in the directory openend at "dirfd".
//
// This function is symlink-safe through the use of Unlinkat().
func DeleteLongNameAt(dirfd int, hashName string) error {
	err := syscallcompat.Unlinkat(dirfd, hashName+LongNameSuffix, 0)
	if err != nil {
		tlog.Warn.Printf("DeleteLongName: %v", err)
	}
	return err
}

// WriteLongName encrypts plainName and writes it into "hashName.name".
// For the convenience of the caller, plainName may also be a path and will be
// Base()named internally.
//
// This function is symlink-safe through the use of Openat().
func (n *NameTransform) WriteLongNameAt(dirfd int, hashName string, plainName string) (err error) {
	plainName = filepath.Base(plainName)

	// Encrypt the basename
	dirIV, err := ReadDirIVAt(dirfd)
	if err != nil {
		return err
	}
	cName := n.EncryptName(plainName, dirIV)

	// Write the encrypted name into hashName.name
	fdRaw, err := syscallcompat.Openat(dirfd, hashName+LongNameSuffix,
		syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL, 0600)
	if err != nil {
		// Don't warn if the file already exists - this is allowed for renames
		// and should be handled by the caller.
		if err != syscall.EEXIST {
			tlog.Warn.Printf("WriteLongName: Openat: %v", err)
		}
		return err
	}
	fd := os.NewFile(uintptr(fdRaw), hashName+LongNameSuffix)
	_, err = fd.Write([]byte(cName))
	if err != nil {
		fd.Close()
		tlog.Warn.Printf("WriteLongName: Write: %v", err)
		// Delete incomplete longname file
		syscallcompat.Unlinkat(dirfd, hashName+LongNameSuffix, 0)
		return err
	}
	err = fd.Close()
	if err != nil {
		tlog.Warn.Printf("WriteLongName: Close: %v", err)
		// Delete incomplete longname file
		syscallcompat.Unlinkat(dirfd, hashName+LongNameSuffix, 0)
		return err
	}
	return nil
}
<commit_msg>nametransform: fix possible incomplete read in ReadLongNameAt<commit_after>package nametransform

import (
	"crypto/sha256"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/rfjakob/gocryptfs/internal/syscallcompat"
	"github.com/rfjakob/gocryptfs/internal/tlog"
)

const (
	// LongNameSuffix is the suffix used for files with long names.
	// Files with long names are stored in two files:
	// gocryptfs.longname.[sha256]       <--- File content, prefix = gocryptfs.longname.
	// gocryptfs.longname.[sha256].name  <--- File name, suffix = .name
	LongNameSuffix = ".name"
	longNamePrefix = "gocryptfs.longname."
)

// HashLongName - take the hash of a long string "name" and return
// "gocryptfs.longname.[sha256]"
//
// This function does not do any I/O.
func (n *NameTransform) HashLongName(name string) string {
	hashBin := sha256.Sum256([]byte(name))
	hashBase64 := n.B64.EncodeToString(hashBin[:])
	return longNamePrefix + hashBase64
}

// Values returned by IsLongName
const (
	// LongNameContent is the file that stores the file content.
	// Example: gocryptfs.longname.URrM8kgxTKYMgCk4hKk7RO9Lcfr30XQof4L_5bD9Iro=
	LongNameContent = iota
	// LongNameFilename is the file that stores the full encrypted filename.
	// Example: gocryptfs.longname.URrM8kgxTKYMgCk4hKk7RO9Lcfr30XQof4L_5bD9Iro=.name
	LongNameFilename = iota
	// LongNameNone is used when the file does not have a long name.
	// Example: i1bpTaVLZq7sRNA9mL_2Ig==
	LongNameNone = iota
)

// NameType - detect if cName is
// gocryptfs.longname.[sha256]  ........ LongNameContent (content of a long name file)
// gocryptfs.longname.[sha256].name .... LongNameFilename (full file name of a long name file)
// else ................................ LongNameNone (normal file)
//
// This function does not do any I/O.
func NameType(cName string) int {
	if !strings.HasPrefix(cName, longNamePrefix) {
		return LongNameNone
	}
	if strings.HasSuffix(cName, LongNameSuffix) {
		return LongNameFilename
	}
	return LongNameContent
}

// IsLongContent returns true if "cName" is the content store of a long name
// file (looks like "gocryptfs.longname.[sha256]").
//
// This function does not do any I/O.
func IsLongContent(cName string) bool {
	return NameType(cName) == LongNameContent
}

// ReadLongName - read cName + ".name" from the directory opened as dirfd.
//
// Symlink-safe through Openat().
func ReadLongNameAt(dirfd int, cName string) (string, error) {
	cName += LongNameSuffix
	var f *os.File
	{
		fd, err := syscallcompat.Openat(dirfd, cName, syscall.O_NOFOLLOW, 0)
		if err != nil {
			return "", err
		}
		f = os.NewFile(uintptr(fd), "")
		// fd runs out of scope here
	}
	defer f.Close()
	// 256 (=255 padded to 16) bytes base64-encoded take 344 bytes: "AAAAAAA...AAA=="
	lim := 344
	// Allocate a bigger buffer so we see whether the file is too big
	buf := make([]byte, lim+1)
	n, err := f.ReadAt(buf, 0)
	if err != nil && err != io.EOF {
		return "", err
	}
	if n == 0 {
		return "", fmt.Errorf("ReadLongName: empty file")
	}
	if n > lim {
		return "", fmt.Errorf("ReadLongName: size=%d > limit=%d", n, lim)
	}
	return string(buf[0:n]), nil
}

// DeleteLongName deletes "hashName.name" in the directory openend at "dirfd".
//
// This function is symlink-safe through the use of Unlinkat().
func DeleteLongNameAt(dirfd int, hashName string) error {
	err := syscallcompat.Unlinkat(dirfd, hashName+LongNameSuffix, 0)
	if err != nil {
		tlog.Warn.Printf("DeleteLongName: %v", err)
	}
	return err
}

// WriteLongName encrypts plainName and writes it into "hashName.name".
// For the convenience of the caller, plainName may also be a path and will be
// Base()named internally.
//
// This function is symlink-safe through the use of Openat().
func (n *NameTransform) WriteLongNameAt(dirfd int, hashName string, plainName string) (err error) {
	plainName = filepath.Base(plainName)

	// Encrypt the basename
	dirIV, err := ReadDirIVAt(dirfd)
	if err != nil {
		return err
	}
	cName := n.EncryptName(plainName, dirIV)

	// Write the encrypted name into hashName.name
	fdRaw, err := syscallcompat.Openat(dirfd, hashName+LongNameSuffix,
		syscall.O_WRONLY|syscall.O_CREAT|syscall.O_EXCL, 0600)
	if err != nil {
		// Don't warn if the file already exists - this is allowed for renames
		// and should be handled by the caller.
		if err != syscall.EEXIST {
			tlog.Warn.Printf("WriteLongName: Openat: %v", err)
		}
		return err
	}
	fd := os.NewFile(uintptr(fdRaw), hashName+LongNameSuffix)
	_, err = fd.Write([]byte(cName))
	if err != nil {
		fd.Close()
		tlog.Warn.Printf("WriteLongName: Write: %v", err)
		// Delete incomplete longname file
		syscallcompat.Unlinkat(dirfd, hashName+LongNameSuffix, 0)
		return err
	}
	err = fd.Close()
	if err != nil {
		tlog.Warn.Printf("WriteLongName: Close: %v", err)
		// Delete incomplete longname file
		syscallcompat.Unlinkat(dirfd, hashName+LongNameSuffix, 0)
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package maas_test

import (
	stdtesting "testing"

	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"
	"launchpad.net/gomaasapi"

	"github.com/juju/juju/environs/config"
	envtesting "github.com/juju/juju/environs/testing"
	"github.com/juju/juju/feature"
	"github.com/juju/juju/provider/maas"
	coretesting "github.com/juju/juju/testing"
)

type environSuite struct {
	coretesting.BaseSuite
	envtesting.ToolsFixture
	testMAASObject  *gomaasapi.TestMAASObject
	restoreTimeouts func()
}

var _ = gc.Suite(&environSuite{})

func TestMAAS(t *stdtesting.T) {
	gc.TestingT(t)
}

// TDOO: jam 2013-12-06 This is copied from the providerSuite which is in a
// whitebox package maas. Either move that into a whitebox test so it can be
// shared, or into a 'testing' package so we can use it here.
func (s *environSuite) SetUpSuite(c *gc.C) {
	s.restoreTimeouts = envtesting.PatchAttemptStrategies(maas.ShortAttempt)
	s.BaseSuite.SetUpSuite(c)
	TestMAASObject := gomaasapi.NewTestMAAS("1.0")
	s.testMAASObject = TestMAASObject
}

func (s *environSuite) SetUpTest(c *gc.C) {
	s.BaseSuite.SetUpTest(c)
	s.ToolsFixture.SetUpTest(c)
	s.SetFeatureFlags(feature.AddressAllocation)
}

func (s *environSuite) TearDownTest(c *gc.C) {
	s.testMAASObject.TestServer.Clear()
	s.ToolsFixture.TearDownTest(c)
	s.BaseSuite.TearDownTest(c)
}

func (s *environSuite) TearDownSuite(c *gc.C) {
	s.testMAASObject.Close()
	s.restoreTimeouts()
	s.BaseSuite.TearDownSuite(c)
}

func getSimpleTestConfig(c *gc.C, extraAttrs coretesting.Attrs) *config.Config {
	attrs := coretesting.FakeConfig()
	attrs["type"] = "maas"
	attrs["maas-server"] = "http://maas.testing.invalid"
	attrs["maas-oauth"] = "a:b:c"
	for k, v := range extraAttrs {
		attrs[k] = v
	}
	cfg, err := config.New(config.NoDefaults, attrs)
	c.Assert(err, jc.ErrorIsNil)
	return cfg
}

func (*environSuite) TestSetConfigValidatesFirst(c *gc.C) {
	// SetConfig() validates the config change and disallows, for example,
	// changes in the environment name.
	oldCfg := getSimpleTestConfig(c, coretesting.Attrs{"name": "old-name"})
	newCfg := getSimpleTestConfig(c, coretesting.Attrs{"name": "new-name"})
	env, err := maas.NewEnviron(oldCfg)
	c.Assert(err, jc.ErrorIsNil)

	// SetConfig() fails, even though both the old and the new config are
	// individually valid.
	err = env.SetConfig(newCfg)
	c.Assert(err, gc.NotNil)
	c.Check(err, gc.ErrorMatches, ".*cannot change name.*")

	// The old config is still in place.  The new config never took effect.
	c.Check(env.Config().Name(), gc.Equals, "old-name")
}

func (*environSuite) TestSetConfigRefusesChangingAgentName(c *gc.C) {
	oldCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-one"})
	newCfgTwo := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-two"})
	env, err := maas.NewEnviron(oldCfg)
	c.Assert(err, jc.ErrorIsNil)

	// SetConfig() fails, even though both the old and the new config are
	// individually valid.
	err = env.SetConfig(newCfgTwo)
	c.Assert(err, gc.NotNil)
	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")

	// The old config is still in place.  The new config never took effect.
	c.Check(maas.MAASAgentName(env), gc.Equals, "agent-one")

	// It also refuses to set it to the empty string:
	err = env.SetConfig(getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""}))
	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")

	// And to nil
	err = env.SetConfig(getSimpleTestConfig(c, nil))
	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")
}

func (*environSuite) TestSetConfigAllowsEmptyFromNilAgentName(c *gc.C) {
	// bug #1256179 is that when using an older version of Juju (<1.16.2)
	// we didn't include maas-agent-name in the database, so it was 'nil'
	// in the OldConfig. However, when setting an environment, we would set
	// it to "" (because maasEnvironConfig.Validate ensures it is a 'valid'
	// string). We can't create that from NewEnviron or newConfig because
	// both of them Validate the contents. 'cmd/juju/environment
	// SetEnvironmentCommand' instead uses conn.State.EnvironConfig() which
	// just reads the content of the database into a map, so we just create
	// the map ourselves.

	// Even though we use 'nil' here, it actually stores it as "" because
	// 1.16.2 already validates the value
	baseCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""})
	c.Check(baseCfg.UnknownAttrs()["maas-agent-name"], gc.Equals, "")
	env, err := maas.NewEnviron(baseCfg)
	c.Assert(err, jc.ErrorIsNil)
	provider := env.Provider()

	attrs := coretesting.FakeConfig()
	// These are attrs we need to make it a valid Config, but would usually
	// be set by other infrastructure
	attrs["type"] = "maas"
	nilCfg, err := config.New(config.NoDefaults, attrs)
	c.Assert(err, jc.ErrorIsNil)
	validatedConfig, err := provider.Validate(baseCfg, nilCfg)
	c.Assert(err, jc.ErrorIsNil)
	c.Check(validatedConfig.UnknownAttrs()["maas-agent-name"], gc.Equals, "")
	// However, you can't set it to an actual value if you haven't been using a value
	valueCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-name"})
	_, err = provider.Validate(valueCfg, nilCfg)
	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")
}

func (*environSuite) TestSetConfigAllowsChangingNilAgentNameToEmptyString(c *gc.C) {
	oldCfg := getSimpleTestConfig(c, nil)
	newCfgTwo := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""})
	env, err := maas.NewEnviron(oldCfg)
	c.Assert(err, jc.ErrorIsNil)

	err = env.SetConfig(newCfgTwo)
	c.Assert(err, jc.ErrorIsNil)
	c.Check(maas.MAASAgentName(env), gc.Equals, "")
}

func (*environSuite) TestSetConfigUpdatesConfig(c *gc.C) {
	origAttrs := coretesting.Attrs{
		"server-name":  "http://maas2.testing.invalid",
		"maas-oauth":   "a:b:c",
		"admin-secret": "secret",
	}
	cfg := getSimpleTestConfig(c, origAttrs)
	env, err := maas.NewEnviron(cfg)
	c.Check(err, jc.ErrorIsNil)
	c.Check(env.Config().Name(), gc.Equals, "testenv")

	anotherServer := "http://maas.testing.invalid"
	anotherOauth := "c:d:e"
	anotherSecret := "secret2"
	newAttrs := coretesting.Attrs{
		"server-name":  anotherServer,
		"maas-oauth":   anotherOauth,
		"admin-secret": anotherSecret,
	}
	cfg2 := getSimpleTestConfig(c, newAttrs)
	errSetConfig := env.SetConfig(cfg2)
	c.Check(errSetConfig, gc.IsNil)
	c.Check(env.Config().Name(), gc.Equals, "testenv")
	authClient, _ := gomaasapi.NewAuthenticatedClient(anotherServer, anotherOauth, maas.APIVersion)
	maasClient := gomaasapi.NewMAAS(*authClient)
	MAASServer := maas.GetMAASClient(env)
	c.Check(MAASServer, gc.DeepEquals, maasClient)
}

func (*environSuite) TestNewEnvironSetsConfig(c *gc.C) {
	cfg := getSimpleTestConfig(c, nil)

	env, err := maas.NewEnviron(cfg)

	c.Check(err, jc.ErrorIsNil)
	c.Check(env.Config().Name(), gc.Equals, "testenv")
}

var expectedCloudinitConfig = []string{
	"set -xe",
	"mkdir -p '/var/lib/juju'\ncat > '/var/lib/juju/MAASmachine.txt' << 'EOF'\n'hostname: testing.invalid\n'\nEOF\nchmod 0755 '/var/lib/juju/MAASmachine.txt'",
}

var expectedCloudinitConfigWithBridge = []interface{}{
	"set -xe",
	"mkdir -p '/var/lib/juju'\ninstall -m 755 /dev/null '/var/lib/juju/MAASmachine.txt'\nprintf '%s\\n' ''\"'\"'hostname: testing.invalid\n'\"'\"'' > '/var/lib/juju/MAASmachine.txt'",
	"\n# In case we already created the bridge, don't do it again.\ngrep -q \"iface juju-br0 inet dhcp\" && exit 0\n\n# Discover primary interface at run-time using the default route (if set)\nPRIMARY_IFACE=$(ip route list exact 0/0 | egrep -o 'dev [^ ]+' | cut -b5-)\n\n# If $PRIMARY_IFACE is empty, there's nothing to do.\n[ -z \"$PRIMARY_IFACE\" ] && exit 0\n\n# Change the config to make $PRIMARY_IFACE manual instead of DHCP,\n# then create the bridge and enslave $PRIMARY_IFACE into it.\ngrep -q \"iface ${PRIMARY_IFACE} inet dhcp\" /etc/network/interfaces && \\\nsed -i \"s/iface ${PRIMARY_IFACE} inet dhcp//\" /etc/network/interfaces && \\\ncat >> /etc/network/interfaces << EOF\n\n# Primary interface (defining the default route)\niface ${PRIMARY_IFACE} inet manual\n\n# Bridge to use for LXC/KVM containers\nauto juju-br0\niface juju-br0 inet dhcp\n    bridge_ports ${PRIMARY_IFACE}\nEOF\n\n# Make the primary interface not auto-starting.\ngrep -q \"auto ${PRIMARY_IFACE}\" /etc/network/interfaces && \\\nsed -i \"s/auto ${PRIMARY_IFACE}//\" /etc/network/interfaces\n\n# Finally, stop $PRIMARY_IFACE and start the bridge instead.\nifdown -v ${PRIMARY_IFACE} ; ifup -v juju-br0\n",
}

func (*environSuite) TestNewCloudinitConfigWithFeatureFlag(c *gc.C) {
	cfg := getSimpleTestConfig(c, nil)
	env, err := maas.NewEnviron(cfg)
	c.Assert(err, jc.ErrorIsNil)
	cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal")
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue)
	c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedCloudinitConfig)
}

func (s *environSuite) TestNewCloudinitConfigNoFeatureFlag(c *gc.C) {
	s.SetFeatureFlags() // clear the flags.
	cfg := getSimpleTestConfig(c, nil)
	env, err := maas.NewEnviron(cfg)
	c.Assert(err, jc.ErrorIsNil)
	testCase := func() {
		cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal")
		c.Assert(err, jc.ErrorIsNil)
		c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue)
		c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedCloudinitConfig)
	}
	// First test the default case (address allocation feature flag on).
	testCase()

	// Now test with the flag off - expect the same.
	s.SetFeatureFlags() // clear the flags.
	testCase()
}

func (*environSuite) TestNewCloudinitConfigWithDisabledNetworkManagement(c *gc.C) {
	attrs := coretesting.Attrs{
		"disable-network-management": true,
	}
	cfg := getSimpleTestConfig(c, attrs)
	env, err := maas.NewEnviron(cfg)
	c.Assert(err, jc.ErrorIsNil)
	cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal")
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue)
	c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedCloudinitConfig)
}
<commit_msg>Remove spurious code<commit_after>// Copyright 2013 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package maas_test

import (
	stdtesting "testing"

	jc "github.com/juju/testing/checkers"
	gc "gopkg.in/check.v1"
	"launchpad.net/gomaasapi"

	"github.com/juju/juju/environs/config"
	envtesting "github.com/juju/juju/environs/testing"
	"github.com/juju/juju/feature"
	"github.com/juju/juju/provider/maas"
	coretesting "github.com/juju/juju/testing"
)

type environSuite struct {
	coretesting.BaseSuite
	envtesting.ToolsFixture
	testMAASObject  *gomaasapi.TestMAASObject
	restoreTimeouts func()
}

var _ = gc.Suite(&environSuite{})

func TestMAAS(t *stdtesting.T) {
	gc.TestingT(t)
}

// TDOO: jam 2013-12-06 This is copied from the providerSuite which is in a
// whitebox package maas. Either move that into a whitebox test so it can be
// shared, or into a 'testing' package so we can use it here.
func (s *environSuite) SetUpSuite(c *gc.C) {
	s.restoreTimeouts = envtesting.PatchAttemptStrategies(maas.ShortAttempt)
	s.BaseSuite.SetUpSuite(c)
	TestMAASObject := gomaasapi.NewTestMAAS("1.0")
	s.testMAASObject = TestMAASObject
}

func (s *environSuite) SetUpTest(c *gc.C) {
	s.BaseSuite.SetUpTest(c)
	s.ToolsFixture.SetUpTest(c)
	s.SetFeatureFlags(feature.AddressAllocation)
}

func (s *environSuite) TearDownTest(c *gc.C) {
	s.testMAASObject.TestServer.Clear()
	s.ToolsFixture.TearDownTest(c)
	s.BaseSuite.TearDownTest(c)
}

func (s *environSuite) TearDownSuite(c *gc.C) {
	s.testMAASObject.Close()
	s.restoreTimeouts()
	s.BaseSuite.TearDownSuite(c)
}

func getSimpleTestConfig(c *gc.C, extraAttrs coretesting.Attrs) *config.Config {
	attrs := coretesting.FakeConfig()
	attrs["type"] = "maas"
	attrs["maas-server"] = "http://maas.testing.invalid"
	attrs["maas-oauth"] = "a:b:c"
	for k, v := range extraAttrs {
		attrs[k] = v
	}
	cfg, err := config.New(config.NoDefaults, attrs)
	c.Assert(err, jc.ErrorIsNil)
	return cfg
}

func (*environSuite) TestSetConfigValidatesFirst(c *gc.C) {
	// SetConfig() validates the config change and disallows, for example,
	// changes in the environment name.
	oldCfg := getSimpleTestConfig(c, coretesting.Attrs{"name": "old-name"})
	newCfg := getSimpleTestConfig(c, coretesting.Attrs{"name": "new-name"})
	env, err := maas.NewEnviron(oldCfg)
	c.Assert(err, jc.ErrorIsNil)

	// SetConfig() fails, even though both the old and the new config are
	// individually valid.
	err = env.SetConfig(newCfg)
	c.Assert(err, gc.NotNil)
	c.Check(err, gc.ErrorMatches, ".*cannot change name.*")

	// The old config is still in place.  The new config never took effect.
	c.Check(env.Config().Name(), gc.Equals, "old-name")
}

func (*environSuite) TestSetConfigRefusesChangingAgentName(c *gc.C) {
	oldCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-one"})
	newCfgTwo := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-two"})
	env, err := maas.NewEnviron(oldCfg)
	c.Assert(err, jc.ErrorIsNil)

	// SetConfig() fails, even though both the old and the new config are
	// individually valid.
	err = env.SetConfig(newCfgTwo)
	c.Assert(err, gc.NotNil)
	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")

	// The old config is still in place.  The new config never took effect.
	c.Check(maas.MAASAgentName(env), gc.Equals, "agent-one")

	// It also refuses to set it to the empty string:
	err = env.SetConfig(getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""}))
	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")

	// And to nil
	err = env.SetConfig(getSimpleTestConfig(c, nil))
	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")
}

func (*environSuite) TestSetConfigAllowsEmptyFromNilAgentName(c *gc.C) {
	// bug #1256179 is that when using an older version of Juju (<1.16.2)
	// we didn't include maas-agent-name in the database, so it was 'nil'
	// in the OldConfig. However, when setting an environment, we would set
	// it to "" (because maasEnvironConfig.Validate ensures it is a 'valid'
	// string). We can't create that from NewEnviron or newConfig because
	// both of them Validate the contents. 'cmd/juju/environment
	// SetEnvironmentCommand' instead uses conn.State.EnvironConfig() which
	// just reads the content of the database into a map, so we just create
	// the map ourselves.

	// Even though we use 'nil' here, it actually stores it as "" because
	// 1.16.2 already validates the value
	baseCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""})
	c.Check(baseCfg.UnknownAttrs()["maas-agent-name"], gc.Equals, "")
	env, err := maas.NewEnviron(baseCfg)
	c.Assert(err, jc.ErrorIsNil)
	provider := env.Provider()

	attrs := coretesting.FakeConfig()
	// These are attrs we need to make it a valid Config, but would usually
	// be set by other infrastructure
	attrs["type"] = "maas"
	nilCfg, err := config.New(config.NoDefaults, attrs)
	c.Assert(err, jc.ErrorIsNil)
	validatedConfig, err := provider.Validate(baseCfg, nilCfg)
	c.Assert(err, jc.ErrorIsNil)
	c.Check(validatedConfig.UnknownAttrs()["maas-agent-name"], gc.Equals, "")
	// However, you can't set it to an actual value if you haven't been using a value
	valueCfg := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": "agent-name"})
	_, err = provider.Validate(valueCfg, nilCfg)
	c.Check(err, gc.ErrorMatches, ".*cannot change maas-agent-name.*")
}

func (*environSuite) TestSetConfigAllowsChangingNilAgentNameToEmptyString(c *gc.C) {
	oldCfg := getSimpleTestConfig(c, nil)
	newCfgTwo := getSimpleTestConfig(c, coretesting.Attrs{"maas-agent-name": ""})
	env, err := maas.NewEnviron(oldCfg)
	c.Assert(err, jc.ErrorIsNil)

	err = env.SetConfig(newCfgTwo)
	c.Assert(err, jc.ErrorIsNil)
	c.Check(maas.MAASAgentName(env), gc.Equals, "")
}

func (*environSuite) TestSetConfigUpdatesConfig(c *gc.C) {
	origAttrs := coretesting.Attrs{
		"server-name":  "http://maas2.testing.invalid",
		"maas-oauth":   "a:b:c",
		"admin-secret": "secret",
	}
	cfg := getSimpleTestConfig(c, origAttrs)
	env, err := maas.NewEnviron(cfg)
	c.Check(err, jc.ErrorIsNil)
	c.Check(env.Config().Name(), gc.Equals, "testenv")

	anotherServer := "http://maas.testing.invalid"
	anotherOauth := "c:d:e"
	anotherSecret := "secret2"
	newAttrs := coretesting.Attrs{
		"server-name":  anotherServer,
		"maas-oauth":   anotherOauth,
		"admin-secret": anotherSecret,
	}
	cfg2 := getSimpleTestConfig(c, newAttrs)
	errSetConfig := env.SetConfig(cfg2)
	c.Check(errSetConfig, gc.IsNil)
	c.Check(env.Config().Name(), gc.Equals, "testenv")
	authClient, _ := gomaasapi.NewAuthenticatedClient(anotherServer, anotherOauth, maas.APIVersion)
	maasClient := gomaasapi.NewMAAS(*authClient)
	MAASServer := maas.GetMAASClient(env)
	c.Check(MAASServer, gc.DeepEquals, maasClient)
}

func (*environSuite) TestNewEnvironSetsConfig(c *gc.C) {
	cfg := getSimpleTestConfig(c, nil)

	env, err := maas.NewEnviron(cfg)

	c.Check(err, jc.ErrorIsNil)
	c.Check(env.Config().Name(), gc.Equals, "testenv")
}

var expectedCloudinitConfig = []string{
	"set -xe",
	"mkdir -p '/var/lib/juju'\ncat > '/var/lib/juju/MAASmachine.txt' << 'EOF'\n'hostname: testing.invalid\n'\nEOF\nchmod 0755 '/var/lib/juju/MAASmachine.txt'",
}

var expectedCloudinitConfigWithBridge = []interface{}{
	"set -xe",
	"mkdir -p '/var/lib/juju'\ninstall -m 755 /dev/null '/var/lib/juju/MAASmachine.txt'\nprintf '%s\\n' ''\"'\"'hostname: testing.invalid\n'\"'\"'' > '/var/lib/juju/MAASmachine.txt'",
	"\n# In case we already created the bridge, don't do it again.\ngrep -q \"iface juju-br0 inet dhcp\" && exit 0\n\n# Discover primary interface at run-time using the default route (if set)\nPRIMARY_IFACE=$(ip route list exact 0/0 | egrep -o 'dev [^ ]+' | cut -b5-)\n\n# If $PRIMARY_IFACE is empty, there's nothing to do.\n[ -z \"$PRIMARY_IFACE\" ] && exit 0\n\n# Change the config to make $PRIMARY_IFACE manual instead of DHCP,\n# then create the bridge and enslave $PRIMARY_IFACE into it.\ngrep -q \"iface ${PRIMARY_IFACE} inet dhcp\" /etc/network/interfaces && \\\nsed -i \"s/iface ${PRIMARY_IFACE} inet dhcp//\" /etc/network/interfaces && \\\ncat >> /etc/network/interfaces << EOF\n\n# Primary interface (defining the default route)\niface ${PRIMARY_IFACE} inet manual\n\n# Bridge to use for LXC/KVM containers\nauto juju-br0\niface juju-br0 inet dhcp\n    bridge_ports ${PRIMARY_IFACE}\nEOF\n\n# Make the primary interface not auto-starting.\ngrep -q \"auto ${PRIMARY_IFACE}\" /etc/network/interfaces && \\\nsed -i \"s/auto ${PRIMARY_IFACE}//\" /etc/network/interfaces\n\n# Finally, stop $PRIMARY_IFACE and start the bridge instead.\nifdown -v ${PRIMARY_IFACE} ; ifup -v juju-br0\n",
}

func (*environSuite) TestNewCloudinitConfigWithFeatureFlag(c *gc.C) {
	cfg := getSimpleTestConfig(c, nil)
	env, err := maas.NewEnviron(cfg)
	c.Assert(err, jc.ErrorIsNil)
	cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal")
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue)
	c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedCloudinitConfig)
}

func (s *environSuite) TestNewCloudinitConfigNoFeatureFlag(c *gc.C) {
	cfg := getSimpleTestConfig(c, nil)
	env, err := maas.NewEnviron(cfg)
	c.Assert(err, jc.ErrorIsNil)
	testCase := func() {
		cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal")
		c.Assert(err, jc.ErrorIsNil)
		c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue)
		c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedCloudinitConfig)
	}
	// First test the default case (address allocation feature flag on).
	testCase()

	// Now test with the flag off - expect the same.
	s.SetFeatureFlags() // clear the flags.
	testCase()
}

func (*environSuite) TestNewCloudinitConfigWithDisabledNetworkManagement(c *gc.C) {
	attrs := coretesting.Attrs{
		"disable-network-management": true,
	}
	cfg := getSimpleTestConfig(c, attrs)
	env, err := maas.NewEnviron(cfg)
	c.Assert(err, jc.ErrorIsNil)
	cloudcfg, err := maas.NewCloudinitConfig(env, "testing.invalid", "eth0", "quantal")
	c.Assert(err, jc.ErrorIsNil)
	c.Assert(cloudcfg.SystemUpdate(), jc.IsTrue)
	c.Assert(cloudcfg.RunCmds(), jc.DeepEquals, expectedCloudinitConfig)
}
<|endoftext|>


<commit_before>package dfa

import (
	"hash/fnv"
)

type PredicateFunc func(interface{}) bool
type ActionFunc func(interface{}) interface{}

type exprBase struct {
	id   uint64
	expr string
}

type Node interface {
	Hash() uint64
	String() string
}

func (self *exprBase) String() string {
	return self.expr
}

func (self *exprBase) Hash() uint64 {
	return self.id
}

func (self *exprBase) Equals(other Node) bool {
	if self == other {
		return true
	} else if self == nil || other == nil {
		return false
	}
	return self.Hash() == other.Hash() && self.String() == other.String()
}

func MakeExprBase(expr string) exprBase {
	h := fnv.New64a()
	h.Write([]byte(expr))
	return exprBase{id: h.Sum64(), expr: expr}
}

type Predicate struct {
	exprBase
	functor PredicateFunc
}

func MakePredicate(expr string, functor PredicateFunc) *Predicate {
	return &Predicate{exprBase: MakeExprBase(expr), functor: functor}
}

func (self *Predicate) IsTrue(data interface{}) bool {
	return self.functor(data)
}

type Action struct {
	exprBase
	functor ActionFunc
}

func MakeAction(expr string, functor ActionFunc) *Action {
	return &Action{exprBase: MakeExprBase(expr), functor: functor}
}

func (self *Action) Apply(val interface{}) interface{} {
	return self.functor(val)
}

type Rule struct {
	Predicates []*Predicate
	Action     *Action
}

func MakeRule(preds []*Predicate, act *Action) *Rule {
	return &Rule{Predicates: preds, Action: act}
}

/**
some functions
*/

type BoolFn func(interface{}, interface{}) bool

func ltFn(a interface{}, b interface{}) bool {
	return a.(float64) < b.(float64)
}

func gtFn(a interface{}, b interface{}) bool {
	return a.(float64) > b.(float64)
}

func leFn(a interface{}, b interface{}) bool {
	return a.(float64) <= b.(float64)
}

func geFn(a interface{}, b interface{}) bool {
	return a.(float64) >= b.(float64)
}

func eqFn(a interface{}, b interface{}) bool {
	return a == b
}

func neFn(a interface{}, b interface{}) bool {
	return a != b
}

/**
we have lazy evaluation...
*/
<commit_msg>more refactoring<commit_after>package dfa

import (
	"hash/fnv"
)

// PredicateFn a function that represents the logic of a Predicate
type PredicateFn func(interface{}) bool

// ActionFn a function that represents the logic of an Action
type ActionFn func(interface{}) interface{}

type exprBase struct {
	id   uint64
	expr string
}

// Node a node in ast
type Node interface {
	Hash() uint64
	String() string
}

// String() return string representation of this expression
func (expr *exprBase) String() string {
	return expr.expr
}

func (expr *exprBase) Hash() uint64 {
	return expr.id
}

func (expr *exprBase) Equals(other Node) bool {
	if expr == other {
		return true
	} else if expr == nil || other == nil {
		return false
	}
	return expr.Hash() == other.Hash() && expr.String() == other.String()
}

func makeExprBase(expr string) exprBase {
	h := fnv.New64a()
	h.Write([]byte(expr))
	return exprBase{id: h.Sum64(), expr: expr}
}

// Predicate a predicate
type Predicate struct {
	exprBase
	functor PredicateFn
}

// MakePredicate create a predicate
func MakePredicate(expr string, functor PredicateFn) *Predicate {
	return &Predicate{exprBase: makeExprBase(expr), functor: functor}
}

// IsTrue given data, return whether the predicate evaluates to true
func (expr *Predicate) IsTrue(data interface{}) bool {
	return expr.functor(data)
}

// Action an action
type Action struct {
	exprBase
	functor ActionFn
}

// MakeAction create an Action
func MakeAction(expr string, functor ActionFn) *Action {
	return &Action{exprBase: makeExprBase(expr), functor: functor}
}

// Apply apply the action
func (expr *Action) Apply(val interface{}) interface{} {
	return expr.functor(val)
}

// Rule a rule
type Rule struct {
	Predicates []*Predicate
	Action     *Action
}

// MakeRule create a rule
func MakeRule(preds []*Predicate, act *Action) *Rule {
	return &Rule{Predicates: preds, Action: act}
}

/**
some functions
*/

// BoolFn functions that return bool
type BoolFn func(interface{}, interface{}) bool

// LtFn compare a and b
func LtFn(a interface{}, b interface{}) bool {
	return a.(float64) < b.(float64)
}

// GtFn compare a and b
func GtFn(a interface{}, b interface{}) bool {
	return a.(float64) > b.(float64)
}

// LeFn compare a and b
func LeFn(a interface{}, b interface{}) bool {
	return a.(float64) <= b.(float64)
}

// GeFn compare a and b
func GeFn(a interface{}, b interface{}) bool {
	return a.(float64) >= b.(float64)
}

// EqFn compare a and b
func EqFn(a interface{}, b interface{}) bool {
	return a == b
}

// NeFn compare a and b
func NeFn(a interface{}, b interface{}) bool {
	return a != b
}

/**
we have lazy evaluation...
*/
<|endoftext|>


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

// TODO: Dashboard upload

package main

import (
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
)

var cmdGet = &Command{
	UsageLine: "get [-d] [-fix] [-t] [-u] [build flags] [packages]",
	Short:     "download and install packages and dependencies",
	Long: `
Get downloads and installs the packages named by the import paths,
along with their dependencies.

The -d flag instructs get to stop after downloading the packages; that is,
it instructs get not to install the packages.

The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code.

The -t flag instructs get to also download the packages required to build
the tests for the specified packages.

The -u flag instructs get to use the network to update the named packages
and their dependencies.  By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages.

Get also accepts all the flags in the 'go build' and 'go install' commands,
to control the installation. See 'go help build'.

When checking out or updating a package, get looks for a branch or tag
that matches the locally installed version of Go. The most important
rule is that if the local installation is running version "go1", get
searches for a branch or tag named "go1". If no such version exists it
retrieves the most recent version of the package.

For more about specifying packages, see 'go help packages'.

For more about how 'go get' finds source code to
download, see 'go help remote'.

See also: go build, go install, go clean.
	`,
}

var getD = cmdGet.Flag.Bool("d", false, "")
var getT = cmdGet.Flag.Bool("t", false, "")
var getU = cmdGet.Flag.Bool("u", false, "")
var getFix = cmdGet.Flag.Bool("fix", false, "")

func init() {
	addBuildFlags(cmdGet)
	cmdGet.Run = runGet // break init loop
}

func runGet(cmd *Command, args []string) {
	// Phase 1.  Download/update.
	var stk importStack
	for _, arg := range downloadPaths(args) {
		download(arg, &stk, *getT)
	}
	exitIfErrors()

	// Phase 2. Rescan packages and reevaluate args list.

	// Code we downloaded and all code that depends on it
	// needs to be evicted from the package cache so that
	// the information will be recomputed.  Instead of keeping
	// track of the reverse dependency information, evict
	// everything.
	for name := range packageCache {
		delete(packageCache, name)
	}

	args = importPaths(args)

	// Phase 3.  Install.
	if *getD {
		// Download only.
		// Check delayed until now so that importPaths
		// has a chance to print errors.
		return
	}

	runInstall(cmd, args)
}

// downloadPaths prepares the list of paths to pass to download.
// It expands ... patterns that can be expanded.  If there is no match
// for a particular pattern, downloadPaths leaves it in the result list,
// in the hope that we can figure out the repository from the
// initial ...-free prefix.
func downloadPaths(args []string) []string {
	args = importPathsNoDotExpansion(args)
	var out []string
	for _, a := range args {
		if strings.Contains(a, "...") {
			var expand []string
			// Use matchPackagesInFS to avoid printing
			// warnings.  They will be printed by the
			// eventual call to importPaths instead.
			if build.IsLocalImport(a) {
				expand = matchPackagesInFS(a)
			} else {
				expand = matchPackages(a)
			}
			if len(expand) > 0 {
				out = append(out, expand...)
				continue
			}
		}
		out = append(out, a)
	}
	return out
}

// downloadCache records the import paths we have already
// considered during the download, to avoid duplicate work when
// there is more than one dependency sequence leading to
// a particular package.
var downloadCache = map[string]bool{}

// downloadRootCache records the version control repository
// root directories we have already considered during the download.
// For example, all the packages in the code.google.com/p/codesearch repo
// share the same root (the directory for that path), and we only need
// to run the hg commands to consider each repository once.
var downloadRootCache = map[string]bool{}

// download runs the download half of the get command
// for the package named by the argument.
func download(arg string, stk *importStack, getTestDeps bool) {
	p := loadPackage(arg, stk)

	// There's nothing to do if this is a package in the standard library.
	if p.Standard {
		return
	}

	// Only process each package once.
	if downloadCache[arg] {
		return
	}
	downloadCache[arg] = true

	pkgs := []*Package{p}
	wildcardOkay := len(*stk) == 0

	// Download if the package is missing, or update if we're using -u.
	if p.Dir == "" || *getU {
		// The actual download.
		stk.push(p.ImportPath)
		err := downloadPackage(p)
		if err != nil {
			errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
			stk.pop()
			return
		}

		args := []string{arg}
		// If the argument has a wildcard in it, re-evaluate the wildcard.
		// We delay this until after reloadPackage so that the old entry
		// for p has been replaced in the package cache.
		if wildcardOkay && strings.Contains(arg, "...") {
			if build.IsLocalImport(arg) {
				args = matchPackagesInFS(arg)
			} else {
				args = matchPackages(arg)
			}
		}

		// Clear all relevant package cache entries before
		// doing any new loads.
		for _, arg := range args {
			p := packageCache[arg]
			if p != nil {
				delete(packageCache, p.Dir)
				delete(packageCache, p.ImportPath)
			}
		}

		pkgs = pkgs[:0]
		for _, arg := range args {
			stk.push(arg)
			p := loadPackage(arg, stk)
			stk.pop()
			if p.Error != nil {
				errorf("%s", p.Error)
				continue
			}
			pkgs = append(pkgs, p)
		}
	}

	// Process package, which might now be multiple packages
	// due to wildcard expansion.
	for _, p := range pkgs {
		if *getFix {
			run(stringList(tool("fix"), relPaths(p.allgofiles)))

			// The imports might have changed, so reload again.
			p = reloadPackage(arg, stk)
			if p.Error != nil {
				errorf("%s", p.Error)
				return
			}
		}

		// Process dependencies, now that we know what they are.
		for _, dep := range p.deps {
			// Don't get test dependencies recursively.
			download(dep.ImportPath, stk, false)
		}
		if getTestDeps {
			// Process test dependencies when -t is specified.
			// (Don't get test dependencies for test dependencies.)
			for _, path := range p.TestImports {
				download(path, stk, false)
			}
			for _, path := range p.XTestImports {
				download(path, stk, false)
			}
		}
	}
}

// downloadPackage runs the create or download command
// to make the first copy of or update a copy of the given package.
func downloadPackage(p *Package) error {
	var (
		vcs            *vcsCmd
		repo, rootPath string
		err            error
	)
	if p.build.SrcRoot != "" {
		// Directory exists.  Look for checkout along path to src.
		vcs, rootPath, err = vcsForDir(p)
		if err != nil {
			return err
		}
		repo = "<local>" // should be unused; make distinctive
	} else {
		// Analyze the import path to determine the version control system,
		// repository, and the import path for the root of the repository.
		rr, err := repoRootForImportPath(p.ImportPath)
		if err != nil {
			return err
		}
		vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
	}

	if p.build.SrcRoot == "" {
		// Package not found.  Put in first directory of $GOPATH.
		list := filepath.SplitList(buildContext.GOPATH)
		if len(list) == 0 {
			return fmt.Errorf("cannot download, $GOPATH not set. For more details see: go help gopath")
		}
		// Guard against people setting GOPATH=$GOROOT.
		if list[0] == goroot {
			return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath")
		}
		p.build.SrcRoot = filepath.Join(list[0], "src")
		p.build.PkgRoot = filepath.Join(list[0], "pkg")
	}
	root := filepath.Join(p.build.SrcRoot, rootPath)
	// If we've considered this repository already, don't do it again.
	if downloadRootCache[root] {
		return nil
	}
	downloadRootCache[root] = true

	if buildV {
		fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
	}

	// Check that this is an appropriate place for the repo to be checked out.
	// The target directory must either not exist or have a repo checked out already.
	meta := filepath.Join(root, "."+vcs.cmd)
	st, err := os.Stat(meta)
	if err == nil && !st.IsDir() {
		return fmt.Errorf("%s exists but is not a directory", meta)
	}
	if err != nil {
		// Metadata directory does not exist.  Prepare to checkout new copy.
		// Some version control tools require the target directory not to exist.
		// We require that too, just to avoid stepping on existing work.
		if _, err := os.Stat(root); err == nil {
			return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
		}
		// Some version control tools require the parent of the target to exist.
		parent, _ := filepath.Split(root)
		if err = os.MkdirAll(parent, 0777); err != nil {
			return err
		}
		if err = vcs.create(root, repo); err != nil {
			return err
		}
	} else {
		// Metadata directory does exist; download incremental updates.
		if err = vcs.download(root); err != nil {
			return err
		}
	}

	if buildN {
		// Do not show tag sync in -n; it's noise more than anything,
		// and since we're not running commands, no tag will be found.
		// But avoid printing nothing.
		fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
		return nil
	}

	// Select and sync to appropriate version of the repository.
	tags, err := vcs.tags(root)
	if err != nil {
		return err
	}
	vers := runtime.Version()
	if i := strings.Index(vers, " "); i >= 0 {
		vers = vers[:i]
	}
	if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
		return err
	}

	return nil
}

// goTag matches go release tags such as go1 and go1.2.3.
// The numbers involved must be small (at most 4 digits),
// have no unnecessary leading zeros, and the version cannot
// end in .0 - it is go1, not go1.0 or go1.0.0.
var goTag = regexp.MustCompile(
	`^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`,
)

// selectTag returns the closest matching tag for a given version.
// Closest means the latest one that is not after the current release.
// Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
// Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
//
// NOTE(rsc): Eventually we will need to decide on some logic here.
// For now, there is only "go1".  This matches the docs in go help get.
func selectTag(goVersion string, tags []string) (match string) {
	for _, t := range tags {
		if t == "go1" {
			return "go1"
		}
	}
	return ""

	/*
		if goTag.MatchString(goVersion) {
			v := goVersion
			for _, t := range tags {
				if !goTag.MatchString(t) {
					continue
				}
				if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 {
					match = t
				}
			}
		}

		return match
	*/
}

// cmpGoVersion returns -1, 0, +1 reporting whether
// x < y, x == y, or x > y.
func cmpGoVersion(x, y string) int {
	// Malformed strings compare less than well-formed strings.
	if !goTag.MatchString(x) {
		return -1
	}
	if !goTag.MatchString(y) {
		return +1
	}

	// Compare numbers in sequence.
	xx := strings.Split(x[len("go"):], ".")
	yy := strings.Split(y[len("go"):], ".")

	for i := 0; i < len(xx) && i < len(yy); i++ {
		// The Atoi are guaranteed to succeed
		// because the versions match goTag.
		xi, _ := strconv.Atoi(xx[i])
		yi, _ := strconv.Atoi(yy[i])
		if xi < yi {
			return -1
		} else if xi > yi {
			return +1
		}
	}

	if len(xx) < len(yy) {
		return -1
	}
	if len(xx) > len(yy) {
		return +1
	}
	return 0
}
<commit_msg>cmd/go: report real package in errors for go get with wildcard<commit_after>// Copyright 2011 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.

// TODO: Dashboard upload

package main

import (
	"fmt"
	"go/build"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
)

var cmdGet = &Command{
	UsageLine: "get [-d] [-fix] [-t] [-u] [build flags] [packages]",
	Short:     "download and install packages and dependencies",
	Long: `
Get downloads and installs the packages named by the import paths,
along with their dependencies.

The -d flag instructs get to stop after downloading the packages; that is,
it instructs get not to install the packages.

The -fix flag instructs get to run the fix tool on the downloaded packages
before resolving dependencies or building the code.

The -t flag instructs get to also download the packages required to build
the tests for the specified packages.

The -u flag instructs get to use the network to update the named packages
and their dependencies.  By default, get uses the network to check out
missing packages but does not use it to look for updates to existing packages.

Get also accepts all the flags in the 'go build' and 'go install' commands,
to control the installation. See 'go help build'.

When checking out or updating a package, get looks for a branch or tag
that matches the locally installed version of Go. The most important
rule is that if the local installation is running version "go1", get
searches for a branch or tag named "go1". If no such version exists it
retrieves the most recent version of the package.

For more about specifying packages, see 'go help packages'.

For more about how 'go get' finds source code to
download, see 'go help remote'.

See also: go build, go install, go clean.
	`,
}

var getD = cmdGet.Flag.Bool("d", false, "")
var getT = cmdGet.Flag.Bool("t", false, "")
var getU = cmdGet.Flag.Bool("u", false, "")
var getFix = cmdGet.Flag.Bool("fix", false, "")

func init() {
	addBuildFlags(cmdGet)
	cmdGet.Run = runGet // break init loop
}

func runGet(cmd *Command, args []string) {
	// Phase 1.  Download/update.
	var stk importStack
	for _, arg := range downloadPaths(args) {
		download(arg, &stk, *getT)
	}
	exitIfErrors()

	// Phase 2. Rescan packages and reevaluate args list.

	// Code we downloaded and all code that depends on it
	// needs to be evicted from the package cache so that
	// the information will be recomputed.  Instead of keeping
	// track of the reverse dependency information, evict
	// everything.
	for name := range packageCache {
		delete(packageCache, name)
	}

	args = importPaths(args)

	// Phase 3.  Install.
	if *getD {
		// Download only.
		// Check delayed until now so that importPaths
		// has a chance to print errors.
		return
	}

	runInstall(cmd, args)
}

// downloadPaths prepares the list of paths to pass to download.
// It expands ... patterns that can be expanded.  If there is no match
// for a particular pattern, downloadPaths leaves it in the result list,
// in the hope that we can figure out the repository from the
// initial ...-free prefix.
func downloadPaths(args []string) []string {
	args = importPathsNoDotExpansion(args)
	var out []string
	for _, a := range args {
		if strings.Contains(a, "...") {
			var expand []string
			// Use matchPackagesInFS to avoid printing
			// warnings.  They will be printed by the
			// eventual call to importPaths instead.
			if build.IsLocalImport(a) {
				expand = matchPackagesInFS(a)
			} else {
				expand = matchPackages(a)
			}
			if len(expand) > 0 {
				out = append(out, expand...)
				continue
			}
		}
		out = append(out, a)
	}
	return out
}

// downloadCache records the import paths we have already
// considered during the download, to avoid duplicate work when
// there is more than one dependency sequence leading to
// a particular package.
var downloadCache = map[string]bool{}

// downloadRootCache records the version control repository
// root directories we have already considered during the download.
// For example, all the packages in the code.google.com/p/codesearch repo
// share the same root (the directory for that path), and we only need
// to run the hg commands to consider each repository once.
var downloadRootCache = map[string]bool{}

// download runs the download half of the get command
// for the package named by the argument.
func download(arg string, stk *importStack, getTestDeps bool) {
	p := loadPackage(arg, stk)

	// There's nothing to do if this is a package in the standard library.
	if p.Standard {
		return
	}

	// Only process each package once.
	if downloadCache[arg] {
		return
	}
	downloadCache[arg] = true

	pkgs := []*Package{p}
	wildcardOkay := len(*stk) == 0
	isWildcard := false

	// Download if the package is missing, or update if we're using -u.
	if p.Dir == "" || *getU {
		// The actual download.
		stk.push(p.ImportPath)
		err := downloadPackage(p)
		if err != nil {
			errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
			stk.pop()
			return
		}

		args := []string{arg}
		// If the argument has a wildcard in it, re-evaluate the wildcard.
		// We delay this until after reloadPackage so that the old entry
		// for p has been replaced in the package cache.
		if wildcardOkay && strings.Contains(arg, "...") {
			if build.IsLocalImport(arg) {
				args = matchPackagesInFS(arg)
			} else {
				args = matchPackages(arg)
			}
			isWildcard = true
		}

		// Clear all relevant package cache entries before
		// doing any new loads.
		for _, arg := range args {
			p := packageCache[arg]
			if p != nil {
				delete(packageCache, p.Dir)
				delete(packageCache, p.ImportPath)
			}
		}

		pkgs = pkgs[:0]
		for _, arg := range args {
			stk.push(arg)
			p := loadPackage(arg, stk)
			stk.pop()
			if p.Error != nil {
				errorf("%s", p.Error)
				continue
			}
			pkgs = append(pkgs, p)
		}
	}

	// Process package, which might now be multiple packages
	// due to wildcard expansion.
	for _, p := range pkgs {
		if *getFix {
			run(stringList(tool("fix"), relPaths(p.allgofiles)))

			// The imports might have changed, so reload again.
			p = reloadPackage(arg, stk)
			if p.Error != nil {
				errorf("%s", p.Error)
				return
			}
		}

		if isWildcard {
			// Report both the real package and the
			// wildcard in any error message.
			stk.push(p.ImportPath)
		}

		// Process dependencies, now that we know what they are.
		for _, dep := range p.deps {
			// Don't get test dependencies recursively.
			download(dep.ImportPath, stk, false)
		}
		if getTestDeps {
			// Process test dependencies when -t is specified.
			// (Don't get test dependencies for test dependencies.)
			for _, path := range p.TestImports {
				download(path, stk, false)
			}
			for _, path := range p.XTestImports {
				download(path, stk, false)
			}
		}

		if isWildcard {
			stk.pop()
		}
	}
}

// downloadPackage runs the create or download command
// to make the first copy of or update a copy of the given package.
func downloadPackage(p *Package) error {
	var (
		vcs            *vcsCmd
		repo, rootPath string
		err            error
	)
	if p.build.SrcRoot != "" {
		// Directory exists.  Look for checkout along path to src.
		vcs, rootPath, err = vcsForDir(p)
		if err != nil {
			return err
		}
		repo = "<local>" // should be unused; make distinctive
	} else {
		// Analyze the import path to determine the version control system,
		// repository, and the import path for the root of the repository.
		rr, err := repoRootForImportPath(p.ImportPath)
		if err != nil {
			return err
		}
		vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
	}

	if p.build.SrcRoot == "" {
		// Package not found.  Put in first directory of $GOPATH.
		list := filepath.SplitList(buildContext.GOPATH)
		if len(list) == 0 {
			return fmt.Errorf("cannot download, $GOPATH not set. For more details see: go help gopath")
		}
		// Guard against people setting GOPATH=$GOROOT.
		if list[0] == goroot {
			return fmt.Errorf("cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath")
		}
		p.build.SrcRoot = filepath.Join(list[0], "src")
		p.build.PkgRoot = filepath.Join(list[0], "pkg")
	}
	root := filepath.Join(p.build.SrcRoot, rootPath)
	// If we've considered this repository already, don't do it again.
	if downloadRootCache[root] {
		return nil
	}
	downloadRootCache[root] = true

	if buildV {
		fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath)
	}

	// Check that this is an appropriate place for the repo to be checked out.
	// The target directory must either not exist or have a repo checked out already.
	meta := filepath.Join(root, "."+vcs.cmd)
	st, err := os.Stat(meta)
	if err == nil && !st.IsDir() {
		return fmt.Errorf("%s exists but is not a directory", meta)
	}
	if err != nil {
		// Metadata directory does not exist.  Prepare to checkout new copy.
		// Some version control tools require the target directory not to exist.
		// We require that too, just to avoid stepping on existing work.
		if _, err := os.Stat(root); err == nil {
			return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta)
		}
		// Some version control tools require the parent of the target to exist.
		parent, _ := filepath.Split(root)
		if err = os.MkdirAll(parent, 0777); err != nil {
			return err
		}
		if err = vcs.create(root, repo); err != nil {
			return err
		}
	} else {
		// Metadata directory does exist; download incremental updates.
		if err = vcs.download(root); err != nil {
			return err
		}
	}

	if buildN {
		// Do not show tag sync in -n; it's noise more than anything,
		// and since we're not running commands, no tag will be found.
		// But avoid printing nothing.
		fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcs.cmd)
		return nil
	}

	// Select and sync to appropriate version of the repository.
	tags, err := vcs.tags(root)
	if err != nil {
		return err
	}
	vers := runtime.Version()
	if i := strings.Index(vers, " "); i >= 0 {
		vers = vers[:i]
	}
	if err := vcs.tagSync(root, selectTag(vers, tags)); err != nil {
		return err
	}

	return nil
}

// goTag matches go release tags such as go1 and go1.2.3.
// The numbers involved must be small (at most 4 digits),
// have no unnecessary leading zeros, and the version cannot
// end in .0 - it is go1, not go1.0 or go1.0.0.
var goTag = regexp.MustCompile(
	`^go((0|[1-9][0-9]{0,3})\.)*([1-9][0-9]{0,3})$`,
)

// selectTag returns the closest matching tag for a given version.
// Closest means the latest one that is not after the current release.
// Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form.
// Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number).
// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD".
//
// NOTE(rsc): Eventually we will need to decide on some logic here.
// For now, there is only "go1".  This matches the docs in go help get.
func selectTag(goVersion string, tags []string) (match string) {
	for _, t := range tags {
		if t == "go1" {
			return "go1"
		}
	}
	return ""

	/*
		if goTag.MatchString(goVersion) {
			v := goVersion
			for _, t := range tags {
				if !goTag.MatchString(t) {
					continue
				}
				if cmpGoVersion(match, t) < 0 && cmpGoVersion(t, v) <= 0 {
					match = t
				}
			}
		}

		return match
	*/
}

// cmpGoVersion returns -1, 0, +1 reporting whether
// x < y, x == y, or x > y.
func cmpGoVersion(x, y string) int {
	// Malformed strings compare less than well-formed strings.
	if !goTag.MatchString(x) {
		return -1
	}
	if !goTag.MatchString(y) {
		return +1
	}

	// Compare numbers in sequence.
	xx := strings.Split(x[len("go"):], ".")
	yy := strings.Split(y[len("go"):], ".")

	for i := 0; i < len(xx) && i < len(yy); i++ {
		// The Atoi are guaranteed to succeed
		// because the versions match goTag.
		xi, _ := strconv.Atoi(xx[i])
		yi, _ := strconv.Atoi(yy[i])
		if xi < yi {
			return -1
		} else if xi > yi {
			return +1
		}
	}

	if len(xx) < len(yy) {
		return -1
	}
	if len(xx) > len(yy) {
		return +1
	}
	return 0
}
<|endoftext|>


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

/*
 move (rename) files
 created by Beletti (rhiguita@gmail.com)
*/

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
)

func usage() {
	fmt.Printf("mv - missing file operand\n")
	os.Exit(1)
}

func main() {
	todir := false
	flag.Parse()

	switch flag.NArg() {
	case 0, 1:
		usage()
	}

	files := flag.Args()
	lf := files[len(files)-1]
	lfdir, err := os.Stat(lf)
	if err == nil {
		todir = lfdir.IsDir()
	}
	if flag.NArg() > 2 && todir == false {
		fmt.Printf("not a directory: %s\n", lf)
		os.Exit(1)
	}

	if len(files) == 2 && todir == false {
		// rename file
		err := os.Rename(files[0], files[1])
		if err != nil {
			log.Fatalf("%v", err)
		}
	} else {
		// "copying" N files to 1 directory
		for i := 0; i < flag.NArg()-1; i++ {
			ndir := lf + "/" + files[i]
			err := os.Rename(files[i], ndir)
			if err != nil {
				log.Fatalf("%v", err)
			}
		}
	}
}
<commit_msg>fix mv.go: path.Join<commit_after>// Copyright 2012 the u-root Authors. All rights reserved
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
 move (rename) files
 created by Beletti (rhiguita@gmail.com)
*/

package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"path"
)

func usage() {
	fmt.Printf("mv - missing file operand\n")
	os.Exit(1)
}

func main() {
	todir := false
	flag.Parse()

	switch flag.NArg() {
	case 0, 1:
		usage()
	}

	files := flag.Args()
	lf := files[len(files)-1]
	lfdir, err := os.Stat(lf)
	if err == nil {
		todir = lfdir.IsDir()
	}
	if flag.NArg() > 2 && todir == false {
		fmt.Printf("not a directory: %s\n", lf)
		os.Exit(1)
	}

	if len(files) == 2 && todir == false {
		// rename file
		err := os.Rename(files[0], files[1])
		if err != nil {
			log.Fatalf("%v", err)
		}
	} else {
		// "copying" N files to 1 directory
		for i := 0; i < flag.NArg()-1; i++ {
			ndir := path.Join(lf, files[i])
			err := os.Rename(files[i], ndir)
			if err != nil {
				log.Fatalf("%v", err)
			}
		}
	}
}
<|endoftext|>