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

package gapidapk

import (
	"bytes"
	"context"
	"io/ioutil"
	"strings"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/google/gapid/core/app"
	"github.com/google/gapid/core/event/task"
	"github.com/google/gapid/core/log"
	"github.com/google/gapid/core/os/android"
	"github.com/google/gapid/core/os/android/adb"
	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/core/os/flock"
)

const (
	sendDevInfoAction     = "com.google.android.gapid.action.SEND_DEV_INFO"
	sendDevInfoService    = "com.google.android.gapid.DeviceInfoService"
	sendDevInfoPort       = "gapid-devinfo"
	startServiceAttempts  = 3
	portListeningAttempts = 5
)

func init() {
	adb.RegisterDeviceInfoProvider(fetchDeviceInfo)
}

// Returns true if the device is listening to sendDevInfoPort, false if not.
// Error if failed at getting the port info.
func devInfoPortListening(ctx context.Context, d adb.Device) (bool, error) {
	var stdout bytes.Buffer
	if err := d.Shell("cat", "/proc/net/unix").Capture(&stdout, nil).Run(ctx); err != nil {
		return false, log.Errf(ctx, err, "Getting unix abstract port info...")
	}
	if strings.Contains(stdout.String(), sendDevInfoPort) {
		return true, nil
	}
	return false, nil
}

// startDevInfoService tries to start the fresh run of the package and start
// the service to send device info.
func startDevInfoService(ctx context.Context, d adb.Device, apk *APK) error {
	ctx = log.Enter(ctx, "startDevInfoService")
	var listening bool

	action := apk.ServiceActions.FindByName(sendDevInfoAction, sendDevInfoService)
	if action == nil {
		return log.Err(ctx, nil, "Service intent was not found")
	}

	// Try to start service.
	err := task.Retry(ctx, startServiceAttempts, 100*time.Millisecond,
		func(ctx context.Context) (bool, error) {
			log.I(ctx, "Attempt to start service: %s", sendDevInfoService)
			if err := d.StartService(ctx, *action); err != nil {
				return false, err
			}
			err := task.Retry(ctx, portListeningAttempts, time.Second, func(
				ctx context.Context) (bool, error) {
				var err error
				listening, err = devInfoPortListening(ctx, d)
				return listening, err
			})
			return listening, err
		})
	if listening {
		return nil
	}
	return log.Errf(ctx, err, "Start DevInfo service: Run out of attempts: %v",
		startServiceAttempts)
}

func fetchDeviceInfo(ctx context.Context, d adb.Device) error {
	apk, err := EnsureInstalled(ctx, d, device.UnknownABI)
	if err != nil {
		// The gapid.apk was not found. This can happen with partial builds used
		// for testing.
		// Don't return an error as this will prevent the device from being
		// registered and the device already comes with basic usable
		// information.
		log.W(ctx, "Couldn't find gapid.apk for device. Error: %v", err)
		return nil
	}

	// Close any previous runs of the apk
	apk.Stop(ctx)

	var cleanup app.Cleanup

	packages := []string{}
	supported, packageName, nextCleanup, err := d.PrepareGpuProfiling(ctx, apk.InstalledPackage)
	cleanup = cleanup.Then(nextCleanup)
	if err != nil {
		cleanup.Invoke(ctx)
		return err
	}
	if packageName != "" {
		packages = append(packages, packageName)
	}

	if supported {
		// Set driver package
		nextCleanup, err := android.SetupLayers(ctx, d, apk.Name, packages, []string{})
		cleanup = cleanup.Then(nextCleanup)
		defer cleanup.Invoke(ctx)
		if err != nil {
			return err
		}

		// Start perfetto producer
		if d.Instance().GetConfiguration().GetOS().GetAPIVersion() >= 29 {
			if err := EnsurePerfettoProducerLaunched(ctx, d); err != nil {
				return err
			}
		}
	}

	// Make sure the device is available to query device info, this is to prevent
	// Vulkan trace from happening at the same time than device info query.
	m := flock.Lock(d.Instance().GetSerial())
	defer m.Unlock()

	// Tries to start the device info service.
	if err := startDevInfoService(ctx, d, apk); err != nil {
		return log.Err(ctx, err, "Starting service")
	}

	sock, err := adb.ForwardAndConnect(ctx, d, sendDevInfoPort)
	if err != nil {
		return log.Err(ctx, err, "Connecting to service port")
	}

	defer sock.Close()

	data, err := ioutil.ReadAll(sock)
	if err != nil {
		return log.Err(ctx, err, "Reading data")
	}

	if err := proto.UnmarshalMerge(data, d.Instance()); err != nil {
		return log.Err(ctx, err, "Unmarshalling device Instance")
	}

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

package gapidapk

import (
	"bytes"
	"context"
	"io/ioutil"
	"strings"
	"time"

	"github.com/golang/protobuf/proto"
	"github.com/google/gapid/core/app"
	"github.com/google/gapid/core/event/task"
	"github.com/google/gapid/core/log"
	"github.com/google/gapid/core/os/android"
	"github.com/google/gapid/core/os/android/adb"
	"github.com/google/gapid/core/os/device"
	"github.com/google/gapid/core/os/flock"
)

const (
	sendDevInfoAction     = "com.google.android.gapid.action.SEND_DEV_INFO"
	sendDevInfoService    = "com.google.android.gapid.DeviceInfoService"
	sendDevInfoPort       = "gapid-devinfo"
	startServiceAttempts  = 3
	portListeningAttempts = 5
)

func init() {
	adb.RegisterDeviceInfoProvider(fetchDeviceInfo)
}

// Returns true if the device is listening to sendDevInfoPort, false if not.
// Error if failed at getting the port info.
func devInfoPortListening(ctx context.Context, d adb.Device) (bool, error) {
	var stdout bytes.Buffer
	if err := d.Shell("cat", "/proc/net/unix").Capture(&stdout, nil).Run(ctx); err != nil {
		return false, log.Errf(ctx, err, "Getting unix abstract port info...")
	}
	if strings.Contains(stdout.String(), sendDevInfoPort) {
		return true, nil
	}
	return false, nil
}

// startDevInfoService tries to start the fresh run of the package and start
// the service to send device info.
func startDevInfoService(ctx context.Context, d adb.Device, apk *APK) error {
	ctx = log.Enter(ctx, "startDevInfoService")
	var listening bool

	action := apk.ServiceActions.FindByName(sendDevInfoAction, sendDevInfoService)
	if action == nil {
		return log.Err(ctx, nil, "Service intent was not found")
	}

	// Try to start service.
	err := task.Retry(ctx, startServiceAttempts, 100*time.Millisecond,
		func(ctx context.Context) (bool, error) {
			log.I(ctx, "Attempt to start service: %s", sendDevInfoService)
			if err := d.StartService(ctx, *action); err != nil {
				return false, err
			}
			err := task.Retry(ctx, portListeningAttempts, time.Second, func(
				ctx context.Context) (bool, error) {
				var err error
				listening, err = devInfoPortListening(ctx, d)
				return listening, err
			})
			return listening, err
		})
	if listening {
		return nil
	}
	return log.Errf(ctx, err, "Start DevInfo service: Run out of attempts: %v",
		startServiceAttempts)
}

func fetchDeviceInfo(ctx context.Context, d adb.Device) error {
	apk, err := EnsureInstalled(ctx, d, device.UnknownABI)
	if err != nil {
		// The gapid.apk was not found. This can happen with partial builds used
		// for testing.
		// Don't return an error as this will prevent the device from being
		// registered and the device already comes with basic usable
		// information.
		log.W(ctx, "Couldn't find gapid.apk for device. Error: %v", err)
		return nil
	}

	// Close any previous runs of the apk
	apk.Stop(ctx)

	var cleanup app.Cleanup

	packages := []string{}
	supported, packageName, nextCleanup, err := d.PrepareGpuProfiling(ctx, apk.InstalledPackage)
	cleanup = cleanup.Then(nextCleanup)
	if err != nil {
		cleanup.Invoke(ctx)
		return err
	}
	if packageName != "" {
		packages = append(packages, packageName)
	}

	if supported {
		// Set driver package
		nextCleanup, err := android.SetupLayers(ctx, d, apk.Name, packages, []string{})
		cleanup = cleanup.Then(nextCleanup)
		defer cleanup.Invoke(ctx)
		if err != nil {
			return err
		}

		// Start perfetto producer
		if d.Instance().GetConfiguration().GetOS().GetAPIVersion() >= 29 {
			EnsurePerfettoProducerLaunched(ctx, d)
		}
	}

	// Make sure the device is available to query device info, this is to prevent
	// Vulkan trace from happening at the same time than device info query.
	m := flock.Lock(d.Instance().GetSerial())
	defer m.Unlock()

	// Tries to start the device info service.
	if err := startDevInfoService(ctx, d, apk); err != nil {
		return log.Err(ctx, err, "Starting service")
	}

	sock, err := adb.ForwardAndConnect(ctx, d, sendDevInfoPort)
	if err != nil {
		return log.Err(ctx, err, "Connecting to service port")
	}

	defer sock.Close()

	data, err := ioutil.ReadAll(sock)
	if err != nil {
		return log.Err(ctx, err, "Reading data")
	}

	if err := proto.UnmarshalMerge(data, d.Instance()); err != nil {
		return log.Err(ctx, err, "Unmarshalling device Instance")
	}

	return nil
}
<|endoftext|>


<commit_before>/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides encoding and decoding for Ethernet (both EthernetII and 802.3)
// packets.
package eth

import "fmt"
import "net"

import "github.com/ghedo/hype/packet"

type Packet struct {
	DstAddr     net.HardwareAddr `string:"dst"`
	SrcAddr     net.HardwareAddr `string:"src"`
	Type        EtherType
	Length      uint16
	pkt_payload packet.Packet    `string:"skip"`
}

type EtherType uint16

const (
	None EtherType = 0x0000
	ARP            = 0x0806
	IPv4           = 0x0800
	IPv6           = 0x86dd
	LLC            = 0x0001  /* pseudo ethertype */
	LLDP           = 0x088cc
	QinQ           = 0x88a8
	TRILL          = 0x22f3
	VLAN           = 0x8100
	WoL            = 0x0842
)

func Make() *Packet {
	return &Packet{
		DstAddr: make([]byte, 6),
		SrcAddr: make([]byte, 6),
		Length:  14,
	}
}

func (p *Packet) Equals(other packet.Packet) bool {
	return packet.Compare(p, other)
}

func (p *Packet) Answers(other packet.Packet) bool {
	if other == nil || other.GetType() != packet.Eth {
		return false
	}

	if p.Type != other.(*Packet).Type {
		return false
	}

	if p.Payload() != nil {
		return p.Payload().Answers(other.Payload())
	}

	return true
}

func (p *Packet) GetType() packet.Type {
	return packet.Eth
}

func (p *Packet) GetLength() uint16 {
	if p.Length > 0 && p.Type == LLC {
		return p.Length
	}

	if p.pkt_payload != nil {
		return p.pkt_payload.GetLength() + 14
	}

	return 14
}

func (p *Packet) Pack(raw_pkt *packet.Buffer) error {
	raw_pkt.Write(p.DstAddr)
	raw_pkt.Write(p.SrcAddr)

	if p.Type != LLC {
		raw_pkt.WriteI(p.Type)
	} else {
		raw_pkt.WriteI(p.Length)
	}

	return nil
}

func (p *Packet) Unpack(raw_pkt *packet.Buffer) error {
	p.DstAddr = net.HardwareAddr(raw_pkt.Next(6))
	p.SrcAddr = net.HardwareAddr(raw_pkt.Next(6))

	raw_pkt.ReadI(&p.Type)

	if p.Type < 0x0600 {
		p.Length = uint16(p.Type)
		p.Type   = LLC
	}

	return nil
}

func (p *Packet) Payload() packet.Packet {
	return p.pkt_payload
}

func (p *Packet) GuessPayloadType() packet.Type {
	return EtherTypeToType(p.Type)
}

func (p *Packet) SetPayload(pl packet.Packet) error {
	p.pkt_payload = pl
	p.Type        = TypeToEtherType(pl.GetType())
	p.Length     += pl.GetLength()

	return nil
}

func (p *Packet) InitChecksum(csum uint32) {
}

func (p *Packet) String() string {
	return packet.Stringify(p)
}

var ethertype_to_type_map = [][2]uint16{
	{ uint16(None),  uint16(packet.None)  },
	{ uint16(ARP),   uint16(packet.ARP)   },
	{ uint16(IPv4),  uint16(packet.IPv4)  },
	{ uint16(IPv6),  uint16(packet.IPv6)  },
	{ uint16(LLC),   uint16(packet.LLC)   },
	{ uint16(LLDP),  uint16(packet.LLDP)  },
	{ uint16(VLAN),  uint16(packet.VLAN)  },
	{ uint16(QinQ),  uint16(packet.VLAN)  },
	{ uint16(TRILL), uint16(packet.TRILL) },
	{ uint16(WoL),   uint16(packet.WoL)   },
}

// Create a new Type from the given EtherType.
func EtherTypeToType(ethertype EtherType) packet.Type {
	for _, t := range ethertype_to_type_map {
		if t[0] == uint16(ethertype) {
			return packet.Type(t[1])
		}
	}

	return packet.Raw
}

// Convert the Type to the corresponding EtherType.
func TypeToEtherType(pkttype packet.Type) EtherType {
	for _, t := range ethertype_to_type_map {
		if t[1] == uint16(pkttype) {
			return EtherType(t[0])
		}
	}

	return None
}

func (t EtherType) String() string {
	switch t {
	case ARP:   return "ARP"
	case IPv4:  return "IPv4"
	case IPv6:  return "IPv6"
	case LLC:   return "LLC"
	case LLDP:  return "LLDP"
	case None:  return "None"
	case QinQ:  return "QinQ"
	case TRILL: return "TRILL"
	case VLAN:  return "VLAN"
	case WoL:   return "WoL"
	default:    return fmt.Sprintf("0x%x", uint16(t))
	}
}
<commit_msg>eth: don't update length if not a 802.3 frame<commit_after>/*
 * Network packet analysis framework.
 *
 * Copyright (c) 2014, Alessandro Ghedini
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Provides encoding and decoding for Ethernet (both EthernetII and 802.3)
// packets.
package eth

import "fmt"
import "net"

import "github.com/ghedo/hype/packet"

type Packet struct {
	DstAddr     net.HardwareAddr `string:"dst"`
	SrcAddr     net.HardwareAddr `string:"src"`
	Type        EtherType
	Length      uint16
	pkt_payload packet.Packet    `string:"skip"`
}

type EtherType uint16

const (
	None EtherType = 0x0000
	ARP            = 0x0806
	IPv4           = 0x0800
	IPv6           = 0x86dd
	LLC            = 0x0001  /* pseudo ethertype */
	LLDP           = 0x088cc
	QinQ           = 0x88a8
	TRILL          = 0x22f3
	VLAN           = 0x8100
	WoL            = 0x0842
)

func Make() *Packet {
	return &Packet{
		DstAddr: make([]byte, 6),
		SrcAddr: make([]byte, 6),
		Length:  14,
	}
}

func (p *Packet) Equals(other packet.Packet) bool {
	return packet.Compare(p, other)
}

func (p *Packet) Answers(other packet.Packet) bool {
	if other == nil || other.GetType() != packet.Eth {
		return false
	}

	if p.Type != other.(*Packet).Type {
		return false
	}

	if p.Payload() != nil {
		return p.Payload().Answers(other.Payload())
	}

	return true
}

func (p *Packet) GetType() packet.Type {
	return packet.Eth
}

func (p *Packet) GetLength() uint16 {
	if p.Length > 0 && p.Type == LLC {
		return p.Length
	}

	if p.pkt_payload != nil {
		return p.pkt_payload.GetLength() + 14
	}

	return 14
}

func (p *Packet) Pack(raw_pkt *packet.Buffer) error {
	raw_pkt.Write(p.DstAddr)
	raw_pkt.Write(p.SrcAddr)

	if p.Type != LLC {
		raw_pkt.WriteI(p.Type)
	} else {
		raw_pkt.WriteI(p.Length)
	}

	return nil
}

func (p *Packet) Unpack(raw_pkt *packet.Buffer) error {
	p.DstAddr = net.HardwareAddr(raw_pkt.Next(6))
	p.SrcAddr = net.HardwareAddr(raw_pkt.Next(6))

	raw_pkt.ReadI(&p.Type)

	if p.Type < 0x0600 {
		p.Length = uint16(p.Type)
		p.Type   = LLC
	}

	return nil
}

func (p *Packet) Payload() packet.Packet {
	return p.pkt_payload
}

func (p *Packet) GuessPayloadType() packet.Type {
	return EtherTypeToType(p.Type)
}

func (p *Packet) SetPayload(pl packet.Packet) error {
	p.pkt_payload = pl
	p.Type        = TypeToEtherType(pl.GetType())

	if p.Type < 0x0600 {
		p.Length += pl.GetLength()
	}

	return nil
}

func (p *Packet) InitChecksum(csum uint32) {
}

func (p *Packet) String() string {
	return packet.Stringify(p)
}

var ethertype_to_type_map = [][2]uint16{
	{ uint16(None),  uint16(packet.None)  },
	{ uint16(ARP),   uint16(packet.ARP)   },
	{ uint16(IPv4),  uint16(packet.IPv4)  },
	{ uint16(IPv6),  uint16(packet.IPv6)  },
	{ uint16(LLC),   uint16(packet.LLC)   },
	{ uint16(LLDP),  uint16(packet.LLDP)  },
	{ uint16(VLAN),  uint16(packet.VLAN)  },
	{ uint16(QinQ),  uint16(packet.VLAN)  },
	{ uint16(TRILL), uint16(packet.TRILL) },
	{ uint16(WoL),   uint16(packet.WoL)   },
}

// Create a new Type from the given EtherType.
func EtherTypeToType(ethertype EtherType) packet.Type {
	for _, t := range ethertype_to_type_map {
		if t[0] == uint16(ethertype) {
			return packet.Type(t[1])
		}
	}

	return packet.Raw
}

// Convert the Type to the corresponding EtherType.
func TypeToEtherType(pkttype packet.Type) EtherType {
	for _, t := range ethertype_to_type_map {
		if t[1] == uint16(pkttype) {
			return EtherType(t[0])
		}
	}

	return None
}

func (t EtherType) String() string {
	switch t {
	case ARP:   return "ARP"
	case IPv4:  return "IPv4"
	case IPv6:  return "IPv6"
	case LLC:   return "LLC"
	case LLDP:  return "LLDP"
	case None:  return "None"
	case QinQ:  return "QinQ"
	case TRILL: return "TRILL"
	case VLAN:  return "VLAN"
	case WoL:   return "WoL"
	default:    return fmt.Sprintf("0x%x", uint16(t))
	}
}
<|endoftext|>


<commit_before>/*
This program generates the protobuf and SteamLanguage files from the SteamKit data.
*/
package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

var printCommands = false

func main() {
	args := strings.Join(os.Args[1:], " ")

	found := false
	if strings.Contains(args, "clean") {
		clean()
		found = true
	}
	if strings.Contains(args, "steamlang") {
		buildSteamLanguage()
		found = true
	}
	if strings.Contains(args, "proto") {
		buildProto()
		found = true
	}

	if !found {
		os.Stderr.WriteString("Invalid target!\nAvailable targets: clean, proto, steamlang\n")
		os.Exit(1)
	}
}

func clean() {
	print("# Cleaning")
	cleanGlob("../internal/**/*.pb.go")
	cleanGlob("../tf2/internal/**/*.pb.go")

	os.Remove("../internal/steamlang/enums.go")
	os.Remove("../internal/steamlang/messages.go")
}

func cleanGlob(pattern string) {
	protos, _ := filepath.Glob(pattern)
	for _, proto := range protos {
		err := os.Remove(proto)
		if err != nil {
			panic(err)
		}
	}
}

func buildSteamLanguage() {
	print("# Building Steam Language")
	exePath := "./GoSteamLanguageGenerator/bin/Debug/GoSteamLanguageGenerator.exe"

	if runtime.GOOS != "windows" {
		execute("mono", exePath, "./SteamKit", "../internal/steamlang")
	} else {
		execute(exePath, "./SteamKit", "../internal/steamlang")
	}
	execute("gofmt", "-w", "../internal/steamlang/enums.go", "../internal/steamlang/messages.go")
}

func buildProto() {
	print("# Building Protobufs")

	buildProtoMap("steamclient", clientProtoFiles, "../internal/protobuf")
	buildProtoMap("tf", tf2ProtoFiles, "../tf2/internal/protobuf")
}

func buildProtoMap(srcSubdir string, files map[string]string, outDir string) {
	os.MkdirAll(outDir, os.ModePerm)
	for proto, out := range files {
		full := filepath.Join(outDir, out)
		compileProto("SteamKit/Resources/Protobufs", srcSubdir, proto, full)
		fixProto(full)
	}
}

// Maps the proto files to their target files.
// See `SteamKit/Resources/Protobufs/steamclient/generate-base.bat` for reference.
var clientProtoFiles = map[string]string{
	"steammessages_base.proto":   "base.pb.go",
	"encrypted_app_ticket.proto": "app_ticket.pb.go",

	"steammessages_clientserver.proto":   "client_server.pb.go",
	"steammessages_clientserver_2.proto": "client_server_2.pb.go",

	"content_manifest.proto": "content_manifest.pb.go",

	"steammessages_unified_base.steamclient.proto":      "unified/base.pb.go",
	"steammessages_cloud.steamclient.proto":             "unified/cloud.pb.go",
	"steammessages_credentials.steamclient.proto":       "unified/credentials.pb.go",
	"steammessages_deviceauth.steamclient.proto":        "unified/deviceauth.pb.go",
	"steammessages_gamenotifications.steamclient.proto": "unified/gamenotifications.pb.go",
	"steammessages_offline.steamclient.proto":           "unified/offline.pb.go",
	"steammessages_parental.steamclient.proto":          "unified/parental.pb.go",
	"steammessages_partnerapps.steamclient.proto":       "unified/partnerapps.pb.go",
	"steammessages_player.steamclient.proto":            "unified/player.pb.go",
	"steammessages_publishedfile.steamclient.proto":     "unified/publishedfile.pb.go",
}

var tf2ProtoFiles = map[string]string{
	"base_gcmessages.proto":  "base.pb.go",
	"econ_gcmessages.proto":  "econ.pb.go",
	"gcsdk_gcmessages.proto": "gcsdk.pb.go",
	"tf_gcmessages.proto":    "tf.pb.go",
	"gcsystemmsgs.proto":     "system.pb.go",
}

func compileProto(srcBase, srcSubdir, proto, target string) {
	outDir, _ := filepath.Split(target)
	err := os.MkdirAll(outDir, os.ModePerm)
	if err != nil {
		panic(err)
	}
	execute("protoc", "--go_out="+outDir, "-I="+srcBase+"/"+srcSubdir, "-I="+srcBase, filepath.Join(srcBase, srcSubdir, proto))
	out := strings.Replace(filepath.Join(outDir, proto), ".proto", ".pb.go", 1)
	err = forceRename(out, target)
	if err != nil {
		panic(err)
	}
}

func forceRename(from, to string) error {
	if from != to {
		os.Remove(to)
	}
	return os.Rename(from, to)
}

var pkgRegex = regexp.MustCompile(`(package \w+)`)
var pkgCommentRegex = regexp.MustCompile(`(?s)(\/\*.*?\*\/\n)package`)
var unusedImportCommentRegex = regexp.MustCompile("// discarding unused import .*\n")

func fixProto(path string) {
	// goprotobuf is really bad at dependencies, so we must fix them manually...
	// It tries to load each dependency of a file as a seperate package (but in a very, very wrong way).
	// Because we want some files in the same package, we'll remove those imports to local files.

	file, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, path, file, parser.ImportsOnly)
	if err != nil {
		panic("Error parsing " + path + ": " + err.Error())
	}

	importsToRemove := make([]*ast.ImportSpec, 0)
	for _, i := range f.Imports {
		// We remove all local imports
		if i.Path.Value == "\".\"" {
			importsToRemove = append(importsToRemove, i)
		}
	}

	for _, itr := range importsToRemove {
		// remove the package name from all types
		file = bytes.Replace(file, []byte(itr.Name.Name+"."), []byte{}, -1)
		// and remove the import itself
		file = bytes.Replace(file, []byte(fmt.Sprintf("import %v %v\n", itr.Name.Name, itr.Path.Value)), []byte{}, -1)
	}

	// remove the package comment because it just includes a list of all messages and
	// creates collisions between the others.
	file = cutAllSubmatch(pkgCommentRegex, file, 1)

	// remove warnings
	file = unusedImportCommentRegex.ReplaceAllLiteral(file, []byte{})

	// fix the package name
	file = pkgRegex.ReplaceAll(file, []byte("package "+inferPackageName(path)))

	// fix the google dependency;
	// we just reuse the one from protoc-gen-go
	file = bytes.Replace(file, []byte("google/protobuf"), []byte("github.com/golang/protobuf/protoc-gen-go/descriptor"), -1)

	err = ioutil.WriteFile(path, file, os.ModePerm)
	if err != nil {
		panic(err)
	}
}

func inferPackageName(path string) string {
	pieces := strings.Split(path, string(filepath.Separator))
	return pieces[len(pieces)-2]
}

func cutAllSubmatch(r *regexp.Regexp, b []byte, n int) []byte {
	i := r.FindSubmatchIndex(b)
	return bytesCut(b, i[2*n], i[2*n+1])
}

// Removes the given section from the byte array
func bytesCut(b []byte, from, to int) []byte {
	buf := new(bytes.Buffer)
	buf.Write(b[:from])
	buf.Write(b[to:])
	return buf.Bytes()
}

func print(text string) { os.Stdout.WriteString(text + "\n") }

func printerr(text string) { os.Stderr.WriteString(text + "\n") }

// This writer appends a "> " after every newline so that the outpout appears quoted.
type QuotedWriter struct {
	w       io.Writer
	started bool
}

func NewQuotedWriter(w io.Writer) *QuotedWriter {
	return &QuotedWriter{w, false}
}

func (w *QuotedWriter) Write(p []byte) (n int, err error) {
	if !w.started {
		_, err = w.w.Write([]byte("> "))
		if err != nil {
			return n, err
		}
		w.started = true
	}

	for i, c := range p {
		if c == '\n' {
			nw, err := w.w.Write(p[n : i+1])
			n += nw
			if err != nil {
				return n, err
			}

			_, err = w.w.Write([]byte("> "))
			if err != nil {
				return n, err
			}
		}
	}
	if n != len(p) {
		nw, err := w.w.Write(p[n:len(p)])
		n += nw
		return n, err
	}
	return
}

func execute(command string, args ...string) {
	if printCommands {
		print(command + " " + strings.Join(args, " "))
	}
	cmd := exec.Command(command, args...)
	cmd.Stdout = NewQuotedWriter(os.Stdout)
	cmd.Stderr = NewQuotedWriter(os.Stderr)
	err := cmd.Run()
	if err != nil {
		printerr(err.Error())
		os.Exit(1)
	}
}
<commit_msg>Fix compilation of generated protobuf structs by adding yet another hack to generator.go.<commit_after>/*
This program generates the protobuf and SteamLanguage files from the SteamKit data.
*/
package main

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/parser"
	"go/token"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
)

var printCommands = false

func main() {
	args := strings.Join(os.Args[1:], " ")

	found := false
	if strings.Contains(args, "clean") {
		clean()
		found = true
	}
	if strings.Contains(args, "steamlang") {
		buildSteamLanguage()
		found = true
	}
	if strings.Contains(args, "proto") {
		buildProto()
		found = true
	}

	if !found {
		os.Stderr.WriteString("Invalid target!\nAvailable targets: clean, proto, steamlang\n")
		os.Exit(1)
	}
}

func clean() {
	print("# Cleaning")
	cleanGlob("../internal/**/*.pb.go")
	cleanGlob("../tf2/internal/**/*.pb.go")

	os.Remove("../internal/steamlang/enums.go")
	os.Remove("../internal/steamlang/messages.go")
}

func cleanGlob(pattern string) {
	protos, _ := filepath.Glob(pattern)
	for _, proto := range protos {
		err := os.Remove(proto)
		if err != nil {
			panic(err)
		}
	}
}

func buildSteamLanguage() {
	print("# Building Steam Language")
	exePath := "./GoSteamLanguageGenerator/bin/Debug/GoSteamLanguageGenerator.exe"

	if runtime.GOOS != "windows" {
		execute("mono", exePath, "./SteamKit", "../internal/steamlang")
	} else {
		execute(exePath, "./SteamKit", "../internal/steamlang")
	}
	execute("gofmt", "-w", "../internal/steamlang/enums.go", "../internal/steamlang/messages.go")
}

func buildProto() {
	print("# Building Protobufs")

	buildProtoMap("steamclient", clientProtoFiles, "../internal/protobuf")
	buildProtoMap("tf", tf2ProtoFiles, "../tf2/internal/protobuf")
}

func buildProtoMap(srcSubdir string, files map[string]string, outDir string) {
	os.MkdirAll(outDir, os.ModePerm)
	for proto, out := range files {
		full := filepath.Join(outDir, out)
		compileProto("SteamKit/Resources/Protobufs", srcSubdir, proto, full)
		fixProto(full)
	}
}

// Maps the proto files to their target files.
// See `SteamKit/Resources/Protobufs/steamclient/generate-base.bat` for reference.
var clientProtoFiles = map[string]string{
	"steammessages_base.proto":   "base.pb.go",
	"encrypted_app_ticket.proto": "app_ticket.pb.go",

	"steammessages_clientserver.proto":   "client_server.pb.go",
	"steammessages_clientserver_2.proto": "client_server_2.pb.go",

	"content_manifest.proto": "content_manifest.pb.go",

	"steammessages_unified_base.steamclient.proto":      "unified/base.pb.go",
	"steammessages_cloud.steamclient.proto":             "unified/cloud.pb.go",
	"steammessages_credentials.steamclient.proto":       "unified/credentials.pb.go",
	"steammessages_deviceauth.steamclient.proto":        "unified/deviceauth.pb.go",
	"steammessages_gamenotifications.steamclient.proto": "unified/gamenotifications.pb.go",
	"steammessages_offline.steamclient.proto":           "unified/offline.pb.go",
	"steammessages_parental.steamclient.proto":          "unified/parental.pb.go",
	"steammessages_partnerapps.steamclient.proto":       "unified/partnerapps.pb.go",
	"steammessages_player.steamclient.proto":            "unified/player.pb.go",
	"steammessages_publishedfile.steamclient.proto":     "unified/publishedfile.pb.go",
}

var tf2ProtoFiles = map[string]string{
	"base_gcmessages.proto":  "base.pb.go",
	"econ_gcmessages.proto":  "econ.pb.go",
	"gcsdk_gcmessages.proto": "gcsdk.pb.go",
	"tf_gcmessages.proto":    "tf.pb.go",
	"gcsystemmsgs.proto":     "system.pb.go",
}

func compileProto(srcBase, srcSubdir, proto, target string) {
	outDir, _ := filepath.Split(target)
	err := os.MkdirAll(outDir, os.ModePerm)
	if err != nil {
		panic(err)
	}
	execute("protoc", "--go_out="+outDir, "-I="+srcBase+"/"+srcSubdir, "-I="+srcBase, filepath.Join(srcBase, srcSubdir, proto))
	out := strings.Replace(filepath.Join(outDir, proto), ".proto", ".pb.go", 1)
	err = forceRename(out, target)
	if err != nil {
		panic(err)
	}
}

func forceRename(from, to string) error {
	if from != to {
		os.Remove(to)
	}
	return os.Rename(from, to)
}

var pkgRegex = regexp.MustCompile(`(package \w+)`)
var pkgCommentRegex = regexp.MustCompile(`(?s)(\/\*.*?\*\/\n)package`)
var unusedImportCommentRegex = regexp.MustCompile("// discarding unused import .*\n")
var fileDescriptorVarRegex = regexp.MustCompile(`fileDescriptor\d+`)

func fixProto(path string) {
	// goprotobuf is really bad at dependencies, so we must fix them manually...
	// It tries to load each dependency of a file as a seperate package (but in a very, very wrong way).
	// Because we want some files in the same package, we'll remove those imports to local files.

	file, err := ioutil.ReadFile(path)
	if err != nil {
		panic(err)
	}

	fset := token.NewFileSet()
	f, err := parser.ParseFile(fset, path, file, parser.ImportsOnly)
	if err != nil {
		panic("Error parsing " + path + ": " + err.Error())
	}

	importsToRemove := make([]*ast.ImportSpec, 0)
	for _, i := range f.Imports {
		// We remove all local imports
		if i.Path.Value == "\".\"" {
			importsToRemove = append(importsToRemove, i)
		}
	}

	for _, itr := range importsToRemove {
		// remove the package name from all types
		file = bytes.Replace(file, []byte(itr.Name.Name+"."), []byte{}, -1)
		// and remove the import itself
		file = bytes.Replace(file, []byte(fmt.Sprintf("import %v %v\n", itr.Name.Name, itr.Path.Value)), []byte{}, -1)
	}

	// remove the package comment because it just includes a list of all messages and
	// collides not only with the other compiled protobuf files, but also our own documentation.
	file = cutAllSubmatch(pkgCommentRegex, file, 1)

	// remove warnings
	file = unusedImportCommentRegex.ReplaceAllLiteral(file, []byte{})

	// fix the package name
	file = pkgRegex.ReplaceAll(file, []byte("package "+inferPackageName(path)))

	// fix the google dependency;
	// we just reuse the one from protoc-gen-go
	file = bytes.Replace(file, []byte("google/protobuf"), []byte("github.com/golang/protobuf/protoc-gen-go/descriptor"), -1)

	// we need to prefix local variables created by protoc-gen-go so that they don't clash with others in the same package
	filename := strings.Split(filepath.Base(path), ".")[0]
	file = fileDescriptorVarRegex.ReplaceAllFunc(file, func(match []byte) []byte {
		return []byte(filename + "_" + string(match))
	})

	err = ioutil.WriteFile(path, file, os.ModePerm)
	if err != nil {
		panic(err)
	}
}

func inferPackageName(path string) string {
	pieces := strings.Split(path, string(filepath.Separator))
	return pieces[len(pieces)-2]
}

func cutAllSubmatch(r *regexp.Regexp, b []byte, n int) []byte {
	i := r.FindSubmatchIndex(b)
	return bytesCut(b, i[2*n], i[2*n+1])
}

// Removes the given section from the byte array
func bytesCut(b []byte, from, to int) []byte {
	buf := new(bytes.Buffer)
	buf.Write(b[:from])
	buf.Write(b[to:])
	return buf.Bytes()
}

func print(text string) { os.Stdout.WriteString(text + "\n") }

func printerr(text string) { os.Stderr.WriteString(text + "\n") }

// This writer appends a "> " after every newline so that the outpout appears quoted.
type QuotedWriter struct {
	w       io.Writer
	started bool
}

func NewQuotedWriter(w io.Writer) *QuotedWriter {
	return &QuotedWriter{w, false}
}

func (w *QuotedWriter) Write(p []byte) (n int, err error) {
	if !w.started {
		_, err = w.w.Write([]byte("> "))
		if err != nil {
			return n, err
		}
		w.started = true
	}

	for i, c := range p {
		if c == '\n' {
			nw, err := w.w.Write(p[n : i+1])
			n += nw
			if err != nil {
				return n, err
			}

			_, err = w.w.Write([]byte("> "))
			if err != nil {
				return n, err
			}
		}
	}
	if n != len(p) {
		nw, err := w.w.Write(p[n:len(p)])
		n += nw
		return n, err
	}
	return
}

func execute(command string, args ...string) {
	if printCommands {
		print(command + " " + strings.Join(args, " "))
	}
	cmd := exec.Command(command, args...)
	cmd.Stdout = NewQuotedWriter(os.Stdout)
	cmd.Stderr = NewQuotedWriter(os.Stderr)
	err := cmd.Run()
	if err != nil {
		printerr(err.Error())
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 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 util

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

	"golang.org/x/sys/unix"

	"github.com/golang/glog"
)

// VolumeUtil is an interface for local filesystem operations
type VolumeUtil interface {
	// IsDir checks if the given path is a directory
	IsDir(fullPath string) (bool, error)

	// ReadDir returns a list of files under the specified directory
	ReadDir(fullPath string) ([]string, error)

	// Delete all the contents under the given path, but not the path itself
	DeleteContents(fullPath string) error

	// Get available capacity for fs on full path
	GetFsAvailableByte(fullPath string) (uint64, error)
}

var _ VolumeUtil = &volumeUtil{}

type volumeUtil struct{}

// NewVolumeUtil returns a VolumeUtil object for performing local filesystem operations
func NewVolumeUtil() VolumeUtil {
	return &volumeUtil{}
}

// IsDir checks if the given path is a directory
func (u *volumeUtil) IsDir(fullPath string) (bool, error) {
	dir, err := os.Open(fullPath)
	if err != nil {
		return false, err
	}
	defer dir.Close()

	stat, err := dir.Stat()
	if err != nil {
		return false, err
	}

	return stat.IsDir(), nil
}

// ReadDir returns a list all the files under the given directory
func (u *volumeUtil) ReadDir(fullPath string) ([]string, error) {
	dir, err := os.Open(fullPath)
	if err != nil {
		return nil, err
	}
	defer dir.Close()

	files, err := dir.Readdirnames(-1)
	if err != nil {
		return nil, err
	}
	return files, nil
}

// DeleteContents deletes all the contents under the given directory
func (u *volumeUtil) DeleteContents(fullPath string) error {
	dir, err := os.Open(fullPath)
	if err != nil {
		return err
	}
	defer dir.Close()

	files, err := dir.Readdirnames(-1)
	if err != nil {
		return err
	}

	for _, file := range files {
		err = os.RemoveAll(filepath.Join(fullPath, file))
		if err != nil {
			// TODO: accumulate errors
			return err
		}
	}
	return nil
}

// GetFsAvailableByte returns available capacity in byte about a mounted filesystem.
// fullPath is the pathname of any file within the mounted filesystem. Capacity
// returned here is total capacity available to non-root users, and does not include
// fs reserved space.
func (u *volumeUtil) GetFsAvailableByte(fullPath string) (uint64, error) {
	var s unix.Statfs_t
	if err := unix.Statfs(fullPath, &s); err != nil {
		return 0, err
	}
	return uint64(s.Frsize) * (s.Blocks - s.Bfree + s.Bavail), nil
}

var _ VolumeUtil = &FakeVolumeUtil{}

// FakeVolumeUtil is a stub interface for unit testing
type FakeVolumeUtil struct {
	// List of files underneath the given path
	directoryFiles map[string][]*FakeFile
	// True if DeleteContents should fail
	deleteShouldFail bool
}

// FakeFile contains a representation of a file under a directory
type FakeFile struct {
	Name     string
	IsNotDir bool
	// Expected hash value of the PV name
	Hash     uint32
	Capacity uint64
}

// NewFakeVolumeUtil returns a VolumeUtil object for use in unit testing
func NewFakeVolumeUtil(deleteShouldFail bool) *FakeVolumeUtil {
	return &FakeVolumeUtil{
		directoryFiles:   map[string][]*FakeFile{},
		deleteShouldFail: deleteShouldFail,
	}
}

// IsDir checks if the given path is a directory
func (u *FakeVolumeUtil) IsDir(fullPath string) (bool, error) {
	dir, file := filepath.Split(fullPath)
	dir = filepath.Clean(dir)
	files, found := u.directoryFiles[dir]
	if !found {
		return false, fmt.Errorf("Directory %q not found", dir)
	}

	for _, f := range files {
		if file == f.Name {
			return !f.IsNotDir, nil
		}
	}
	return false, fmt.Errorf("File %q not found", fullPath)
}

// ReadDir returns the list of all files under the given directory
func (u *FakeVolumeUtil) ReadDir(fullPath string) ([]string, error) {
	fileNames := []string{}
	files, found := u.directoryFiles[fullPath]
	if !found {
		return nil, fmt.Errorf("Directory %q not found", fullPath)
	}
	for _, file := range files {
		fileNames = append(fileNames, file.Name)
	}
	return fileNames, nil
}

// DeleteContents removes all the contents under the given directory
func (u *FakeVolumeUtil) DeleteContents(fullPath string) error {
	if u.deleteShouldFail {
		return fmt.Errorf("Fake delete contents failed")
	}
	return nil
}

// GetFsAvailableByte returns available capacity in byte about a mounted filesystem.
func (u *FakeVolumeUtil) GetFsAvailableByte(fullPath string) (uint64, error) {
	dir, file := filepath.Split(fullPath)
	dir = filepath.Clean(dir)
	files, found := u.directoryFiles[dir]
	if !found {
		return 0, fmt.Errorf("Directory %q not found", dir)
	}

	for _, f := range files {
		if file == f.Name {
			return f.Capacity, nil
		}
	}
	return 0, fmt.Errorf("File %q not found", fullPath)
}

// AddNewFiles adds the given files to the current directory listing
// This is only for testing
func (u *FakeVolumeUtil) AddNewFiles(mountDir string, dirFiles map[string][]*FakeFile) {
	for dir, files := range dirFiles {
		mountedPath := filepath.Join(mountDir, dir)
		curFiles := u.directoryFiles[mountedPath]
		if curFiles == nil {
			curFiles = []*FakeFile{}
		}
		glog.Infof("Adding to directory %q: files %v\n", dir, files)
		u.directoryFiles[mountedPath] = append(curFiles, files...)
	}
}
<commit_msg>Refactored GetFsAvailableByte to avoid using Frsize<commit_after>/*
Copyright 2017 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 util

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

	"github.com/golang/glog"

	"k8s.io/kubernetes/pkg/volume/util"
)

// VolumeUtil is an interface for local filesystem operations
type VolumeUtil interface {
	// IsDir checks if the given path is a directory
	IsDir(fullPath string) (bool, error)

	// ReadDir returns a list of files under the specified directory
	ReadDir(fullPath string) ([]string, error)

	// Delete all the contents under the given path, but not the path itself
	DeleteContents(fullPath string) error

	// Get available capacity for fs on full path
	GetFsAvailableByte(fullPath string) (uint64, error)
}

var _ VolumeUtil = &volumeUtil{}

type volumeUtil struct{}

// NewVolumeUtil returns a VolumeUtil object for performing local filesystem operations
func NewVolumeUtil() VolumeUtil {
	return &volumeUtil{}
}

// IsDir checks if the given path is a directory
func (u *volumeUtil) IsDir(fullPath string) (bool, error) {
	dir, err := os.Open(fullPath)
	if err != nil {
		return false, err
	}
	defer dir.Close()

	stat, err := dir.Stat()
	if err != nil {
		return false, err
	}

	return stat.IsDir(), nil
}

// ReadDir returns a list all the files under the given directory
func (u *volumeUtil) ReadDir(fullPath string) ([]string, error) {
	dir, err := os.Open(fullPath)
	if err != nil {
		return nil, err
	}
	defer dir.Close()

	files, err := dir.Readdirnames(-1)
	if err != nil {
		return nil, err
	}
	return files, nil
}

// DeleteContents deletes all the contents under the given directory
func (u *volumeUtil) DeleteContents(fullPath string) error {
	dir, err := os.Open(fullPath)
	if err != nil {
		return err
	}
	defer dir.Close()

	files, err := dir.Readdirnames(-1)
	if err != nil {
		return err
	}

	for _, file := range files {
		err = os.RemoveAll(filepath.Join(fullPath, file))
		if err != nil {
			// TODO: accumulate errors
			return err
		}
	}
	return nil
}

// GetFsAvailableByte returns available capacity in byte about a mounted filesystem.
// fullPath is the pathname of any file within the mounted filesystem. Capacity
// returned here is total capacity available.
func (u *volumeUtil) GetFsAvailableByte(fullPath string) (uint64, error) {
	available, _, _, _, _, _, err := util.FsInfo(fullPath)
	return uint64(available), err
}

var _ VolumeUtil = &FakeVolumeUtil{}

// FakeVolumeUtil is a stub interface for unit testing
type FakeVolumeUtil struct {
	// List of files underneath the given path
	directoryFiles map[string][]*FakeFile
	// True if DeleteContents should fail
	deleteShouldFail bool
}

// FakeFile contains a representation of a file under a directory
type FakeFile struct {
	Name     string
	IsNotDir bool
	// Expected hash value of the PV name
	Hash     uint32
	Capacity uint64
}

// NewFakeVolumeUtil returns a VolumeUtil object for use in unit testing
func NewFakeVolumeUtil(deleteShouldFail bool) *FakeVolumeUtil {
	return &FakeVolumeUtil{
		directoryFiles:   map[string][]*FakeFile{},
		deleteShouldFail: deleteShouldFail,
	}
}

// IsDir checks if the given path is a directory
func (u *FakeVolumeUtil) IsDir(fullPath string) (bool, error) {
	dir, file := filepath.Split(fullPath)
	dir = filepath.Clean(dir)
	files, found := u.directoryFiles[dir]
	if !found {
		return false, fmt.Errorf("Directory %q not found", dir)
	}

	for _, f := range files {
		if file == f.Name {
			return !f.IsNotDir, nil
		}
	}
	return false, fmt.Errorf("File %q not found", fullPath)
}

// ReadDir returns the list of all files under the given directory
func (u *FakeVolumeUtil) ReadDir(fullPath string) ([]string, error) {
	fileNames := []string{}
	files, found := u.directoryFiles[fullPath]
	if !found {
		return nil, fmt.Errorf("Directory %q not found", fullPath)
	}
	for _, file := range files {
		fileNames = append(fileNames, file.Name)
	}
	return fileNames, nil
}

// DeleteContents removes all the contents under the given directory
func (u *FakeVolumeUtil) DeleteContents(fullPath string) error {
	if u.deleteShouldFail {
		return fmt.Errorf("Fake delete contents failed")
	}
	return nil
}

// GetFsAvailableByte returns available capacity in byte about a mounted filesystem.
func (u *FakeVolumeUtil) GetFsAvailableByte(fullPath string) (uint64, error) {
	dir, file := filepath.Split(fullPath)
	dir = filepath.Clean(dir)
	files, found := u.directoryFiles[dir]
	if !found {
		return 0, fmt.Errorf("Directory %q not found", dir)
	}

	for _, f := range files {
		if file == f.Name {
			return f.Capacity, nil
		}
	}
	return 0, fmt.Errorf("File %q not found", fullPath)
}

// AddNewFiles adds the given files to the current directory listing
// This is only for testing
func (u *FakeVolumeUtil) AddNewFiles(mountDir string, dirFiles map[string][]*FakeFile) {
	for dir, files := range dirFiles {
		mountedPath := filepath.Join(mountDir, dir)
		curFiles := u.directoryFiles[mountedPath]
		if curFiles == nil {
			curFiles = []*FakeFile{}
		}
		glog.Infof("Adding to directory %q: files %v\n", dir, files)
		u.directoryFiles[mountedPath] = append(curFiles, files...)
	}
}
<|endoftext|>


<commit_before>package main
import "fmt"

func main () {
	fmt.Printf("hello, world\n")
}

<commit_msg>Sqrt added<commit_after>package main
import (
	"fmt"

	"github.com/phichan/newmath"
)
func main () {
	fmt.Printf("hello, world.   Sqrt(2) = %v\n", newmath.Sqrt(2))
}

<|endoftext|>


<commit_before>package githop

import (
	"fmt"
	"time"

	"appengine"
	"appengine/datastore"
	"appengine/delay"
	"appengine/taskqueue"

	"github.com/google/go-github/github"
)

const (
	VintageDateFormat = "January 2, 2006"
)

type RepoVintage struct {
	UserId  int       `datastore:",noindex"`
	RepoId  int       `datastore:",noindex"`
	Vintage time.Time `datastore:",noindex"`
}

func getVintageKey(c appengine.Context, userId int, repoId int) *datastore.Key {
	return datastore.NewKey(c, "RepoVintage", fmt.Sprintf("%d-%d", userId, repoId), 0, nil)
}

var computeVintageFunc *delay.Function
func computeVintage(c appengine.Context, userId int, userLogin string, repoOwnerLogin string, repoName string) error {
	account, err := getAccount(c, userId)
	if err != nil {
		c.Errorf("Could not load account %d: %s", userId, err.Error())
		return err
	}

	oauthTransport := githubOAuthTransport(c)
	oauthTransport.Token = &account.OAuthToken
	githubClient := github.NewClient(oauthTransport.Client())

	repo, _, err := githubClient.Repositories.Get(repoOwnerLogin, repoName)
	if err != nil {
		c.Errorf("Could not load repo %d %d: %s", repoOwnerLogin, repoName, err.Error())
		return err
	}

	// Cheap check to see if there are commits before the creation time.
	vintage := repo.CreatedAt.UTC()
	beforeCreationTime := repo.CreatedAt.UTC().AddDate(0, 0, -1)
	commits, _, err := githubClient.Repositories.ListCommits(
		repoOwnerLogin,
		repoName,
		&github.CommitsListOptions{
			ListOptions: github.ListOptions{PerPage: 1},
			Author:      userLogin,
			Until:       beforeCreationTime,
		})
	if err != nil {
		c.Errorf("Could not load commits for repo %s: %s", *repo.FullName, err.Error())
		return err
	}

	// If there are, then we use the contributor stats API to figure out when
	// the user's first commit in the repository was.
	if len(commits) > 0 {
		stats, response, err := githubClient.Repositories.ListContributorsStats(repoOwnerLogin, repoName)
		if response.StatusCode == 202 {
			c.Infof("Stats were not available for %s, will try again later", *repo.FullName)
			task, err := computeVintageFunc.Task(userId, userLogin, repoOwnerLogin, repoName)
			if err != nil {
				c.Errorf("Could create delayed task for %s: %s", *repo.FullName, err.Error())
				return err
			}
			task.Delay = time.Second * 10
			taskqueue.Add(c, task, "")
			return nil
		}
		if err != nil {
			c.Errorf("Could not load stats for repo %s: %s", *repo.FullName, err.Error())
			return err
		}
		for _, stat := range stats {
			if *stat.Author.ID == userId {
				for i := range stat.Weeks {
					weekTimestamp := stat.Weeks[i].Week.UTC()
					if weekTimestamp.Before(vintage) {
						vintage = weekTimestamp
					}
				}
				break
			}
		}
	}

	_, err = datastore.Put(c, getVintageKey(c, userId, *repo.ID), &RepoVintage{
		UserId:  userId,
		RepoId:  *repo.ID,
		Vintage: vintage,
	})
	if err != nil {
		c.Errorf("Could save vintage for repo %s: %s", *repo.FullName, err.Error())
		return err
	}

	return nil
}

func init() {
	computeVintageFunc = delay.Func("computeVintage", computeVintage)
}

func fillVintages(c appengine.Context, user *github.User, repos []*Repo) error {
	keys := make([]*datastore.Key, len(repos))
	for i := range repos {
		keys[i] = getVintageKey(c, *user.ID, *repos[i].ID)
	}
	vintages := make([]*RepoVintage, len(repos))
	for i := range vintages {
		vintages[i] = new(RepoVintage)
	}
	err := datastore.GetMulti(c, keys, vintages)
	if err != nil {
		if errs, ok := err.(appengine.MultiError); ok {
			for i, err := range errs {
				if err == datastore.ErrNoSuchEntity {
					vintages[i] = nil
				} else if err != nil {
					c.Errorf("%d/%s vintage fetch error: %s", i, *repos[i].FullName, err.Error())
					return err
				}
			}
		} else {
			return err
		}
	}
	for i := range vintages {
		repo := repos[i]
		vintage := vintages[i]
		if vintage != nil {
			repo.Vintage = vintage.Vintage
			continue
		}
		computeVintageFunc.Call(c, *user.ID, *user.Login, *repo.Owner.Login, *repo.Name)
	}
	return nil
}

type Repos struct {
	AllRepos       []*Repo
	UserRepos      []*Repo
	OtherUserRepos []*UserRepos
	OrgRepos       []*OrgRepos
	OldestVintage  time.Time
}

type Repo struct {
	*github.Repository
	Vintage time.Time
}

func newRepo(githubRepo *github.Repository) *Repo {
	return &Repo{githubRepo, githubRepo.CreatedAt.UTC()}
}

func (repo *Repo) TypeAsOcticonName() string {
	if *repo.Fork {
		return "repo-forked"
	}
	if *repo.Private {
		return "lock"
	}
	return "repo"
}

func (repo *Repo) TypeAsClassName() string {
	if *repo.Fork {
		return "fork"
	}
	if *repo.Private {
		return "private"
	}
	return ""
}

func (repo *Repo) DisplayVintage() string {
	return repo.Vintage.Format(VintageDateFormat)
}

type UserRepos struct {
	User  *github.User
	Repos []*Repo
}

type OrgRepos struct {
	Org   *github.Organization
	Repos []*Repo
}

func getRepos(c appengine.Context, githubClient *github.Client, user *github.User) (*Repos, error) {
	// The username parameter must be left blank so that we can get all of the
	// repositories the user has access to, not just ones that they own.
	clientUserRepos, _, err := githubClient.Repositories.List("", nil)
	if err != nil {
		return nil, err
	}

	repos := &Repos{}
	repos.UserRepos = make([]*Repo, 0, len(clientUserRepos))
	repos.OtherUserRepos = make([]*UserRepos, 0)
	allRepoCount := len(clientUserRepos)
	for i := range clientUserRepos {
		ownerID := *clientUserRepos[i].Owner.ID
		if ownerID == *user.ID {
			repos.UserRepos = append(repos.UserRepos, newRepo(&clientUserRepos[i]))
		} else {
			var userRepos *UserRepos
			for j := range repos.OtherUserRepos {
				if *repos.OtherUserRepos[j].User.ID == ownerID {
					userRepos = repos.OtherUserRepos[j]
					break
				}
			}
			if userRepos == nil {
				userRepos = &UserRepos{
					User:  clientUserRepos[i].Owner,
					Repos: make([]*Repo, 0),
				}
				repos.OtherUserRepos = append(repos.OtherUserRepos, userRepos)
			}
			userRepos.Repos = append(userRepos.Repos, newRepo(&clientUserRepos[i]))
		}
	}

	orgs, _, err := githubClient.Organizations.List("", nil)
	if err != nil {
		return nil, err
	}

	repos.OrgRepos = make([]*OrgRepos, 0, len(orgs))
	for i := range orgs {
		org := &orgs[i]
		clientOrgRepos, _, err := githubClient.Repositories.ListByOrg(*org.Login, nil)
		if err != nil {
			return nil, err
		}

		orgRepos := make([]*Repo, 0, len(clientOrgRepos))
		allRepoCount += len(clientOrgRepos)
		for j := range clientOrgRepos {
			orgRepos = append(orgRepos, newRepo(&clientOrgRepos[j]))
		}
		repos.OrgRepos = append(repos.OrgRepos, &OrgRepos{org, orgRepos})
	}

	repos.AllRepos = make([]*Repo, 0, allRepoCount)
	repos.AllRepos = append(repos.AllRepos, repos.UserRepos...)
	for _, userRepos := range repos.OtherUserRepos {
		repos.AllRepos = append(repos.AllRepos, userRepos.Repos...)
	}
	for _, org := range repos.OrgRepos {
		repos.AllRepos = append(repos.AllRepos, org.Repos...)
	}

	err = fillVintages(c, user, repos.AllRepos)
	if err != nil {
		return nil, err
	}

	repos.OldestVintage = time.Now().UTC()
	for _, repo := range repos.AllRepos {
		repoVintage := repo.Vintage
		if repoVintage.Before(repos.OldestVintage) {
			repos.OldestVintage = repoVintage
		}
	}

	return repos, nil
}
<commit_msg>Run gofmt.<commit_after>package githop

import (
	"fmt"
	"time"

	"appengine"
	"appengine/datastore"
	"appengine/delay"
	"appengine/taskqueue"

	"github.com/google/go-github/github"
)

const (
	VintageDateFormat = "January 2, 2006"
)

type RepoVintage struct {
	UserId  int       `datastore:",noindex"`
	RepoId  int       `datastore:",noindex"`
	Vintage time.Time `datastore:",noindex"`
}

func getVintageKey(c appengine.Context, userId int, repoId int) *datastore.Key {
	return datastore.NewKey(c, "RepoVintage", fmt.Sprintf("%d-%d", userId, repoId), 0, nil)
}

var computeVintageFunc *delay.Function

func computeVintage(c appengine.Context, userId int, userLogin string, repoOwnerLogin string, repoName string) error {
	account, err := getAccount(c, userId)
	if err != nil {
		c.Errorf("Could not load account %d: %s", userId, err.Error())
		return err
	}

	oauthTransport := githubOAuthTransport(c)
	oauthTransport.Token = &account.OAuthToken
	githubClient := github.NewClient(oauthTransport.Client())

	repo, _, err := githubClient.Repositories.Get(repoOwnerLogin, repoName)
	if err != nil {
		c.Errorf("Could not load repo %d %d: %s", repoOwnerLogin, repoName, err.Error())
		return err
	}

	// Cheap check to see if there are commits before the creation time.
	vintage := repo.CreatedAt.UTC()
	beforeCreationTime := repo.CreatedAt.UTC().AddDate(0, 0, -1)
	commits, _, err := githubClient.Repositories.ListCommits(
		repoOwnerLogin,
		repoName,
		&github.CommitsListOptions{
			ListOptions: github.ListOptions{PerPage: 1},
			Author:      userLogin,
			Until:       beforeCreationTime,
		})
	if err != nil {
		c.Errorf("Could not load commits for repo %s: %s", *repo.FullName, err.Error())
		return err
	}

	// If there are, then we use the contributor stats API to figure out when
	// the user's first commit in the repository was.
	if len(commits) > 0 {
		stats, response, err := githubClient.Repositories.ListContributorsStats(repoOwnerLogin, repoName)
		if response.StatusCode == 202 {
			c.Infof("Stats were not available for %s, will try again later", *repo.FullName)
			task, err := computeVintageFunc.Task(userId, userLogin, repoOwnerLogin, repoName)
			if err != nil {
				c.Errorf("Could create delayed task for %s: %s", *repo.FullName, err.Error())
				return err
			}
			task.Delay = time.Second * 10
			taskqueue.Add(c, task, "")
			return nil
		}
		if err != nil {
			c.Errorf("Could not load stats for repo %s: %s", *repo.FullName, err.Error())
			return err
		}
		for _, stat := range stats {
			if *stat.Author.ID == userId {
				for i := range stat.Weeks {
					weekTimestamp := stat.Weeks[i].Week.UTC()
					if weekTimestamp.Before(vintage) {
						vintage = weekTimestamp
					}
				}
				break
			}
		}
	}

	_, err = datastore.Put(c, getVintageKey(c, userId, *repo.ID), &RepoVintage{
		UserId:  userId,
		RepoId:  *repo.ID,
		Vintage: vintage,
	})
	if err != nil {
		c.Errorf("Could save vintage for repo %s: %s", *repo.FullName, err.Error())
		return err
	}

	return nil
}

func init() {
	computeVintageFunc = delay.Func("computeVintage", computeVintage)
}

func fillVintages(c appengine.Context, user *github.User, repos []*Repo) error {
	keys := make([]*datastore.Key, len(repos))
	for i := range repos {
		keys[i] = getVintageKey(c, *user.ID, *repos[i].ID)
	}
	vintages := make([]*RepoVintage, len(repos))
	for i := range vintages {
		vintages[i] = new(RepoVintage)
	}
	err := datastore.GetMulti(c, keys, vintages)
	if err != nil {
		if errs, ok := err.(appengine.MultiError); ok {
			for i, err := range errs {
				if err == datastore.ErrNoSuchEntity {
					vintages[i] = nil
				} else if err != nil {
					c.Errorf("%d/%s vintage fetch error: %s", i, *repos[i].FullName, err.Error())
					return err
				}
			}
		} else {
			return err
		}
	}
	for i := range vintages {
		repo := repos[i]
		vintage := vintages[i]
		if vintage != nil {
			repo.Vintage = vintage.Vintage
			continue
		}
		computeVintageFunc.Call(c, *user.ID, *user.Login, *repo.Owner.Login, *repo.Name)
	}
	return nil
}

type Repos struct {
	AllRepos       []*Repo
	UserRepos      []*Repo
	OtherUserRepos []*UserRepos
	OrgRepos       []*OrgRepos
	OldestVintage  time.Time
}

type Repo struct {
	*github.Repository
	Vintage time.Time
}

func newRepo(githubRepo *github.Repository) *Repo {
	return &Repo{githubRepo, githubRepo.CreatedAt.UTC()}
}

func (repo *Repo) TypeAsOcticonName() string {
	if *repo.Fork {
		return "repo-forked"
	}
	if *repo.Private {
		return "lock"
	}
	return "repo"
}

func (repo *Repo) TypeAsClassName() string {
	if *repo.Fork {
		return "fork"
	}
	if *repo.Private {
		return "private"
	}
	return ""
}

func (repo *Repo) DisplayVintage() string {
	return repo.Vintage.Format(VintageDateFormat)
}

type UserRepos struct {
	User  *github.User
	Repos []*Repo
}

type OrgRepos struct {
	Org   *github.Organization
	Repos []*Repo
}

func getRepos(c appengine.Context, githubClient *github.Client, user *github.User) (*Repos, error) {
	// The username parameter must be left blank so that we can get all of the
	// repositories the user has access to, not just ones that they own.
	clientUserRepos, _, err := githubClient.Repositories.List("", nil)
	if err != nil {
		return nil, err
	}

	repos := &Repos{}
	repos.UserRepos = make([]*Repo, 0, len(clientUserRepos))
	repos.OtherUserRepos = make([]*UserRepos, 0)
	allRepoCount := len(clientUserRepos)
	for i := range clientUserRepos {
		ownerID := *clientUserRepos[i].Owner.ID
		if ownerID == *user.ID {
			repos.UserRepos = append(repos.UserRepos, newRepo(&clientUserRepos[i]))
		} else {
			var userRepos *UserRepos
			for j := range repos.OtherUserRepos {
				if *repos.OtherUserRepos[j].User.ID == ownerID {
					userRepos = repos.OtherUserRepos[j]
					break
				}
			}
			if userRepos == nil {
				userRepos = &UserRepos{
					User:  clientUserRepos[i].Owner,
					Repos: make([]*Repo, 0),
				}
				repos.OtherUserRepos = append(repos.OtherUserRepos, userRepos)
			}
			userRepos.Repos = append(userRepos.Repos, newRepo(&clientUserRepos[i]))
		}
	}

	orgs, _, err := githubClient.Organizations.List("", nil)
	if err != nil {
		return nil, err
	}

	repos.OrgRepos = make([]*OrgRepos, 0, len(orgs))
	for i := range orgs {
		org := &orgs[i]
		clientOrgRepos, _, err := githubClient.Repositories.ListByOrg(*org.Login, nil)
		if err != nil {
			return nil, err
		}

		orgRepos := make([]*Repo, 0, len(clientOrgRepos))
		allRepoCount += len(clientOrgRepos)
		for j := range clientOrgRepos {
			orgRepos = append(orgRepos, newRepo(&clientOrgRepos[j]))
		}
		repos.OrgRepos = append(repos.OrgRepos, &OrgRepos{org, orgRepos})
	}

	repos.AllRepos = make([]*Repo, 0, allRepoCount)
	repos.AllRepos = append(repos.AllRepos, repos.UserRepos...)
	for _, userRepos := range repos.OtherUserRepos {
		repos.AllRepos = append(repos.AllRepos, userRepos.Repos...)
	}
	for _, org := range repos.OrgRepos {
		repos.AllRepos = append(repos.AllRepos, org.Repos...)
	}

	err = fillVintages(c, user, repos.AllRepos)
	if err != nil {
		return nil, err
	}

	repos.OldestVintage = time.Now().UTC()
	for _, repo := range repos.AllRepos {
		repoVintage := repo.Vintage
		if repoVintage.Before(repos.OldestVintage) {
			repos.OldestVintage = repoVintage
		}
	}

	return repos, nil
}
<|endoftext|>


<commit_before>// Copyright 2014 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 parser

import (
	"fmt"
	"strconv"
	"strings"
	"text/scanner"
	"unicode"
)

var noPos scanner.Position

type printer struct {
	defs     []Definition
	comments []*CommentGroup

	curComment int

	pos scanner.Position

	pendingSpace   bool
	pendingNewline int

	output []byte

	indentList []int
	wsBuf      []byte

	skippedComments []*CommentGroup
}

func newPrinter(file *File) *printer {
	return &printer{
		defs:       file.Defs,
		comments:   file.Comments,
		indentList: []int{0},

		// pendingNewLine is initialized to -1 to eat initial spaces if the first token is a comment
		pendingNewline: -1,

		pos: scanner.Position{
			Line: 1,
		},
	}
}

func Print(file *File) ([]byte, error) {
	p := newPrinter(file)

	for _, def := range p.defs {
		p.printDef(def)
	}
	p.flush()
	return p.output, nil
}

func (p *printer) Print() ([]byte, error) {
	for _, def := range p.defs {
		p.printDef(def)
	}
	p.flush()
	return p.output, nil
}

func (p *printer) printDef(def Definition) {
	if assignment, ok := def.(*Assignment); ok {
		p.printAssignment(assignment)
	} else if module, ok := def.(*Module); ok {
		p.printModule(module)
	} else {
		panic("Unknown definition")
	}
}

func (p *printer) printAssignment(assignment *Assignment) {
	p.printToken(assignment.Name, assignment.NamePos)
	p.requestSpace()
	p.printToken(assignment.Assigner, assignment.EqualsPos)
	p.requestSpace()
	p.printExpression(assignment.OrigValue)
	p.requestNewline()
}

func (p *printer) printModule(module *Module) {
	p.printToken(module.Type, module.TypePos)
	p.printMap(&module.Map)
	p.requestDoubleNewline()
}

func (p *printer) printExpression(value Expression) {
	switch v := value.(type) {
	case *Variable:
		p.printToken(v.Name, v.NamePos)
	case *Operator:
		p.printOperator(v)
	case *Bool:
		var s string
		if v.Value {
			s = "true"
		} else {
			s = "false"
		}
		p.printToken(s, v.LiteralPos)
	case *String:
		p.printToken(strconv.Quote(v.Value), v.LiteralPos)
	case *List:
		p.printList(v.Values, v.LBracePos, v.RBracePos)
	case *Map:
		p.printMap(v)
	default:
		panic(fmt.Errorf("bad property type: %s", value.Type()))
	}
}

func (p *printer) printList(list []Expression, pos, endPos scanner.Position) {
	p.requestSpace()
	p.printToken("[", pos)
	if len(list) > 1 || pos.Line != endPos.Line {
		p.requestNewline()
		p.indent(p.curIndent() + 4)
		for _, value := range list {
			p.printExpression(value)
			p.printToken(",", noPos)
			p.requestNewline()
		}
		p.unindent(endPos)
	} else {
		for _, value := range list {
			p.printExpression(value)
		}
	}
	p.printToken("]", endPos)
}

func (p *printer) printMap(m *Map) {
	p.requestSpace()
	p.printToken("{", m.LBracePos)
	if len(m.Properties) > 0 || m.LBracePos.Line != m.RBracePos.Line {
		p.requestNewline()
		p.indent(p.curIndent() + 4)
		for _, prop := range m.Properties {
			p.printProperty(prop)
			p.printToken(",", noPos)
			p.requestNewline()
		}
		p.unindent(m.RBracePos)
	}
	p.printToken("}", m.RBracePos)
}

func (p *printer) printOperator(operator *Operator) {
	p.printExpression(operator.Args[0])
	p.requestSpace()
	p.printToken(string(operator.Operator), operator.OperatorPos)
	if operator.Args[0].End().Line == operator.Args[1].Pos().Line {
		p.requestSpace()
	} else {
		p.requestNewline()
	}
	p.printExpression(operator.Args[1])
}

func (p *printer) printProperty(property *Property) {
	p.printToken(property.Name, property.NamePos)
	p.printToken(":", property.ColonPos)
	p.requestSpace()
	p.printExpression(property.Value)
}

// Print a single token, including any necessary comments or whitespace between
// this token and the previously printed token
func (p *printer) printToken(s string, pos scanner.Position) {
	newline := p.pendingNewline != 0

	if pos == noPos {
		pos = p.pos
	}

	if newline {
		p.printEndOfLineCommentsBefore(pos)
		p.requestNewlinesForPos(pos)
	}

	p.printInLineCommentsBefore(pos)

	p.flushSpace()

	p.output = append(p.output, s...)

	p.pos = pos
}

// Print any in-line (single line /* */) comments that appear _before_ pos
func (p *printer) printInLineCommentsBefore(pos scanner.Position) {
	for p.curComment < len(p.comments) && p.comments[p.curComment].Pos().Offset < pos.Offset {
		c := p.comments[p.curComment]
		if c.Comments[0].Comment[0][0:2] == "//" || len(c.Comments[0].Comment) > 1 {
			p.skippedComments = append(p.skippedComments, c)
		} else {
			p.printComment(c)
			p.requestSpace()
		}
		p.curComment++
	}
}

// Print any comments, including end of line comments, that appear _before_ the line specified
// by pos
func (p *printer) printEndOfLineCommentsBefore(pos scanner.Position) {
	if len(p.skippedComments) > 0 {
		for _, c := range p.skippedComments {
			p.printComment(c)
		}
		p._requestNewline()
		p.skippedComments = nil
	}
	for p.curComment < len(p.comments) && p.comments[p.curComment].Pos().Line < pos.Line {
		c := p.comments[p.curComment]
		p.printComment(c)
		p._requestNewline()
		p.curComment++
	}
}

// Compare the line numbers of the previous and current positions to determine whether extra
// newlines should be inserted.  A second newline is allowed anywhere requestNewline() is called.
func (p *printer) requestNewlinesForPos(pos scanner.Position) bool {
	if pos.Line > p.pos.Line {
		p._requestNewline()
		if pos.Line > p.pos.Line+1 {
			p.pendingNewline = 2
		}
		return true
	}

	return false
}

func (p *printer) requestSpace() {
	p.pendingSpace = true
}

// Ask for a newline to be inserted before the next token, but do not insert any comments.  Used
// by the comment printers.
func (p *printer) _requestNewline() {
	if p.pendingNewline == 0 {
		p.pendingNewline = 1
	}
}

// Ask for a newline to be inserted before the next token.  Also inserts any end-of line comments
// for the current line
func (p *printer) requestNewline() {
	pos := p.pos
	pos.Line++
	p.printEndOfLineCommentsBefore(pos)
	p._requestNewline()
}

// Ask for two newlines to be inserted before the next token.  Also inserts any end-of line comments
// for the current line
func (p *printer) requestDoubleNewline() {
	p.requestNewline()
	p.pendingNewline = 2
}

// Flush any pending whitespace, ignoring pending spaces if there is a pending newline
func (p *printer) flushSpace() {
	if p.pendingNewline == 1 {
		p.output = append(p.output, '\n')
		p.pad(p.curIndent())
	} else if p.pendingNewline == 2 {
		p.output = append(p.output, "\n\n"...)
		p.pad(p.curIndent())
	} else if p.pendingSpace == true && p.pendingNewline != -1 {
		p.output = append(p.output, ' ')
	}

	p.pendingSpace = false
	p.pendingNewline = 0
}

// Print a single comment, which may be a multi-line comment
func (p *printer) printComment(cg *CommentGroup) {
	for _, comment := range cg.Comments {
		if !p.requestNewlinesForPos(comment.Pos()) {
			p.requestSpace()
		}
		for i, line := range comment.Comment {
			line = strings.TrimRightFunc(line, unicode.IsSpace)
			p.flushSpace()
			if i != 0 {
				lineIndent := strings.IndexFunc(line, func(r rune) bool { return !unicode.IsSpace(r) })
				lineIndent = max(lineIndent, p.curIndent())
				p.pad(lineIndent - p.curIndent())
			}
			p.output = append(p.output, strings.TrimSpace(line)...)
			if i < len(comment.Comment)-1 {
				p._requestNewline()
			}
		}
		p.pos = comment.End()
	}
}

// Print any comments that occur after the last token, and a trailing newline
func (p *printer) flush() {
	for _, c := range p.skippedComments {
		if !p.requestNewlinesForPos(c.Pos()) {
			p.requestSpace()
		}
		p.printComment(c)
	}
	for p.curComment < len(p.comments) {
		p.printComment(p.comments[p.curComment])
		p.curComment++
	}
	p.output = append(p.output, '\n')
}

// Print whitespace to pad from column l to column max
func (p *printer) pad(l int) {
	if l > len(p.wsBuf) {
		p.wsBuf = make([]byte, l)
		for i := range p.wsBuf {
			p.wsBuf[i] = ' '
		}
	}
	p.output = append(p.output, p.wsBuf[0:l]...)
}

func (p *printer) indent(i int) {
	p.indentList = append(p.indentList, i)
}

func (p *printer) unindent(pos scanner.Position) {
	p.printEndOfLineCommentsBefore(pos)
	p.indentList = p.indentList[0 : len(p.indentList)-1]
}

func (p *printer) curIndent() int {
	return p.indentList[len(p.indentList)-1]
}

func max(a, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}
<commit_msg>Utils to support removing duplicate shared_libs<commit_after>// Copyright 2014 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 parser

import (
	"fmt"
	"strconv"
	"strings"
	"text/scanner"
	"unicode"
)

var noPos scanner.Position

type printer struct {
	defs     []Definition
	comments []*CommentGroup

	curComment int

	pos scanner.Position

	pendingSpace   bool
	pendingNewline int

	output []byte

	indentList []int
	wsBuf      []byte

	skippedComments []*CommentGroup
}

func newPrinter(file *File) *printer {
	return &printer{
		defs:       file.Defs,
		comments:   file.Comments,
		indentList: []int{0},

		// pendingNewLine is initialized to -1 to eat initial spaces if the first token is a comment
		pendingNewline: -1,

		pos: scanner.Position{
			Line: 1,
		},
	}
}

func Print(file *File) ([]byte, error) {
	p := newPrinter(file)

	for _, def := range p.defs {
		p.printDef(def)
	}
	p.flush()
	return p.output, nil
}

func PrintExpression(expression Expression) ([]byte, error) {
	dummyFile := &File{}
	p := newPrinter(dummyFile)
	p.printExpression(expression)
	p.flush()
	return p.output, nil
}

func (p *printer) Print() ([]byte, error) {
	for _, def := range p.defs {
		p.printDef(def)
	}
	p.flush()
	return p.output, nil
}

func (p *printer) printDef(def Definition) {
	if assignment, ok := def.(*Assignment); ok {
		p.printAssignment(assignment)
	} else if module, ok := def.(*Module); ok {
		p.printModule(module)
	} else {
		panic("Unknown definition")
	}
}

func (p *printer) printAssignment(assignment *Assignment) {
	p.printToken(assignment.Name, assignment.NamePos)
	p.requestSpace()
	p.printToken(assignment.Assigner, assignment.EqualsPos)
	p.requestSpace()
	p.printExpression(assignment.OrigValue)
	p.requestNewline()
}

func (p *printer) printModule(module *Module) {
	p.printToken(module.Type, module.TypePos)
	p.printMap(&module.Map)
	p.requestDoubleNewline()
}

func (p *printer) printExpression(value Expression) {
	switch v := value.(type) {
	case *Variable:
		p.printToken(v.Name, v.NamePos)
	case *Operator:
		p.printOperator(v)
	case *Bool:
		var s string
		if v.Value {
			s = "true"
		} else {
			s = "false"
		}
		p.printToken(s, v.LiteralPos)
	case *String:
		p.printToken(strconv.Quote(v.Value), v.LiteralPos)
	case *List:
		p.printList(v.Values, v.LBracePos, v.RBracePos)
	case *Map:
		p.printMap(v)
	default:
		panic(fmt.Errorf("bad property type: %s", value.Type()))
	}
}

func (p *printer) printList(list []Expression, pos, endPos scanner.Position) {
	p.requestSpace()
	p.printToken("[", pos)
	if len(list) > 1 || pos.Line != endPos.Line {
		p.requestNewline()
		p.indent(p.curIndent() + 4)
		for _, value := range list {
			p.printExpression(value)
			p.printToken(",", noPos)
			p.requestNewline()
		}
		p.unindent(endPos)
	} else {
		for _, value := range list {
			p.printExpression(value)
		}
	}
	p.printToken("]", endPos)
}

func (p *printer) printMap(m *Map) {
	p.requestSpace()
	p.printToken("{", m.LBracePos)
	if len(m.Properties) > 0 || m.LBracePos.Line != m.RBracePos.Line {
		p.requestNewline()
		p.indent(p.curIndent() + 4)
		for _, prop := range m.Properties {
			p.printProperty(prop)
			p.printToken(",", noPos)
			p.requestNewline()
		}
		p.unindent(m.RBracePos)
	}
	p.printToken("}", m.RBracePos)
}

func (p *printer) printOperator(operator *Operator) {
	p.printExpression(operator.Args[0])
	p.requestSpace()
	p.printToken(string(operator.Operator), operator.OperatorPos)
	if operator.Args[0].End().Line == operator.Args[1].Pos().Line {
		p.requestSpace()
	} else {
		p.requestNewline()
	}
	p.printExpression(operator.Args[1])
}

func (p *printer) printProperty(property *Property) {
	p.printToken(property.Name, property.NamePos)
	p.printToken(":", property.ColonPos)
	p.requestSpace()
	p.printExpression(property.Value)
}

// Print a single token, including any necessary comments or whitespace between
// this token and the previously printed token
func (p *printer) printToken(s string, pos scanner.Position) {
	newline := p.pendingNewline != 0

	if pos == noPos {
		pos = p.pos
	}

	if newline {
		p.printEndOfLineCommentsBefore(pos)
		p.requestNewlinesForPos(pos)
	}

	p.printInLineCommentsBefore(pos)

	p.flushSpace()

	p.output = append(p.output, s...)

	p.pos = pos
}

// Print any in-line (single line /* */) comments that appear _before_ pos
func (p *printer) printInLineCommentsBefore(pos scanner.Position) {
	for p.curComment < len(p.comments) && p.comments[p.curComment].Pos().Offset < pos.Offset {
		c := p.comments[p.curComment]
		if c.Comments[0].Comment[0][0:2] == "//" || len(c.Comments[0].Comment) > 1 {
			p.skippedComments = append(p.skippedComments, c)
		} else {
			p.printComment(c)
			p.requestSpace()
		}
		p.curComment++
	}
}

// Print any comments, including end of line comments, that appear _before_ the line specified
// by pos
func (p *printer) printEndOfLineCommentsBefore(pos scanner.Position) {
	if len(p.skippedComments) > 0 {
		for _, c := range p.skippedComments {
			p.printComment(c)
		}
		p._requestNewline()
		p.skippedComments = nil
	}
	for p.curComment < len(p.comments) && p.comments[p.curComment].Pos().Line < pos.Line {
		c := p.comments[p.curComment]
		p.printComment(c)
		p._requestNewline()
		p.curComment++
	}
}

// Compare the line numbers of the previous and current positions to determine whether extra
// newlines should be inserted.  A second newline is allowed anywhere requestNewline() is called.
func (p *printer) requestNewlinesForPos(pos scanner.Position) bool {
	if pos.Line > p.pos.Line {
		p._requestNewline()
		if pos.Line > p.pos.Line+1 {
			p.pendingNewline = 2
		}
		return true
	}

	return false
}

func (p *printer) requestSpace() {
	p.pendingSpace = true
}

// Ask for a newline to be inserted before the next token, but do not insert any comments.  Used
// by the comment printers.
func (p *printer) _requestNewline() {
	if p.pendingNewline == 0 {
		p.pendingNewline = 1
	}
}

// Ask for a newline to be inserted before the next token.  Also inserts any end-of line comments
// for the current line
func (p *printer) requestNewline() {
	pos := p.pos
	pos.Line++
	p.printEndOfLineCommentsBefore(pos)
	p._requestNewline()
}

// Ask for two newlines to be inserted before the next token.  Also inserts any end-of line comments
// for the current line
func (p *printer) requestDoubleNewline() {
	p.requestNewline()
	p.pendingNewline = 2
}

// Flush any pending whitespace, ignoring pending spaces if there is a pending newline
func (p *printer) flushSpace() {
	if p.pendingNewline == 1 {
		p.output = append(p.output, '\n')
		p.pad(p.curIndent())
	} else if p.pendingNewline == 2 {
		p.output = append(p.output, "\n\n"...)
		p.pad(p.curIndent())
	} else if p.pendingSpace == true && p.pendingNewline != -1 {
		p.output = append(p.output, ' ')
	}

	p.pendingSpace = false
	p.pendingNewline = 0
}

// Print a single comment, which may be a multi-line comment
func (p *printer) printComment(cg *CommentGroup) {
	for _, comment := range cg.Comments {
		if !p.requestNewlinesForPos(comment.Pos()) {
			p.requestSpace()
		}
		for i, line := range comment.Comment {
			line = strings.TrimRightFunc(line, unicode.IsSpace)
			p.flushSpace()
			if i != 0 {
				lineIndent := strings.IndexFunc(line, func(r rune) bool { return !unicode.IsSpace(r) })
				lineIndent = max(lineIndent, p.curIndent())
				p.pad(lineIndent - p.curIndent())
			}
			p.output = append(p.output, strings.TrimSpace(line)...)
			if i < len(comment.Comment)-1 {
				p._requestNewline()
			}
		}
		p.pos = comment.End()
	}
}

// Print any comments that occur after the last token, and a trailing newline
func (p *printer) flush() {
	for _, c := range p.skippedComments {
		if !p.requestNewlinesForPos(c.Pos()) {
			p.requestSpace()
		}
		p.printComment(c)
	}
	for p.curComment < len(p.comments) {
		p.printComment(p.comments[p.curComment])
		p.curComment++
	}
	p.output = append(p.output, '\n')
}

// Print whitespace to pad from column l to column max
func (p *printer) pad(l int) {
	if l > len(p.wsBuf) {
		p.wsBuf = make([]byte, l)
		for i := range p.wsBuf {
			p.wsBuf[i] = ' '
		}
	}
	p.output = append(p.output, p.wsBuf[0:l]...)
}

func (p *printer) indent(i int) {
	p.indentList = append(p.indentList, i)
}

func (p *printer) unindent(pos scanner.Position) {
	p.printEndOfLineCommentsBefore(pos)
	p.indentList = p.indentList[0 : len(p.indentList)-1]
}

func (p *printer) curIndent() int {
	return p.indentList[len(p.indentList)-1]
}

func max(a, b int) int {
	if a > b {
		return a
	} else {
		return b
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package buildbucket

import (
	"errors"
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/luci/luci-go/milo/appengine/common"
	"github.com/luci/luci-go/server/router"
	"github.com/luci/luci-go/server/templates"
)

// TODO(nodir): move this value to luci-config.
const defaultServer = "cr-buildbucket.appspot.com"

func parseBuilderQuery(r *http.Request, p httprouter.Params) (query builderQuery, err error) {
	query.Server = r.FormValue("server")
	if query.Server == "" {
		query.Server = defaultServer
	}

	query.Bucket = p.ByName("bucket")
	if query.Bucket == "" {
		err = errors.New("No bucket")
		return
	}

	builder := p.ByName("builder")
	if builder == "" {
		err = errors.New("No builder")
		return
	}

	// limit is a name of the query string parameter for specifying
	// maximum number of builds to show.
	query.Limit, err = common.GetLimit(r)
	return
}

// BuilderHandler renders the builder view page.
// Note: The builder html template contains self links to "?limit=123", which could
// potentially override any other request parameters set.
func BuilderHandler(c *router.Context) {
	query, err := parseBuilderQuery(c.Request, c.Params)
	if err != nil {
		common.ErrorPage(c, http.StatusBadRequest, err.Error())
		return
	}

	result, err := builderImpl(c.Context, query)
	if err != nil {
		common.ErrorPage(c, http.StatusInternalServerError, err.Error())
		return
	}

	templates.MustRender(c.Context, c.Writer, "pages/builder.html", templates.Args{
		"Builder": result,
	})
}
<commit_msg>milo: fix buildbucket.parseBuilderQuery<commit_after>// Copyright 2016 The LUCI Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.

package buildbucket

import (
	"errors"
	"net/http"

	"github.com/julienschmidt/httprouter"
	"github.com/luci/luci-go/milo/appengine/common"
	"github.com/luci/luci-go/server/router"
	"github.com/luci/luci-go/server/templates"
)

// TODO(nodir): move this value to luci-config.
const defaultServer = "cr-buildbucket.appspot.com"

func parseBuilderQuery(r *http.Request, p httprouter.Params) (query builderQuery, err error) {
	query.Server = r.FormValue("server")
	if query.Server == "" {
		query.Server = defaultServer
	}

	query.Bucket = p.ByName("bucket")
	if query.Bucket == "" {
		err = errors.New("No bucket")
		return
	}

	query.Builder = p.ByName("builder")
	if query.Builder == "" {
		err = errors.New("No builder")
		return
	}

	// limit is a name of the query string parameter for specifying
	// maximum number of builds to show.
	query.Limit, err = common.GetLimit(r)
	return
}

// BuilderHandler renders the builder view page.
// Note: The builder html template contains self links to "?limit=123", which could
// potentially override any other request parameters set.
func BuilderHandler(c *router.Context) {
	query, err := parseBuilderQuery(c.Request, c.Params)
	if err != nil {
		common.ErrorPage(c, http.StatusBadRequest, err.Error())
		return
	}

	result, err := builderImpl(c.Context, query)
	if err != nil {
		common.ErrorPage(c, http.StatusInternalServerError, err.Error())
		return
	}

	templates.MustRender(c.Context, c.Writer, "pages/builder.html", templates.Args{
		"Builder": result,
	})
}
<|endoftext|>


<commit_before>package command

import (
	"testing"

	"github.com/hashicorp/nomad/command/agent"
	"github.com/mitchellh/cli"
	"github.com/stretchr/testify/assert"
)

func TestACLBootstrapCommand_Implements(t *testing.T) {
	t.Parallel()
	assert := assert.New(t)

	// create a acl-enabled server without bootstrapping the token
	config := func(c *agent.Config) {
		c.ACL.Enabled = true
		c.ACL.PolicyTTL = 0
	}

	srv, _, url := testServer(t, true, config)
	defer srv.Shutdown()

	assert.Nil(srv.RootToken)

	ui := new(cli.MockUi)
	cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}}

	code := cmd.Run([]string{"-address=" + url})
	assert.Equal(0, code)

	out := ui.OutputWriter.String()
	assert.Contains(out, "Secret ID")
}
<commit_msg>add failure test cases<commit_after>package command

import (
	"testing"

	"github.com/hashicorp/nomad/command/agent"
	"github.com/mitchellh/cli"
	"github.com/stretchr/testify/assert"
)

func TestACLBootstrapCommand(t *testing.T) {
	t.Parallel()
	assert := assert.New(t)

	// create a acl-enabled server without bootstrapping the token
	config := func(c *agent.Config) {
		c.ACL.Enabled = true
		c.ACL.PolicyTTL = 0
	}

	srv, _, url := testServer(t, true, config)
	defer srv.Shutdown()

	assert.Nil(srv.RootToken)

	ui := new(cli.MockUi)
	cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}}

	code := cmd.Run([]string{"-address=" + url})
	assert.Equal(0, code)

	out := ui.OutputWriter.String()
	assert.Contains(out, "Secret ID")
}

// If a bootsrap token has already been created, attempts to create more should
// fail.
func TestACLBootstrapCommand_ExistingBootstrapToken(t *testing.T) {
	t.Parallel()
	assert := assert.New(t)

	config := func(c *agent.Config) {
		c.ACL.Enabled = true
	}

	srv, _, url := testServer(t, true, config)
	defer srv.Shutdown()

	assert.NotNil(srv.RootToken)

	ui := new(cli.MockUi)
	cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}}

	code := cmd.Run([]string{"-address=" + url})
	assert.Equal(1, code)

	out := ui.OutputWriter.String()
	assert.NotContains(out, "Secret ID")
}

// Attempting to bootstrap a token on a non-ACL enabled server should fail.
func TestACLBootstrapCommand_NonACLServer(t *testing.T) {
	t.Parallel()
	assert := assert.New(t)

	srv, _, url := testServer(t, true, nil)
	defer srv.Shutdown()

	ui := new(cli.MockUi)
	cmd := &ACLBootstrapCommand{Meta: Meta{Ui: ui, flagAddress: url}}

	code := cmd.Run([]string{"-address=" + url})
	assert.Equal(1, code)

	out := ui.OutputWriter.String()
	assert.NotContains(out, "Secret ID")
}
<|endoftext|>


<commit_before>package agent

import (
	"bytes"
	"github.com/hashicorp/serf/client"
	"github.com/hashicorp/serf/testutil"
	"github.com/mitchellh/cli"
	"log"
	"testing"
	"time"
)

func TestCommand_implements(t *testing.T) {
	var _ cli.Command = new(Command)
}

func TestCommandRun(t *testing.T) {
	shutdownCh := make(chan struct{})
	defer close(shutdownCh)

	ui := new(cli.MockUi)
	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         ui,
	}

	args := []string{
		"-bind", testutil.GetBindAddr().String(),
		"-rpc-addr", getRPCAddr(),
	}

	resultCh := make(chan int)
	go func() {
		resultCh <- c.Run(args)
	}()

	testutil.Yield()

	// Verify it runs "forever"
	select {
	case <-resultCh:
		t.Fatalf("ended too soon, err: %s", ui.ErrorWriter.String())
	case <-time.After(50 * time.Millisecond):
	}

	// Send a shutdown request
	shutdownCh <- struct{}{}

	select {
	case code := <-resultCh:
		if code != 0 {
			t.Fatalf("bad code: %d", code)
		}
	case <-time.After(50 * time.Millisecond):
		t.Fatalf("timeout")
	}
}

func TestCommandRun_rpc(t *testing.T) {
	doneCh := make(chan struct{})
	shutdownCh := make(chan struct{})
	defer func() {
		close(shutdownCh)
		<-doneCh
	}()

	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         new(cli.MockUi),
	}

	rpcAddr := getRPCAddr()
	args := []string{
		"-bind", testutil.GetBindAddr().String(),
		"-rpc-addr", rpcAddr,
	}

	go func() {
		code := c.Run(args)
		if code != 0 {
			log.Printf("bad: %d", code)
		}

		close(doneCh)
	}()

	testutil.Yield()

	client, err := client.NewRPCClient(rpcAddr)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	defer client.Close()

	members, err := client.Members()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(members) != 1 {
		t.Fatalf("bad: %#v", members)
	}
}

func TestCommandRun_join(t *testing.T) {
	a1 := testAgent(nil)
	if err := a1.Start(); err != nil {
		t.Fatalf("err: %s", err)
	}
	defer a1.Shutdown()

	doneCh := make(chan struct{})
	shutdownCh := make(chan struct{})
	defer func() {
		close(shutdownCh)
		<-doneCh
	}()

	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         new(cli.MockUi),
	}

	args := []string{
		"-bind", testutil.GetBindAddr().String(),
		"-join", a1.conf.MemberlistConfig.BindAddr,
		"-replay",
	}

	go func() {
		code := c.Run(args)
		if code != 0 {
			log.Printf("bad: %d", code)
		}

		close(doneCh)
	}()

	testutil.Yield()

	if len(a1.Serf().Members()) != 2 {
		t.Fatalf("bad: %#v", a1.Serf().Members())
	}
}

func TestCommandRun_joinFail(t *testing.T) {
	shutdownCh := make(chan struct{})
	defer close(shutdownCh)

	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         new(cli.MockUi),
	}

	args := []string{
		"-bind", testutil.GetBindAddr().String(),
		"-join", testutil.GetBindAddr().String(),
	}

	code := c.Run(args)
	if code == 0 {
		t.Fatal("should fail")
	}
}

func TestCommandRun_advertiseAddr(t *testing.T) {
	doneCh := make(chan struct{})
	shutdownCh := make(chan struct{})
	defer func() {
		close(shutdownCh)
		<-doneCh
	}()

	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         new(cli.MockUi),
	}

	rpcAddr := getRPCAddr()
	args := []string{
		"-bind", testutil.GetBindAddr().String(),
		"-rpc-addr", rpcAddr,
		"-advertise", "127.0.0.10:12345",
	}

	go func() {
		code := c.Run(args)
		if code != 0 {
			log.Printf("bad: %d", code)
		}

		close(doneCh)
	}()

	testutil.Yield()

	client, err := client.NewRPCClient(rpcAddr)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	defer client.Close()

	members, err := client.Members()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(members) != 1 {
		t.Fatalf("bad: %#v", members)
	}

	// Check the addr and port is as advertised!
	m := members[0]
	if bytes.Compare(m.Addr, []byte{127, 0, 0, 10}) != 0 {
		t.Fatalf("bad: %#v", m)
	}
	if m.Port != 12345 {
		t.Fatalf("bad: %#v", m)
	}
}

func TestCommandRun_mDNS(t *testing.T) {
	// Start an agent
	doneCh := make(chan struct{})
	shutdownCh := make(chan struct{})
	defer func() {
		close(shutdownCh)
		<-doneCh
	}()

	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         new(cli.MockUi),
	}

	args := []string{
		"-node", "foo",
		"-bind", testutil.GetBindAddr().String(),
		"-discover", "test",
		"-rpc-addr", getRPCAddr(),
	}

	go func() {
		code := c.Run(args)
		if code != 0 {
			log.Printf("bad: %d", code)
		}
		close(doneCh)
	}()

	// Start a second agent
	doneCh2 := make(chan struct{})
	shutdownCh2 := make(chan struct{})
	defer func() {
		close(shutdownCh2)
		<-doneCh2
	}()

	c2 := &Command{
		ShutdownCh: shutdownCh2,
		Ui:         new(cli.MockUi),
	}

	addr2 := getRPCAddr()
	args2 := []string{
		"-node", "bar",
		"-bind", testutil.GetBindAddr().String(),
		"-discover", "test",
		"-rpc-addr", addr2,
	}

	go func() {
		code := c2.Run(args2)
		if code != 0 {
			log.Printf("bad: %d", code)
		}
		close(doneCh2)
	}()

	time.Sleep(150 * time.Millisecond)

	client, err := client.NewRPCClient(addr2)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	defer client.Close()

	members, err := client.Members()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(members) != 2 {
		t.Fatalf("bad: %#v", members)
	}
}
<commit_msg>Disable mDNS test in Travis CI<commit_after>package agent

import (
	"bytes"
	"github.com/hashicorp/serf/client"
	"github.com/hashicorp/serf/testutil"
	"github.com/mitchellh/cli"
	"log"
	"os"
	"testing"
	"time"
)

func TestCommand_implements(t *testing.T) {
	var _ cli.Command = new(Command)
}

func TestCommandRun(t *testing.T) {
	shutdownCh := make(chan struct{})
	defer close(shutdownCh)

	ui := new(cli.MockUi)
	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         ui,
	}

	args := []string{
		"-bind", testutil.GetBindAddr().String(),
		"-rpc-addr", getRPCAddr(),
	}

	resultCh := make(chan int)
	go func() {
		resultCh <- c.Run(args)
	}()

	testutil.Yield()

	// Verify it runs "forever"
	select {
	case <-resultCh:
		t.Fatalf("ended too soon, err: %s", ui.ErrorWriter.String())
	case <-time.After(50 * time.Millisecond):
	}

	// Send a shutdown request
	shutdownCh <- struct{}{}

	select {
	case code := <-resultCh:
		if code != 0 {
			t.Fatalf("bad code: %d", code)
		}
	case <-time.After(50 * time.Millisecond):
		t.Fatalf("timeout")
	}
}

func TestCommandRun_rpc(t *testing.T) {
	doneCh := make(chan struct{})
	shutdownCh := make(chan struct{})
	defer func() {
		close(shutdownCh)
		<-doneCh
	}()

	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         new(cli.MockUi),
	}

	rpcAddr := getRPCAddr()
	args := []string{
		"-bind", testutil.GetBindAddr().String(),
		"-rpc-addr", rpcAddr,
	}

	go func() {
		code := c.Run(args)
		if code != 0 {
			log.Printf("bad: %d", code)
		}

		close(doneCh)
	}()

	testutil.Yield()

	client, err := client.NewRPCClient(rpcAddr)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	defer client.Close()

	members, err := client.Members()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(members) != 1 {
		t.Fatalf("bad: %#v", members)
	}
}

func TestCommandRun_join(t *testing.T) {
	a1 := testAgent(nil)
	if err := a1.Start(); err != nil {
		t.Fatalf("err: %s", err)
	}
	defer a1.Shutdown()

	doneCh := make(chan struct{})
	shutdownCh := make(chan struct{})
	defer func() {
		close(shutdownCh)
		<-doneCh
	}()

	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         new(cli.MockUi),
	}

	args := []string{
		"-bind", testutil.GetBindAddr().String(),
		"-join", a1.conf.MemberlistConfig.BindAddr,
		"-replay",
	}

	go func() {
		code := c.Run(args)
		if code != 0 {
			log.Printf("bad: %d", code)
		}

		close(doneCh)
	}()

	testutil.Yield()

	if len(a1.Serf().Members()) != 2 {
		t.Fatalf("bad: %#v", a1.Serf().Members())
	}
}

func TestCommandRun_joinFail(t *testing.T) {
	shutdownCh := make(chan struct{})
	defer close(shutdownCh)

	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         new(cli.MockUi),
	}

	args := []string{
		"-bind", testutil.GetBindAddr().String(),
		"-join", testutil.GetBindAddr().String(),
	}

	code := c.Run(args)
	if code == 0 {
		t.Fatal("should fail")
	}
}

func TestCommandRun_advertiseAddr(t *testing.T) {
	doneCh := make(chan struct{})
	shutdownCh := make(chan struct{})
	defer func() {
		close(shutdownCh)
		<-doneCh
	}()

	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         new(cli.MockUi),
	}

	rpcAddr := getRPCAddr()
	args := []string{
		"-bind", testutil.GetBindAddr().String(),
		"-rpc-addr", rpcAddr,
		"-advertise", "127.0.0.10:12345",
	}

	go func() {
		code := c.Run(args)
		if code != 0 {
			log.Printf("bad: %d", code)
		}

		close(doneCh)
	}()

	testutil.Yield()

	client, err := client.NewRPCClient(rpcAddr)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	defer client.Close()

	members, err := client.Members()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(members) != 1 {
		t.Fatalf("bad: %#v", members)
	}

	// Check the addr and port is as advertised!
	m := members[0]
	if bytes.Compare(m.Addr, []byte{127, 0, 0, 10}) != 0 {
		t.Fatalf("bad: %#v", m)
	}
	if m.Port != 12345 {
		t.Fatalf("bad: %#v", m)
	}
}

func TestCommandRun_mDNS(t *testing.T) {
	// mDNS does not work in travis
	if os.Getenv("TRAVIS") != "" {
		t.SkipNow()
	}

	// Start an agent
	doneCh := make(chan struct{})
	shutdownCh := make(chan struct{})
	defer func() {
		close(shutdownCh)
		<-doneCh
	}()

	c := &Command{
		ShutdownCh: shutdownCh,
		Ui:         new(cli.MockUi),
	}

	args := []string{
		"-node", "foo",
		"-bind", testutil.GetBindAddr().String(),
		"-discover", "test",
		"-rpc-addr", getRPCAddr(),
	}

	go func() {
		code := c.Run(args)
		if code != 0 {
			log.Printf("bad: %d", code)
		}
		close(doneCh)
	}()

	// Start a second agent
	doneCh2 := make(chan struct{})
	shutdownCh2 := make(chan struct{})
	defer func() {
		close(shutdownCh2)
		<-doneCh2
	}()

	c2 := &Command{
		ShutdownCh: shutdownCh2,
		Ui:         new(cli.MockUi),
	}

	addr2 := getRPCAddr()
	args2 := []string{
		"-node", "bar",
		"-bind", testutil.GetBindAddr().String(),
		"-discover", "test",
		"-rpc-addr", addr2,
	}

	go func() {
		code := c2.Run(args2)
		if code != 0 {
			log.Printf("bad: %d", code)
		}
		close(doneCh2)
	}()

	time.Sleep(150 * time.Millisecond)

	client, err := client.NewRPCClient(addr2)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	defer client.Close()

	members, err := client.Members()
	if err != nil {
		t.Fatalf("err: %s", err)
	}

	if len(members) != 2 {
		t.Fatalf("bad: %#v", members)
	}
}
<|endoftext|>