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

// This file implements the Modules type.  This includes the processing of
// include and import statements, which must be done prior to turning the
// module into an Entry tree.

import "fmt"

// Modules contains information about all the top level modules and
// submodules that are read into it via its Read method.
type Modules struct {
	Modules    map[string]*Module // All "module" nodes
	SubModules map[string]*Module // All "submodule" nodes
	includes   map[*Module]bool   // Modules we have already done include on
	byPrefix   map[string]*Module // Cache of prefix lookup
}

// NewModules returns a newly created and initialized Modules.
func NewModules() *Modules {
	return &Modules{
		Modules:    map[string]*Module{},
		SubModules: map[string]*Module{},
		includes:   map[*Module]bool{},
		byPrefix:   map[string]*Module{},
	}
}

// Read reads the named yang module into ms.  The name can be the name of an
// actual .yang file or a module/submodule name (the base name of a .yang file,
// e.g., foo.yang is named foo).  An error is returned if the file is not
// found or there was an error parsing the file.
func (ms *Modules) Read(name string) error {
	name, data, err := findFile(name)
	if err != nil {
		return err
	}
	return ms.Parse(string(data), name)
}

// Parse parses data as YANG source and adds it to ms.  The name should reflect
// the source of data.
func (ms *Modules) Parse(data, name string) error {
	ss, err := Parse(data, name)
	if err != nil {
		return err
	}
	for _, s := range ss {
		n, err := BuildAST(s)
		if err != nil {
			return err
		}
		ms.add(n)
	}
	return nil
}

// GetModule returns the Entry of the module named by name.  GetModule will
// search for and read the file named name + ".yang" if it cannot satisfy the
// request from what it has currntly read.
//
// GetModule is a convience function for calling Read and Process, and
// then looking up the module name.  It is safe to call Read and Process prior
// to calling GetModule.
func (ms *Modules) GetModule(name string) (*Entry, []error) {
	if ms.Modules[name] == nil {
		if err := ms.Read(name); err != nil {
			return nil, []error{err}
		}
		if ms.Modules[name] == nil {
			return nil, []error{fmt.Errorf("module not found: %s", name)}
		}
	}
	// Make sure that the modules have all been processed and have no
	// errors.
	if errs := ms.Process(); len(errs) != 0 {
		return nil, errs
	}
	return ToEntry(ms.Modules[name]), nil
}

// GetModule optionally reads in a set of YANG source files, named by sources,
// and then returns the Entry for the module named module.  If sources is
// missing, or the named module is not yet known, GetModule searchs for name
// with the suffix ".yang".  GetModule either returns an Entry or returns
// one or more errors.
//
// GetModule is a convience function for calling NewModules, Read, and Process,
// and then looking up the module name.
func GetModule(name string, sources ...string) (*Entry, []error) {
	var errs []error
	ms := NewModules()
	for _, source := range sources {
		if err := ms.Read(source); err != nil {
			errs = append(errs, err)
		}
	}
	if len(errs) > 0 {
		return nil, errs
	}
	return ms.GetModule(name)
}

// add adds Node n to ms.  n must be assignable to *Module (i.e., it is a
// "module" or "submodule").  An error is returned if n is a duplicate of
// a name already added, or n is not assignable to *Module.
func (ms *Modules) add(n Node) error {
	var m map[string]*Module

	name := n.NName()
	kind := n.Kind()
	switch kind {
	case "module":
		m = ms.Modules
	case "submodule":
		m = ms.SubModules
	default:
		return fmt.Errorf("not a module or submodule: %s is of type %s", name, kind)
	}

	mod := n.(*Module)
	fullName := mod.FullName()
	mod.modules = ms

	if o := m[fullName]; o != nil {
		return fmt.Errorf("duplicate %s %s at %s and %s", kind, fullName, Source(o), Source(n))
	}
	m[fullName] = mod
	if fullName == name {
		return nil
	}

	// Add us to the map if:
	// name has not been added before
	// fullname is a more recent version of the entry.
	if o := m[name]; o == nil || o.FullName() < fullName {
		m[name] = mod
	}
	return nil
}

// FindModule returns the Module/Submodule specified by n, which must be a
// *Include or *Import.  If n is a *Include then a submodule is returned.  If n
// is a *Import then a module is returned.
func (ms *Modules) FindModule(n Node) *Module {
	name := n.NName()
	rev := name
	var m map[string]*Module

	switch i := n.(type) {
	case *Include:
		m = ms.SubModules
		if i.RevisionDate != nil {
			rev = name + "@" + i.RevisionDate.Name
		}
		// TODO(borman): we should check the BelongsTo field below?
	case *Import:
		m = ms.Modules
		if i.RevisionDate != nil {
			rev = name + "@" + i.RevisionDate.Name
		}
	default:
		return nil
	}
	if n := m[rev]; n != nil {
		return n
	}
	if n := m[name]; n != nil {
		return n
	}

	// Try to read it in.
	if err := ms.Read(name); err != nil {
		return nil
	}
	if n := m[rev]; n != nil {
		return n
	}
	return m[name]
}

// FindModuleByPrefix either returns the Module specified by prefix or returns
// an error.
func (ms *Modules) FindModuleByPrefix(prefix string) (*Module, error) {
	if m, ok := ms.byPrefix[prefix]; ok {
		return m, nil
	}
	var found *Module
	for _, m := range ms.Modules {
		if m.Prefix.Name == prefix {
			switch {
			case m == found:
			case found != nil:
				return nil, fmt.Errorf("prefix % matches two or more modules (%s, %s)\n", found.Name, m.Name)
			default:
				found = m
			}
		}
	}
	ms.byPrefix[prefix] = found
	if found == nil {
		return nil, fmt.Errorf("%s: no such prefix", prefix)
	}
	return found, nil
}

// process satisfies all include and import statements and verifies that all
// link ref paths reference a known node.  If an import or include references
// a [sub]module that is not already known, Process will search for a .yang
// file that contains it, returning an error if not found.  An error is also
// returned if there is an unknown link ref path or other parsing errors.
//
// Process must be called once all the source modules have been read in and
// prior to converting Node tree into an Entry tree.
func (ms *Modules) process() []error {
	var mods []*Module
	var errs []error

	// Collect the list of modules we know about now so when we range
	// below we don't pick up new modules.  We assume the user tells
	// us explicitly which modules they are interested in.
	for _, m := range ms.Modules {
		mods = append(mods, m)
	}
	for _, m := range mods {
		if err := ms.include(m); err != nil {
			errs = append(errs, err)
		}
	}

	// Append any errors found trying to resolve typedefs
	errs = append(errs, resolveTypedefs()...)
	return errs
}

// Process processes all the modules and submodules that have been read into
// ms.  While processing, if an include or import is found for which there
// is no matching module, Process attempts to locate the source file (using
// Path) and automatically load them.  If a file cannot be found then an
// error is returned.  When looking for a source file, Process searches for a
// file using the module's or submodule's name with ".yang" appended.  After
// searching the current directory, the directories in Path are searched.
//
// Process builds Entry trees for each modules and submodules in ms.  These
// trees are accessed using the ToEntry function.  Process does augmentation
// on Entry trees once all the modules and submodules in ms have been built.
// Following augmentation, Process inserts implied case statements.  I.e.,
//
//   choice interface-type {
//       container ethernet { ... }
//   }
//
// has a case statement inserted to become:
//
//   choice interface-type {
//       case ethernet {
//           container ethernet { ... }
//       }
//   }
//
// Process may return multiple errors if multiple errors were encountered
// while processing.  Even though multiple errors may be returned, this does
// not mean these are all the errors.  Process will terminate processing early
// based on the type and location of the error.
func (ms *Modules) Process() []error {
	errs := ms.process()
	if len(errs) > 0 {
		return errorSort(errs)
	}

	for _, m := range ms.Modules {
		errs = append(errs, ToEntry(m).GetErrors()...)
	}
	for _, m := range ms.SubModules {
		errs = append(errs, ToEntry(m).GetErrors()...)
	}

	if len(errs) > 0 {
		return errorSort(errs)
	}

	// Now handle all the augments.  We don't have a good way to know
	// what order to process them in, so repeat until no progress is made

	mods := make([]*Module, 0, len(ms.Modules)+len(ms.SubModules))
	for _, m := range ms.Modules {
		mods = append(mods, m)
	}
	for _, m := range ms.SubModules {
		mods = append(mods, m)
	}
	for len(mods) > 0 {
		var processed, skipped int
		for i := 0; i < len(mods); {
			m := mods[i]
			p, s := ToEntry(m).Augment(false)
			processed += p
			skipped += p
			if s == 0 {
				mods[i] = mods[len(mods)-1]
				mods = mods[:len(mods)-1]
				continue
			}
			i++
		}
		if processed == 0 {
			break
		}
	}

	// Now fix up all the choice statements to add in the missing case
	// statements.
	for _, m := range ms.Modules {
		ToEntry(m).FixChoice()
	}
	for _, m := range ms.SubModules {
		ToEntry(m).FixChoice()
	}

	// Go through any modules that have remaining augments and collect
	// the errors.
	for _, m := range mods {
		ToEntry(m).Augment(true)
		errs = append(errs, ToEntry(m).GetErrors()...)
	}
	return errorSort(errs)
}

// include resolves all the include and import statements for m.  It returns
// an error if m, or recursively, any of the modules it includes or imports,
// reference a module that cannot be found.
func (ms *Modules) include(m *Module) error {
	if ms.includes[m] {
		return nil
	}
	ms.includes[m] = true

	// First process any includes in this module.
	for _, i := range m.Include {
		im := ms.FindModule(i)
		if im == nil {
			// TODO(borman): should print @rev if available
			return fmt.Errorf("no such submodule: %s", i.Name)
		}
		// Process the include statements in our included module.
		if err := ms.include(im); err != nil {
			return err
		}
		i.Module = im
	}

	// Next process any imports in this module.  Imports are used
	// when searching.
	for _, i := range m.Import {
		im := ms.FindModule(i)
		if im == nil {
			// TODO(borman): should print @rev if available
			return fmt.Errorf("no such module: %s", i.Name)
		}
		// Process the include statements in our included module.
		if err := ms.include(im); err != nil {
			return err
		}
		i.Module = im
	}
	return nil
}
<commit_msg>modules: Correct string formatting format<commit_after>// Copyright 2015 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 yang

// This file implements the Modules type.  This includes the processing of
// include and import statements, which must be done prior to turning the
// module into an Entry tree.

import "fmt"

// Modules contains information about all the top level modules and
// submodules that are read into it via its Read method.
type Modules struct {
	Modules    map[string]*Module // All "module" nodes
	SubModules map[string]*Module // All "submodule" nodes
	includes   map[*Module]bool   // Modules we have already done include on
	byPrefix   map[string]*Module // Cache of prefix lookup
}

// NewModules returns a newly created and initialized Modules.
func NewModules() *Modules {
	return &Modules{
		Modules:    map[string]*Module{},
		SubModules: map[string]*Module{},
		includes:   map[*Module]bool{},
		byPrefix:   map[string]*Module{},
	}
}

// Read reads the named yang module into ms.  The name can be the name of an
// actual .yang file or a module/submodule name (the base name of a .yang file,
// e.g., foo.yang is named foo).  An error is returned if the file is not
// found or there was an error parsing the file.
func (ms *Modules) Read(name string) error {
	name, data, err := findFile(name)
	if err != nil {
		return err
	}
	return ms.Parse(string(data), name)
}

// Parse parses data as YANG source and adds it to ms.  The name should reflect
// the source of data.
func (ms *Modules) Parse(data, name string) error {
	ss, err := Parse(data, name)
	if err != nil {
		return err
	}
	for _, s := range ss {
		n, err := BuildAST(s)
		if err != nil {
			return err
		}
		ms.add(n)
	}
	return nil
}

// GetModule returns the Entry of the module named by name.  GetModule will
// search for and read the file named name + ".yang" if it cannot satisfy the
// request from what it has currntly read.
//
// GetModule is a convience function for calling Read and Process, and
// then looking up the module name.  It is safe to call Read and Process prior
// to calling GetModule.
func (ms *Modules) GetModule(name string) (*Entry, []error) {
	if ms.Modules[name] == nil {
		if err := ms.Read(name); err != nil {
			return nil, []error{err}
		}
		if ms.Modules[name] == nil {
			return nil, []error{fmt.Errorf("module not found: %s", name)}
		}
	}
	// Make sure that the modules have all been processed and have no
	// errors.
	if errs := ms.Process(); len(errs) != 0 {
		return nil, errs
	}
	return ToEntry(ms.Modules[name]), nil
}

// GetModule optionally reads in a set of YANG source files, named by sources,
// and then returns the Entry for the module named module.  If sources is
// missing, or the named module is not yet known, GetModule searchs for name
// with the suffix ".yang".  GetModule either returns an Entry or returns
// one or more errors.
//
// GetModule is a convience function for calling NewModules, Read, and Process,
// and then looking up the module name.
func GetModule(name string, sources ...string) (*Entry, []error) {
	var errs []error
	ms := NewModules()
	for _, source := range sources {
		if err := ms.Read(source); err != nil {
			errs = append(errs, err)
		}
	}
	if len(errs) > 0 {
		return nil, errs
	}
	return ms.GetModule(name)
}

// add adds Node n to ms.  n must be assignable to *Module (i.e., it is a
// "module" or "submodule").  An error is returned if n is a duplicate of
// a name already added, or n is not assignable to *Module.
func (ms *Modules) add(n Node) error {
	var m map[string]*Module

	name := n.NName()
	kind := n.Kind()
	switch kind {
	case "module":
		m = ms.Modules
	case "submodule":
		m = ms.SubModules
	default:
		return fmt.Errorf("not a module or submodule: %s is of type %s", name, kind)
	}

	mod := n.(*Module)
	fullName := mod.FullName()
	mod.modules = ms

	if o := m[fullName]; o != nil {
		return fmt.Errorf("duplicate %s %s at %s and %s", kind, fullName, Source(o), Source(n))
	}
	m[fullName] = mod
	if fullName == name {
		return nil
	}

	// Add us to the map if:
	// name has not been added before
	// fullname is a more recent version of the entry.
	if o := m[name]; o == nil || o.FullName() < fullName {
		m[name] = mod
	}
	return nil
}

// FindModule returns the Module/Submodule specified by n, which must be a
// *Include or *Import.  If n is a *Include then a submodule is returned.  If n
// is a *Import then a module is returned.
func (ms *Modules) FindModule(n Node) *Module {
	name := n.NName()
	rev := name
	var m map[string]*Module

	switch i := n.(type) {
	case *Include:
		m = ms.SubModules
		if i.RevisionDate != nil {
			rev = name + "@" + i.RevisionDate.Name
		}
		// TODO(borman): we should check the BelongsTo field below?
	case *Import:
		m = ms.Modules
		if i.RevisionDate != nil {
			rev = name + "@" + i.RevisionDate.Name
		}
	default:
		return nil
	}
	if n := m[rev]; n != nil {
		return n
	}
	if n := m[name]; n != nil {
		return n
	}

	// Try to read it in.
	if err := ms.Read(name); err != nil {
		return nil
	}
	if n := m[rev]; n != nil {
		return n
	}
	return m[name]
}

// FindModuleByPrefix either returns the Module specified by prefix or returns
// an error.
func (ms *Modules) FindModuleByPrefix(prefix string) (*Module, error) {
	if m, ok := ms.byPrefix[prefix]; ok {
		return m, nil
	}
	var found *Module
	for _, m := range ms.Modules {
		if m.Prefix.Name == prefix {
			switch {
			case m == found:
			case found != nil:
				return nil, fmt.Errorf("prefix %s matches two or more modules (%s, %s)\n", prefix, found.Name, m.Name)
			default:
				found = m
			}
		}
	}
	ms.byPrefix[prefix] = found
	if found == nil {
		return nil, fmt.Errorf("%s: no such prefix", prefix)
	}
	return found, nil
}

// process satisfies all include and import statements and verifies that all
// link ref paths reference a known node.  If an import or include references
// a [sub]module that is not already known, Process will search for a .yang
// file that contains it, returning an error if not found.  An error is also
// returned if there is an unknown link ref path or other parsing errors.
//
// Process must be called once all the source modules have been read in and
// prior to converting Node tree into an Entry tree.
func (ms *Modules) process() []error {
	var mods []*Module
	var errs []error

	// Collect the list of modules we know about now so when we range
	// below we don't pick up new modules.  We assume the user tells
	// us explicitly which modules they are interested in.
	for _, m := range ms.Modules {
		mods = append(mods, m)
	}
	for _, m := range mods {
		if err := ms.include(m); err != nil {
			errs = append(errs, err)
		}
	}

	// Append any errors found trying to resolve typedefs
	errs = append(errs, resolveTypedefs()...)
	return errs
}

// Process processes all the modules and submodules that have been read into
// ms.  While processing, if an include or import is found for which there
// is no matching module, Process attempts to locate the source file (using
// Path) and automatically load them.  If a file cannot be found then an
// error is returned.  When looking for a source file, Process searches for a
// file using the module's or submodule's name with ".yang" appended.  After
// searching the current directory, the directories in Path are searched.
//
// Process builds Entry trees for each modules and submodules in ms.  These
// trees are accessed using the ToEntry function.  Process does augmentation
// on Entry trees once all the modules and submodules in ms have been built.
// Following augmentation, Process inserts implied case statements.  I.e.,
//
//   choice interface-type {
//       container ethernet { ... }
//   }
//
// has a case statement inserted to become:
//
//   choice interface-type {
//       case ethernet {
//           container ethernet { ... }
//       }
//   }
//
// Process may return multiple errors if multiple errors were encountered
// while processing.  Even though multiple errors may be returned, this does
// not mean these are all the errors.  Process will terminate processing early
// based on the type and location of the error.
func (ms *Modules) Process() []error {
	errs := ms.process()
	if len(errs) > 0 {
		return errorSort(errs)
	}

	for _, m := range ms.Modules {
		errs = append(errs, ToEntry(m).GetErrors()...)
	}
	for _, m := range ms.SubModules {
		errs = append(errs, ToEntry(m).GetErrors()...)
	}

	if len(errs) > 0 {
		return errorSort(errs)
	}

	// Now handle all the augments.  We don't have a good way to know
	// what order to process them in, so repeat until no progress is made

	mods := make([]*Module, 0, len(ms.Modules)+len(ms.SubModules))
	for _, m := range ms.Modules {
		mods = append(mods, m)
	}
	for _, m := range ms.SubModules {
		mods = append(mods, m)
	}
	for len(mods) > 0 {
		var processed, skipped int
		for i := 0; i < len(mods); {
			m := mods[i]
			p, s := ToEntry(m).Augment(false)
			processed += p
			skipped += p
			if s == 0 {
				mods[i] = mods[len(mods)-1]
				mods = mods[:len(mods)-1]
				continue
			}
			i++
		}
		if processed == 0 {
			break
		}
	}

	// Now fix up all the choice statements to add in the missing case
	// statements.
	for _, m := range ms.Modules {
		ToEntry(m).FixChoice()
	}
	for _, m := range ms.SubModules {
		ToEntry(m).FixChoice()
	}

	// Go through any modules that have remaining augments and collect
	// the errors.
	for _, m := range mods {
		ToEntry(m).Augment(true)
		errs = append(errs, ToEntry(m).GetErrors()...)
	}
	return errorSort(errs)
}

// include resolves all the include and import statements for m.  It returns
// an error if m, or recursively, any of the modules it includes or imports,
// reference a module that cannot be found.
func (ms *Modules) include(m *Module) error {
	if ms.includes[m] {
		return nil
	}
	ms.includes[m] = true

	// First process any includes in this module.
	for _, i := range m.Include {
		im := ms.FindModule(i)
		if im == nil {
			// TODO(borman): should print @rev if available
			return fmt.Errorf("no such submodule: %s", i.Name)
		}
		// Process the include statements in our included module.
		if err := ms.include(im); err != nil {
			return err
		}
		i.Module = im
	}

	// Next process any imports in this module.  Imports are used
	// when searching.
	for _, i := range m.Import {
		im := ms.FindModule(i)
		if im == nil {
			// TODO(borman): should print @rev if available
			return fmt.Errorf("no such module: %s", i.Name)
		}
		// Process the include statements in our included module.
		if err := ms.include(im); err != nil {
			return err
		}
		i.Module = im
	}
	return nil
}
<|endoftext|>


<commit_before>package nvml

/*
// #cgo CPPFLAGS: -I/path/to/install
#cgo LDFLAGS: -L/usr/src/gdk/nvml/lib/ -l nvidia-ml

#include "nvmlbridge.h"
*/
import "C"

import (
	"errors"
	"log"
	"unsafe"
)

type Device struct {
	nvmldevice C.nvmlDevice_t
	index      uint
	pcibus     string
	name       string
	uuid       string
}

// NewDevice is a contstructor function for Device structs. Given an nvmlDevice_t
// object as input, it populates some static property fields and returns a Device
func NewDevice(cdevice C.nvmlDevice_t) (*Device, error) {
	device := Device{
		nvmldevice: cdevice,
	}

	uuid, err := device.UUID()
	if err != nil {
		return nil, errors.New("Cannot retrieve UUID property")
	}
	device.uuid = uuid

	name, err := device.Name()
	if err != nil {
		return nil, errors.New("Cannot retrieve Name property")
	}
	device.name = name

	index, err := device.Index()
	if err != nil {
		return nil, errors.New("Cannot retrieve Index property")
	}
	device.index = index

	return &device, nil
}

func (gpu *Device) PowerState() (int, error) {
	var pstate C.nvmlPstates_t
	var result C.nvmlReturn_t

	result = C.nvmlDeviceGetPowerState(gpu.nvmldevice, &pstate)
	if result != C.NVML_SUCCESS {
		return -1, errors.New("GetPowerState returned error")
	}

	return int(pstate), nil
}

// Temp returns the current temperature of the card in degrees Celsius
func (gpu *Device) Temp() (uint, error) {
	var result C.nvmlReturn_t
	var ctemp C.uint

	result = C.nvmlDeviceGetTemperature(gpu.nvmldevice, C.NVML_TEMPERATURE_GPU, &ctemp)
	if result != C.NVML_SUCCESS {
		return 0, errors.New("GetPowerState returned error")
	}

	return uint(ctemp), nil
}

type cIntPropFunc struct {
	f C.getintProperty
}

var intpropfunctions = map[string]*cIntPropFunc{
	"Index":                        {C.getintProperty(C.nvmlDeviceGetIndex)},
	"MinorNumber":                  {C.getintProperty(C.nvmlDeviceGetMinorNumber)},
	"InforomConfigurationChecksum": {C.getintProperty(C.nvmlDeviceGetInforomConfigurationChecksum)},
	"MaxPcieLinkGeneration":        {C.getintProperty(C.nvmlDeviceGetMaxPcieLinkGeneration)},
	"MaxPcieLinkWidth":             {C.getintProperty(C.nvmlDeviceGetMaxPcieLinkWidth)},
	"CurrPcieLinkGeneration":       {C.getintProperty(C.nvmlDeviceGetCurrPcieLinkGeneration)},
	"CurrPcieLinkWidth":            {C.getintProperty(C.nvmlDeviceGetCurrPcieLinkWidth)},
	"PcieReplayCounter":            {C.getintProperty(C.nvmlDeviceGetPcieReplayCounter)},
	"FanSpeed":                     {C.getintProperty(C.nvmlDeviceGetFanSpeed)},
	"PowerManagementLimit":         {C.getintProperty(C.nvmlDeviceGetPowerManagementLimit)},
	"PowerManagementDefaultLimit":  {C.getintProperty(C.nvmlDeviceGetPowerManagementDefaultLimit)},
	"PowerUsage":                   {C.getintProperty(C.nvmlDeviceGetPowerUsage)},
	"EnforcedPowerLimit":           {C.getintProperty(C.nvmlDeviceGetEnforcedPowerLimit)},
	"BoardId":                      {C.getintProperty(C.nvmlDeviceGetBoardId)},
	"MultiGpuBoard":                {C.getintProperty(C.nvmlDeviceGetMultiGpuBoard)},
	"AccountingBufferSize":         {C.getintProperty(C.nvmlDeviceGetAccountingBufferSize)},
}

func (gpu *Device) intProperty(property string) (uint, error) {
	var cuintproperty C.uint

	ipf, ok := intpropfunctions[property]
	if ok == false {
		return 0, errors.New("property not found")
	}

	result := C.bridge_get_int_property(ipf.f, gpu.nvmldevice, &cuintproperty)
	if result != C.EXIT_SUCCESS {
		return 0, errors.New("getintProperty bridge returned error")
	}

	return uint(cuintproperty), nil
}

func (gpu *Device) Index() (uint, error) {
	return gpu.intProperty("Index")
}

func (gpu *Device) MinorNumber() (uint, error) {
	return gpu.intProperty("MinorNumber")
}

func (gpu *Device) InforomConfigurationChecksum() (uint, error) {
	return gpu.intProperty("InforomConfigurationChecksum")
}

func (gpu *Device) MaxPcieLinkGeneration() (uint, error) {
	return gpu.intProperty("MaxPcieLinkGeneration")
}

func (gpu *Device) MaxPcieLinkWidth() (uint, error) {
	return gpu.intProperty("MaxPcieLinkWidth")
}

func (gpu *Device) CurrPcieLinkGeneration() (uint, error) {
	return gpu.intProperty("CurrPcieLinkGeneration")
}

func (gpu *Device) CurrPcieLinkWidth() (uint, error) {
	return gpu.intProperty("CurrPcieLinkWidth")
}

func (gpu *Device) PcieReplayCounter() (uint, error) {
	return gpu.intProperty("PcieReplayCounter")
}

func (gpu *Device) FanSpeed() (uint, error) {
	return gpu.intProperty("FanSpeed")
}

func (gpu *Device) PowerManagementLimit() (uint, error) {
	return gpu.intProperty("PowerManagementLimit")
}

func (gpu *Device) PowerManagementDefaultLimit() (uint, error) {
	return gpu.intProperty("PowerManagementDefaultLimit")
}

func (gpu *Device) PowerUsage() (uint, error) {
	return gpu.intProperty("PowerUsage")
}

func (gpu *Device) EnforcedPowerLimit() (uint, error) {
	return gpu.intProperty("EnforcedPowerLimit")
}

func (gpu *Device) BoardId() (uint, error) {
	return gpu.intProperty("BoardId")
}

func (gpu *Device) MultiGpuBoard() (uint, error) {
	return gpu.intProperty("MultiGpuBoard")
}

func (gpu *Device) AccountingBufferSize() (uint, error) {
	return gpu.intProperty("AccountingBufferSize")
}

type cTextPropFunc struct {
	f      C.gettextProperty
	length C.uint
}

var textpropfunctions = map[string]*cTextPropFunc{
	"Name":                {C.gettextProperty(C.nvmlDeviceGetName), C.NVML_DEVICE_NAME_BUFFER_SIZE},
	"Serial":              {C.gettextProperty(C.nvmlDeviceGetSerial), C.NVML_DEVICE_SERIAL_BUFFER_SIZE},
	"UUID":                {C.gettextProperty(C.nvmlDeviceGetUUID), C.NVML_DEVICE_UUID_BUFFER_SIZE},
	"InforomImageVersion": {C.gettextProperty(C.nvmlDeviceGetInforomImageVersion), C.NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE},
	"VbiosVersion":        {C.gettextProperty(C.nvmlDeviceGetVbiosVersion), C.NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE},
}

// textProperty takes a propertyname as input and then runs the corresponding
// function in the textpropfunctions map, returning the result as a Go string.
//
// textProperty takes care of allocating (and freeing) the text buffers of
// proper size.
func (gpu *Device) textProperty(property string) (string, error) {
	var propvalue string

	// If there isn't a valid entry for this property in the map, there's no reason
	// to process any further
	tpf, ok := textpropfunctions[property]
	if ok == false {
		return "", errors.New("property not found")
	}

	var buf *C.char = genCStringBuffer(uint(tpf.length))
	defer C.free(unsafe.Pointer(buf))

	result := C.bridge_get_text_property(tpf.f, gpu.nvmldevice, buf, tpf.length)
	if result != C.EXIT_SUCCESS {
		return propvalue, errors.New("gettextProperty bridge returned error")
	}

	propvalue = strndup(buf, uint(tpf.length))
	if len(propvalue) > 0 {
		return propvalue, nil
	} else {
		return "", errors.New("textProperty returned empty string")
	}
}

func (gpu *Device) InforomImageVersion() (string, error) {
	return gpu.textProperty("InforomImageVersion")
}

func (gpu *Device) VbiosVersion() (string, error) {
	return gpu.textProperty("VbiosVersion")
}

// Return the product name of the device, e.g. "Tesla K40m"
func (gpu *Device) Name() (string, error) {
	return gpu.textProperty("Name")
}

// Return the UUID of the device
func (gpu *Device) UUID() (string, error) {
	return gpu.textProperty("UUID")
}

// Return the serial number of the device
func (gpu *Device) Serial() (string, error) {
	return gpu.textProperty("Serial")
}

// Go correspondent of the C.nvmlMemory_t struct. Memory in bytes
type NVMLMemory struct {
	Free  uint64
	Total uint64
	Used  uint64
}

// MemoryInfo returns a NVMLMemory struct populated with the amount of memory used,
// free, and in total on the device, in bytes.
func (gpu *Device) MemoryInfo() (NVMLMemory, error) {
	var result C.nvmlReturn_t
	var cmeminfo C.nvmlMemory_t
	var meminfo NVMLMemory

	result = C.nvmlDeviceGetMemoryInfo(gpu.nvmldevice, &cmeminfo)
	if result != C.NVML_SUCCESS {
		return meminfo, errors.New("GetPowerState returned error")
	}

	meminfo.Free = uint64(cmeminfo.free)
	meminfo.Total = uint64(cmeminfo.total)
	meminfo.Used = uint64(cmeminfo.used)

	return meminfo, nil
}

// Return a proper golang error of representation of the nvmlReturn_t error
func (gpu *Device) Error(cerror C.nvmlReturn_t) error {
	var cerrorstring *C.char

	// No need to process anything further if the nvml call succeeded
	if cerror == C.NVML_SUCCESS {
		return nil
	}

	cerrorstring = C.nvmlErrorString(cerror)
	if cerrorstring == nil {
		// I'm not sure how this could happen, but it's easy to check for
		return errors.New("Error not found in nvml.h")
	}

	return errors.New(C.GoString(cerrorstring))
}

func nvmlDeviceGetCount() (int, error) {
	var count C.uint

	result := C.nvmlDeviceGetCount(&count)
	if result != C.NVML_SUCCESS {
		return -1, errors.New("nvmlDeviceGetCount failed")
	}

	return int(count), nil
}

// GetAllGPUs will return a slice of type Device for all NVML devices present on
// the host system
func GetAllGPUs() ([]Device, error) {
	var devices []Device
	cdevices, err := getAllDevices()
	if err != nil {
		return devices, err
	}

	for _, cdevice := range cdevices {
		device, err := NewDevice(cdevice)
		if err != nil {
			break
		}

		devices = append(devices, *device)
	}

	return devices, nil
}

// getAllDevices returns an array of nvmlDevice_t structs representing all GPU
// devices in the system.
func getAllDevices() ([]C.nvmlDevice_t, error) {
	var devices []C.nvmlDevice_t

	device_count, err := nvmlDeviceGetCount()
	if err != nil {
		log.Fatal(err)
	}

	for i := 0; i < device_count; i++ {
		var device C.nvmlDevice_t
		result := C.nvmlDeviceGetHandleByIndex(C.uint(i), &device)
		if result != C.NVML_SUCCESS {
			return devices, errors.New("nvmlDeviceGetHandleByIndex returns error")
		}

		devices = append(devices, device)
	}

	if len(devices) == 0 {
		return devices, errors.New("No devices found")
	}

	return devices, nil
}
<commit_msg>Add descriptions to all the property functions<commit_after>package nvml

/*
// #cgo CPPFLAGS: -I/path/to/install
#cgo LDFLAGS: -L/usr/src/gdk/nvml/lib/ -l nvidia-ml

#include "nvmlbridge.h"
*/
import "C"

import (
	"errors"
	"log"
	"unsafe"
)

type Device struct {
	nvmldevice C.nvmlDevice_t
	index      uint
	pcibus     string
	name       string
	uuid       string
}

// NewDevice is a contstructor function for Device structs. Given an nvmlDevice_t
// object as input, it populates some static property fields and returns a Device
func NewDevice(cdevice C.nvmlDevice_t) (*Device, error) {
	device := Device{
		nvmldevice: cdevice,
	}

	uuid, err := device.UUID()
	if err != nil {
		return nil, errors.New("Cannot retrieve UUID property")
	}
	device.uuid = uuid

	name, err := device.Name()
	if err != nil {
		return nil, errors.New("Cannot retrieve Name property")
	}
	device.name = name

	index, err := device.Index()
	if err != nil {
		return nil, errors.New("Cannot retrieve Index property")
	}
	device.index = index

	return &device, nil
}

func (gpu *Device) PowerState() (int, error) {
	var pstate C.nvmlPstates_t
	var result C.nvmlReturn_t

	result = C.nvmlDeviceGetPowerState(gpu.nvmldevice, &pstate)
	if result != C.NVML_SUCCESS {
		return -1, errors.New("GetPowerState returned error")
	}

	return int(pstate), nil
}

// Temp returns the current temperature of the card in degrees Celsius
func (gpu *Device) Temp() (uint, error) {
	var result C.nvmlReturn_t
	var ctemp C.uint

	result = C.nvmlDeviceGetTemperature(gpu.nvmldevice, C.NVML_TEMPERATURE_GPU, &ctemp)
	if result != C.NVML_SUCCESS {
		return 0, errors.New("GetPowerState returned error")
	}

	return uint(ctemp), nil
}

type cIntPropFunc struct {
	f C.getintProperty
}

var intpropfunctions = map[string]*cIntPropFunc{
	"Index":                        {C.getintProperty(C.nvmlDeviceGetIndex)},
	"MinorNumber":                  {C.getintProperty(C.nvmlDeviceGetMinorNumber)},
	"InforomConfigurationChecksum": {C.getintProperty(C.nvmlDeviceGetInforomConfigurationChecksum)},
	"MaxPCIeLinkGeneration":        {C.getintProperty(C.nvmlDeviceGetMaxPCIeLinkGeneration)},
	"MaxPCIeLinkWidth":             {C.getintProperty(C.nvmlDeviceGetMaxPCIeLinkWidth)},
	"CurrPCIeLinkGeneration":       {C.getintProperty(C.nvmlDeviceGetCurrPCIeLinkGeneration)},
	"CurrPCIeLinkWidth":            {C.getintProperty(C.nvmlDeviceGetCurrPCIeLinkWidth)},
	"PCIeReplayCounter":            {C.getintProperty(C.nvmlDeviceGetPCIeReplayCounter)},
	"FanSpeed":                     {C.getintProperty(C.nvmlDeviceGetFanSpeed)},
	"PowerManagementLimit":         {C.getintProperty(C.nvmlDeviceGetPowerManagementLimit)},
	"PowerManagementDefaultLimit":  {C.getintProperty(C.nvmlDeviceGetPowerManagementDefaultLimit)},
	"PowerUsage":                   {C.getintProperty(C.nvmlDeviceGetPowerUsage)},
	"EnforcedPowerLimit":           {C.getintProperty(C.nvmlDeviceGetEnforcedPowerLimit)},
	"BoardId":                      {C.getintProperty(C.nvmlDeviceGetBoardId)},
	"MultiGpuBoard":                {C.getintProperty(C.nvmlDeviceGetMultiGpuBoard)},
}

func (gpu *Device) intProperty(property string) (uint, error) {
	var cuintproperty C.uint

	ipf, ok := intpropfunctions[property]
	if ok == false {
		return 0, errors.New("property not found")
	}

	result := C.bridge_get_int_property(ipf.f, gpu.nvmldevice, &cuintproperty)
	if result != C.EXIT_SUCCESS {
		return 0, errors.New("getintProperty bridge returned error")
	}

	return uint(cuintproperty), nil
}

// Index returns the NVML index of the device.
func (gpu *Device) Index() (uint, error) {
	return gpu.intProperty("Index")
}

// MinorNumber returns the minor number of the device. The minor number
// is the integer such that the device node file for the GPU will be
// /dev/nvidia[Device.MinorNumber]
func (gpu *Device) MinorNumber() (uint, error) {
	return gpu.intProperty("MinorNumber")
}

// InforomConfigurationChecksum returns the checksum of the configuration
// stored in the device's inforom. (Can be used to verify identical configuration
// between devices.)
func (gpu *Device) InforomConfigurationChecksum() (uint, error) {
	return gpu.intProperty("InforomConfigurationChecksum")
}

// MaxPCIeLinkGeneration returns the maximum PCIe link generation possible with this
// device and system.
func (gpu *Device) MaxPCIeLinkGeneration() (uint, error) {
	return gpu.intProperty("MaxPCIeLinkGeneration")
}

// MaxPCIeLinkWidth returns the maximum PCIe link width possible with this device
// and system
func (gpu *Device) MaxPCIeLinkWidth() (uint, error) {
	return gpu.intProperty("MaxPCIeLinkWidth")
}

// CurrPCIeLinkGeneration returns the current PCIe link generation number
func (gpu *Device) CurrPCIeLinkGeneration() (uint, error) {
	return gpu.intProperty("CurrPCIeLinkGeneration")
}

// CurrPCIeLinkWidth returns the current PCIe link width
func (gpu *Device) CurrPCIeLinkWidth() (uint, error) {
	return gpu.intProperty("CurrPCIeLinkWidth")
}

// PCIeReplayCounter returns the replay counter and rollover info.
func (gpu *Device) PCIeReplayCounter() (uint, error) {
	return gpu.intProperty("PCIeReplayCounter")
}

// FanSpeed returns the current fan speed of the device, on devices that
// have fans.
func (gpu *Device) FanSpeed() (uint, error) {
	return gpu.intProperty("FanSpeed")
}

// PowerManagementLimit returns the power management limit for the device, in mW
func (gpu *Device) PowerManagementLimit() (uint, error) {
	return gpu.intProperty("PowerManagementLimit")
}

// PowerManagementDefaultLimit returns the upper limit for the amount of power
// the card is allowed to draw, in mW.
func (gpu *Device) PowerManagementDefaultLimit() (uint, error) {
	return gpu.intProperty("PowerManagementDefaultLimit")
}

// PowerUsage returns the current power usage of the device, in mW.
func (gpu *Device) PowerUsage() (uint, error) {
	return gpu.intProperty("PowerUsage")
}

// EnforcedPowerLimit returns the effective power limit that the driver enforces after
// taking into account all limiters.
func (gpu *Device) EnforcedPowerLimit() (uint, error) {
	return gpu.intProperty("EnforcedPowerLimit")
}

// BoardID returns the device boardId, which will be identical for GPUs connected to
// the same PLX
func (gpu *Device) BoardId() (uint, error) {
	return gpu.intProperty("BoardId")
}

// MultiGpuBoard
func (gpu *Device) MultiGpuBoard() (bool, error) {
	p, err := gpu.intProperty("MultiGpuBoard")
	if int(p) == 0 {
		return true, err
	} else {
		return false, err
	}
}

type cTextPropFunc struct {
	f      C.gettextProperty
	length C.uint
}

var textpropfunctions = map[string]*cTextPropFunc{
	"Name":                {C.gettextProperty(C.nvmlDeviceGetName), C.NVML_DEVICE_NAME_BUFFER_SIZE},
	"Serial":              {C.gettextProperty(C.nvmlDeviceGetSerial), C.NVML_DEVICE_SERIAL_BUFFER_SIZE},
	"UUID":                {C.gettextProperty(C.nvmlDeviceGetUUID), C.NVML_DEVICE_UUID_BUFFER_SIZE},
	"InforomImageVersion": {C.gettextProperty(C.nvmlDeviceGetInforomImageVersion), C.NVML_DEVICE_INFOROM_VERSION_BUFFER_SIZE},
	"VbiosVersion":        {C.gettextProperty(C.nvmlDeviceGetVbiosVersion), C.NVML_DEVICE_VBIOS_VERSION_BUFFER_SIZE},
}

// textProperty takes a propertyname as input and then runs the corresponding
// function in the textpropfunctions map, returning the result as a Go string.
//
// textProperty takes care of allocating (and freeing) the text buffers of
// proper size.
func (gpu *Device) textProperty(property string) (string, error) {
	var propvalue string

	// If there isn't a valid entry for this property in the map, there's no reason
	// to process any further
	tpf, ok := textpropfunctions[property]
	if ok == false {
		return "", errors.New("property not found")
	}

	var buf *C.char = genCStringBuffer(uint(tpf.length))
	defer C.free(unsafe.Pointer(buf))

	result := C.bridge_get_text_property(tpf.f, gpu.nvmldevice, buf, tpf.length)
	if result != C.EXIT_SUCCESS {
		return propvalue, errors.New("gettextProperty bridge returned error")
	}

	propvalue = strndup(buf, uint(tpf.length))
	if len(propvalue) > 0 {
		return propvalue, nil
	} else {
		return "", errors.New("textProperty returned empty string")
	}
}

// InforomImageVersion returns the global inforom image version
func (gpu *Device) InforomImageVersion() (string, error) {
	return gpu.textProperty("InforomImageVersion")
}

// VbiosVersion returns the VBIOS version of the device
func (gpu *Device) VbiosVersion() (string, error) {
	return gpu.textProperty("VbiosVersion")
}

// Return the product name of the device, e.g. "Tesla K40m"
func (gpu *Device) Name() (string, error) {
	return gpu.textProperty("Name")
}

// Return the UUID of the device
func (gpu *Device) UUID() (string, error) {
	return gpu.textProperty("UUID")
}

// Return the serial number of the device
func (gpu *Device) Serial() (string, error) {
	return gpu.textProperty("Serial")
}

// Go correspondent of the C.nvmlMemory_t struct. Memory in bytes
type NVMLMemory struct {
	Free  uint64
	Total uint64
	Used  uint64
}

// MemoryInfo returns a NVMLMemory struct populated with the amount of memory used,
// free, and in total on the device, in bytes.
func (gpu *Device) MemoryInfo() (NVMLMemory, error) {
	var result C.nvmlReturn_t
	var cmeminfo C.nvmlMemory_t
	var meminfo NVMLMemory

	result = C.nvmlDeviceGetMemoryInfo(gpu.nvmldevice, &cmeminfo)
	if result != C.NVML_SUCCESS {
		return meminfo, errors.New("GetPowerState returned error")
	}

	meminfo.Free = uint64(cmeminfo.free)
	meminfo.Total = uint64(cmeminfo.total)
	meminfo.Used = uint64(cmeminfo.used)

	return meminfo, nil
}

// Return a proper golang error of representation of the nvmlReturn_t error
func (gpu *Device) Error(cerror C.nvmlReturn_t) error {
	var cerrorstring *C.char

	// No need to process anything further if the nvml call succeeded
	if cerror == C.NVML_SUCCESS {
		return nil
	}

	cerrorstring = C.nvmlErrorString(cerror)
	if cerrorstring == nil {
		// I'm not sure how this could happen, but it's easy to check for
		return errors.New("Error not found in nvml.h")
	}

	return errors.New(C.GoString(cerrorstring))
}

func nvmlDeviceGetCount() (int, error) {
	var count C.uint

	result := C.nvmlDeviceGetCount(&count)
	if result != C.NVML_SUCCESS {
		return -1, errors.New("nvmlDeviceGetCount failed")
	}

	return int(count), nil
}

// GetAllGPUs will return a slice of type Device for all NVML devices present on
// the host system
func GetAllGPUs() ([]Device, error) {
	var devices []Device
	cdevices, err := getAllDevices()
	if err != nil {
		return devices, err
	}

	for _, cdevice := range cdevices {
		device, err := NewDevice(cdevice)
		if err != nil {
			break
		}

		devices = append(devices, *device)
	}

	return devices, nil
}

// getAllDevices returns an array of nvmlDevice_t structs representing all GPU
// devices in the system.
func getAllDevices() ([]C.nvmlDevice_t, error) {
	var devices []C.nvmlDevice_t

	device_count, err := nvmlDeviceGetCount()
	if err != nil {
		log.Fatal(err)
	}

	for i := 0; i < device_count; i++ {
		var device C.nvmlDevice_t
		result := C.nvmlDeviceGetHandleByIndex(C.uint(i), &device)
		if result != C.NVML_SUCCESS {
			return devices, errors.New("nvmlDeviceGetHandleByIndex returns error")
		}

		devices = append(devices, device)
	}

	if len(devices) == 0 {
		return devices, errors.New("No devices found")
	}

	return devices, nil
}
<|endoftext|>


<commit_before>// Copyright (c) 2015-2017 The usbtmc developers. All rights reserved.
// Project site: https://github.com/gotmc/usbtmc
// Use of this source code is governed by a MIT-style license that
// can be found in the LICENSE.txt file for the project.

package usbtmc

import (
	"bytes"
	"io"
	"log"

	"github.com/gotmc/usbtmc/driver"
)

// Device models a USBTMC device, which includes a USB device and the required
// USBTMC attributes and methods.
type Device struct {
	usbDevice       driver.USBDevice
	bTag            byte
	termChar        byte
	termCharEnabled bool
}

// Write creates the appropriate USBMTC header, writes the header and data on
// the bulk out endpoint, and returns the number of bytes written and any
// errors.
func (d *Device) Write(p []byte) (n int, err error) {
	// FIXME(mdr): I need to change this so that I look at the size of the buf
	// being written to see if it can truly fit into one transfer, and if not
	// split it into multiple transfers.
	d.bTag = nextbTag(d.bTag)
	header := createDevDepMsgOutBulkOutHeader(d.bTag, uint32(len(p)), true)
	data := append(header[:], p...)
	if moduloFour := len(data) % 4; moduloFour > 0 {
		numAlignment := 4 - moduloFour
		alignment := bytes.Repeat([]byte{0x00}, numAlignment)
		data = append(data, alignment...)
	}
	return d.usbDevice.Write(data)
}

// Read creates and sends the header on the bulk out endpoint and then reads
// from the bulk in endpoint per USBTMC standard.
func (d *Device) Read(p []byte) (n int, err error) {
	// FIXME(mdr): Seems like I shouldn't use 1024 as a magic number or as a hard
	// size limit.
	usbtmcHeaderLen := 12
	temp := make([]byte, 1024)
	d.bTag = nextbTag(d.bTag)
	header := createRequestDevDepMsgInBulkOutHeader(d.bTag, uint32(len(p)), d.termCharEnabled, d.termChar)
	// log.Printf("RequestDevDepMsg Header to write = %v", header)
	n, err = d.usbDevice.Write(header[:])
	n, err = d.usbDevice.Read(temp)
	log.Println("Foo")
	// log.Printf("Read %d bytes on BulkInEndpoint", n)
	// Remove the USBMTC Bulk-IN Header from the data and the number of bytes
	if n < usbtmcHeaderLen {
		return 0, err
	}
	reader := bytes.NewReader(temp)
	_, err = reader.ReadAt(p, int64(usbtmcHeaderLen))
	if err != nil && err != io.EOF {
		return n - usbtmcHeaderLen, err
	}
	return n - usbtmcHeaderLen, nil
}

// Close closes the underlying USB device.
func (d *Device) Close() error {
	return d.usbDevice.Close()
}

// WriteString writes a string using the underlying USB device.
func (d *Device) WriteString(s string) (n int, err error) {
	return d.Write([]byte(s))
}
<commit_msg>Stub out Device's Query method for visa package<commit_after>// Copyright (c) 2015-2017 The usbtmc developers. All rights reserved.
// Project site: https://github.com/gotmc/usbtmc
// Use of this source code is governed by a MIT-style license that
// can be found in the LICENSE.txt file for the project.

package usbtmc

import (
	"bytes"
	"errors"
	"io"
	"log"

	"github.com/gotmc/usbtmc/driver"
)

// Device models a USBTMC device, which includes a USB device and the required
// USBTMC attributes and methods.
type Device struct {
	usbDevice       driver.USBDevice
	bTag            byte
	termChar        byte
	termCharEnabled bool
}

// Write creates the appropriate USBMTC header, writes the header and data on
// the bulk out endpoint, and returns the number of bytes written and any
// errors.
func (d *Device) Write(p []byte) (n int, err error) {
	// FIXME(mdr): I need to change this so that I look at the size of the buf
	// being written to see if it can truly fit into one transfer, and if not
	// split it into multiple transfers.
	d.bTag = nextbTag(d.bTag)
	header := createDevDepMsgOutBulkOutHeader(d.bTag, uint32(len(p)), true)
	data := append(header[:], p...)
	if moduloFour := len(data) % 4; moduloFour > 0 {
		numAlignment := 4 - moduloFour
		alignment := bytes.Repeat([]byte{0x00}, numAlignment)
		data = append(data, alignment...)
	}
	return d.usbDevice.Write(data)
}

// Read creates and sends the header on the bulk out endpoint and then reads
// from the bulk in endpoint per USBTMC standard.
func (d *Device) Read(p []byte) (n int, err error) {
	// FIXME(mdr): Seems like I shouldn't use 1024 as a magic number or as a hard
	// size limit.
	usbtmcHeaderLen := 12
	temp := make([]byte, 1024)
	d.bTag = nextbTag(d.bTag)
	header := createRequestDevDepMsgInBulkOutHeader(d.bTag, uint32(len(p)), d.termCharEnabled, d.termChar)
	// log.Printf("RequestDevDepMsg Header to write = %v", header)
	n, err = d.usbDevice.Write(header[:])
	n, err = d.usbDevice.Read(temp)
	log.Println("Foo")
	// log.Printf("Read %d bytes on BulkInEndpoint", n)
	// Remove the USBMTC Bulk-IN Header from the data and the number of bytes
	if n < usbtmcHeaderLen {
		return 0, err
	}
	reader := bytes.NewReader(temp)
	_, err = reader.ReadAt(p, int64(usbtmcHeaderLen))
	if err != nil && err != io.EOF {
		return n - usbtmcHeaderLen, err
	}
	return n - usbtmcHeaderLen, nil
}

// Close closes the underlying USB device.
func (d *Device) Close() error {
	return d.usbDevice.Close()
}

// WriteString writes a string using the underlying USB device.
func (d *Device) WriteString(s string) (n int, err error) {
	return d.Write([]byte(s))
}

func (c *Device) Query(s string) (value string, err error) {
	return "", errors.New("Please implement the Query method for Device.")
}
<|endoftext|>


<commit_before>package sphere

import (
	"errors"

	"github.com/streamrail/concurrent-map"
)

const (
	// BrokerErrorOverrideOnSubscribe to warn use to override OnSubsribe function
	BrokerErrorOverrideOnSubscribe = "please override OnSubscribe"
	// BrokerErrorOverrideOnUnsubscribe to warn use to override OnUnsubscribe function
	BrokerErrorOverrideOnUnsubscribe = "please override OnUnsubscribe"
	// BrokerErrorOverrideOnPublish to warn use to override OnPublish function
	BrokerErrorOverrideOnPublish = "please override OnPublish"
	// BrokerErrorOverrideOnMessage to warn use to override OnMessage function
	BrokerErrorOverrideOnMessage = "please override OnMessage"
)

// Agent represents Broker instance
type Agent interface {
	ID() string                        // => Broker ID
	ChannelName(string, string) string // => Broker generate channel name with namespace and channel
	IsSubscribed(string) bool          // => Broker channel subscribe state
	OnSubscribe(*Channel) error        // => Broker OnSubscribe
	OnUnsubscribe(*Channel) error      // => Broker OnUnsubscribe
	OnPublish(*Channel, *Packet) error // => Broker OnPublish
	OnMessage(*Channel, *Packet) error // => Broker OnMessage
}

// ExtendBroker creates a broker instance
func ExtendBroker() *Broker {
	return &Broker{
		id:    guid.String(),
		store: cmap.New(),
	}
}

// Broker allows you to interact directly with Websocket internal data and pub/sub channels
type Broker struct {
	// Broker ID
	id string
	// Channel store
	store cmap.ConcurrentMap
}

// ID returns the unique id for the broker
func (broker *Broker) ID() string {
	return broker.id
}

// ChannelName returns channel name with provided namespace and room name
func (broker *Broker) ChannelName(namespace string, room string) string {
	return namespace + ":" + room
}

// IsSubscribed return the broker state of the channel
func (broker *Broker) IsSubscribed(namespace string, room string) bool {
	return broker.store.Has(broker.ChannelName(namespace, room))
}

// OnSubscribe when websocket subscribes to a channel
func (broker *Broker) OnSubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnSubscribe)
}

// OnUnsubscribe when websocket unsubscribes from a channel
func (broker *Broker) OnUnsubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnUnsubscribe)
}

// OnPublish when websocket publishes data to a particular channel from the current broker
func (broker *Broker) OnPublish(channel *Channel, data *Packet) error {
	return errors.New(BrokerErrorOverrideOnPublish)
}

// OnMessage when websocket receive data from the broker subscriber
func (broker *Broker) OnMessage(channel *Channel, data *Packet) error {
	return errors.New(BrokerErrorOverrideOnMessage)
}
<commit_msg>fix merge conflict<commit_after>package sphere

import (
	"errors"

	"github.com/streamrail/concurrent-map"
)

const (
	// BrokerErrorOverrideOnSubscribe to warn use to override OnSubsribe function
	BrokerErrorOverrideOnSubscribe = "please override OnSubscribe"
	// BrokerErrorOverrideOnUnsubscribe to warn use to override OnUnsubscribe function
	BrokerErrorOverrideOnUnsubscribe = "please override OnUnsubscribe"
	// BrokerErrorOverrideOnPublish to warn use to override OnPublish function
	BrokerErrorOverrideOnPublish = "please override OnPublish"
	// BrokerErrorOverrideOnMessage to warn use to override OnMessage function
	BrokerErrorOverrideOnMessage = "please override OnMessage"
)

// Agent represents Broker instance
type Agent interface {
	ID() string                        // => Broker ID
	ChannelName(string, string) string // => Broker generate channel name with namespace and channel
	IsSubscribed(string, string) bool  // => Broker channel subscribe state
	OnSubscribe(*Channel) error        // => Broker OnSubscribe
	OnUnsubscribe(*Channel) error      // => Broker OnUnsubscribe
	OnPublish(*Channel, *Packet) error // => Broker OnPublish
	OnMessage(*Channel, *Packet) error // => Broker OnMessage
}

// ExtendBroker creates a broker instance
func ExtendBroker() *Broker {
	return &Broker{
		id:    guid.String(),
		store: cmap.New(),
	}
}

// Broker allows you to interact directly with Websocket internal data and pub/sub channels
type Broker struct {
	// Broker ID
	id string
	// Channel store
	store cmap.ConcurrentMap
}

// ID returns the unique id for the broker
func (broker *Broker) ID() string {
	return broker.id
}

// ChannelName returns channel name with provided namespace and room name
func (broker *Broker) ChannelName(namespace string, room string) string {
	return namespace + ":" + room
}

// IsSubscribed return the broker state of the channel
func (broker *Broker) IsSubscribed(namespace string, room string) bool {
	return broker.store.Has(broker.ChannelName(namespace, room))
}

// OnSubscribe when websocket subscribes to a channel
func (broker *Broker) OnSubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnSubscribe)
}

// OnUnsubscribe when websocket unsubscribes from a channel
func (broker *Broker) OnUnsubscribe(channel *Channel) error {
	return errors.New(BrokerErrorOverrideOnUnsubscribe)
}

// OnPublish when websocket publishes data to a particular channel from the current broker
func (broker *Broker) OnPublish(channel *Channel, data *Packet) error {
	return errors.New(BrokerErrorOverrideOnPublish)
}

// OnMessage when websocket receive data from the broker subscriber
func (broker *Broker) OnMessage(channel *Channel, data *Packet) error {
	return errors.New(BrokerErrorOverrideOnMessage)
}
<|endoftext|>


<commit_before>package b2

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
)

type Bucket struct {
	BucketID   string     `json:"bucketId"`
	BucketName string     `json:"bucketName"`
	BucketType BucketType `json:"bucketType"`
	B2         *B2        `json:"-"`
}

type BucketType string

const (
	AllPrivate BucketType = "allPrivate"
	AllPublic  BucketType = "allPublic"
)

type listBucketsResponse struct {
	Buckets []Bucket `json:"buckets"`
}

type bucketRequest struct {
	AccountID  string     `json:"accountId"`
	BucketID   string     `json:"bucketId,omitempty"`
	BucketName string     `json:"bucketName,omitempty"`
	BucketType BucketType `json:"bucketType,omitempty"`
}

func (b *B2) ListBuckets() ([]Bucket, error) {
	reqBody, err := json.Marshal(bucketRequest{AccountID: b.AccountID})
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(
		"POST", b.MakeApiUrl("/b2api/v1/b2_list_buckets"), bytes.NewReader(reqBody))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", b.AuthorizationToken)

	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode == 200 {
		buckets := listBucketsResponse{}
		if err := json.Unmarshal(body, &buckets); err != nil {
			return nil, err
		}

		for i := range buckets.Buckets {
			buckets.Buckets[i].B2 = b
		}

		return buckets.Buckets, nil
	} else {
		errJson := errorResponse{}
		if err := json.Unmarshal(body, &errJson); err != nil {
			return nil, err
		}

		return nil, errJson
	}
}

func (b *B2) CreateBucket(name string, bType BucketType) (*Bucket, error) {
	return nil, nil
}

func (b *Bucket) Update(bType BucketType) (*Bucket, error) {
	return nil, nil
}

func (b *Bucket) Delete() error {
	return nil
}
<commit_msg>Implement all bucket actions, refactor impending<commit_after>package b2

import (
	"bytes"
	"encoding/json"
	"io/ioutil"
	"net/http"
)

type Bucket struct {
	BucketID   string     `json:"bucketId"`
	BucketName string     `json:"bucketName"`
	BucketType BucketType `json:"bucketType"`
	B2         *B2        `json:"-"`
}

type BucketType string

const (
	AllPrivate BucketType = "allPrivate"
	AllPublic  BucketType = "allPublic"
)

type listBucketsResponse struct {
	Buckets []Bucket `json:"buckets"`
}

type bucketRequest struct {
	AccountID  string     `json:"accountId"`
	BucketID   string     `json:"bucketId,omitempty"`
	BucketName string     `json:"bucketName,omitempty"`
	BucketType BucketType `json:"bucketType,omitempty"`
}

func (b *B2) ListBuckets() ([]Bucket, error) {
	reqBody, err := json.Marshal(bucketRequest{AccountID: b.AccountID})
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest(
		"POST", b.MakeApiUrl("/b2api/v1/b2_list_buckets"), bytes.NewReader(reqBody))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", b.AuthorizationToken)

	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode == 200 {
		buckets := listBucketsResponse{}
		if err := json.Unmarshal(body, &buckets); err != nil {
			return nil, err
		}

		for i := range buckets.Buckets {
			buckets.Buckets[i].B2 = b
		}

		return buckets.Buckets, nil
	} else {
		errJson := errorResponse{}
		if err := json.Unmarshal(body, &errJson); err != nil {
			return nil, err
		}

		return nil, errJson
	}
}

func (b *B2) CreateBucket(name string, bType BucketType) (*Bucket, error) {
	reqBody, err := json.Marshal(bucketRequest{
		AccountID:  b.AccountID,
		BucketName: name,
		BucketType: bType,
	})
	if err != nil {
		return nil, err
	}

	req, err := http.NewRequest("POST",
		b.MakeApiUrl("/b2api/v1/b2_create_bucket"), bytes.NewReader(reqBody))
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", b.AuthorizationToken)

	resp, err := httpClient.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode == 200 {
		bucket := &Bucket{}
		if err := json.Unmarshal(body, bucket); err != nil {
			return nil, err
		}

		bucket.B2 = b

		return bucket, nil
	} else {
		errJson := errorResponse{}
		if err := json.Unmarshal(body, &errJson); err != nil {
			return nil, err
		}

		return nil, errJson
	}
}

func (b *Bucket) Update(newBucketType BucketType) error {
	reqBody, err := json.Marshal(bucketRequest{
		AccountID:  b.B2.AccountID,
		BucketID:   b.BucketID,
		BucketType: newBucketType,
	})
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST",
		b.B2.MakeApiUrl("/b2api/v1/b2_update_bucket"), bytes.NewReader(reqBody))
	if err != nil {
		return err
	}

	req.Header.Set("Authorization", b.B2.AuthorizationToken)

	resp, err := httpClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode == 200 {
		bucket := &Bucket{}
		if err := json.Unmarshal(body, bucket); err != nil {
			return err
		}

		b.BucketType = bucket.BucketType

		return nil
	} else {
		errJson := errorResponse{}
		if err := json.Unmarshal(body, &errJson); err != nil {
			return err
		}

		return errJson
	}
}

func (b *Bucket) Delete() error {
	reqBody, err := json.Marshal(bucketRequest{
		AccountID: b.B2.AccountID,
		BucketID:  b.BucketID,
	})
	if err != nil {
		return err
	}

	req, err := http.NewRequest("POST",
		b.B2.MakeApiUrl("/b2api/v1/b2_delete_bucket"), bytes.NewReader(reqBody))
	if err != nil {
		return err
	}

	req.Header.Set("Authorization", b.B2.AuthorizationToken)

	resp, err := httpClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}

	if resp.StatusCode == 200 {
		bucket := &Bucket{}
		if err := json.Unmarshal(body, bucket); err != nil {
			return err
		}

		return nil
	} else {
		errJson := errorResponse{}
		if err := json.Unmarshal(body, &errJson); err != nil {
			return err
		}

		return errJson
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"strings"
	"sync"

	"github.com/Luzifer/dockermanager/config"
	log "github.com/sirupsen/logrus"
	"github.com/fsouza/go-dockerclient"
)

const (
	labelIsManaged   = "io.luzifer.dockermanager.managed"
	labelConfigHash  = "io.luzifer.dockermanager.cfghash"
	labelIsScheduled = "io.luzifer.dockermanager.scheduler"

	strTrue = "true"
)

var (
	pullLock     = map[string]bool{}
	pullLockLock sync.RWMutex
)

func pullImage(image, tag string) {
	pullLockLock.Lock()
	if pullLock[image+":"+tag] {
		log.Debugf("Image %q is already pulling, starting no new pull", image+":"+tag)
		pullLockLock.Unlock()
		return
	}
	pullLock[image+":"+tag] = true
	pullLockLock.Unlock()

	defer func() {
		pullLockLock.Lock()
		pullLock[image+":"+tag] = false
		pullLockLock.Unlock()
	}()

	auth := docker.AuthConfiguration{}

	reginfo := strings.SplitN(image, "/", 2)
	if len(reginfo) == 2 {
		for s, a := range authConfig.Configs {
			if strings.Contains(s, reginfo[0]) {
				auth = a
			}
		}
	}

	log.Debugf("Refreshing repo %s:%s...", image, tag)
	if err := dockerClient.PullImage(docker.PullImageOptions{
		Repository: image,
		Tag:        tag,
	}, auth); err != nil {
		log.WithFields(log.Fields{
			"repo": image + ":" + tag,
		}).Errorf("An error occurred while image pulling: %s", err)
	}
}

func bootContainer(name string, ccfg *config.ContainerConfig) error {
	var (
		container *docker.Container
		err       error
	)

	cs, err := ccfg.Checksum()
	if err != nil {
		return fmt.Errorf("Unable to calculate checksum: %s", err)
	}

	labels := map[string]string{}
	if labels != nil {
		for k, v := range ccfg.Labels {
			labels[k] = v
		}
	}
	labels[labelConfigHash] = cs
	labels[labelIsManaged] = strTrue

	if ccfg.StartTimes != "" {
		labels[labelIsScheduled] = strTrue
	}

	volumes, binds := parseMounts(ccfg.Volumes)

	newcfg := &docker.Config{
		AttachStdin:  false,
		AttachStdout: true,
		AttachStderr: true,
		Image:        strings.Join([]string{ccfg.Image, ccfg.Tag}, ":"),
		Env:          ccfg.Environment,
		Cmd:          ccfg.Command,
		Labels:       labels,
		Volumes:      volumes,
	}

	hostConfig := &docker.HostConfig{
		Binds:        binds,
		Links:        ccfg.Links,
		Privileged:   false,
		PortBindings: make(map[docker.Port][]docker.PortBinding),
		CapAdd:       ccfg.AddCapabilities,
	}

	for _, v := range ccfg.Ports {
		s := strings.Split(v.Local, ":")
		hostConfig.PortBindings[docker.Port(v.Container)] = []docker.PortBinding{{
			HostIP:   s[0],
			HostPort: s[1],
		}}
	}

	log.Debugf("Creating container %s", name)
	container, err = dockerClient.CreateContainer(docker.CreateContainerOptions{
		Name:       name,
		Config:     newcfg,
		HostConfig: hostConfig,
	})

	if err != nil {
		return fmt.Errorf("Unable to create container: %s", err)
	}

	log.Infof("Starting container %q...", container.Name)
	if err := dockerClient.StartContainer(container.Name, nil); err != nil {
		return fmt.Errorf("Unable to start created container: %s", err)
	}

	return nil
}

func parseMounts(mountIn []string) (volumes map[string]struct{}, binds []string) {
	volumes = make(map[string]struct{})
	for _, m := range mountIn {
		if len(m) == 0 {
			continue
		}

		parts := strings.Split(m, ":")
		if len(parts) != 2 && len(parts) != 3 {
			log.Errorf("Invalid default mount: %s", m)
			continue
		}

		binds = append(binds, m)
		volumes[parts[1]] = struct{}{}
	}

	return
}
<commit_msg>Fix: Stating this once is enough<commit_after>package main

import (
	"fmt"
	"strings"
	"sync"

	"github.com/Luzifer/dockermanager/config"
	"github.com/fsouza/go-dockerclient"
	log "github.com/sirupsen/logrus"
)

const (
	labelIsManaged   = "io.luzifer.dockermanager.managed"
	labelConfigHash  = "io.luzifer.dockermanager.cfghash"
	labelIsScheduled = "io.luzifer.dockermanager.scheduler"

	strTrue = "true"
)

var (
	pullLock     = map[string]bool{}
	pullLockLock sync.RWMutex
)

func pullImage(image, tag string) {
	pullLockLock.Lock()
	if pullLock[image+":"+tag] {
		log.Debugf("Image %q is already pulling, starting no new pull", image+":"+tag)
		pullLockLock.Unlock()
		return
	}
	pullLock[image+":"+tag] = true
	pullLockLock.Unlock()

	defer func() {
		pullLockLock.Lock()
		pullLock[image+":"+tag] = false
		pullLockLock.Unlock()
	}()

	auth := docker.AuthConfiguration{}

	reginfo := strings.SplitN(image, "/", 2)
	if len(reginfo) == 2 {
		for s, a := range authConfig.Configs {
			if strings.Contains(s, reginfo[0]) {
				auth = a
			}
		}
	}

	if err := dockerClient.PullImage(docker.PullImageOptions{
		Repository: image,
		Tag:        tag,
	}, auth); err != nil {
		log.WithFields(log.Fields{
			"repo": image + ":" + tag,
		}).Errorf("An error occurred while image pulling: %s", err)
	}
}

func bootContainer(name string, ccfg *config.ContainerConfig) error {
	var (
		container *docker.Container
		err       error
	)

	cs, err := ccfg.Checksum()
	if err != nil {
		return fmt.Errorf("Unable to calculate checksum: %s", err)
	}

	labels := map[string]string{}
	if labels != nil {
		for k, v := range ccfg.Labels {
			labels[k] = v
		}
	}
	labels[labelConfigHash] = cs
	labels[labelIsManaged] = strTrue

	if ccfg.StartTimes != "" {
		labels[labelIsScheduled] = strTrue
	}

	volumes, binds := parseMounts(ccfg.Volumes)

	newcfg := &docker.Config{
		AttachStdin:  false,
		AttachStdout: true,
		AttachStderr: true,
		Image:        strings.Join([]string{ccfg.Image, ccfg.Tag}, ":"),
		Env:          ccfg.Environment,
		Cmd:          ccfg.Command,
		Labels:       labels,
		Volumes:      volumes,
	}

	hostConfig := &docker.HostConfig{
		Binds:        binds,
		Links:        ccfg.Links,
		Privileged:   false,
		PortBindings: make(map[docker.Port][]docker.PortBinding),
		CapAdd:       ccfg.AddCapabilities,
	}

	for _, v := range ccfg.Ports {
		s := strings.Split(v.Local, ":")
		hostConfig.PortBindings[docker.Port(v.Container)] = []docker.PortBinding{{
			HostIP:   s[0],
			HostPort: s[1],
		}}
	}

	log.Debugf("Creating container %s", name)
	container, err = dockerClient.CreateContainer(docker.CreateContainerOptions{
		Name:       name,
		Config:     newcfg,
		HostConfig: hostConfig,
	})

	if err != nil {
		return fmt.Errorf("Unable to create container: %s", err)
	}

	log.Infof("Starting container %q...", container.Name)
	if err := dockerClient.StartContainer(container.Name, nil); err != nil {
		return fmt.Errorf("Unable to start created container: %s", err)
	}

	return nil
}

func parseMounts(mountIn []string) (volumes map[string]struct{}, binds []string) {
	volumes = make(map[string]struct{})
	for _, m := range mountIn {
		if len(m) == 0 {
			continue
		}

		parts := strings.Split(m, ":")
		if len(parts) != 2 && len(parts) != 3 {
			log.Errorf("Invalid default mount: %s", m)
			continue
		}

		binds = append(binds, m)
		volumes[parts[1]] = struct{}{}
	}

	return
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, 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 platform

import (
	"compress/gzip"
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/coreos/pkg/multierror"

	"github.com/coreos/mantle/network/journal"
	"github.com/coreos/mantle/util"
)

// Journal manages recording the journal of a Machine.
type Journal struct {
	journal    io.WriteCloser
	journalRaw io.WriteCloser
	recorder   *journal.Recorder
	cancel     context.CancelFunc
}

// NewJournal creates a Journal recorder that will log to "journal.txt"
// and "journal-raw.txt.gz" inside the given output directory.
func NewJournal(dir string) (*Journal, error) {
	p := filepath.Join(dir, "journal.txt")
	j, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		return nil, err
	}

	p = filepath.Join(dir, "journal-raw.txt.gz")
	jr, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		return nil, err
	}
	// gzip to save space; a single test can generate well over 1M of logs
	jrz, err := gzip.NewWriterLevel(jr, gzip.BestCompression)
	if err != nil {
		return nil, err
	}

	return &Journal{
		journal:    j,
		journalRaw: jrz,
		recorder:   journal.NewRecorder(journal.ShortWriter(j), jrz),
	}, nil
}

// Start begins/resumes streaming the system journal to journal.txt.
func (j *Journal) Start(ctx context.Context, m Machine) error {
	if j.cancel != nil {
		j.cancel()
		j.cancel = nil
		j.recorder.Wait() // Just need to consume the status.
	}
	ctx, cancel := context.WithCancel(ctx)

	start := func() error {
		client, err := m.SSHClient()
		if err != nil {
			return err
		}

		return j.recorder.StartSSH(ctx, client)
	}

	// Retry for a while because this should be run before CheckMachine
	if err := util.Retry(sshRetries, sshTimeout, start); err != nil {
		cancel()
		return fmt.Errorf("ssh journalctl failed: %v", err)
	}

	j.cancel = cancel
	return nil
}

func (j *Journal) Destroy() error {
	var err multierror.Error
	if j.cancel != nil {
		j.cancel()
		if e := j.recorder.Wait(); e != nil {
			err = append(err, e)
		}
	}
	if e := j.journal.Close(); e != nil {
		err = append(err, e)
	}
	if e := j.journalRaw.Close(); e != nil {
		err = append(err, e)
	}
	return err.AsError()
}
<commit_msg>platform/journal: fix leaked file handle<commit_after>// Copyright 2017 CoreOS, 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 platform

import (
	"compress/gzip"
	"context"
	"fmt"
	"io"
	"os"
	"path/filepath"

	"github.com/coreos/pkg/multierror"

	"github.com/coreos/mantle/network/journal"
	"github.com/coreos/mantle/util"
)

// Journal manages recording the journal of a Machine.
type Journal struct {
	journal    io.WriteCloser
	journalRaw io.WriteCloser
	recorder   *journal.Recorder
	cancel     context.CancelFunc
}

// wrapper that also closes the underlying file
type gzWriteCloser struct {
	*gzip.Writer
	underlying io.Closer
}

func (g gzWriteCloser) Close() error {
	var err multierror.Error
	if e := g.Writer.Close(); e != nil {
		err = append(err, e)
	}
	if e := g.underlying.Close(); e != nil {
		err = append(err, e)
	}
	return err.AsError()
}

// NewJournal creates a Journal recorder that will log to "journal.txt"
// and "journal-raw.txt.gz" inside the given output directory.
func NewJournal(dir string) (*Journal, error) {
	p := filepath.Join(dir, "journal.txt")
	j, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		return nil, err
	}

	p = filepath.Join(dir, "journal-raw.txt.gz")
	jr, err := os.OpenFile(p, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		return nil, err
	}
	// gzip to save space; a single test can generate well over 1M of logs
	jrz, err := gzip.NewWriterLevel(jr, gzip.BestCompression)
	if err != nil {
		return nil, err
	}
	jrzc := gzWriteCloser{
		underlying: jr,
		Writer:     jrz,
	}

	return &Journal{
		journal:    j,
		journalRaw: jrzc,
		recorder:   journal.NewRecorder(journal.ShortWriter(j), jrzc),
	}, nil
}

// Start begins/resumes streaming the system journal to journal.txt.
func (j *Journal) Start(ctx context.Context, m Machine) error {
	if j.cancel != nil {
		j.cancel()
		j.cancel = nil
		j.recorder.Wait() // Just need to consume the status.
	}
	ctx, cancel := context.WithCancel(ctx)

	start := func() error {
		client, err := m.SSHClient()
		if err != nil {
			return err
		}

		return j.recorder.StartSSH(ctx, client)
	}

	// Retry for a while because this should be run before CheckMachine
	if err := util.Retry(sshRetries, sshTimeout, start); err != nil {
		cancel()
		return fmt.Errorf("ssh journalctl failed: %v", err)
	}

	j.cancel = cancel
	return nil
}

func (j *Journal) Destroy() error {
	var err multierror.Error
	if j.cancel != nil {
		j.cancel()
		if e := j.recorder.Wait(); e != nil {
			err = append(err, e)
		}
	}
	if e := j.journal.Close(); e != nil {
		err = append(err, e)
	}
	if e := j.journalRaw.Close(); e != nil {
		err = append(err, e)
	}
	return err.AsError()
}
<|endoftext|>


<commit_before>package selenoid

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/aandryashin/selenoid/config"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
	"github.com/heroku/docker-registry-client/registry"
	"net/http"
	"sort"
)

const (
	latest   = "latest"
	firefox  = "firefox"
	opera    = "opera"
	tag_1216 = "12.16"
)

type Configurator struct {
	Limit       int
	Verbose     bool
	Pull        bool
	RegistryUrl string
	docker      *client.Client
	reg         *registry.Registry
}

func (c *Configurator) Init() error {
	err := c.initDockerClient()
	if err != nil {
		return err
	}
	err = c.initRegistryClient()
	if err != nil {
		return err
	}
	return nil
}

func (c *Configurator) initDockerClient() error {
	docker, err := client.NewEnvClient()
	if err != nil {
		return fmt.Errorf("Failed to init Docker client: %v", err)
	}
	c.docker = docker
	return nil
}

func (c *Configurator) initRegistryClient() error {
	logF := registry.Quiet
	if c.Verbose {
		logF = registry.Log
	}
	reg := &registry.Registry{
		URL:    c.RegistryUrl,
		Client: http.DefaultClient,
		Logf:   logF,
	}
	if err := reg.Ping(); err != nil {
		return errors.New("Docker Registry is not available")
	}
	c.reg = reg
	return nil
}

func (c *Configurator) Close() {
	if c.docker != nil {
		c.docker.Close()
	}
}

func (c *Configurator) Configure() (string, error) {
	browsers := c.createConfig()
	data, err := json.Marshal(browsers)
	if err != nil {
		return "", fmt.Errorf("Failed to generate configuration: %v", err)
	}
	return string(data), nil
}

func (c *Configurator) createConfig() map[string]config.Versions {
	supportedBrowsers := c.getSupportedBrowsers()
	browsers := make(map[string]config.Versions)
	for browserName, image := range supportedBrowsers {
		c.printf("Processing browser \"%s\"...\n", browserName)
		tags := c.fetchImageTags(image)
		pulledTags := tags
		if c.Pull {
			pulledTags = c.pullImages(image, tags)
		} else if c.Limit > 0 && c.Limit <= len(tags) {
			fmt.Println(pulledTags)
			pulledTags = tags[:c.Limit]
		}

		if len(pulledTags) > 0 {
			browsers[browserName] = c.createVersions(browserName, image, pulledTags)
		}
	}
	return browsers
}

func (c *Configurator) getSupportedBrowsers() map[string]string {
	supportedBrowsers := make(map[string]string)
	supportedBrowsers["firefox"] = "selenoid/firefox"
	supportedBrowsers["chrome"] = "selenoid/chrome"
	supportedBrowsers["opera"] = "selenoid/opera"
	supportedBrowsers["phantomjs"] = "selenoid/phantomjs"
	return supportedBrowsers
}

func (c *Configurator) printf(format string, v ...interface{}) {
	if c.Verbose {
		fmt.Printf(format, v...)
	}
}

func (c *Configurator) fetchImageTags(image string) []string {
	c.printf("Fetching tags for image \"%s\"...\n", image)
	tags, err := c.reg.Tags(image)
	if err != nil {
		c.printf("Failed to fetch tags for image \"%s\"\n", image)
		return nil
	}
	tagsWithoutLatest := filterOutLatest(tags)
	strSlice := sort.StringSlice(tagsWithoutLatest)
	sort.Sort(sort.Reverse(strSlice))
	return tagsWithoutLatest
}

func filterOutLatest(tags []string) []string {
	ret := []string{}
	for _, tag := range tags {
		if tag != latest {
			ret = append(ret, tag)
		}
	}
	return ret
}

func (c *Configurator) createVersions(browserName string, image string, tags []string) config.Versions {
	versions := config.Versions{
		Default:  tags[0],
		Versions: make(map[string]*config.Browser),
	}
	for _, tag := range tags {
		browser := &config.Browser{
			Image: imageWithTag(image, tag),
			Port:  "4444",
			Path:  "/",
		}
		if browserName == firefox || (browserName == opera && tag == tag_1216) {
			browser.Path = "/wd/hub"
		}
		versions.Versions[tag] = browser
	}
	return versions
}

func imageWithTag(image string, tag string) string {
	return fmt.Sprintf("%s:%s", image, tag)
}

func (c *Configurator) pullImages(image string, tags []string) []string {
	pulledTags := []string{}
	ctx := context.Background()
loop:
	for _, tag := range tags {
		ref := imageWithTag(image, tag)
		c.printf("Pulling image \"%s\"...\n", ref)
		resp, err := c.docker.ImagePull(ctx, ref, types.ImagePullOptions{})
		if resp != nil {
			resp.Close()
		}
		if err != nil {
			c.printf("Failed to pull image \"%s\": %v\n", ref, err)
			continue
		}
		pulledTags = append(pulledTags, tag)
		if c.Limit > 0 && len(pulledTags) == c.Limit {
			break loop
		}
	}
	return pulledTags
}
<commit_msg>Better disabling output<commit_after>package selenoid

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/aandryashin/selenoid/config"
	"github.com/docker/docker/api/types"
	"github.com/docker/docker/client"
	"github.com/heroku/docker-registry-client/registry"
	"sort"
	"log"
	"io/ioutil"
)

const (
	latest   = "latest"
	firefox  = "firefox"
	opera    = "opera"
	tag_1216 = "12.16"
)

type Configurator struct {
	Limit       int
	Verbose     bool
	Pull        bool
	RegistryUrl string
	docker      *client.Client
	reg         *registry.Registry
}

func (c *Configurator) Init() error {
	if !c.Verbose {
		log.SetFlags(0)
		log.SetOutput(ioutil.Discard)
	}
	err := c.initDockerClient()
	if err != nil {
		return err
	}
	err = c.initRegistryClient()
	if err != nil {
		return err
	}
	return nil
}

func (c *Configurator) initDockerClient() error {
	docker, err := client.NewEnvClient()
	if err != nil {
		return fmt.Errorf("Failed to init Docker client: %v", err)
	}
	c.docker = docker
	return nil
}

func (c *Configurator) initRegistryClient() error {
	reg, err := registry.New(c.RegistryUrl, "", "")
	if err != nil {
		return errors.New("Docker Registry is not available")
	}
	c.reg = reg
	return nil
}

func (c *Configurator) Close() {
	if c.docker != nil {
		c.docker.Close()
	}
}

func (c *Configurator) Configure() (string, error) {
	browsers := c.createConfig()
	data, err := json.Marshal(browsers)
	if err != nil {
		return "", fmt.Errorf("Failed to generate configuration: %v", err)
	}
	return string(data), nil
}

func (c *Configurator) createConfig() map[string]config.Versions {
	supportedBrowsers := c.getSupportedBrowsers()
	browsers := make(map[string]config.Versions)
	for browserName, image := range supportedBrowsers {
		c.printf("Processing browser \"%s\"...\n", browserName)
		tags := c.fetchImageTags(image)
		pulledTags := tags
		if c.Pull {
			pulledTags = c.pullImages(image, tags)
		} else if c.Limit > 0 && c.Limit <= len(tags) {
			fmt.Println(pulledTags)
			pulledTags = tags[:c.Limit]
		}

		if len(pulledTags) > 0 {
			browsers[browserName] = c.createVersions(browserName, image, pulledTags)
		}
	}
	return browsers
}

func (c *Configurator) getSupportedBrowsers() map[string]string {
	supportedBrowsers := make(map[string]string)
	supportedBrowsers["firefox"] = "selenoid/firefox"
	supportedBrowsers["chrome"] = "selenoid/chrome"
	supportedBrowsers["opera"] = "selenoid/opera"
	supportedBrowsers["phantomjs"] = "selenoid/phantomjs"
	return supportedBrowsers
}

func (c *Configurator) printf(format string, v ...interface{}) {
	if c.Verbose {
		fmt.Printf(format, v...)
	}
}

func (c *Configurator) fetchImageTags(image string) []string {
	c.printf("Fetching tags for image \"%s\"...\n", image)
	tags, err := c.reg.Tags(image)
	if err != nil {
		c.printf("Failed to fetch tags for image \"%s\"\n", image)
		return nil
	}
	tagsWithoutLatest := filterOutLatest(tags)
	strSlice := sort.StringSlice(tagsWithoutLatest)
	sort.Sort(sort.Reverse(strSlice))
	return tagsWithoutLatest
}

func filterOutLatest(tags []string) []string {
	ret := []string{}
	for _, tag := range tags {
		if tag != latest {
			ret = append(ret, tag)
		}
	}
	return ret
}

func (c *Configurator) createVersions(browserName string, image string, tags []string) config.Versions {
	versions := config.Versions{
		Default:  tags[0],
		Versions: make(map[string]*config.Browser),
	}
	for _, tag := range tags {
		browser := &config.Browser{
			Image: imageWithTag(image, tag),
			Port:  "4444",
			Path:  "/",
		}
		if browserName == firefox || (browserName == opera && tag == tag_1216) {
			browser.Path = "/wd/hub"
		}
		versions.Versions[tag] = browser
	}
	return versions
}

func imageWithTag(image string, tag string) string {
	return fmt.Sprintf("%s:%s", image, tag)
}

func (c *Configurator) pullImages(image string, tags []string) []string {
	pulledTags := []string{}
	ctx := context.Background()
loop:
	for _, tag := range tags {
		ref := imageWithTag(image, tag)
		c.printf("Pulling image \"%s\"...\n", ref)
		resp, err := c.docker.ImagePull(ctx, ref, types.ImagePullOptions{})
		if resp != nil {
			resp.Close()
		}
		if err != nil {
			c.printf("Failed to pull image \"%s\": %v\n", ref, err)
			continue
		}
		pulledTags = append(pulledTags, tag)
		if c.Limit > 0 && len(pulledTags) == c.Limit {
			break loop
		}
	}
	return pulledTags
}
<|endoftext|>


<commit_before>package datastructures

type LinkedList struct {
	head *Node
}

type Node struct {
	value int
	next  *Node
}

func (l *LinkedList) insert(val int) error {
	return nil
}

func (l *LinkedList) deleteFromFront() error {
	return nil
}

func (l *LinkedList) search(val int) (bool, error) {
	return false, nil
}

func (l *LinkedList) delete(val int) error {
	return nil
}
<commit_msg>implement some linked list operations<commit_after>package datastructures

type LinkedList struct {
	head *Node
}

type Node struct {
	value int
	next  *Node
}

func NewLinkedList() *LinkedList {
	return &LinkedList{nil}
}

func (l *LinkedList) insertAtFront(val int) error {
	node := Node{val, l.head}
	l.head = &node
	return nil
}

func (l *LinkedList) insertAtEnd(val int) error {
	node := Node{val, nil}
	if l.head == nil {
		return l.insertAtFront(val)
	}
	previous, current := l.head, l.head
	for current != nil {
		previous = current
		current = current.next
	}
	previous.next = &node
	return nil
}

func (l *LinkedList) deleteFromFront() error {
	l.head = l.head.next
	return nil
}

func (l *LinkedList) deleteFromEnd() error {
	previous, current := l.head, l.head
	for current.next != nil {
		previous = current
		current = current.next
	}
	previous.next = nil
	return nil
}

func (l *LinkedList) search(val int) (bool, error) {
	return false, nil
}

func (l *LinkedList) delete(val int) error {
	return nil
}
<|endoftext|>


<commit_before>//
//   date  : 2014-06-04
//   author: xjdrew
//

package main

import (
	"bufio"
	"encoding/binary"
	"net"
)

type TunnelPayload struct {
	Linkid uint16
	Data   []byte
}

type Tunnel struct {
	inputCh  chan TunnelPayload
	outputCh chan TunnelPayload
	conn     *net.TCPConn
}

func (self *Tunnel) Put(payload *TunnelPayload) {
	self.inputCh <- *payload
}

func (self *Tunnel) Pop() *TunnelPayload {
	payload, ok := <-self.outputCh
	if !ok {
		return nil
	}
	return &payload
}

// read
func (self *Tunnel) PumpOut() (err error) {
	defer close(self.outputCh)

	var header struct {
		Linkid uint16
		Sz     uint8
	}

	rd := bufio.NewReaderSize(self.conn, 4096)
	for {
		err = binary.Read(rd, binary.LittleEndian, &header)
		if err != nil {
			Error("read tunnel failed:%s", err.Error())
			return
		}

		var data []byte

		// if header.Sz == 0, it's ok too
		data = make([]byte, header.Sz)
		c := 0
		for c < int(header.Sz) {
			var n int
			n, err = rd.Read(data[c:])
			if err != nil {
				Error("read tunnel failed:%s", err.Error())
				return
			}
			c += n
		}

		self.outputCh <- TunnelPayload{header.Linkid, data}
	}
	return
}

// write
func (self *Tunnel) PumpUp() (err error) {
	var header struct {
		Linkid uint16
		Sz     uint8
	}
	for {
		payload := <-self.inputCh

		sz := len(payload.Data)
		if sz > 0xff {
			Panic("receive malformed payload, linkid:%d, sz:%d", payload.Linkid, sz)
			break
		}

		header.Linkid = payload.Linkid
		header.Sz = uint8(sz)
		err = binary.Write(self.conn, binary.LittleEndian, &header)
		if err != nil {
			Error("write tunnel failed:%s", err.Error())
			return
		}

		c := 0
		for c < sz {
			var n int
			n, err = self.conn.Write(payload.Data[c:])
			if err != nil {
				Error("write tunnel failed:%s", err.Error())
				return
			}
			c += n
		}
	}
	return
}

func NewTunnel(conn *net.TCPConn) *Tunnel {
	return &Tunnel{make(chan TunnelPayload, 65535), make(chan TunnelPayload, 65535), conn}
}
<commit_msg>use less pointer<commit_after>//
//   date  : 2014-06-04
//   author: xjdrew
//

package main

import (
	"bufio"
	"encoding/binary"
	"net"
)

type TunnelPayload struct {
	Linkid uint16
	Data   []byte
}

type Tunnel struct {
	inputCh  chan *TunnelPayload
	outputCh chan *TunnelPayload
	conn     *net.TCPConn
}

func (self *Tunnel) Put(payload *TunnelPayload) {
	self.inputCh <- payload
}

func (self *Tunnel) Pop() *TunnelPayload {
	payload, ok := <-self.outputCh
	if !ok {
		return nil
	}
	return payload
}

// read
func (self *Tunnel) PumpOut() (err error) {
	defer close(self.outputCh)

	var header struct {
		Linkid uint16
		Sz     uint8
	}

	rd := bufio.NewReaderSize(self.conn, 4096)
	for {
		err = binary.Read(rd, binary.LittleEndian, &header)
		if err != nil {
			Error("read tunnel failed:%s", err.Error())
			return
		}

		var data []byte

		// if header.Sz == 0, it's ok too
		data = make([]byte, header.Sz)
		c := 0
		for c < int(header.Sz) {
			var n int
			n, err = rd.Read(data[c:])
			if err != nil {
				Error("read tunnel failed:%s", err.Error())
				return
			}
			c += n
		}

		self.outputCh <- &TunnelPayload{header.Linkid, data}
	}
	return
}

// write
func (self *Tunnel) PumpUp() (err error) {
	var header struct {
		Linkid uint16
		Sz     uint8
	}
	for {
		payload := <-self.inputCh

		sz := len(payload.Data)
		if sz > 0xff {
			Panic("receive malformed payload, linkid:%d, sz:%d", payload.Linkid, sz)
			break
		}

		header.Linkid = payload.Linkid
		header.Sz = uint8(sz)
		err = binary.Write(self.conn, binary.LittleEndian, &header)
		if err != nil {
			Error("write tunnel failed:%s", err.Error())
			return
		}

		c := 0
		for c < sz {
			var n int
			n, err = self.conn.Write(payload.Data[c:])
			if err != nil {
				Error("write tunnel failed:%s", err.Error())
				return
			}
			c += n
		}
	}
	return
}

func NewTunnel(conn *net.TCPConn) *Tunnel {
	return &Tunnel{make(chan *TunnelPayload, 65535), make(chan *TunnelPayload, 65535), conn}
}
<|endoftext|>


<commit_before>package service

import (
	"errors"
	"fmt"
	"strings"

	"github.com/cloudfoundry/cli/cf/actors/plan_builder"
	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/command_metadata"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/flag_helpers"
	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/json"
	"github.com/codegangsta/cli"
)

type UpdateService struct {
	ui          terminal.UI
	config      core_config.Reader
	serviceRepo api.ServiceRepository
	planBuilder plan_builder.PlanBuilder
}

func NewUpdateService(ui terminal.UI, config core_config.Reader, serviceRepo api.ServiceRepository, planBuilder plan_builder.PlanBuilder) (cmd *UpdateService) {
	return &UpdateService{
		ui:          ui,
		config:      config,
		serviceRepo: serviceRepo,
		planBuilder: planBuilder,
	}
}

func (cmd *UpdateService) Metadata() command_metadata.CommandMetadata {
	return command_metadata.CommandMetadata{
		Name:        "update-service",
		Description: T("Update a service instance"),
		Usage:       T("CF_NAME update-service SERVICE [-p NEW_PLAN]"),
		Flags: []cli.Flag{
			flag_helpers.NewStringFlag("p", T("Change service plan for a service instance")),
			flag_helpers.NewStringFlag("c", T("Valid JSON object containing service-specific configuration parameters, provided either in-line or in a file. For a list of supported configuration parameters, see documentation for the particular service offering.")),
		},
	}
}

func (cmd *UpdateService) GetRequirements(requirementsFactory requirements.Factory, c *cli.Context) (reqs []requirements.Requirement, err error) {
	if len(c.Args()) != 1 {
		cmd.ui.FailWithUsage(c)
	}

	reqs = []requirements.Requirement{
		requirementsFactory.NewLoginRequirement(),
		requirementsFactory.NewTargetedSpaceRequirement(),
	}

	return
}

func (cmd *UpdateService) Run(c *cli.Context) {
	serviceInstanceName := c.Args()[0]

	serviceInstance, err := cmd.serviceRepo.FindInstanceByName(serviceInstanceName)
	if err != nil {
		cmd.ui.Failed(err.Error())
		return
	}

	planName := c.String("p")
	params := c.String("c")
	paramsMap, err := json.ParseJsonFromFileOrString(params)
	if err != nil {
		cmd.ui.Failed("Invalid JSON provided in -c argument")
	}

	if planName != "" {
		cmd.ui.Say(T("Updating service instance {{.ServiceName}} as {{.UserName}}...",
			map[string]interface{}{
				"ServiceName": terminal.EntityNameColor(serviceInstanceName),
				"UserName":    terminal.EntityNameColor(cmd.config.Username()),
			}))

		if cmd.config.IsMinApiVersion("2.16.0") {
			err := cmd.updateServiceWithPlan(serviceInstance, planName, paramsMap)
			switch err.(type) {
			case nil:
				err = printSuccessMessageForServiceInstance(serviceInstanceName, cmd.serviceRepo, cmd.ui)
				if err != nil {
					cmd.ui.Failed(err.Error())
				}
			default:
				cmd.ui.Failed(err.Error())
			}
		} else {
			cmd.ui.Failed(T("Updating a plan requires API v{{.RequiredCCAPIVersion}} or newer. Your current target is v{{.CurrentCCAPIVersion}}.",
				map[string]interface{}{
					"RequiredCCAPIVersion": "2.16.0",
					"CurrentCCAPIVersion":  cmd.config.ApiVersion(),
				}))
		}
	} else {
		cmd.ui.Ok()
		cmd.ui.Say(T("No changes were made"))
	}
}

func (cmd *UpdateService) updateServiceWithPlan(serviceInstance models.ServiceInstance, planName string, paramsMap map[string]interface{}) (err error) {
	plans, err := cmd.planBuilder.GetPlansForServiceForOrg(serviceInstance.ServiceOffering.Guid, cmd.config.OrganizationFields().Name)
	if err != nil {
		return
	}

	for _, plan := range plans {
		if plan.Name == planName {
			err = cmd.serviceRepo.UpdateServiceInstance(serviceInstance.Guid, plan.Guid, paramsMap)
			return
		}
	}
	err = errors.New(T("Plan does not exist for the {{.ServiceName}} service",
		map[string]interface{}{"ServiceName": serviceInstance.ServiceOffering.Label}))

	return
}

func printSuccessMessageForServiceInstance(serviceInstanceName string, serviceRepo api.ServiceRepository, ui terminal.UI) error {
	instance, apiErr := serviceRepo.FindInstanceByName(serviceInstanceName)
	if apiErr != nil {
		return apiErr
	}

	if instance.ServiceInstanceFields.LastOperation.State == "in progress" {
		ui.Ok()
		ui.Say("")
		ui.Say(T("{{.State}} in progress. Use '{{.ServicesCommand}}' or '{{.ServiceCommand}}' to check operation status.",
			map[string]interface{}{
				"State":           strings.Title(instance.ServiceInstanceFields.LastOperation.Type),
				"ServicesCommand": terminal.CommandColor("cf services"),
				"ServiceCommand":  terminal.CommandColor(fmt.Sprintf("cf service %s", serviceInstanceName)),
			}))
	} else {
		ui.Ok()
	}

	return nil
}
<commit_msg>Add translation for error during update-service with arbitrary params<commit_after>package service

import (
	"errors"
	"fmt"
	"strings"

	"github.com/cloudfoundry/cli/cf/actors/plan_builder"
	"github.com/cloudfoundry/cli/cf/api"
	"github.com/cloudfoundry/cli/cf/command_metadata"
	"github.com/cloudfoundry/cli/cf/configuration/core_config"
	"github.com/cloudfoundry/cli/cf/flag_helpers"
	. "github.com/cloudfoundry/cli/cf/i18n"
	"github.com/cloudfoundry/cli/cf/models"
	"github.com/cloudfoundry/cli/cf/requirements"
	"github.com/cloudfoundry/cli/cf/terminal"
	"github.com/cloudfoundry/cli/json"
	"github.com/codegangsta/cli"
)

type UpdateService struct {
	ui          terminal.UI
	config      core_config.Reader
	serviceRepo api.ServiceRepository
	planBuilder plan_builder.PlanBuilder
}

func NewUpdateService(ui terminal.UI, config core_config.Reader, serviceRepo api.ServiceRepository, planBuilder plan_builder.PlanBuilder) (cmd *UpdateService) {
	return &UpdateService{
		ui:          ui,
		config:      config,
		serviceRepo: serviceRepo,
		planBuilder: planBuilder,
	}
}

func (cmd *UpdateService) Metadata() command_metadata.CommandMetadata {
	return command_metadata.CommandMetadata{
		Name:        "update-service",
		Description: T("Update a service instance"),
		Usage:       T("CF_NAME update-service SERVICE [-p NEW_PLAN]"),
		Flags: []cli.Flag{
			flag_helpers.NewStringFlag("p", T("Change service plan for a service instance")),
			flag_helpers.NewStringFlag("c", T("Valid JSON object containing service-specific configuration parameters, provided either in-line or in a file. For a list of supported configuration parameters, see documentation for the particular service offering.")),
		},
	}
}

func (cmd *UpdateService) GetRequirements(requirementsFactory requirements.Factory, c *cli.Context) (reqs []requirements.Requirement, err error) {
	if len(c.Args()) != 1 {
		cmd.ui.FailWithUsage(c)
	}

	reqs = []requirements.Requirement{
		requirementsFactory.NewLoginRequirement(),
		requirementsFactory.NewTargetedSpaceRequirement(),
	}

	return
}

func (cmd *UpdateService) Run(c *cli.Context) {
	serviceInstanceName := c.Args()[0]

	serviceInstance, err := cmd.serviceRepo.FindInstanceByName(serviceInstanceName)
	if err != nil {
		cmd.ui.Failed(err.Error())
		return
	}

	planName := c.String("p")
	params := c.String("c")
	paramsMap, err := json.ParseJsonFromFileOrString(params)
	if err != nil {
		cmd.ui.Failed(T("Invalid JSON provided in -c argument"))
	}

	if planName != "" {
		cmd.ui.Say(T("Updating service instance {{.ServiceName}} as {{.UserName}}...",
			map[string]interface{}{
				"ServiceName": terminal.EntityNameColor(serviceInstanceName),
				"UserName":    terminal.EntityNameColor(cmd.config.Username()),
			}))

		if cmd.config.IsMinApiVersion("2.16.0") {
			err := cmd.updateServiceWithPlan(serviceInstance, planName, paramsMap)
			switch err.(type) {
			case nil:
				err = printSuccessMessageForServiceInstance(serviceInstanceName, cmd.serviceRepo, cmd.ui)
				if err != nil {
					cmd.ui.Failed(err.Error())
				}
			default:
				cmd.ui.Failed(err.Error())
			}
		} else {
			cmd.ui.Failed(T("Updating a plan requires API v{{.RequiredCCAPIVersion}} or newer. Your current target is v{{.CurrentCCAPIVersion}}.",
				map[string]interface{}{
					"RequiredCCAPIVersion": "2.16.0",
					"CurrentCCAPIVersion":  cmd.config.ApiVersion(),
				}))
		}
	} else {
		cmd.ui.Ok()
		cmd.ui.Say(T("No changes were made"))
	}
}

func (cmd *UpdateService) updateServiceWithPlan(serviceInstance models.ServiceInstance, planName string, paramsMap map[string]interface{}) (err error) {
	plans, err := cmd.planBuilder.GetPlansForServiceForOrg(serviceInstance.ServiceOffering.Guid, cmd.config.OrganizationFields().Name)
	if err != nil {
		return
	}

	for _, plan := range plans {
		if plan.Name == planName {
			err = cmd.serviceRepo.UpdateServiceInstance(serviceInstance.Guid, plan.Guid, paramsMap)
			return
		}
	}
	err = errors.New(T("Plan does not exist for the {{.ServiceName}} service",
		map[string]interface{}{"ServiceName": serviceInstance.ServiceOffering.Label}))

	return
}

func printSuccessMessageForServiceInstance(serviceInstanceName string, serviceRepo api.ServiceRepository, ui terminal.UI) error {
	instance, apiErr := serviceRepo.FindInstanceByName(serviceInstanceName)
	if apiErr != nil {
		return apiErr
	}

	if instance.ServiceInstanceFields.LastOperation.State == "in progress" {
		ui.Ok()
		ui.Say("")
		ui.Say(T("{{.State}} in progress. Use '{{.ServicesCommand}}' or '{{.ServiceCommand}}' to check operation status.",
			map[string]interface{}{
				"State":           strings.Title(instance.ServiceInstanceFields.LastOperation.Type),
				"ServicesCommand": terminal.CommandColor("cf services"),
				"ServiceCommand":  terminal.CommandColor(fmt.Sprintf("cf service %s", serviceInstanceName)),
			}))
	} else {
		ui.Ok()
	}

	return nil
}
<|endoftext|>