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

package sshexec

import (
	"fmt"
	"github.com/heketi/heketi/executors"
	"github.com/lpabon/godbc"
)

const (
	rootMountPoint = "/var/lib/heketi/mounts"
)

// Return the mount point for the brick
func (s *SshExecutor) brickMountPoint(brick *executors.BrickRequest) string {
	return rootMountPoint + "/" +
		s.vgName(brick.VgId) + "/" +
		s.brickName(brick.Name)
}

// Device node for the lvm volume
func (s *SshExecutor) devnode(brick *executors.BrickRequest) string {
	return "/dev/" + s.vgName(brick.VgId) +
		"/" + s.brickName(brick.Name)
}

func (s *SshExecutor) BrickCreate(host string,
	brick *executors.BrickRequest) (*executors.BrickInfo, error) {

	godbc.Require(brick != nil)
	godbc.Require(host != "")
	godbc.Require(brick.Name != "")
	godbc.Require(brick.Size > 0)
	godbc.Require(brick.TpSize >= brick.Size)
	godbc.Require(brick.VgId != "")

	// Create mountpoint name
	mountpoint := s.brickMountPoint(brick)

	// Create command set to execute on the node
	commands := []string{

		// Create a directory
		fmt.Sprintf("sudo mkdir -p %v", mountpoint),

		// Setup the LV
		fmt.Sprintf("sudo lvcreate --poolmetadatasize %vK -c 256K -L %vK -T %v/%v -V %vK -n %v",
			// MetadataSize
			brick.PoolMetadataSize,

			//Thin Pool Size
			brick.TpSize,

			// volume group
			s.vgName(brick.VgId),

			// ThinP name
			s.tpName(brick.Name),

			// Allocation size
			brick.Size,

			// Logical Vol name
			s.brickName(brick.Name)),

		// Format
		fmt.Sprintf("sudo mkfs.xfs -i size=512 -n size=8192 %v", s.devnode(brick)),

		// Fstab
		fmt.Sprintf("echo \"%v %v xfs rw,inode64,noatime,nouuid 1 2\" | sudo tee -a /etc/fstab > /dev/null ",
			s.devnode(brick),
			mountpoint),

		// Mount
		fmt.Sprintf("sudo mount %v %v", s.devnode(brick), mountpoint),

		// Create a directory inside the formated volume for GlusterFS
		fmt.Sprintf("sudo mkdir %v/brick", mountpoint),
	}

	// Execute commands
	_, err := s.sshExec(host, commands, 10)
	if err != nil {
		// Cleanup
		s.BrickDestroy(host, brick)
		return nil, err
	}

	// Save brick location
	b := &executors.BrickInfo{
		Path: fmt.Sprintf("%v/brick", mountpoint),
	}
	return b, nil
}

func (s *SshExecutor) BrickDestroy(host string,
	brick *executors.BrickRequest) error {

	godbc.Require(brick != nil)
	godbc.Require(host != "")
	godbc.Require(brick.Name != "")
	godbc.Require(brick.VgId != "")

	// Try to unmount first
	commands := []string{
		fmt.Sprintf("sudo umount %v", s.brickMountPoint(brick)),
	}
	_, err := s.sshExec(host, commands, 5)
	if err != nil {
		logger.Err(err)
	}

	// Now try to remove the LV
	commands = []string{
		fmt.Sprintf("sudo lvremove -f %v/%v", s.vgName(brick.VgId), s.tpName(brick.Name)),
	}
	_, err = s.sshExec(host, commands, 5)
	if err != nil {
		logger.Err(err)
	}

	// Now cleanup the mount point
	commands = []string{
		fmt.Sprintf("sudo rmdir %v", s.brickMountPoint(brick)),
	}
	_, err = s.sshExec(host, commands, 5)
	if err != nil {
		logger.Err(err)
	}

	// Remove from fstab
	commands = []string{
		fmt.Sprintf("sudo sed -i.save '/%v/d' /etc/fstab", s.brickName(brick.Name)),
	}
	_, err = s.sshExec(host, commands, 5)
	if err != nil {
		logger.Err(err)
	}

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

package sshexec

import (
	"fmt"
	"github.com/heketi/heketi/executors"
	"github.com/lpabon/godbc"
)

const (
	rootMountPoint = "/var/lib/heketi/mounts"
)

// Return the mount point for the brick
func (s *SshExecutor) brickMountPoint(brick *executors.BrickRequest) string {
	return rootMountPoint + "/" +
		s.vgName(brick.VgId) + "/" +
		s.brickName(brick.Name)
}

// Device node for the lvm volume
func (s *SshExecutor) devnode(brick *executors.BrickRequest) string {
	return "/dev/" + s.vgName(brick.VgId) +
		"/" + s.brickName(brick.Name)
}

func (s *SshExecutor) BrickCreate(host string,
	brick *executors.BrickRequest) (*executors.BrickInfo, error) {

	godbc.Require(brick != nil)
	godbc.Require(host != "")
	godbc.Require(brick.Name != "")
	godbc.Require(brick.Size > 0)
	godbc.Require(brick.TpSize >= brick.Size)
	godbc.Require(brick.VgId != "")

	// Create mountpoint name
	mountpoint := s.brickMountPoint(brick)

	// Create command set to execute on the node
	commands := []string{

		// Create a directory
		fmt.Sprintf("sudo mkdir -p %v", mountpoint),

		// Setup the LV
		fmt.Sprintf("sudo lvcreate --poolmetadatasize %vK -c 256K -L %vK -T %v/%v -V %vK -n %v",
			// MetadataSize
			brick.PoolMetadataSize,

			//Thin Pool Size
			brick.TpSize,

			// volume group
			s.vgName(brick.VgId),

			// ThinP name
			s.tpName(brick.Name),

			// Allocation size
			brick.Size,

			// Logical Vol name
			s.brickName(brick.Name)),

		// Format
		fmt.Sprintf("sudo mkfs.xfs -i size=512 -n size=8192 %v", s.devnode(brick)),

		// Fstab
		fmt.Sprintf("echo \"%v %v xfs rw,inode64,noatime,nouuid 1 2\" | sudo tee -a /etc/fstab > /dev/null ",
			s.devnode(brick),
			mountpoint),

		// Mount
		fmt.Sprintf("sudo mount -o rw,inode64,noatime,nouuid %v %v", s.devnode(brick), mountpoint),

		// Create a directory inside the formated volume for GlusterFS
		fmt.Sprintf("sudo mkdir %v/brick", mountpoint),
	}

	// Execute commands
	_, err := s.sshExec(host, commands, 10)
	if err != nil {
		// Cleanup
		s.BrickDestroy(host, brick)
		return nil, err
	}

	// Save brick location
	b := &executors.BrickInfo{
		Path: fmt.Sprintf("%v/brick", mountpoint),
	}
	return b, nil
}

func (s *SshExecutor) BrickDestroy(host string,
	brick *executors.BrickRequest) error {

	godbc.Require(brick != nil)
	godbc.Require(host != "")
	godbc.Require(brick.Name != "")
	godbc.Require(brick.VgId != "")

	// Try to unmount first
	commands := []string{
		fmt.Sprintf("sudo umount %v", s.brickMountPoint(brick)),
	}
	_, err := s.sshExec(host, commands, 5)
	if err != nil {
		logger.Err(err)
	}

	// Now try to remove the LV
	commands = []string{
		fmt.Sprintf("sudo lvremove -f %v/%v", s.vgName(brick.VgId), s.tpName(brick.Name)),
	}
	_, err = s.sshExec(host, commands, 5)
	if err != nil {
		logger.Err(err)
	}

	// Now cleanup the mount point
	commands = []string{
		fmt.Sprintf("sudo rmdir %v", s.brickMountPoint(brick)),
	}
	_, err = s.sshExec(host, commands, 5)
	if err != nil {
		logger.Err(err)
	}

	// Remove from fstab
	commands = []string{
		fmt.Sprintf("sudo sed -i.save '/%v/d' /etc/fstab", s.brickName(brick.Name)),
	}
	_, err = s.sshExec(host, commands, 5)
	if err != nil {
		logger.Err(err)
	}

	return nil
}
<|endoftext|>


<commit_before>// Package flagenv populates flags from environment variables.
package flagenv

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

// If set to true, the corresponding environment variable name for a flag will be uppercased.
// ie: For a flag named "foobar", the corresponding environment variable will be "FOOBAR"
var UseUpperCaseFlagNames = false

func parse() (err error) {
	set := make(map[*flag.Flag]bool, 0)
	flag.Visit(func(f *flag.Flag) {
		set[f] = true
	})

	defer func() {
		if e := recover(); e != nil {
			err = e.(error)
		}
	}()

	flag.VisitAll(func(f *flag.Flag) {
		if !set[f] {
			r := strings.NewReplacer(".", "_", "-", "_")
			name := r.Replace(f.Name)
			if UseUpperCaseFlagNames {
				name = strings.ToUpper(name)
			}
			val := os.Getenv(name)
			if val != "" {
				err := f.Value.Set(val)
				if err != nil {
					panic(fmt.Errorf("Failed to set flag %s with value %s", f.Name, val))
				}
			}
		}
	})

	return nil
}

// For each declared flag, Parse() will get the value of the corresponding
// environment variable and will set it. If dots or dash are presents in the
// flag name, they will be converted to underscores. If you want flag names to
// be converted to uppercase, you can set `UseUpperCaseFlagNames` to `true`.
//
// If Parse fails, a fatal error is issued.
func Parse() {
	if err := parse(); err != nil {
		log.Fatalln(err)
	}
}
<commit_msg>Stop using panic/recover for flow control<commit_after>// Package flagenv populates flags from environment variables.
package flagenv

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

// If set to true, the corresponding environment variable name for a flag will be uppercased.
// ie: For a flag named "foobar", the corresponding environment variable will be "FOOBAR"
var UseUpperCaseFlagNames = false

func parse() (err error) {
	set := make(map[*flag.Flag]bool, 0)
	flag.Visit(func(f *flag.Flag) {
		set[f] = true
	})

	flag.VisitAll(func(f *flag.Flag) {
		if !set[f] && err == nil {
			r := strings.NewReplacer(".", "_", "-", "_")
			name := r.Replace(f.Name)
			if UseUpperCaseFlagNames {
				name = strings.ToUpper(name)
			}
			val := os.Getenv(name)
			if val != "" {
				if seterr := f.Value.Set(val); seterr != nil {
					err = fmt.Errorf("Failed to set flag %s with value %s", f.Name, val)
				}
			}
		}
	})

	return
}

// For each declared flag, Parse() will get the value of the corresponding
// environment variable and will set it. If dots or dash are presents in the
// flag name, they will be converted to underscores. If you want flag names to
// be converted to uppercase, you can set `UseUpperCaseFlagNames` to `true`.
//
// If Parse fails, a fatal error is issued.
func Parse() {
	if err := parse(); err != nil {
		log.Fatalln(err)
	}
}
<|endoftext|>


<commit_before>package engineio

import (
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"github.com/kaicheng/goport/events"
)

type Options map[string]interface{}

type Server struct {
	events.EventEmitter

	Clients      map[string]*Socket
	clientsCount int

	pingTimeout    time.Duration
	pingInterval   time.Duration
	upgradeTimeout time.Duration

	maxHttpBufferSize int
	transports        []string
	allowUpgrades     bool
	allowRequest      func(*Request, func(int, bool))
	cookie            string
}

type Request struct {
	events.EventEmitter

	httpReq *http.Request
	query   url.Values
	res     http.ResponseWriter

	abort   func() // used by polling
	cleanup func() // used by polling
}

var gi = 0

func generateId() string {
	gi++
	return fmt.Sprintf("%d", gi)
}

func getBool(val []string) bool {
	if len(val) == 0 {
		return false
	}
	res, err := strconv.ParseBool(val[0])
	if err != nil {
		return false
	}
	return res
}

func valueOrDefault(m Options, key string, def interface{}) interface{} {
	if value, ok := m[key]; ok {
		return value
	} else {
		return def
	}
}

func NewServer(opts Options) (srv *Server) {
	srv = new(Server)
	srv.InitEventEmitter()

	srv.Clients = make(map[string]*Socket)
	srv.clientsCount = 0

	transportsArray := make([]string, len(transports))
	i := 0
	for key, _ := range transports {
		transportsArray[i] = key
		i++
	}

	srv.pingTimeout = (time.Duration(valueOrDefault(opts, "pingTimeout", 60000).(int)) * time.Millisecond)
	srv.pingInterval = (time.Duration(valueOrDefault(opts, "pingInterval", 25000).(int)) * time.Millisecond)
	srv.upgradeTimeout = (time.Duration(valueOrDefault(opts, "upgradeTimeout", 10000).(int)) * time.Millisecond)

	srv.maxHttpBufferSize = valueOrDefault(opts, "maxHttpBufferSize", 100000000).(int)
	srv.transports = valueOrDefault(opts, "transports", transportsArray).([]string)
	srv.allowUpgrades = false // original default true
	srv.allowRequest = nil
	srv.cookie = valueOrDefault(opts, "cookie", "io").(string)

	return
}

const (
	UNKNOWN_TRANSPORT int = iota
	UNKNOWN_SID
	BAD_HANDSHAKE_METHOD
	BAD_REQUEST
)

var ErrorMessages = []string{"Transport unknown", "Session ID unknown", "Bad handshake method", "Bad request"}

// TODO(kaicheng): allow upgrades.
func (srv *Server) upgrades(transport string) []string {
	return []string{}
}

func (srv *Server) verify(req *Request, upgrade bool, fn func(int, bool)) {
	transport := req.query.Get("transport")
	sid := req.query.Get("sid")

	if trans, ok := transports[transport]; !ok || trans == nil {
		fn(UNKNOWN_TRANSPORT, false)
		return
	}

	if len(sid) > 0 {
		client, ok := srv.Clients[sid]
		if !ok {
			fn(UNKNOWN_SID, false)
			return
		}
		if !upgrade && client.transport.Name() != transport {
			fn(BAD_REQUEST, false)
		}
	} else {
		if "GET" != req.httpReq.Method {
			fn(BAD_HANDSHAKE_METHOD, false)
			return
		}
		if srv.allowRequest == nil {
			fn(0, true)
			return
		}
		srv.allowRequest(req, fn)
		return
	}

	fn(0, true)
	return
}

func sendErrorMessage(res http.ResponseWriter, code int) {
	res.Header().Set("Content-type", "application/json")
	res.WriteHeader(400)
	data := fmt.Sprintf("{\"code\":%d,\"message\":\"%s\"}", code, ErrorMessages[code])
	res.Write([]byte(data))
}

func (srv *Server) ServeHTTP(res http.ResponseWriter, httpreq *http.Request) {
	req := new(Request)
	req.InitEventEmitter()
	req.httpReq = httpreq
	req.query = httpreq.URL.Query()
	req.res = res

	srv.verify(req, false, func(err int, success bool) {
		if !success {
			sendErrorMessage(res, err)
			return
		}

		if len(req.query["sid"]) > 0 {
			srv.Clients[req.query.Get("sid")].transport.onRequest(req)
		} else {
			srv.handshake(req.query.Get("transport"), req)
		}
	})
}

func (srv *Server) Close() {
	for _, socket := range srv.Clients {
		socket.close()
	}
}

func (srv *Server) handshake(transportName string, req *Request) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
			sendErrorMessage(req.res, BAD_REQUEST)
		}
	}()

	id := generateId()

	transport := transports[transportName](req)

	if "polling" == transportName {
		transport.setMaxHTTPBufferSize(srv.maxHttpBufferSize)
	}

	if getBool(req.query["b64"]) {
		transport.setSupportsBinary(false)
	} else {
		transport.setSupportsBinary(true)
	}

	socket := newSocket(id, srv, transport, req)

	if len(srv.cookie) > 0 {
		transport.On("headers", func(header http.Header) {
			header.Set("Set-Cookie", srv.cookie+"="+id)
		})
	}

	transport.onRequest(req)

	srv.Clients[id] = socket
	srv.clientsCount++

	socket.Once("close", func() {
		delete(srv.Clients, id)
		srv.clientsCount--
	})

	srv.Emit("connection", socket)
}
<commit_msg>make req.query public<commit_after>package engineio

import (
	"fmt"
	"net/http"
	"net/url"
	"strconv"
	"time"

	"github.com/kaicheng/goport/events"
)

type Options map[string]interface{}

type Server struct {
	events.EventEmitter

	Clients      map[string]*Socket
	clientsCount int

	pingTimeout    time.Duration
	pingInterval   time.Duration
	upgradeTimeout time.Duration

	maxHttpBufferSize int
	transports        []string
	allowUpgrades     bool
	allowRequest      func(*Request, func(int, bool))
	cookie            string
}

type Request struct {
	events.EventEmitter

	httpReq *http.Request
	Query   url.Values
	res     http.ResponseWriter

	abort   func() // used by polling
	cleanup func() // used by polling
}

var gi = 0

func generateId() string {
	gi++
	return fmt.Sprintf("%d", gi)
}

func getBool(val []string) bool {
	if len(val) == 0 {
		return false
	}
	res, err := strconv.ParseBool(val[0])
	if err != nil {
		return false
	}
	return res
}

func valueOrDefault(m Options, key string, def interface{}) interface{} {
	if value, ok := m[key]; ok {
		return value
	} else {
		return def
	}
}

func NewServer(opts Options) (srv *Server) {
	srv = new(Server)
	srv.InitEventEmitter()

	srv.Clients = make(map[string]*Socket)
	srv.clientsCount = 0

	transportsArray := make([]string, len(transports))
	i := 0
	for key, _ := range transports {
		transportsArray[i] = key
		i++
	}

	srv.pingTimeout = (time.Duration(valueOrDefault(opts, "pingTimeout", 60000).(int)) * time.Millisecond)
	srv.pingInterval = (time.Duration(valueOrDefault(opts, "pingInterval", 25000).(int)) * time.Millisecond)
	srv.upgradeTimeout = (time.Duration(valueOrDefault(opts, "upgradeTimeout", 10000).(int)) * time.Millisecond)

	srv.maxHttpBufferSize = valueOrDefault(opts, "maxHttpBufferSize", 100000000).(int)
	srv.transports = valueOrDefault(opts, "transports", transportsArray).([]string)
	srv.allowUpgrades = false // original default true
	srv.allowRequest = nil
	srv.cookie = valueOrDefault(opts, "cookie", "io").(string)

	return
}

const (
	UNKNOWN_TRANSPORT int = iota
	UNKNOWN_SID
	BAD_HANDSHAKE_METHOD
	BAD_REQUEST
)

var ErrorMessages = []string{"Transport unknown", "Session ID unknown", "Bad handshake method", "Bad request"}

// TODO(kaicheng): allow upgrades.
func (srv *Server) upgrades(transport string) []string {
	return []string{}
}

func (srv *Server) verify(req *Request, upgrade bool, fn func(int, bool)) {
	transport := req.Query.Get("transport")
	sid := req.Query.Get("sid")

	if trans, ok := transports[transport]; !ok || trans == nil {
		fn(UNKNOWN_TRANSPORT, false)
		return
	}

	if len(sid) > 0 {
		client, ok := srv.Clients[sid]
		if !ok {
			fn(UNKNOWN_SID, false)
			return
		}
		if !upgrade && client.transport.Name() != transport {
			fn(BAD_REQUEST, false)
		}
	} else {
		if "GET" != req.httpReq.Method {
			fn(BAD_HANDSHAKE_METHOD, false)
			return
		}
		if srv.allowRequest == nil {
			fn(0, true)
			return
		}
		srv.allowRequest(req, fn)
		return
	}

	fn(0, true)
	return
}

func sendErrorMessage(res http.ResponseWriter, code int) {
	res.Header().Set("Content-type", "application/json")
	res.WriteHeader(400)
	data := fmt.Sprintf("{\"code\":%d,\"message\":\"%s\"}", code, ErrorMessages[code])
	res.Write([]byte(data))
}

func (srv *Server) ServeHTTP(res http.ResponseWriter, httpreq *http.Request) {
	req := new(Request)
	req.InitEventEmitter()
	req.httpReq = httpreq
	req.Query = httpreq.URL.Query()
	req.res = res

	srv.verify(req, false, func(err int, success bool) {
		if !success {
			sendErrorMessage(res, err)
			return
		}

		if len(req.Query["sid"]) > 0 {
			srv.Clients[req.Query.Get("sid")].transport.onRequest(req)
		} else {
			srv.handshake(req.Query.Get("transport"), req)
		}
	})
}

func (srv *Server) Close() {
	for _, socket := range srv.Clients {
		socket.close()
	}
}

func (srv *Server) handshake(transportName string, req *Request) {
	defer func() {
		if err := recover(); err != nil {
			fmt.Println(err)
			sendErrorMessage(req.res, BAD_REQUEST)
		}
	}()

	id := generateId()

	transport := transports[transportName](req)

	if "polling" == transportName {
		transport.setMaxHTTPBufferSize(srv.maxHttpBufferSize)
	}

	if getBool(req.Query["b64"]) {
		transport.setSupportsBinary(false)
	} else {
		transport.setSupportsBinary(true)
	}

	socket := newSocket(id, srv, transport, req)

	if len(srv.cookie) > 0 {
		transport.On("headers", func(header http.Header) {
			header.Set("Set-Cookie", srv.cookie+"="+id)
		})
	}

	transport.onRequest(req)

	srv.Clients[id] = socket
	srv.clientsCount++

	socket.Once("close", func() {
		delete(srv.Clients, id)
		srv.clientsCount--
	})

	srv.Emit("connection", socket)
}
<|endoftext|>


<commit_before>package logging

import (
	"errors"
	"github.com/vaughan0/go-ini"
	"io"
	"os"
	"strings"
)

type Config ini.File

// ErrTypeNotSpecified is returned when an output section does not contain a "type" option.
var ErrTypeNotSpecified = errors.New("plugin name not specified")

// ErrUnknownPlugin is returned when an output section's "type" option refers to an unknown plugin.
type ErrUnknownPlugin string

func (e ErrUnknownPlugin) Error() string {
	return "unknown logging plugin: " + string(e)
}

// An OutputPlugin is responsible for creating Outputters from simple key-value configuration variables.
type OutputPlugin interface {
	CreateOutputter(options map[string]string) (Outputter, error)
}

// OutputPluginFunc is a utility type that implements OutputPlugin.
type OutputPluginFunc func(options map[string]string) (Outputter, error)

// Implements OutputPlugin.
func (o OutputPluginFunc) CreateOutputter(options map[string]string) (Outputter, error) {
	return o(options)
}

var outputPlugins = make(map[string]OutputPlugin)

// Registers an output plugin by name.
func RegisterOutputPlugin(name string, plugin OutputPlugin) {
	lock.Lock()
	defer lock.Unlock()
	outputPlugins[name] = plugin
}

// Loads the appropriate plugin and creates an outputter, given a configuration section.
func newOutputterConfig(config ini.Section) (Outputter, error) {
	// Get plugin from the "type" option
	name, ok := config["type"]
	if !ok {
		return nil, ErrTypeNotSpecified
	}
	lock.Lock()
	defer lock.Unlock()
	plugin := outputPlugins[name]
	if plugin == nil {
		return nil, ErrUnknownPlugin(name)
	}

	output, err := plugin.CreateOutputter(config)
	if err != nil {
		return nil, err
	}

	// Check for the "threshold" option
	if thresh, ok := config["threshold"]; ok {
		if level, ok := reverseLevelStrings[strings.ToUpper(thresh)]; ok {
			output = ThresholdOutputter{level, output}
		} else {
			return nil, errors.New("invalid threshold: " + thresh)
		}
	}
	return output, nil
}

// Applies configuration to the logging hierarchy.
func (c Config) apply() (err error) {

	// Create outputters
	const keyPrefix = "output_"
	outputters := make(map[string]Outputter)
	for key, section := range c {
		if strings.HasPrefix(key, keyPrefix) {
			key = key[len(keyPrefix):]
			var output Outputter
			if output, err = newOutputterConfig(section); err != nil {
				return
			}
			outputters[key] = output
		}
	}

	loggerSection := c["loggers"]
	if loggerSection == nil {
		return errors.New("loggers section not specified")
	}

	// Setup loggers
	for name, config := range loggerSection {
		parts := strings.Split(config, ",")
		level, ok := reverseLevelStrings[strings.ToUpper(parts[0])]
		if !ok {
			return errors.New("unknown logging level: " + parts[0])
		}
		// Get the logger by its name, treating "root" as a special name
		var logger *Logger
		if name == "root" {
			logger = Root
		} else {
			logger = Get(name)
		}
		logger.Threshold = level
		// Handle extra options
		for _, outputKey := range parts[1:] {
			if outputKey == "nopropagate" {
				logger.NoPropagate = true
			} else {
				// Assign an outputter
				if outputter := outputters[outputKey]; outputter != nil {
					logger.AddOutput(outputter)
				} else {
					return errors.New("unknown logging output: " + outputKey)
				}
			}
		}
	}

	Root.configure()
	configured = true
	return nil
}

// Configures the logging hierarchy from an io.Reader, which should return valid INI source code.
func SetupReader(config io.Reader) (err error) {
	file, err := ini.Load(config)
	if err != nil {
		return
	}
	return Config(file).apply()
}

// Configures the logging hierarchy from an INI file.
func SetupFile(filename string) (err error) {
	file, err := ini.LoadFile(filename)
	if err != nil {
		return
	}
	return Config(file).apply()
}

// Automatically configures the logging hierarchy by loading the INI file specified by the GO_LOGGING_CONFIG environment
// variable.
func Setup() (err error) {
	path := os.Getenv("GO_LOGGING_CONFIG")
	if path == "" {
		return errors.New("GO_LOGGING_CONFIG not set")
	}
	return SetupFile(path)
}
<commit_msg>Removed unnecessary output_ prefix<commit_after>package logging

import (
	"errors"
	"github.com/vaughan0/go-ini"
	"io"
	"os"
	"strings"
)

type Config ini.File

// ErrTypeNotSpecified is returned when an output section does not contain a "type" option.
var ErrTypeNotSpecified = errors.New("plugin name not specified")

// ErrUnknownPlugin is returned when an output section's "type" option refers to an unknown plugin.
type ErrUnknownPlugin string

func (e ErrUnknownPlugin) Error() string {
	return "unknown logging plugin: " + string(e)
}

// An OutputPlugin is responsible for creating Outputters from simple key-value configuration variables.
type OutputPlugin interface {
	CreateOutputter(options map[string]string) (Outputter, error)
}

// OutputPluginFunc is a utility type that implements OutputPlugin.
type OutputPluginFunc func(options map[string]string) (Outputter, error)

// Implements OutputPlugin.
func (o OutputPluginFunc) CreateOutputter(options map[string]string) (Outputter, error) {
	return o(options)
}

var outputPlugins = make(map[string]OutputPlugin)

// Registers an output plugin by name.
func RegisterOutputPlugin(name string, plugin OutputPlugin) {
	lock.Lock()
	defer lock.Unlock()
	outputPlugins[name] = plugin
}

// Loads the appropriate plugin and creates an outputter, given a configuration section.
func newOutputterConfig(config ini.Section) (Outputter, error) {
	// Get plugin from the "type" option
	name, ok := config["type"]
	if !ok {
		return nil, ErrTypeNotSpecified
	}
	lock.Lock()
	defer lock.Unlock()
	plugin := outputPlugins[name]
	if plugin == nil {
		return nil, ErrUnknownPlugin(name)
	}

	output, err := plugin.CreateOutputter(config)
	if err != nil {
		return nil, err
	}

	// Check for the "threshold" option
	if thresh, ok := config["threshold"]; ok {
		if level, ok := reverseLevelStrings[strings.ToUpper(thresh)]; ok {
			output = ThresholdOutputter{level, output}
		} else {
			return nil, errors.New("invalid threshold: " + thresh)
		}
	}
	return output, nil
}

// Applies configuration to the logging hierarchy.
func (c Config) apply() (err error) {

	// Create outputters
	outputters := make(map[string]Outputter)
	for key, section := range c {
		if key != "loggers" && key != "" {
			var output Outputter
			if output, err = newOutputterConfig(section); err != nil {
				return
			}
			outputters[key] = output
		}
	}

	loggerSection := c["loggers"]
	if loggerSection == nil {
		return errors.New("loggers section not specified")
	}

	// Setup loggers
	for name, config := range loggerSection {
		parts := strings.Split(config, ",")
		level, ok := reverseLevelStrings[strings.ToUpper(parts[0])]
		if !ok {
			return errors.New("unknown logging level: " + parts[0])
		}
		// Get the logger by its name, treating "root" as a special name
		var logger *Logger
		if name == "root" {
			logger = Root
		} else {
			logger = Get(name)
		}
		logger.Threshold = level
		// Handle extra options
		for _, outputKey := range parts[1:] {
			if outputKey == "nopropagate" {
				logger.NoPropagate = true
			} else {
				// Assign an outputter
				if outputter := outputters[outputKey]; outputter != nil {
					logger.AddOutput(outputter)
				} else {
					return errors.New("unknown logging output: " + outputKey)
				}
			}
		}
	}

	Root.configure()
	configured = true
	return nil
}

// Configures the logging hierarchy from an io.Reader, which should return valid INI source code.
func SetupReader(config io.Reader) (err error) {
	file, err := ini.Load(config)
	if err != nil {
		return
	}
	return Config(file).apply()
}

// Configures the logging hierarchy from an INI file.
func SetupFile(filename string) (err error) {
	file, err := ini.LoadFile(filename)
	if err != nil {
		return
	}
	return Config(file).apply()
}

// Automatically configures the logging hierarchy by loading the INI file specified by the GO_LOGGING_CONFIG environment
// variable.
func Setup() (err error) {
	path := os.Getenv("GO_LOGGING_CONFIG")
	if path == "" {
		return errors.New("GO_LOGGING_CONFIG not set")
	}
	return SetupFile(path)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"

	"github.com/skratchdot/open-golang/open"
)

const (
	baseURL  = "https://slack.com/oauth/authorize"
	clientID = "7065709201.17699618306"
	scope    = "channels%3Aread+groups%3Aread+im%3Aread+users%3Aread+chat%3Awrite%3Auser+files%3Awrite%3Auser"
)

//Slack team and channel read from file
type Config struct {
	teams          map[string]string
	defaultTeam    string
	defaultChannel string
}

func getConfigPath() string {
	homedir := os.Getenv("HOME")
	if homedir == "" {
		exitErr(fmt.Errorf("$HOME not set"))
	}
	return homedir + "/.slackcat"
}

func (c *Config) parseChannelOpt(channel string) (string, string, error) {
	//use default channel if none provided
	if channel == "" {
		if c.defaultChannel == "" {
			return "", "", fmt.Errorf("no channel provided")
		}
		return c.defaultTeam, c.defaultChannel, nil
	}
	//if channel is prefixed with a team
	if strings.Contains(channel, ":") {
		s := strings.Split(channel, ":")
		return s[0], s[1], nil
	}
	//use default team with provided channel
	return c.defaultTeam, channel, nil
}

func readConfig() *Config {
	config := &Config{
		teams:          make(map[string]string),
		defaultTeam:    "",
		defaultChannel: "",
	}
	lines := readLines(getConfigPath())

	//simple config file
	if len(lines) == 1 {
		config.teams["default"] = lines[0]
		config.defaultTeam = "default"
		return config
	}

	//advanced config file
	for _, line := range lines {
		s := strings.Split(line, "=")
		if len(s) != 2 {
			exitErr(fmt.Errorf("failed to parse config at: %s", line))
		}
		key, val := strip(s[0]), strip(s[1])
		switch key {
		case "default_team":
			config.defaultTeam = val
		case "default_channel":
			config.defaultChannel = val
		default:
			config.teams[key] = val
		}
	}
	return config
}

func strip(s string) string {
	return strings.Replace(s, " ", "", -1)
}

func readLines(path string) []string {
	var lines []string

	file, err := os.Open(path)
	failOnError(err, "unable to read config", true)
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		if scanner.Text() != "" {
			lines = append(lines, scanner.Text())
		}
	}
	return lines
}

func configureOA() {
	oaURL := baseURL + "?scope=" + scope + "&client_id=" + clientID
	output("Creating token request for Slackcat")
	err := open.Run(oaURL)
	if err != nil {
		output("Please open the below URL in your browser to authorize SlackCat")
		output(oaURL)
	}
}
<commit_msg>always output oauth url in case of open() failure<commit_after>package main

import (
	"bufio"
	"fmt"
	"os"
	"strings"

	"github.com/skratchdot/open-golang/open"
)

const (
	baseURL  = "https://slack.com/oauth/authorize"
	clientID = "7065709201.17699618306"
	scope    = "channels%3Aread+groups%3Aread+im%3Aread+users%3Aread+chat%3Awrite%3Auser+files%3Awrite%3Auser"
)

//Slack team and channel read from file
type Config struct {
	teams          map[string]string
	defaultTeam    string
	defaultChannel string
}

func getConfigPath() string {
	homedir := os.Getenv("HOME")
	if homedir == "" {
		exitErr(fmt.Errorf("$HOME not set"))
	}
	return homedir + "/.slackcat"
}

func (c *Config) parseChannelOpt(channel string) (string, string, error) {
	//use default channel if none provided
	if channel == "" {
		if c.defaultChannel == "" {
			return "", "", fmt.Errorf("no channel provided")
		}
		return c.defaultTeam, c.defaultChannel, nil
	}
	//if channel is prefixed with a team
	if strings.Contains(channel, ":") {
		s := strings.Split(channel, ":")
		return s[0], s[1], nil
	}
	//use default team with provided channel
	return c.defaultTeam, channel, nil
}

func readConfig() *Config {
	config := &Config{
		teams:          make(map[string]string),
		defaultTeam:    "",
		defaultChannel: "",
	}
	lines := readLines(getConfigPath())

	//simple config file
	if len(lines) == 1 {
		config.teams["default"] = lines[0]
		config.defaultTeam = "default"
		return config
	}

	//advanced config file
	for _, line := range lines {
		s := strings.Split(line, "=")
		if len(s) != 2 {
			exitErr(fmt.Errorf("failed to parse config at: %s", line))
		}
		key, val := strip(s[0]), strip(s[1])
		switch key {
		case "default_team":
			config.defaultTeam = val
		case "default_channel":
			config.defaultChannel = val
		default:
			config.teams[key] = val
		}
	}
	return config
}

func strip(s string) string {
	return strings.Replace(s, " ", "", -1)
}

func readLines(path string) []string {
	var lines []string

	file, err := os.Open(path)
	failOnError(err, "unable to read config", true)
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		if scanner.Text() != "" {
			lines = append(lines, scanner.Text())
		}
	}
	return lines
}

func configureOA() {
	oaURL := baseURL + "?scope=" + scope + "&client_id=" + clientID
	output("Creating token request for Slackcat")
	open.Run(oaURL)
	output("Use the below URL to authorize slackcat if browser fails to launch")
	output(oaURL)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/BurntSushi/toml"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
	"strings"
)

// Config Struct represents the load balancer's configuration
type Config struct {

	// the backend services to balance
	Backends []string `toml:"backends"`

	// The port the load balancer is bound to
	Bind string `toml:"bind"`

	// The load balancing mode (i.e. round-robin)
	// Currently, only round-robin is used, and configurable mode is not supported.
	Mode string `toml:"mode"`

	// Path to certificate file
	Certfile string `toml:certFile`

	// Path to private key file related to certificate
	Keyfile string `toml:keyFile`
}

// singleton Config instance initially set to nil
var config *Config = nil

// GetConfig implements a singleton pattern for access the Config instance.
func GetConfig(configFile string) *Config {
	if config == nil {
		config = new(Config)
		config.init(configFile)
	}
	return config
}

// init initializes a new Config instance by reading from the config file
// It will unmarshal the toml file into the Config struct
func (c *Config) init(configFile string) {
	_, err := os.Stat(configFile)

	if err != nil {
		log.Fatal("Config file not found: ", configFile)
	}
	if _, err := toml.DecodeFile(configFile, c); err != nil {
		log.Fatal(err)
	}
}

// handleUserInput checks command line input and overrides config file settings
// Backends is parsed from a raw string to a slice of strings
func (c *Config) handleUserInput() {

	if *backendStr != "" {
		// Remove whitespace from backends
		*backendStr = strings.Replace(*backendStr, " ", "", -1)
		// Throwing backends into an array
		c.Backends = strings.Split(*backendStr, ",")
	}
	if *bind != "" {
		c.Bind = *bind
	}
	if *mode != "" {
		c.Mode = *mode
	}
	if *certFile != "" {
		c.Certfile = *certFile
	}
	if *keyFile != "" {
		c.Keyfile = *keyFile
	}
}

// printConfigInfo prints to stderr host and port settings applied to current process
func (c *Config) printConfigInfo() {
	// tell the user what info the load balancer is using
	for _, v := range c.Backends {
		log.Println("using " + v + " as a backend")
	}
	log.Println("listening on port " + c.Bind)
}

// makeProxies creates slice of ReverseProxies based on the Config's backend hosts
// It returns a slice of httputil.ReverseProxy
func (c *Config) makeProxies() []*httputil.ReverseProxy {
	// Create a proxy for each backend
	proxies := make([]*httputil.ReverseProxy, len(c.Backends))
	for i := range c.Backends {
		director := func(req *http.Request) {
			req.URL.Scheme = "http"
			req.URL.Host = c.Backends[i]
		}
		proxies[i] = &httputil.ReverseProxy{Director: director}
	}
	return proxies
}
<commit_msg>making imports pretty<commit_after>package main

import (
	"os"
	"log"
	"strings"
	"net/http"
	"net/http/httputil"

	"github.com/BurntSushi/toml"
)

// Config Struct represents the load balancer's configuration
type Config struct {

	// the backend services to balance
	Backends []string `toml:"backends"`

	// The port the load balancer is bound to
	Bind string `toml:"bind"`

	// The load balancing mode (i.e. round-robin)
	// Currently, only round-robin is used, and configurable mode is not supported.
	Mode string `toml:"mode"`

	// Path to certificate file
	Certfile string `toml:certFile`

	// Path to private key file related to certificate
	Keyfile string `toml:keyFile`
}

// singleton Config instance initially set to nil
var config *Config = nil

// GetConfig implements a singleton pattern for access the Config instance.
func GetConfig(configFile string) *Config {
	if config == nil {
		config = new(Config)
		config.init(configFile)
	}
	return config
}

// init initializes a new Config instance by reading from the config file
// It will unmarshal the toml file into the Config struct
func (c *Config) init(configFile string) {
	_, err := os.Stat(configFile)

	if err != nil {
		log.Fatal("Config file not found: ", configFile)
	}
	if _, err := toml.DecodeFile(configFile, c); err != nil {
		log.Fatal(err)
	}
}

// handleUserInput checks command line input and overrides config file settings
// Backends is parsed from a raw string to a slice of strings
func (c *Config) handleUserInput() {

	if *backendStr != "" {
		// Remove whitespace from backends
		*backendStr = strings.Replace(*backendStr, " ", "", -1)
		// Throwing backends into an array
		c.Backends = strings.Split(*backendStr, ",")
	}
	if *bind != "" {
		c.Bind = *bind
	}
	if *mode != "" {
		c.Mode = *mode
	}
	if *certFile != "" {
		c.Certfile = *certFile
	}
	if *keyFile != "" {
		c.Keyfile = *keyFile
	}
}

// printConfigInfo prints to stderr host and port settings applied to current process
func (c *Config) printConfigInfo() {
	// tell the user what info the load balancer is using
	for _, v := range c.Backends {
		log.Println("using " + v + " as a backend")
	}
	log.Println("listening on port " + c.Bind)
}

// makeProxies creates slice of ReverseProxies based on the Config's backend hosts
// It returns a slice of httputil.ReverseProxy
func (c *Config) makeProxies() []*httputil.ReverseProxy {
	// Create a proxy for each backend
	proxies := make([]*httputil.ReverseProxy, len(c.Backends))
	for i := range c.Backends {
		director := func(req *http.Request) {
			req.URL.Scheme = "http"
			req.URL.Host = c.Backends[i]
		}
		proxies[i] = &httputil.ReverseProxy{Director: director}
	}
	return proxies
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path"
	"path/filepath"
	"strconv"
	"strings"
)

// configDir is where config files will saved.
// It is $HOME/.config/tor
var configDir = ""

func init() {
	u, err := user.Current()
	if err != nil {
		panic(err)
	}
	configDir = path.Join(u.HomeDir, ".config", "tor")
	if err := os.MkdirAll(configDir, 0755); err != nil && !os.IsExist(err) {
		panic(err)
	}
}

// saveLastPosition saves a cursor position to
// the 'lastpos' config file.
// Each line is formatted as {filepath}:{line}:{offset}
func saveLastPosition(pth string, l, b int) error {
	abspath, err := filepath.Abs(pth)
	if err != nil {
		return err
	}
	f := path.Join(configDir, "lastpos")
	if _, err = os.Stat(f); os.IsNotExist(err) {
		os.Create(f)
	}
	input, err := ioutil.ReadFile(f)
	if err != nil {
		return err
	}
	lines := strings.Split(string(input), "\n")
	find := false
	for i, ln := range lines {
		if strings.Contains(ln, abspath+":") {
			find = true
			lines[i] = fmt.Sprintf("%v:%v:%v", abspath, l, b)
		}
	}
	if !find {
		lines = append(lines, fmt.Sprintf("%v:%v:%v", abspath, l, b))
	}
	output := strings.Join(lines, "\n")
	err = ioutil.WriteFile(f, []byte(output), 0644)
	if err != nil {
		return err
	}
	return nil
}

// loadLastPosition loads a cursor position from
// the 'lastpos' config file.
// If there is no information about the file in 'lastpos',
// it will return 0, 0.
func loadLastPosition(pth string) (int, int) {
	abspath, err := filepath.Abs(pth)
	if err != nil {
		return 0, 0
	}
	u, err := user.Current()
	if err != nil {
		return 0, 0
	}
	f := path.Join(u.HomeDir, ".config", "tor", "lastpos")
	input, err := ioutil.ReadFile(f)
	if err != nil {
		return 0, 0
	}
	find := false
	findline := ""
	lines := strings.Split(string(input), "\n")
	for _, ln := range lines {
		if strings.Contains(ln, abspath+":") {
			find = true
			findline = ln
		}
	}
	if !find {
		return 0, 0
	}
	tokens := strings.Split(findline, ":")
	if len(tokens) != 3 {
		return 0, 0
	}
	l, err := strconv.Atoi(tokens[1])
	if err != nil {
		return 0, 0
	}
	b, err := strconv.Atoi(tokens[2])
	if err != nil {
		return 0, 0
	}
	return l, b
}

// saveConfig saves a string to ~/.config/tor/{fname} file.
// It will return error if exists.
func saveConfig(fname, s string) error {
	f := path.Join(configDir, fname)
	return ioutil.WriteFile(f, []byte(s), 0644)
}

// loadConfig loads a string from ~/.config/tor/{fname} file.
// On any error, it will return empty string.
func loadConfig(fname string) string {
	f := path.Join(configDir, fname)
	b, err := ioutil.ReadFile(f)
	if err != nil {
		return ""
	}
	return string(b)
}
<commit_msg>change way of initialization of configDir<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path"
	"path/filepath"
	"strconv"
	"strings"
)

// configDir is where config files will saved.
// It is $HOME/.config/tor
var configDir string

func init() {
	u, err := user.Current()
	if err != nil {
		panic(err)
	}
	configDir = path.Join(u.HomeDir, ".config", "tor")
	if err := os.MkdirAll(configDir, 0755); err != nil && !os.IsExist(err) {
		panic(err)
	}
}

// saveLastPosition saves a cursor position to
// the 'lastpos' config file.
// Each line is formatted as {filepath}:{line}:{offset}
func saveLastPosition(pth string, l, b int) error {
	abspath, err := filepath.Abs(pth)
	if err != nil {
		return err
	}
	f := path.Join(configDir, "lastpos")
	if _, err = os.Stat(f); os.IsNotExist(err) {
		os.Create(f)
	}
	input, err := ioutil.ReadFile(f)
	if err != nil {
		return err
	}
	lines := strings.Split(string(input), "\n")
	find := false
	for i, ln := range lines {
		if strings.Contains(ln, abspath+":") {
			find = true
			lines[i] = fmt.Sprintf("%v:%v:%v", abspath, l, b)
		}
	}
	if !find {
		lines = append(lines, fmt.Sprintf("%v:%v:%v", abspath, l, b))
	}
	output := strings.Join(lines, "\n")
	err = ioutil.WriteFile(f, []byte(output), 0644)
	if err != nil {
		return err
	}
	return nil
}

// loadLastPosition loads a cursor position from
// the 'lastpos' config file.
// If there is no information about the file in 'lastpos',
// it will return 0, 0.
func loadLastPosition(pth string) (int, int) {
	abspath, err := filepath.Abs(pth)
	if err != nil {
		return 0, 0
	}
	u, err := user.Current()
	if err != nil {
		return 0, 0
	}
	f := path.Join(u.HomeDir, ".config", "tor", "lastpos")
	input, err := ioutil.ReadFile(f)
	if err != nil {
		return 0, 0
	}
	find := false
	findline := ""
	lines := strings.Split(string(input), "\n")
	for _, ln := range lines {
		if strings.Contains(ln, abspath+":") {
			find = true
			findline = ln
		}
	}
	if !find {
		return 0, 0
	}
	tokens := strings.Split(findline, ":")
	if len(tokens) != 3 {
		return 0, 0
	}
	l, err := strconv.Atoi(tokens[1])
	if err != nil {
		return 0, 0
	}
	b, err := strconv.Atoi(tokens[2])
	if err != nil {
		return 0, 0
	}
	return l, b
}

// saveConfig saves a string to ~/.config/tor/{fname} file.
// It will return error if exists.
func saveConfig(fname, s string) error {
	f := path.Join(configDir, fname)
	return ioutil.WriteFile(f, []byte(s), 0644)
}

// loadConfig loads a string from ~/.config/tor/{fname} file.
// On any error, it will return empty string.
func loadConfig(fname string) string {
	f := path.Join(configDir, fname)
	b, err := ioutil.ReadFile(f)
	if err != nil {
		return ""
	}
	return string(b)
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/BurntSushi/toml"
)

type Config struct {
	Ui   UiSection   `toml:"ui"`
	Core CoreSection `toml:"core"`
}

type UiSection struct {
	Editor string `toml:"editor"`
}

type CoreSection struct {
	Linefeed string `toml:"linefeed"`
}

func SetDefaultConfig(config *Config) {
	if len(config.Ui.Editor) <= 0 {
		config.Ui.Editor = "more"
	}
	if len(config.Core.Linefeed) <= 0 {
		config.Core.Linefeed = "unix"
	}
}

func LoadConfig() (Config, error) {
	var config Config
	var err error
	home, err := GetHomePath()
	if err == nil {
		configFile := filepath.Join(home, ".gookmarkrc")
		_, err = os.Stat(configFile)
		if err == nil {
			_, err = toml.DecodeFile(configFile, &config)
		}
		SetDefaultConfig(&config)
		err = nil
	}
	return config, err
}

type ConfigOption struct {
	Section  string
	Property string
	Value    string
}

func ParseConfigOption(option string) (ConfigOption, error) {
	var err error
	var buff []string

	var configOption ConfigOption

	buff = strings.SplitN(option, ".", 2)
	if len(buff) != 2 {
		err = errors.New("Invalid option")
	} else {
		configOption.Section = buff[0]
		buff = strings.SplitN(buff[1], "=", 2)
		if len(buff) != 2 {
			err = errors.New("Invalid option")
		} else {
			configOption.Property = buff[0]
			configOption.Value = buff[1]
		}
	}

	return configOption, err
}

func WriteNewConfig(config *Config, newConfig string) error {
	configOption, err := ParseConfigOption(newConfig)
	if err != nil {
		return err
	}

	if configOption.Section == "ui" {
		if configOption.Property == "editor" {
			config.Ui.Editor = configOption.Value
		} else {
			err = errors.New("Unknown property: " + configOption.Section + "." + configOption.Property)
		}
	} else if configOption.Section == "core" {
		if configOption.Property == "linefeed" {
			config.Core.Linefeed = configOption.Value
		} else {
			err = errors.New("Unknown property: " + configOption.Section + "." + configOption.Property)
		}
	} else {
		err = errors.New("Unknown section: " + configOption.Section)
	}
	if err != nil {
		return err
	}

	var buffer bytes.Buffer
	err = toml.NewEncoder(&buffer).Encode(config)
	if err != nil {
		return err
	}

	home, err := GetHomePath()
	if err != nil {
		return err
	}
	configFile := filepath.Join(home, ".gookmarkrc")
	fp, err := os.OpenFile(configFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
	if err != nil {
		return err
	}
	defer fp.Close()

	fmt.Fprintln(fp, buffer.String())

	return err
}
<commit_msg>Add alias option getter/setter. but it is not implemented<commit_after>package main

import (
	"bytes"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"github.com/BurntSushi/toml"
)

type Config struct {
	Ui    UiSection         `toml:"ui"`
	Core  CoreSection       `toml:"core"`
	Alias map[string]string `toml:"alias"`
}

type UiSection struct {
	Editor string `toml:"editor"`
}

type CoreSection struct {
	Linefeed string `toml:"linefeed"`
}

func SetDefaultConfig(config *Config) {
	if len(config.Ui.Editor) <= 0 {
		config.Ui.Editor = "more"
	}
	if len(config.Core.Linefeed) <= 0 {
		config.Core.Linefeed = "unix"
	}
}

func LoadConfig() (Config, error) {
	var config Config
	var err error
	home, err := GetHomePath()
	if err == nil {
		configFile := filepath.Join(home, ".gookmarkrc")
		_, err = os.Stat(configFile)
		if err == nil {
			_, err = toml.DecodeFile(configFile, &config)
		}
		SetDefaultConfig(&config)
		err = nil
	}
	return config, err
}

type ConfigOption struct {
	Section  string
	Property string
	Value    string
}

func ParseConfigOption(option string) (ConfigOption, error) {
	var err error
	var buff []string

	var configOption ConfigOption

	buff = strings.SplitN(option, ".", 2)
	if len(buff) != 2 {
		err = errors.New("Invalid option")
	} else {
		configOption.Section = buff[0]
		buff = strings.SplitN(buff[1], "=", 2)
		if len(buff) != 2 {
			err = errors.New("Invalid option")
		} else {
			configOption.Property = buff[0]
			configOption.Value = buff[1]
		}
	}

	return configOption, err
}

func WriteNewConfig(config *Config, newConfig string) error {
	configOption, err := ParseConfigOption(newConfig)
	if err != nil {
		return err
	}

	if configOption.Section == "ui" {
		if configOption.Property == "editor" {
			config.Ui.Editor = configOption.Value
		} else {
			err = errors.New("Unknown property: " + configOption.Section + "." + configOption.Property)
		}
	} else if configOption.Section == "core" {
		if configOption.Property == "linefeed" {
			config.Core.Linefeed = configOption.Value
		} else {
			err = errors.New("Unknown property: " + configOption.Section + "." + configOption.Property)
		}
	} else if configOption.Section == "alias" {
		if config.Alias == nil {
			config.Alias = make(map[string]string)
		}
		config.Alias[configOption.Property] = configOption.Value
	} else {
		err = errors.New("Unknown section: " + configOption.Section)
	}
	if err != nil {
		return err
	}

	var buffer bytes.Buffer
	err = toml.NewEncoder(&buffer).Encode(config)
	if err != nil {
		return err
	}

	home, err := GetHomePath()
	if err != nil {
		return err
	}
	configFile := filepath.Join(home, ".gookmarkrc")
	fp, err := os.OpenFile(configFile, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666)
	if err != nil {
		return err
	}
	defer fp.Close()

	fmt.Fprintln(fp, buffer.String())

	return err
}
<|endoftext|>


<commit_before>// Package config version v1.0.0
package config

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"reflect"
	"strings"

	"gopkg.in/yaml.v2"
)

// Namespace holds the pieces joined together to form the
// directory namespacing for config.
type Namespace struct {
	Organization string // optional additional namespace for orgs.
	System       string // Name of the system associated with this config.
}

// The Config interface implements config.
type Config interface {
	Load(src string, dst interface{}) error
}

// UserBase and SystemBase are the prefixes for the user and system config
// paths, respectively.
const (
	UserBase   string = "~/.config/"
	SystemBase string = "/etc/"
)

// Load expands the provided src path using config.ExpandUser, then reads
// the file and unmarshals into dst using go-yaml.
func Load(src string, dst interface{}) (err error) {
	dstv := reflect.ValueOf(dst)

	if dstv.Kind() != reflect.Ptr {
		err = errors.New("config: not a pointer")
	}
	if err != nil {
		return
	}

	path, err := ExpandUser(src)
	if err != nil {
		return
	}

	data, err := ioutil.ReadFile(path)
	if err != nil {
		return
	}

	err = yaml.Unmarshal(data, dst)
	return
}

// ExpandUser acts kind of like os.path.expanduser in Python, except only
// supports expanding "~/" or "$HOME"
func ExpandUser(path string) (exPath string, err error) {
	usr, err := user.Current()
	if err != nil {
		return
	}

	dir := fmt.Sprintf("%s/", usr.HomeDir)

	exPath = path
	if len(path) > 2 && path[:2] == "~/" {
		exPath = strings.Replace(exPath, "~/", dir, 1)
	} else if len(path) > 5 && path[:5] == "$HOME" {
		exPath = strings.Replace(exPath, "$HOME", dir, 1)
	}

	exPath, err = filepath.Abs(filepath.Clean(exPath))

	if err != nil {
		return "", err
	}

	return
}

// Path returns path to config, chosen by hierarchy and checked for
// existence:
//
// 1. User config (~/.config/podhub/canary/config.yaml)
//
// 2. System config (/etc/podhub/canary/config.yaml)
func (c Namespace) Path() (path string, err error) {
	systemPath, _ := c.systemPath()
	if _, err := os.Stat(systemPath); err == nil {
		path, _ = c.systemPath()
	}

	userPath, _ := c.userPath()
	if _, err := os.Stat(userPath); err == nil {
		path, _ = c.userPath()
	}
	return
}

func (c Namespace) systemPath() (path string, err error) {
	path = filepath.Join(SystemBase, c.Organization, c.System, "config.yaml")
	return
}

func (c Namespace) userPath() (path string, err error) {
	userBase, err := ExpandUser(UserBase)
	if err != nil {
		return "", err
	}

	path = filepath.Join(userBase, c.Organization, c.System, "config.yaml")
	return
}

// Load is a convenience function registered to config.Namespace to
// implement Config.Load().
func (c Namespace) Load(dst interface{}) (err error) {
	cfgPath, err := c.Path()
	if err != nil {
		return
	}

	err = Load(cfgPath, dst)
	return
}
<commit_msg>remove err return from Path()<commit_after>// Package config version v1.0.0
package config

import (
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"os/user"
	"path/filepath"
	"reflect"
	"strings"

	"gopkg.in/yaml.v2"
)

// Namespace holds the pieces joined together to form the
// directory namespacing for config.
type Namespace struct {
	Organization string // optional additional namespace for orgs.
	System       string // Name of the system associated with this config.
}

// The Config interface implements config.
type Config interface {
	Load(src string, dst interface{}) error
}

// UserBase and SystemBase are the prefixes for the user and system config
// paths, respectively.
const (
	UserBase   string = "~/.config/"
	SystemBase string = "/etc/"
)

// Load expands the provided src path using config.ExpandUser, then reads
// the file and unmarshals into dst using go-yaml.
func Load(src string, dst interface{}) (err error) {
	dstv := reflect.ValueOf(dst)

	if dstv.Kind() != reflect.Ptr {
		err = errors.New("config: not a pointer")
	}
	if err != nil {
		return
	}

	path, err := ExpandUser(src)
	if err != nil {
		return
	}

	data, err := ioutil.ReadFile(path)
	if err != nil {
		return
	}

	err = yaml.Unmarshal(data, dst)
	return
}

// ExpandUser acts kind of like os.path.expanduser in Python, except only
// supports expanding "~/" or "$HOME"
func ExpandUser(path string) (exPath string, err error) {
	usr, err := user.Current()
	if err != nil {
		return
	}

	dir := fmt.Sprintf("%s/", usr.HomeDir)

	exPath = path
	if len(path) > 2 && path[:2] == "~/" {
		exPath = strings.Replace(exPath, "~/", dir, 1)
	} else if len(path) > 5 && path[:5] == "$HOME" {
		exPath = strings.Replace(exPath, "$HOME", dir, 1)
	}

	exPath, err = filepath.Abs(filepath.Clean(exPath))

	if err != nil {
		return "", err
	}

	return
}

// Path returns path to config, chosen by hierarchy and checked for
// existence:
//
// 1. User config (~/.config/podhub/canary/config.yaml)
//
// 2. System config (/etc/podhub/canary/config.yaml)
func (c Namespace) Path() (path string) {
	systemPath, _ := c.systemPath()
	if _, err := os.Stat(systemPath); err == nil {
		path, _ = c.systemPath()
	}

	userPath, _ := c.userPath()
	if _, err := os.Stat(userPath); err == nil {
		path, _ = c.userPath()
	}
	return
}

func (c Namespace) systemPath() (path string, err error) {
	path = filepath.Join(SystemBase, c.Organization, c.System, "config.yaml")
	return
}

func (c Namespace) userPath() (path string, err error) {
	userBase, err := ExpandUser(UserBase)
	if err != nil {
		return "", err
	}

	path = filepath.Join(userBase, c.Organization, c.System, "config.yaml")
	return
}

// Load is a convenience function registered to config.Namespace to
// implement Config.Load().
func (c Namespace) Load(dst interface{}) (err error) {
	cfgPath := c.Path()

	err = Load(cfgPath, dst)
	return
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"gopkg.in/yaml.v1"
	"io/ioutil"
	"os"
	"path/filepath"
)

type Config struct {
	Cmd string
	Env map[string]Service
}

type Service struct {
	Format string
	Image  string
	Port   string
	Hooks  map[string][]string
}

func ConfigFromFile() (*Config, error) {
	pwd, _ := os.Getwd()
	_, temakiYml, err := GetTemakiYml(pwd)
	if err != nil {
		return nil, err
	}

	config, err := ioutil.ReadAll(temakiYml)
	if err != nil {
		return nil, err
	}

	conf := Config{}
	if err := yaml.Unmarshal(config, &conf); err != nil {
		return nil, err
	}
	return &conf, nil
}

func GetTemakiYml(basePath string) (string, *os.File, error) {
	fullPath := filepath.Join(basePath, "temaki.yml")
	stat, err := os.Stat(fullPath)
	if err != nil {
		if os.IsNotExist(err) && basePath != "/" {
			return GetTemakiYml(filepath.Dir(basePath))
		}
		return "", nil, err
	}
	if stat.IsDir() {
		return basePath, nil, errors.New(fmt.Sprintf("%s is a directory.", fullPath))
	}

	file, err := os.Open(fullPath)
	if err != nil {
		return "", nil, err
	}

	return basePath, file, nil
}
<commit_msg>Add custom command support<commit_after>package main

import (
	"errors"
	"fmt"
	"gopkg.in/yaml.v1"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

type Config struct {
	Cmd string
	Env map[string]Service
}

type Service struct {
	Format string
	Image  string
	Port   string
	Hooks  map[string][]string
}

func ConfigFromFile() (*Config, error) {
	pwd, _ := os.Getwd()
	_, temakiYml, err := GetTemakiYml(pwd)
	if err != nil {
		return nil, err
	}

	config, err := ioutil.ReadAll(temakiYml)
	if err != nil {
		return nil, err
	}

	conf := Config{}
	if err := yaml.Unmarshal(config, &conf); err != nil {
		return nil, err
	}

	if len(os.Args) > 1 {
		conf.Cmd = strings.Join(os.Args[1:], " ")
	}

	return &conf, nil
}

func GetTemakiYml(basePath string) (string, *os.File, error) {
	fullPath := filepath.Join(basePath, "temaki.yml")
	stat, err := os.Stat(fullPath)
	if err != nil {
		if os.IsNotExist(err) && basePath != "/" {
			return GetTemakiYml(filepath.Dir(basePath))
		}
		return "", nil, err
	}
	if stat.IsDir() {
		return basePath, nil, errors.New(fmt.Sprintf("%s is a directory.", fullPath))
	}

	file, err := os.Open(fullPath)
	if err != nil {
		return "", nil, err
	}

	return basePath, file, nil
}
<|endoftext|>


<commit_before>package config

import (
	"encoding/json"
	"strings"
	"strconv"
	"os"
	"io"
	"context"
	"sync"
)

// Config is struct where stored configuration loaded from file or io stream
type Config struct {
	mu sync.Mutex

	// config data
	data map[string]interface{}
}

// GetString returns string config value
func (cnf *Config) GetString(path string) string {

	result := cnf.Get(path)
	if result == nil {
		return ""
	}

	// Если строка, то это результат
	switch val := result.(type) {
	case string:
		return val

	default:
		return ""
	}
}

// GetArray returns array config value
func (cnf *Config) GetArray(path string) []interface{} {

	result := cnf.Get(path)
	if result == nil {
		return []interface{}{}
	}

	switch val := result.(type) {
	case []interface{}:
		return val

	default:
		return []interface{}{}
	}
}

// GetBool returns bool config value
func (cnf *Config) GetBool(path string) bool {

	result := cnf.Get(path)
	if result == nil {
		return false
	}

	switch val := result.(type) {
	case bool:
		return val

	default:
		return false
	}
}

// GetInt returns int64 config value. It may be in hex & oct variants
func (cnf *Config) GetInt(path string) int64 {

	result := cnf.Get(path)
	if result == nil {
		return 0
	}

	switch val := result.(type) {
	case int:
		return int64(val)
	case int64:
		return val
	case json.Number:
		if res, err := strconv.ParseInt(string(val), 0, 64); err != nil {
			return 0
		} else {
			return res
		}

	default:
		return 0
	}
}

// GetFloat64 returns float64 config value
func (cnf *Config) GetFloat64(path string) float64 {

	result := cnf.Get(path)
	if result == nil {
		return 0
	}

	switch val := result.(type) {
	case float64:
		return val
	case int:
		return float64(val)
	case int64:
		return float64(val)
	case json.Number:
		if res, err := strconv.ParseFloat(string(val), 64); err != nil {
			return 0
		} else {
			return res
		}

	default:
		return 0
	}
}

// Get returns config value by dotted json path. Path should be like this "root.option.item"
func (cnf *Config) Get(path string) interface{} {
	items := strings.Split(path, ".")

	// lock concurrent access
	cnf.mu.Lock()
	defer cnf.mu.Unlock()

	idx := 0
	value := map[string]interface{}(cnf.data)

	// Перебор до предпоследнего элемента
	for idx < len(items)-1 {
		tmp, ok := value[items[idx]]
		if !ok {
			return ""
		}

		value = tmp.(map[string]interface{})
		idx++
	}

	// Последний элемент
	return value[items[idx]]
}

// New creates config from file
func New(file string) (*Config, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return NewFromIO(f)
}

// NewFromIO creates config from io.Reader
func NewFromIO(input io.Reader) (*Config, error) {
	decoder := json.NewDecoder(input)
	decoder.UseNumber()

	res := new(Config)
	if err := decoder.Decode(res); err != nil {
		return nil, err
	} else {
		return res, nil
	}
}

type key int
const keyConfig key = iota

// NewContext creates new context with config
func NewContext(ctx context.Context, filename string) (context.Context, error) {
	if conf, err := New(filename); err != nil {
		return ctx, err
	} else {
		return context.WithValue(ctx, keyConfig, conf), nil
	}
}

// FromContext returns config from context
func FromContext(ctx context.Context) (*Config, bool) {
	value, ok := ctx.Value(keyConfig).(*Config)
	return value, ok
}
<commit_msg>bug: no data<commit_after>package config

import (
	"encoding/json"
	"strings"
	"strconv"
	"os"
	"io"
	"context"
	"sync"
)

// Config is struct where stored configuration loaded from file or io stream
type Config struct {
	mu sync.Mutex

	// config data
	data map[string]interface{}
}

// GetString returns string config value
func (cnf *Config) GetString(path string) string {

	result := cnf.Get(path)
	if result == nil {
		return ""
	}

	// Если строка, то это результат
	switch val := result.(type) {
	case string:
		return val

	default:
		return ""
	}
}

// GetArray returns array config value
func (cnf *Config) GetArray(path string) []interface{} {

	result := cnf.Get(path)
	if result == nil {
		return []interface{}{}
	}

	switch val := result.(type) {
	case []interface{}:
		return val

	default:
		return []interface{}{}
	}
}

// GetBool returns bool config value
func (cnf *Config) GetBool(path string) bool {

	result := cnf.Get(path)
	if result == nil {
		return false
	}

	switch val := result.(type) {
	case bool:
		return val

	default:
		return false
	}
}

// GetInt returns int64 config value. It may be in hex & oct variants
func (cnf *Config) GetInt(path string) int64 {

	result := cnf.Get(path)
	if result == nil {
		return 0
	}

	switch val := result.(type) {
	case int:
		return int64(val)
	case int64:
		return val
	case json.Number:
		if res, err := strconv.ParseInt(string(val), 0, 64); err != nil {
			return 0
		} else {
			return res
		}

	default:
		return 0
	}
}

// GetFloat64 returns float64 config value
func (cnf *Config) GetFloat64(path string) float64 {

	result := cnf.Get(path)
	if result == nil {
		return 0
	}

	switch val := result.(type) {
	case float64:
		return val
	case int:
		return float64(val)
	case int64:
		return float64(val)
	case json.Number:
		if res, err := strconv.ParseFloat(string(val), 64); err != nil {
			return 0
		} else {
			return res
		}

	default:
		return 0
	}
}

// Get returns config value by dotted json path. Path should be like this "root.option.item"
func (cnf *Config) Get(path string) interface{} {
	items := strings.Split(path, ".")

	// lock concurrent access
	cnf.mu.Lock()
	defer cnf.mu.Unlock()

	idx := 0
	value := map[string]interface{}(cnf.data)

	// Перебор до предпоследнего элемента
	for idx < len(items)-1 {
		tmp, ok := value[items[idx]]
		if !ok {
			return ""
		}

		value = tmp.(map[string]interface{})
		idx++
	}

	// Последний элемент
	return value[items[idx]]
}

// New creates config from file
func New(file string) (*Config, error) {
	f, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	return NewFromIO(f)
}

// NewFromIO creates config from io.Reader
func NewFromIO(input io.Reader) (*Config, error) {
	decoder := json.NewDecoder(input)
	decoder.UseNumber()

	res := &Config{
		mu: sync.Mutex{},
		data: make(map[string]interface{}),
	}
	if err := decoder.Decode(&res.data); err != nil {
		return nil, err
	} else {
		return res, nil
	}
}

type key int
const keyConfig key = iota

// NewContext creates new context with config
func NewContext(ctx context.Context, filename string) (context.Context, error) {
	if conf, err := New(filename); err != nil {
		return ctx, err
	} else {
		return context.WithValue(ctx, keyConfig, conf), nil
	}
}

// FromContext returns config from context
func FromContext(ctx context.Context) (*Config, bool) {
	value, ok := ctx.Value(keyConfig).(*Config)
	return value, ok
}
<|endoftext|>


<commit_before>package dns-infoblox

import (
	"fmt"
	"log"

	"github.com/emdem/go-infoblox"
)

type Config struct {
	User string
	Password string
	Url string
}

//Client returns a new client for accessing dnsinfoblox
func(c *Config) Client() (*dns-infoblox.Client, error) {
	client, err := dns-infoblox.NewClient(c.User, c.Password, c.Url)

	if err != nil {
		return nil, fmt.Errorf("Error setting up client: %s", err)
	}

	log.Printf("[INFO] DNSInflbox Client configured for user: %s", client.User)
	return client, nil
}
<commit_msg>Updated config.go to use proper constructor<commit_after>package dns-infoblox

import (
	"fmt"
	"log"

	infoblox "github.com/emdem/go-infoblox"
)

type Config struct {
	User string
	Password string
	Url string
}

//Client returns a new client for accessing dnsinfoblox
func(c *Config) Client() (*dns-infoblox.Client, error) {
	client, err := infoblox.NewClient(c.Url, c.User, c.Password, false, false)

	if err != nil {
		return nil, fmt.Errorf("Error setting up client: %s", err)
	}

	log.Printf("[INFO] DNSInflbox Client configured for user: %s", client.User)
	return client, nil
}
<|endoftext|>


<commit_before>package unpacker

import (
	"bufio"
	"encoding/json"
	"github.com/Symantec/Dominator/lib/srpc"
	"log"
	"os"
	"path"
	"syscall"
	"time"
)

const (
	dirPerms = syscall.S_IRWXU | syscall.S_IRGRP | syscall.S_IXGRP |
		syscall.S_IROTH | syscall.S_IXOTH
)

func load(baseDir string, imageServerAddress string, logger *log.Logger) (
	*Unpacker, error) {
	if err := os.MkdirAll(path.Join(baseDir, "mnt"), dirPerms); err != nil {
		return nil, err
	}
	u := &Unpacker{
		baseDir:             baseDir,
		imageServerResource: srpc.NewClientResource("tcp", imageServerAddress),
		logger:              logger,
	}
	file, err := os.Open(path.Join(baseDir, stateFile))
	if err != nil {
		if os.IsNotExist(err) {
			u.pState.Devices = make(map[string]deviceInfo)
			u.pState.ImageStreams = make(map[string]*imageStreamInfo)
			return u, nil
		}
		return nil, err
	}
	defer file.Close()
	decoder := json.NewDecoder(bufio.NewReader(file))
	if err := decoder.Decode(&u.pState); err != nil {
		return nil, err
	}
	// Fill in sizes.
	for deviceName, device := range u.pState.Devices {
		if err := updateDeviceSize(&device); err != nil {
			return nil, err
		}
		u.pState.Devices[deviceName] = device
	}
	// Set up streams.
	for streamName := range u.pState.ImageStreams {
		if _, err := u.setupStream(streamName); err != nil {
			return nil, err
		}
	}
	u.updateUsageTimeWithLock()
	return u, nil
}

func (u *Unpacker) updateUsageTime() {
	u.rwMutex.Lock()
	defer u.rwMutex.Unlock()
	u.updateUsageTimeWithLock()
}

func (u *Unpacker) updateUsageTimeWithLock() {
	u.lastUsedTime = time.Now()
}
<commit_msg>Set initial last used time in image-unpacker.<commit_after>package unpacker

import (
	"bufio"
	"encoding/json"
	"github.com/Symantec/Dominator/lib/srpc"
	"log"
	"os"
	"path"
	"syscall"
	"time"
)

const (
	dirPerms = syscall.S_IRWXU | syscall.S_IRGRP | syscall.S_IXGRP |
		syscall.S_IROTH | syscall.S_IXOTH
)

func load(baseDir string, imageServerAddress string, logger *log.Logger) (
	*Unpacker, error) {
	if err := os.MkdirAll(path.Join(baseDir, "mnt"), dirPerms); err != nil {
		return nil, err
	}
	u := &Unpacker{
		baseDir:             baseDir,
		imageServerResource: srpc.NewClientResource("tcp", imageServerAddress),
		logger:              logger,
	}
	u.updateUsageTimeWithLock()
	file, err := os.Open(path.Join(baseDir, stateFile))
	if err != nil {
		if os.IsNotExist(err) {
			u.pState.Devices = make(map[string]deviceInfo)
			u.pState.ImageStreams = make(map[string]*imageStreamInfo)
			return u, nil
		}
		return nil, err
	}
	defer file.Close()
	decoder := json.NewDecoder(bufio.NewReader(file))
	if err := decoder.Decode(&u.pState); err != nil {
		return nil, err
	}
	// Fill in sizes.
	for deviceName, device := range u.pState.Devices {
		if err := updateDeviceSize(&device); err != nil {
			return nil, err
		}
		u.pState.Devices[deviceName] = device
	}
	// Set up streams.
	for streamName := range u.pState.ImageStreams {
		if _, err := u.setupStream(streamName); err != nil {
			return nil, err
		}
	}
	u.updateUsageTimeWithLock()
	return u, nil
}

func (u *Unpacker) updateUsageTime() {
	u.rwMutex.Lock()
	defer u.rwMutex.Unlock()
	u.updateUsageTimeWithLock()
}

func (u *Unpacker) updateUsageTimeWithLock() {
	u.lastUsedTime = time.Now()
}
<|endoftext|>


<commit_before>package nopaste

import (
	"crypto/sha1"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

type Nopaste struct {
	config *Config
}

func Run(configPath string) {
	config, err := LoadConfig(configPath)
	if err != nil {
		log.Fatalf("cannot load config file: %v\n", err)
		return
	}
	np := New(config)
	http.Handle("/", np)
	http.ListenAndServe(config.Listen, nil)
}

func New(config *Config) *Nopaste {
	return &Nopaste{
		config: config,
	}
}

func (np *Nopaste) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	upath := req.URL.Path

	if upath == np.config.Root || upath == np.config.Root+"/" {
		np.rootHandler(w, req)
		return
	}

	if p := strings.TrimPrefix(upath, np.config.Root+"/"); len(p) < len(upath) {
		req.URL.Path = p
		np.dataHandler(w, req)
		return
	}

	http.NotFound(w, req)
}

func (np *Nopaste) rootHandler(w http.ResponseWriter, req *http.Request) {
	if req.Method == "POST" {
		np.saveContent(w, req)
	} else if err := tmplRoot.ExecuteTemplate(w, "index", nil); err != nil {
		log.Println(err)
		serverError(w)
	}
}

func (np *Nopaste) saveContent(w http.ResponseWriter, req *http.Request) {
	data := []byte(req.FormValue("text"))
	if len(data) == 0 {
		http.Redirect(w, req, np.config.Root, http.StatusFound)
		return
	}

	hex := fmt.Sprintf("%x", sha1.Sum(data))
	id := hex[0:10]
	log.Printf("saving: %s\n", id)
	err := ioutil.WriteFile(np.dataFilePath(id), data, 0644)
	if err != nil {
		log.Println(err)
		serverError(w)
		return
	}
	http.Redirect(w, req, np.config.Root+"/"+id, http.StatusFound)
}

func (np *Nopaste) dataHandler(w http.ResponseWriter, req *http.Request) {
	id := req.URL.Path
	if len(id) >= 1 && id[0] == '/' {
		id = id[1:]
	}

	f, err := os.Open(np.dataFilePath(id))
	if err != nil {
		log.Println(err)
		http.NotFound(w, req)
		return
	}
	w.Header().Add("Content-Type", "text/plain")
	io.Copy(w, f)
}

func (np *Nopaste) dataFilePath(id string) string {
	return fmt.Sprintf("%s/%s.txt", np.config.DataDir, id)
}

func serverError(w http.ResponseWriter) {
	code := http.StatusInternalServerError
	http.Error(w, http.StatusText(code), code)
}
<commit_msg>英数字しか扱わない<commit_after>package nopaste

import (
	"crypto/sha1"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"strings"
)

type Nopaste struct {
	config *Config
}

func Run(configPath string) {
	config, err := LoadConfig(configPath)
	if err != nil {
		log.Fatalf("cannot load config file: %v\n", err)
		return
	}
	np := New(config)
	http.Handle("/", np)
	http.ListenAndServe(config.Listen, nil)
}

func New(config *Config) *Nopaste {
	return &Nopaste{
		config: config,
	}
}

func isAlnum(r rune) bool {
	return ('a' <= r && r <= 'z') || ('A' <= r && r <= 'Z') || ('0' <= r && r <= '9')
}

func (np *Nopaste) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	upath := req.URL.Path

	if upath == np.config.Root || upath == np.config.Root+"/" {
		np.rootHandler(w, req)
		return
	}

	if p := strings.TrimPrefix(upath, np.config.Root+"/"); len(p) < len(upath) {
		req.URL.Path = p
		if strings.IndexFunc(upath, isAlnum) != -1 {
			np.dataHandler(w, req)
			return
		}
	}

	http.NotFound(w, req)
}

func (np *Nopaste) rootHandler(w http.ResponseWriter, req *http.Request) {
	if req.Method == "POST" {
		np.saveContent(w, req)
	} else if err := tmplRoot.ExecuteTemplate(w, "index", nil); err != nil {
		log.Println(err)
		serverError(w)
	}
}

func (np *Nopaste) saveContent(w http.ResponseWriter, req *http.Request) {
	data := []byte(req.FormValue("text"))
	if len(data) == 0 {
		http.Redirect(w, req, np.config.Root, http.StatusFound)
		return
	}

	hex := fmt.Sprintf("%x", sha1.Sum(data))
	id := hex[0:10]
	log.Printf("saving: %s\n", id)
	err := ioutil.WriteFile(np.dataFilePath(id), data, 0644)
	if err != nil {
		log.Println(err)
		serverError(w)
		return
	}
	http.Redirect(w, req, np.config.Root+"/"+id, http.StatusFound)
}

func (np *Nopaste) dataHandler(w http.ResponseWriter, req *http.Request) {
	id := req.URL.Path
	if len(id) >= 1 && id[0] == '/' {
		id = id[1:]
	}

	f, err := os.Open(np.dataFilePath(id))
	if err != nil {
		log.Println(err)
		http.NotFound(w, req)
		return
	}
	w.Header().Add("Content-Type", "text/plain")
	io.Copy(w, f)
}

func (np *Nopaste) dataFilePath(id string) string {
	return fmt.Sprintf("%s/%s.txt", np.config.DataDir, id)
}

func serverError(w http.ResponseWriter) {
	code := http.StatusInternalServerError
	http.Error(w, http.StatusText(code), code)
}
<|endoftext|>


<commit_before>package notetxt

import (
        "regexp"
        "strings"
        "os"
        "os/exec"
        "fmt"
        "bufio"
        "errors"
        "path"
        "path/filepath"
        "io/ioutil"
)
var title_clearer = regexp.MustCompile("[^a-zA-Z0-9\\s\\.\\-_]+")
var whitespace_clearer = regexp.MustCompile("\\s+")

func TitleToFilename (title string) string {

        // strip all non-conforming characters
        out := title_clearer.ReplaceAllString(title, "")

        // title shall be lowercase
        out = strings.ToLower(out)

        // every whitespace should become a space
        // if there are multiple whitespace insert only one space as a result
        out = whitespace_clearer.ReplaceAllString(out, " ")

        // every white space should become a dash (because they look nice)
        out = strings.Replace(out, " ", "-", -1)
        return out
}

var filename_regex = regexp.MustCompile("^[a-zA-Z0-9\\-\\.]+$")

func FilenameMatches(filename string) bool {
        return filename_regex.MatchString(filename)
}

type Note struct {
        Name string
        Filename string
        Tags []string
}

type NoteList []Note

func (note Note) Matches(text string) bool {
        match, _ := regexp.MatchString("(?i)" + text, note.Name + " " + strings.Join(note.Tags, " "))
        return match
}

func (notes NoteList) FilterBy(text string) (NoteList) {
        var out NoteList
        for _, note := range notes {
            if note.Matches(text) {
                    out = append(out, note)
            }
        }
        return out
}

func (notes NoteList) Print() {
        for i, note := range notes {
                fmt.Printf("%d %s - %v\n", i, note.Name, note.Tags)
        }
}

func readFilesInDir(dir string, subdir string) ([]string, []string) {
        var symlinks []string
        var files []string
        contents, _ := ioutil.ReadDir(dir + "/" + subdir)
        for _, f := range contents {
                if f.IsDir() {
                        t_files, t_syms := readFilesInDir(dir, subdir + "/" + f.Name())
                        files = append(files,t_files...)
                        symlinks = append(symlinks, t_syms...)
                } else {
                        if f.Mode() & os.ModeSymlink != 0 {
                                symlinks = append(symlinks, dir + subdir + "/" + f.Name())
                        } else {
                                files = append(files, dir + subdir + "/" + f.Name())
                        }
                }
        }
        return files, symlinks
}

func findTags(filename string, notedir string, symlinks []string) []string {
        var out []string

        plain_tag := strings.Replace(path.Dir(filename), notedir, "", 1)
        if len(plain_tag) != 0 {
                out = append(out, plain_tag)
        }

        for _, f := range symlinks {
                p, err := filepath.EvalSymlinks(f)
                if err != nil {
                        panic(err);
                }

                if p == filename {
                        out = append(out, strings.Replace(path.Dir(f), notedir, "", 1))
                }
        }

        return out
}

func ParseNote(notedir string, filename string, symlinks []string) (Note, error) {
        var note = Note{}
        note.Filename = filename

        f, err := os.Open(filename)
        if err != nil {
                return note, err
        }

        defer f.Close()
        reader := bufio.NewReaderSize(f, 4*1024)

        line, prefix, err := reader.ReadLine()
        if err != nil {
                return note, err
        }

        if prefix {
                return note, errors.New("Buffer reader too small for the name of the note.")
        }

        note.Name = string(line)

        note.Tags = findTags(filename, notedir, symlinks)

        return note, nil
}

func ParseDir(notedir string) (NoteList, error) {
        var notes NoteList

        notedir, _ = filepath.Abs(notedir)
        files, symlinks := readFilesInDir(notedir, "")

        for _, f := range files {
                note, err := ParseNote(notedir, f, symlinks)
                if err != nil {
                        return nil, err
                }

                notes = append(notes, note)
        }

        return notes, nil
}

func CreateNote(title string, tag string, dir string) (string, error) {
        spacer := "\n" + strings.Repeat("=", len(title))
        text := title + spacer

        directory := fmt.Sprintf("%s/%s", dir, tag)
        err := os.MkdirAll(directory, 755)
        if err != nil {
                return "", err
        }

        file := fmt.Sprintf("%s/%s.rst", directory, TitleToFilename(title))

        if _, err := os.Stat(file); err == nil {
                return "", errors.New("Notefile '" + file + "' already exists. " +
                                        "You can still edit it if you want.")
        }

        e := ioutil.WriteFile(file, []byte(text), 0644)
        if e != nil {
                return "", e
        }

        return file, nil
}

func TagNote(file string, tag string, dir string) error {
        directory := fmt.Sprintf("%s/%s", dir, tag)
        err := os.MkdirAll(directory, 755)
        if err != nil {
                return err
        }

        filename := filepath.Base(file)
        newpath := fmt.Sprintf("%s/%s/%s", dir, tag, filename)

        err = os.Symlink(file, newpath)
        if err != nil {
                return err
        }

        return nil
}

func OpenFileInEditor(file string) {
        editor := os.Getenv("EDITOR")
        if len(editor) == 0 {
                editor = "nano" //FIXME: saner default?
        }

        c := exec.Command(editor, file)

        // nasty hack, see http://stackoverflow.com/a/12089980
        c.Stdin = os.Stdin
        c.Stdout = os.Stdout
        c.Stderr = os.Stderr

        er := c.Run()

        if er != nil {
                fmt.Println(er.Error())
                panic(er)
        }
}
<commit_msg>janitoring: Refactored notetxt.go<commit_after>package notetxt

import (
        "regexp"
        "strings"
        "os"
        "os/exec"
        "fmt"
        "bufio"
        "errors"
        "path"
        "path/filepath"
        "io/ioutil"
)
var title_clearer = regexp.MustCompile("[^a-zA-Z0-9\\s\\.\\-_]+")
var whitespace_clearer = regexp.MustCompile("\\s+")

func TitleToFilename (title string) string {

        // strip all non-conforming characters
        out := title_clearer.ReplaceAllString(title, "")

        // title shall be lowercase
        out = strings.ToLower(out)

        // every whitespace should become a space
        // if there are multiple whitespace insert only one space as a result
        out = whitespace_clearer.ReplaceAllString(out, " ")

        // every white space should become a dash (because they look nice)
        out = strings.Replace(out, " ", "-", -1)
        return out
}

var filename_regex = regexp.MustCompile("^[a-zA-Z0-9\\-\\.]+$")

func FilenameMatches(filename string) bool {
        return filename_regex.MatchString(filename)
}

type Note struct {
        Name string
        Filename string
        Tags []string
}

type NoteList []Note

func (note Note) Matches(text string) bool {
        match, _ := regexp.MatchString("(?i)" + text, note.Name + " " + strings.Join(note.Tags, " "))
        return match
}

func (notes NoteList) FilterBy(text string) (NoteList) {
        var out NoteList
        for _, note := range notes {
            if note.Matches(text) {
                    out = append(out, note)
            }
        }
        return out
}

func (notes NoteList) Print() {
        for i, note := range notes {
                fmt.Printf("%d %s - %v\n", i, note.Name, note.Tags)
        }
}

func readFilesInDir(dir string, subdir string) ([]string, []string) {
        var symlinks []string
        var files []string
        contents, _ := ioutil.ReadDir(dir + "/" + subdir)
        for _, f := range contents {
                if f.IsDir() {
                        t_files, t_syms := readFilesInDir(dir, subdir + "/" + f.Name())
                        files = append(files,t_files...)
                        symlinks = append(symlinks, t_syms...)
                } else {
                        if f.Mode() & os.ModeSymlink != 0 {
                                symlinks = append(symlinks, dir + subdir + "/" + f.Name())
                        } else {
                                files = append(files, dir + subdir + "/" + f.Name())
                        }
                }
        }
        return files, symlinks
}

func findTags(filename string, notedir string, symlinks []string) []string {
        var out []string

        plain_tag := strings.Replace(path.Dir(filename), notedir, "", 1)
        if len(plain_tag) != 0 {
                out = append(out, plain_tag)
        }

        for _, f := range symlinks {
                p, err := filepath.EvalSymlinks(f)
                if err != nil {
                        panic(err);
                }

                if p == filename {
                        out = append(out, strings.Replace(path.Dir(f), notedir, "", 1))
                }
        }

        return out
}

func ParseNote(notedir string, filename string, symlinks []string) (Note, error) {
        var note = Note{}
        note.Filename = filename

        f, err := os.Open(filename)
        if err != nil {
                return note, err
        }

        defer f.Close()
        reader := bufio.NewReaderSize(f, 4*1024)

        line, prefix, err := reader.ReadLine()
        if err != nil {
                return note, err
        }

        if prefix {
                return note, errors.New("Buffer reader too small for the name of the note.")
        }

        note.Name = string(line)

        note.Tags = findTags(filename, notedir, symlinks)

        return note, nil
}

func ParseDir(notedir string) (NoteList, error) {
        var notes NoteList

        notedir, _ = filepath.Abs(notedir)
        files, symlinks := readFilesInDir(notedir, "")

        for _, f := range files {
                note, err := ParseNote(notedir, f, symlinks)
                if err != nil {
                        return nil, err
                }

                notes = append(notes, note)
        }

        return notes, nil
}

func CreateNote(title string, tag string, dir string) (string, error) {
        spacer := "\n" + strings.Repeat("=", len(title))
        text := title + spacer

        directory := fmt.Sprintf("%s/%s", dir, tag)

        if err := os.MkdirAll(directory, 755); err != nil {
                return "", err
        }

        file := fmt.Sprintf("%s/%s.rst", directory, TitleToFilename(title))

        if _, err := os.Stat(file); err == nil {
                return "", errors.New("Notefile '" + file + "' already exists. " +
                                        "You can still edit it if you want.")
        }

        e := ioutil.WriteFile(file, []byte(text), 0644)
        if e != nil {
                return "", e
        }

        return file, nil
}

func TagNote(file string, tag string, dir string) error {
        directory := fmt.Sprintf("%s/%s", dir, tag)

        if err := os.MkdirAll(directory, 755); err != nil {
                return err
        }

        filename := filepath.Base(file)
        newpath := fmt.Sprintf("%s/%s/%s", dir, tag, filename)

        if err := os.Symlink(file, newpath); err != nil {
                return err
        }

        return nil
}

func OpenFileInEditor(file string) {
        editor := os.Getenv("EDITOR")
        if len(editor) == 0 {
                editor = "nano" //FIXME: saner default?
        }

        c := exec.Command(editor, file)

        // nasty hack, see http://stackoverflow.com/a/12089980
        c.Stdin = os.Stdin
        c.Stdout = os.Stdout
        c.Stderr = os.Stderr

        er := c.Run()

        if er != nil {
                fmt.Println(er.Error())
                panic(er)
        }
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"
	"runtime"
	"strings"
)

type Triple struct {
	Subject   string `json:"s"`
	Predicate string `json:"p"`
	Object    string `json:"o"`
}

type Rule struct {
	Pattern  *regexp.Regexp
	Shortcut string
}

func isURIRef(s string) bool {
	return strings.HasPrefix(s, "<") && strings.HasSuffix(s, ">")
}

func isLiteral(s string) bool {
	return strings.HasPrefix(s, "\"")
}

func isNamedNode(s string) bool {
	return strings.HasPrefix(s, "_:")
}

// stripChars makes s, p, o strings unembellished
func stripChars(s string) string {
	if isURIRef(s) {
		s = strings.Trim(s, "<>")
	} else if isLiteral(s) {
		if strings.Contains(s, "@") {
			parts := strings.Split(s, "@")
			s = strings.Join(parts[:len(parts)-1], "")
		}
		if strings.Contains(s, "^^") {
			parts := strings.Split(s, "^^")
			s = strings.Join(parts[:len(parts)-1], "")
		}
		s = strings.Trim(s, "\"")
	}
	return s
}

// readLines reads a whole file into the memory
func readLines(path string) (lines []string, err error) {
	var (
		file   *os.File
		part   []byte
		prefix bool
	)
	if file, err = os.Open(path); err != nil {
		return
	}
	defer file.Close()

	reader := bufio.NewReader(file)
	buffer := bytes.NewBuffer(make([]byte, 0))
	for {
		if part, prefix, err = reader.ReadLine(); err != nil {
			break
		}
		buffer.Write(part)
		if !prefix {
			lines = append(lines, buffer.String())
			buffer.Reset()
		}
	}
	if err == io.EOF {
		err = nil
	}
	return
}

// parseString takes a string, parses out rules and adds them
func parseRules(s string) []Rule {
	var rules []Rule
	for _, line := range strings.Split(s, "\n") {
		line = strings.TrimSpace(line)
		if len(line) == 0 {
			continue
		}
		fields := strings.Fields(line)
		if len(fields) < 2 {
			fmt.Fprintf(os.Stderr, "broken rules: %s", line)
			os.Exit(1)
		}
		pattern := regexp.MustCompile(fields[0])
		rule := Rule{Pattern: pattern, Shortcut: fields[1]}
		rules = append(rules, rule)
	}
	return rules
}

// applyRules takes a string and applies the rules
func applyRules(s string, rules []Rule) string {
	// could optimize this routine on the fly by JIT reordering the rules
	for _, rule := range rules {
		matched := rule.Pattern.FindStringSubmatch(s)
		if len(matched) > 0 {
			s = strings.Replace(rule.Shortcut, "$1", matched[1], -1)
			break
		}
	}
	return s
}

func Convert(fileName string, rules []Rule) {
	// lines will be sent down queue channel
	queue := make(chan *string)
	// send triples down this channel
	triples := make(chan *Triple)

	// start writer
	go TripleWriter(triples)

	// start workers
	for i := 0; i < runtime.NumCPU(); i++ {
		go Worker(i, queue, triples, rules)
	}

	var file *os.File
	if fileName == "-" {
		file = os.Stdin
	} else {
		var err error
		file, err = os.Open(fileName)
		defer file.Close()
		if err != nil {
			fmt.Fprintf(os.Stderr, "no such file or directory\n")
			os.Exit(1)
		}
	}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		var line = scanner.Text()
		queue <- &line
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintf(os.Stderr, "reading input:", err)
	}

	// kill workers
	for n := 0; n < runtime.NumCPU(); n++ {
		queue <- nil
	}
	// kill writer
	triples <- nil
}

// TripleWriter dumps a stream of triples to json
func TripleWriter(triples chan *Triple) {
	var triple *Triple
	for {
		triple = <-triples
		if triples == nil {
			break
		}
		b, err := json.Marshal(triple)
		if err != nil {
			fmt.Fprintf(os.Stderr, "marshalling error:", err)
			os.Exit(1)
		}
		fmt.Println(string(b))
	}
}

// Worker converts NT to JSON
func Worker(id int, queue chan *string, triples chan *Triple, rules []Rule) {
	var line *string
	for {
		line = <-queue
		if line == nil {
			break
		} else {

			trimmed := strings.TrimSpace(*line)

			// ignore comments
			if strings.HasPrefix(trimmed, "#") {
				continue
			}
			words := strings.Fields(trimmed)

			var s, p, o string

			if len(words) < 3 {
				fmt.Fprintf(os.Stderr, "broken input:", trimmed)
				os.Exit(1)
			}

			if len(words) == 4 || len(words) == 3 {
				s = words[0]
				p = words[1]
				o = words[2]
			}
			// take care of possible spaces in Object
			if len(words) > 4 {
				s = words[0]
				p = words[1]
				o = strings.Join(words[2:len(words)-1], " ")
			}
			// make things clean
			s = stripChars(s)
			p = stripChars(p)
			o = stripChars(o)

			// make things short
			s = applyRules(s, rules)
			p = applyRules(p, rules)
			o = applyRules(o, rules)

			// convert to json
			triple := Triple{Subject: s, Predicate: p, Object: o}
			triples <- &triple
		}
	}
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	flag.Parse()

	table := `
	http://dbpedia.org/resource/(.+)                    dbpr:$1
	http://dbpedia.org/ontology/PopulatedPlace/(.+)     dbpl:$1
	http://dbpedia.org/ontology/(.+)                    dbpo:$1
	http://www.w3.org/1999/02/22-rdf-syntax-ns#(.+)     rdf:$1
	http://www.w3.org/2000/01/rdf-schema#(.+)           rdfs:$1
	http://xmlns.com/foaf/0.1/(.+)                      foar:$1
	http://purl.org/dc/elements/1.1/(.+)                dc:$1
	`

	rules := parseRules(table)

	fmt.Fprintf(os.Stderr, "Using %d workers\n", runtime.NumCPU())
	fmt.Fprintf(os.Stderr, "Loaded %d rewrite rules\n", len(rules))

	if flag.NArg() != 1 {
		fmt.Fprintf(os.Stderr, "Usage: %s FILE\n", os.Args[0])
		os.Exit(1)
	}
	fileName := flag.Args()[0]
	Convert(fileName, rules)
}
<commit_msg>show debug info only on valid input<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"regexp"
	"runtime"
	"strings"
)

type Triple struct {
	Subject   string `json:"s"`
	Predicate string `json:"p"`
	Object    string `json:"o"`
}

type Rule struct {
	Pattern  *regexp.Regexp
	Shortcut string
}

func isURIRef(s string) bool {
	return strings.HasPrefix(s, "<") && strings.HasSuffix(s, ">")
}

func isLiteral(s string) bool {
	return strings.HasPrefix(s, "\"")
}

func isNamedNode(s string) bool {
	return strings.HasPrefix(s, "_:")
}

// stripChars makes s, p, o strings unembellished
func stripChars(s string) string {
	if isURIRef(s) {
		s = strings.Trim(s, "<>")
	} else if isLiteral(s) {
		if strings.Contains(s, "@") {
			parts := strings.Split(s, "@")
			s = strings.Join(parts[:len(parts)-1], "")
		}
		if strings.Contains(s, "^^") {
			parts := strings.Split(s, "^^")
			s = strings.Join(parts[:len(parts)-1], "")
		}
		s = strings.Trim(s, "\"")
	}
	return s
}

// readLines reads a whole file into the memory
func readLines(path string) (lines []string, err error) {
	var (
		file   *os.File
		part   []byte
		prefix bool
	)
	if file, err = os.Open(path); err != nil {
		return
	}
	defer file.Close()

	reader := bufio.NewReader(file)
	buffer := bytes.NewBuffer(make([]byte, 0))
	for {
		if part, prefix, err = reader.ReadLine(); err != nil {
			break
		}
		buffer.Write(part)
		if !prefix {
			lines = append(lines, buffer.String())
			buffer.Reset()
		}
	}
	if err == io.EOF {
		err = nil
	}
	return
}

// parseString takes a string, parses out rules and adds them
func parseRules(s string) []Rule {
	var rules []Rule
	for _, line := range strings.Split(s, "\n") {
		line = strings.TrimSpace(line)
		if len(line) == 0 {
			continue
		}
		fields := strings.Fields(line)
		if len(fields) < 2 {
			fmt.Fprintf(os.Stderr, "broken rules: %s", line)
			os.Exit(1)
		}
		pattern := regexp.MustCompile(fields[0])
		rule := Rule{Pattern: pattern, Shortcut: fields[1]}
		rules = append(rules, rule)
	}
	return rules
}

// applyRules takes a string and applies the rules
func applyRules(s string, rules []Rule) string {
	// could optimize this routine on the fly by JIT reordering the rules
	for _, rule := range rules {
		matched := rule.Pattern.FindStringSubmatch(s)
		if len(matched) > 0 {
			s = strings.Replace(rule.Shortcut, "$1", matched[1], -1)
			break
		}
	}
	return s
}

func Convert(fileName string, rules []Rule) {
	// lines will be sent down queue channel
	queue := make(chan *string)
	// send triples down this channel
	triples := make(chan *Triple)

	// start writer
	go TripleWriter(triples)

	// start workers
	for i := 0; i < runtime.NumCPU(); i++ {
		go Worker(i, queue, triples, rules)
	}

	var file *os.File
	if fileName == "-" {
		file = os.Stdin
	} else {
		var err error
		file, err = os.Open(fileName)
		defer file.Close()
		if err != nil {
			fmt.Fprintf(os.Stderr, "no such file or directory\n")
			os.Exit(1)
		}
	}

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		var line = scanner.Text()
		queue <- &line
	}

	if err := scanner.Err(); err != nil {
		fmt.Fprintf(os.Stderr, "reading input:", err)
	}

	// kill workers
	for n := 0; n < runtime.NumCPU(); n++ {
		queue <- nil
	}
	// kill writer
	triples <- nil
}

// TripleWriter dumps a stream of triples to json
func TripleWriter(triples chan *Triple) {
	var triple *Triple
	for {
		triple = <-triples
		if triples == nil {
			break
		}
		b, err := json.Marshal(triple)
		if err != nil {
			fmt.Fprintf(os.Stderr, "marshalling error:", err)
			os.Exit(1)
		}
		fmt.Println(string(b))
	}
}

// Worker converts NT to JSON
func Worker(id int, queue chan *string, triples chan *Triple, rules []Rule) {
	var line *string
	for {
		line = <-queue
		if line == nil {
			break
		} else {

			trimmed := strings.TrimSpace(*line)

			// ignore comments
			if strings.HasPrefix(trimmed, "#") {
				continue
			}
			words := strings.Fields(trimmed)

			var s, p, o string

			if len(words) < 3 {
				fmt.Fprintf(os.Stderr, "broken input:", trimmed)
				os.Exit(1)
			}

			if len(words) == 4 || len(words) == 3 {
				s = words[0]
				p = words[1]
				o = words[2]
			}
			// take care of possible spaces in Object
			if len(words) > 4 {
				s = words[0]
				p = words[1]
				o = strings.Join(words[2:len(words)-1], " ")
			}
			// make things clean
			s = stripChars(s)
			p = stripChars(p)
			o = stripChars(o)

			// make things short
			s = applyRules(s, rules)
			p = applyRules(p, rules)
			o = applyRules(o, rules)

			// convert to json
			triple := Triple{Subject: s, Predicate: p, Object: o}
			triples <- &triple
		}
	}
}

func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())

	flag.Parse()

	table := `
	http://dbpedia.org/resource/(.+)                    dbpr:$1
	http://dbpedia.org/ontology/PopulatedPlace/(.+)     dbpl:$1
	http://dbpedia.org/ontology/(.+)                    dbpo:$1
	http://www.w3.org/1999/02/22-rdf-syntax-ns#(.+)     rdf:$1
	http://www.w3.org/2000/01/rdf-schema#(.+)           rdfs:$1
	http://xmlns.com/foaf/0.1/(.+)                      foar:$1
	http://purl.org/dc/elements/1.1/(.+)                dc:$1
	`

	rules := parseRules(table)

	if flag.NArg() != 1 {
		fmt.Fprintf(os.Stderr, "Usage: %s FILE\n", os.Args[0])
		os.Exit(1)
	}
	fileName := flag.Args()[0]

	fmt.Fprintf(os.Stderr, "Using %d workers\n", runtime.NumCPU())
	fmt.Fprintf(os.Stderr, "Loaded %d rewrite rules\n", len(rules))

	Convert(fileName, rules)
}
<|endoftext|>