<commit_before>/*  Copyright 2013, Raphael Estrada
    Author email:  <galaktor@gmx.de>
    Project home:  <https://github.com/galaktor/gorf24>
    Licensed under The MIT License (see README and LICENSE files)

    Updated to RF24 v.13
    2017, Marian Craciunescu, Marius Staicu
    Authors email:  <marian.craciunescu@esolutions.ro>, <marius.staicu@esolutions.ro>
    Project home:  <https://github.com/mariusstaicu/gorf24>
*/
package gorf24

/*
  #cgo LDFLAGS: -L./RF24_c
  #cgo LDFLAGS: -lrf24_c
  #cgo CFLAGS: -I./RF24_c
  #include "RF24_c.h"
  #include <stdio.h>
*/
import "C"
import (
	// "encoding/binary"
	// "fmt"
	"unsafe"
)

type LibRF24 interface {
	Delete()
	Begin()
	IsChipConnected() bool
	StartListening()
	StopListening()
	Available() bool
	Read(length uint8) ([]byte, bool)
	OpenWritingPipe(address uint64)
	OpenReadingPipe(pipe uint8, address uint64)
	Write(data []byte, length uint8) bool
	PrintDetails()
	AvailablePipe() (bool, uint8)
	IsRxFifoFull() bool
	PowerDown()
	PowerUp()
	WriteMulticast(data []byte, length uint8, multicast bool) bool
	WriteFast(data []byte, length uint8) bool
	WriteFastMulticast(data []byte, length uint8, multicast bool) bool
	WriteBlocking(data []byte, length uint8, timeout uint32) bool
	IsTxStandBy() bool
	IsTxStandByExtended(timeout uint32, startTx bool) bool
	WriteAckPayload(pipe uint8, data []byte, length uint8)
	IsAckPayloadAvailable() bool
	WhatHappened() (tx_ok, tx_fail, rx_ready bool)
	StartWrite(data []byte, length uint8)
	StartFastWrite(data []byte, length uint8, multicast bool, startTx bool)
	ReUseTx()
	FlushTx() uint8
	TestCarrier() bool
	TestRPD() bool
	CloseReadingPipe(pipe uint8)
	SetAddressWidth(width uint8)
	SetRetries(delay uint8, count uint8)
	SetChannel(channel uint8)
	GetChannel(channel uint8) uint8
	SetPayloadSize(size uint8)
	GetPayloadSize() uint8
	GetDynamicPayloadSize() uint8
	EnableAckPayload()
	EnableDynamicPayloads()
	DisableDynamicPayloads()
	EnableDynamicAck()
	IsPVariant() bool
	SetAutoAck(enable bool)
	SetAutoAckPipe(pipe uint8, enable bool)
	SetPALevel(level PA_DBM)
	GetPALevel() PA_DBM
	SetDataRate(rate DATARATE)
	GetDataRate() DATARATE
	SetCRCLength(length CRCLENGTH)
	GetCRCLength() CRCLENGTH
	DisableCRC()
	MaskIRQ(txOk, txFail, rxReady bool)
}

// TODO: more idiomatic:
//   error handling
//   Read/Write interfaces
//   possibly more conventional byte slice passing
//   more type safety?
//   channel for available data, like time.Tick? r.Available() <-chan []byte  or so?
type RF24 struct {
	cptr        C.RF24Handle
	buffer_size uint8
	buffer      []byte
}

/*
func main() {
	var pipe uint64 = 0xF0F0F0F0E1
	r := New(25, 8, 32)
	defer r.Delete()
	r.Begin()
	r.SetRetries(15, 15)
	r.SetAutoAck(true)
	r.OpenReadingPipe(1, pipe)
	r.StartListening()
	r.PrintDetails()
	for {
		if r.Available() {
			data, _ := r.Read(4)
//			fmt.Printf("data: %v\n", data)
			payload := binary.LittleEndian.Uint32(data)
			fmt.Printf("Received %v\n", payload)
		} else {
			//
		}
	}
}
*/
func New(cepin uint8, cspin uint8, spispeed uint32) *RF24 {
	var r RF24
	r.cptr = C.new_rf24(C.uint8_t(cepin), C.uint8_t(cspin), C.uint32_t(spispeed))
	r.buffer = make([]byte, 128) // max payload length according to nrf24 spec
	return &r
}

func (r *RF24) Delete() {
	C.rf24_delete(r.cptr)
	r.cptr = nil
}
func (r *RF24) Begin() {
	C.rf24_begin(r.cptr)
}

func (r *RF24) IsChipConnected() bool {
	return gobool(C.rf24_isChipConnected(r.cptr))
}

func (r *RF24) StartListening() {
	C.rf24_startListening(r.cptr)
}

func (r *RF24) StopListening() {
	C.rf24_stopListening(r.cptr)
}

func (r *RF24) Available() bool {
	return gobool(C.rf24_available(r.cptr))
}

func (r *RF24) Read(length uint8) ([]byte, bool) {
	ok := gobool(C.rf24_read(r.cptr, unsafe.Pointer(&r.buffer[0]), C.uint8_t(length)))
	return r.buffer[:length], ok
}

func (r *RF24) OpenWritingPipe(address uint64) {
	C.rf24_openWritingPipe(r.cptr, C.uint64_t(address))
}

func (r *RF24) OpenReadingPipe(pipe uint8, address uint64) {
	C.rf24_openReadingPipe(r.cptr, C.uint8_t(pipe), C.uint64_t(address))
}

// TODO: implement Reader/Writer compatible interfaces
func (r *RF24) Write(data []byte, length uint8) bool {
	return gobool(C.rf24_write(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length)))
}

// TODO: String() method would be great
func (r *RF24) PrintDetails() {
	C.rf24_printDetails(r.cptr)
}

// TODO: create Pipe type, make this a func on Pipe
func (r *RF24) AvailablePipe() (bool, uint8) {
	var pipe C.uint8_t
	available := gobool(C.rf24_available_pipe(r.cptr, &pipe))
	return available, uint8(pipe)
}

func (r *RF24) IsRxFifoFull() bool {
	return gobool(C.rf24_rxFifoFull(r.cptr))
}

func (r *RF24) PowerDown() {
	C.rf24_powerDown(r.cptr)
}

func (r *RF24) PowerUp() {
	C.rf24_powerUp(r.cptr)
}

func (r *RF24) WriteMulticast(data []byte, length uint8, multicast bool) bool {
	return gobool(C.rf24_writeMulticast(r.cptr, unsafe.Pointer(&data), C.uint8_t(len), cbool(multicast)))
}

func (r *RF24) WriteFast(data []byte, length uint8) bool {
	return gobool(C.rf24_writeFast(r.cptr, unsafe.Pointer(&data), C.uint8_t(length)))
}

func (r *RF24) WriteFastMulticast(data []byte, length uint8, multicast bool) bool {
	return gobool(C.rf24_writeFastMulticast(r.cptr, unsafe.Pointer(&data), C.uint8_t(length), cbool(multicast)))
}

func (r *RF24) WriteBlocking(data []byte, length uint8, timeout uint32) bool {
	return gobool(C.rf24_writeBlocking(r.cptr, unsafe.Pointer(&data), C.uint8_t(length), C.uint32_t(timeout)))
}

func (r *RF24) IsTxStandBy() bool {
	return gobool(C.rf24_txStandBy(r.cptr))
}

func (r *RF24) IsTxStandByExtended(timeout uint32, startTx bool) bool {
	return gobool(C.rf24_txStandByExtended(r.cptr, C.uint32_t(timeout), cbool(startTx)))
}

func (r *RF24) WriteAckPayload(pipe uint8, data []byte, length uint8) {
	C.rf24_writeAckPayload(r.cptr, C.uint8_t(pipe), unsafe.Pointer(&data), C.uint8_t(length))
}

func (r *RF24) IsAckPayloadAvailable() bool {
	return gobool(C.rf24_isAckPayloadAvailable(r.cptr))
}

func (r *RF24) WhatHappened() (tx_ok, tx_fail, rx_ready bool) {
	var out_tx_ok, out_tx_fail, out_rx_ready C.cbool
	C.rf24_whatHappened(r.cptr, &out_tx_ok, &out_tx_fail, &out_rx_ready)
	tx_ok, tx_fail, rx_ready = gobool(out_tx_ok), gobool(out_tx_fail), gobool(out_rx_ready)
	return
}

func (r *RF24) StartWrite(data []byte, length uint8) {
	C.rf24_startWrite(r.cptr, unsafe.Pointer(&data), C.uint8_t(length))
}

func (r *RF24) StartFastWrite(data []byte, length uint8, multicast bool, startTx bool) {
	C.rf24_startFastWrite(r.cptr, unsafe.Pointer(&data), C.uint8_t(length), cbool(multicast), cbool(startTx))
}

func (r *RF24) ReUseTx() {
	C.rf24_reUseTX(r.cptr)
}

func (r *RF24) FlushTx() uint8 {
	return uint8(C.rf24_flush_tx(r.cptr))
}

func (r *RF24) TestCarrier() bool {
	return gobool(C.rf24_testCarrier(r.cptr))
}

func (r *RF24) TestRPD() bool {
	return gobool(C.rf24_testRPD(r.cptr))
}

func (r *RF24) CloseReadingPipe(pipe uint8) {
	C.rf24_closeReadingPipe(r.cptr, C.uint8_t(pipe))
}

func (r *RF24) SetAddressWidth(width uint8) {
	C.rf24_setAddressWidth(r.cptr, C.uint8_t(width))
}

func (r *RF24) SetRetries(delay uint8, count uint8) {
	C.rf24_setRetries(r.cptr, C.uint8_t(delay), C.uint8_t(count))
}

func (r *RF24) SetChannel(channel uint8) {
	C.rf24_setChannel(r.cptr, C.uint8_t(channel))
}

func (r *RF24) GetChannel(channel uint8) uint8 {
	return uint8(C.rf24_getChannel(r.cptr))
}

func (r *RF24) SetPayloadSize(size uint8) {
	C.rf24_setPayloadSize(r.cptr, C.uint8_t(size))
}

func (r *RF24) GetPayloadSize() uint8 {
	return uint8(C.rf24_getPayloadSize(r.cptr))
}

func (r *RF24) GetDynamicPayloadSize() uint8 {
	return uint8(C.rf24_getDynamicPayloadSize(r.cptr))
}

func (r *RF24) EnableAckPayload() {
	C.rf24_enableAckPayload(r.cptr)
}

func (r *RF24) EnableDynamicPayloads() {
	C.rf24_enableDynamicPayloads(r.cptr)
}

func (r *RF24) DisableDynamicPayloads() {
	C.rf24_disableDynamicPayloads(r.cptr)
}

func (r *RF24) EnableDynamicAck() {
	C.rf24_enableDynamicAck(r.cptr)
}

func (r *RF24) IsPVariant() bool {
	return gobool(C.rf24_isPVariant(r.cptr))
}

func (r *RF24) SetAutoAck(enable bool) {
	C.rf24_setAutoAck(r.cptr, cbool(enable))
}

func (r *RF24) SetAutoAckPipe(pipe uint8, enable bool) {
	C.rf24_setAutoAck_pipe(r.cptr, C.uint8_t(pipe), cbool(enable))
}

// Is there any way to use the rf24_pa_dbm_e enum type directly
func (r *RF24) SetPALevel(level PA_DBM) {
	C.rf24_setPALevel(r.cptr, C.rf24_pa_dbm_val(level))
}

func (r *RF24) GetPALevel() PA_DBM {
	return PA_DBM(C.rf24_getPALevel(r.cptr))
}

func (r *RF24) SetDataRate(rate DATARATE) {
	C.rf24_setDataRate(r.cptr, C.rf24_datarate_val(rate))
}

func (r *RF24) GetDataRate() DATARATE {
	return DATARATE(C.rf24_getDataRate(r.cptr))
}

func (r *RF24) SetCRCLength(length CRCLENGTH) {
	C.rf24_setCRCLength(r.cptr, C.rf24_crclength_val(length))
}

func (r *RF24) GetCRCLength() CRCLENGTH {
	return CRCLENGTH(C.rf24_getCRCLength(r.cptr))
}

func (r *RF24) DisableCRC() {
	C.rf24_disableCRC(r.cptr)
}

func (r *RF24) MaskIRQ(txOk, txFail, rxReady bool) {
	C.rf24_maskIRQ(r.cptr, cbool(txOk), cbool(txFail), cbool(rxReady))
}
<commit_msg>minor improvement<commit_after>/*  Copyright 2013, Raphael Estrada
    Author email:  <galaktor@gmx.de>
    Project home:  <https://github.com/galaktor/gorf24>
    Licensed under The MIT License (see README and LICENSE files)

    Updated to RF24 v.13
    2017, Marian Craciunescu, Marius Staicu
    Authors email:  <marian.craciunescu@esolutions.ro>, <marius.staicu@esolutions.ro>
    Project home:  <https://github.com/mariusstaicu/gorf24>
*/
package gorf24

/*
  #cgo LDFLAGS: -L./RF24_c
  #cgo LDFLAGS: -lrf24_c
  #cgo CFLAGS: -I./RF24_c
  #include "RF24_c.h"
  #include <stdio.h>
*/
import "C"
import (
	// "encoding/binary"
	// "fmt"
	"unsafe"
)

type LibRF24 interface {
	Delete()
	Begin()
	IsChipConnected() bool
	StartListening()
	StopListening()
	Available() bool
	Read(length uint8) ([]byte, bool)
	OpenWritingPipe(address uint64)
	OpenReadingPipe(pipe uint8, address uint64)
	Write(data []byte, length uint8) bool
	PrintDetails()
	AvailablePipe() (bool, uint8)
	IsRxFifoFull() bool
	PowerDown()
	PowerUp()
	WriteMulticast(data []byte, length uint8, multicast bool) bool
	WriteFast(data []byte, length uint8) bool
	WriteFastMulticast(data []byte, length uint8, multicast bool) bool
	WriteBlocking(data []byte, length uint8, timeout uint32) bool
	IsTxStandBy() bool
	IsTxStandByExtended(timeout uint32, startTx bool) bool
	WriteAckPayload(pipe uint8, data []byte, length uint8)
	IsAckPayloadAvailable() bool
	WhatHappened() (tx_ok, tx_fail, rx_ready bool)
	StartWrite(data []byte, length uint8, multicast bool)
	StartFastWrite(data []byte, length uint8, multicast bool, startTx bool)
	ReUseTx()
	FlushTx() uint8
	TestCarrier() bool
	TestRPD() bool
	CloseReadingPipe(pipe uint8)
	SetAddressWidth(width uint8)
	SetRetries(delay uint8, count uint8)
	SetChannel(channel uint8)
	GetChannel(channel uint8) uint8
	SetPayloadSize(size uint8)
	GetPayloadSize() uint8
	GetDynamicPayloadSize() uint8
	EnableAckPayload()
	EnableDynamicPayloads()
	DisableDynamicPayloads()
	EnableDynamicAck()
	IsPVariant() bool
	SetAutoAck(enable bool)
	SetAutoAckPipe(pipe uint8, enable bool)
	SetPALevel(level PA_DBM)
	GetPALevel() PA_DBM
	SetDataRate(rate DATARATE)
	GetDataRate() DATARATE
	SetCRCLength(length CRCLENGTH)
	GetCRCLength() CRCLENGTH
	DisableCRC()
	MaskIRQ(txOk, txFail, rxReady bool)
}

// TODO: more idiomatic:
//   error handling
//   Read/Write interfaces
//   possibly more conventional byte slice passing
//   more type safety?
//   channel for available data, like time.Tick? r.Available() <-chan []byte  or so?
type RF24 struct {
	cptr        C.RF24Handle
	buffer_size uint8
	buffer      []byte
}

/*
func main() {
	var pipe uint64 = 0xF0F0F0F0E1
	r := New(25, 8, 32)
	defer r.Delete()
	r.Begin()
	r.SetRetries(15, 15)
	r.SetAutoAck(true)
	r.OpenReadingPipe(1, pipe)
	r.StartListening()
	r.PrintDetails()
	for {
		if r.Available() {
			data, _ := r.Read(4)
//			fmt.Printf("data: %v\n", data)
			payload := binary.LittleEndian.Uint32(data)
			fmt.Printf("Received %v\n", payload)
		} else {
			//
		}
	}
}
*/
func New(cepin uint8, cspin uint8, spispeed uint32) *RF24 {
	var r RF24
	r.cptr = C.new_rf24(C.uint8_t(cepin), C.uint8_t(cspin), C.uint32_t(spispeed))
	r.buffer = make([]byte, 128) // max payload length according to nrf24 spec
	return &r
}

func (r *RF24) Delete() {
	C.rf24_delete(r.cptr)
	r.cptr = nil
}
func (r *RF24) Begin() {
	C.rf24_begin(r.cptr)
}

func (r *RF24) IsChipConnected() bool {
	return gobool(C.rf24_isChipConnected(r.cptr))
}

func (r *RF24) StartListening() {
	C.rf24_startListening(r.cptr)
}

func (r *RF24) StopListening() {
	C.rf24_stopListening(r.cptr)
}

func (r *RF24) Available() bool {
	return gobool(C.rf24_available(r.cptr))
}

func (r *RF24) Read(length uint8) ([]byte, bool) {
	ok := gobool(C.rf24_read(r.cptr, unsafe.Pointer(&r.buffer[0]), C.uint8_t(length)))
	return r.buffer[:length], ok
}

func (r *RF24) OpenWritingPipe(address uint64) {
	C.rf24_openWritingPipe(r.cptr, C.uint64_t(address))
}

func (r *RF24) OpenReadingPipe(pipe uint8, address uint64) {
	C.rf24_openReadingPipe(r.cptr, C.uint8_t(pipe), C.uint64_t(address))
}

// TODO: implement Reader/Writer compatible interfaces
func (r *RF24) Write(data []byte, length uint8) bool {
	return gobool(C.rf24_write(r.cptr, unsafe.Pointer(&data[0]), C.uint8_t(length)))
}

// TODO: String() method would be great
func (r *RF24) PrintDetails() {
	C.rf24_printDetails(r.cptr)
}

// TODO: create Pipe type, make this a func on Pipe
func (r *RF24) AvailablePipe() (bool, uint8) {
	var pipe C.uint8_t
	available := gobool(C.rf24_available_pipe(r.cptr, &pipe))
	return available, uint8(pipe)
}

func (r *RF24) IsRxFifoFull() bool {
	return gobool(C.rf24_rxFifoFull(r.cptr))
}

func (r *RF24) PowerDown() {
	C.rf24_powerDown(r.cptr)
}

func (r *RF24) PowerUp() {
	C.rf24_powerUp(r.cptr)
}

func (r *RF24) WriteMulticast(data []byte, length uint8, multicast bool) bool {
	return gobool(C.rf24_writeMulticast(r.cptr, unsafe.Pointer(&data), C.uint8_t(length), cbool(multicast)))
}

func (r *RF24) WriteFast(data []byte, length uint8) bool {
	return gobool(C.rf24_writeFast(r.cptr, unsafe.Pointer(&data), C.uint8_t(length)))
}

func (r *RF24) WriteFastMulticast(data []byte, length uint8, multicast bool) bool {
	return gobool(C.rf24_writeFastMulticast(r.cptr, unsafe.Pointer(&data), C.uint8_t(length), cbool(multicast)))
}

func (r *RF24) WriteBlocking(data []byte, length uint8, timeout uint32) bool {
	return gobool(C.rf24_writeBlocking(r.cptr, unsafe.Pointer(&data), C.uint8_t(length), C.uint32_t(timeout)))
}

func (r *RF24) IsTxStandBy() bool {
	return gobool(C.rf24_txStandBy(r.cptr))
}

func (r *RF24) IsTxStandByExtended(timeout uint32, startTx bool) bool {
	return gobool(C.rf24_txStandByExtended(r.cptr, C.uint32_t(timeout), cbool(startTx)))
}

func (r *RF24) WriteAckPayload(pipe uint8, data []byte, length uint8) {
	C.rf24_writeAckPayload(r.cptr, C.uint8_t(pipe), unsafe.Pointer(&data), C.uint8_t(length))
}

func (r *RF24) IsAckPayloadAvailable() bool {
	return gobool(C.rf24_isAckPayloadAvailable(r.cptr))
}

func (r *RF24) WhatHappened() (tx_ok, tx_fail, rx_ready bool) {
	var out_tx_ok, out_tx_fail, out_rx_ready C.cbool
	C.rf24_whatHappened(r.cptr, &out_tx_ok, &out_tx_fail, &out_rx_ready)
	tx_ok, tx_fail, rx_ready = gobool(out_tx_ok), gobool(out_tx_fail), gobool(out_rx_ready)
	return
}

func (r *RF24) StartWrite(data []byte, length uint8, multicast bool) {
	C.rf24_startWrite(r.cptr, unsafe.Pointer(&data), C.uint8_t(length), cbool(multicast))
}

func (r *RF24) StartFastWrite(data []byte, length uint8, multicast bool, startTx bool) {
	C.rf24_startFastWrite(r.cptr, unsafe.Pointer(&data), C.uint8_t(length), cbool(multicast), cbool(startTx))
}

func (r *RF24) ReUseTx() {
	C.rf24_reUseTX(r.cptr)
}

func (r *RF24) FlushTx() uint8 {
	return uint8(C.rf24_flush_tx(r.cptr))
}

func (r *RF24) TestCarrier() bool {
	return gobool(C.rf24_testCarrier(r.cptr))
}

func (r *RF24) TestRPD() bool {
	return gobool(C.rf24_testRPD(r.cptr))
}

func (r *RF24) CloseReadingPipe(pipe uint8) {
	C.rf24_closeReadingPipe(r.cptr, C.uint8_t(pipe))
}

func (r *RF24) SetAddressWidth(width uint8) {
	C.rf24_setAddressWidth(r.cptr, C.uint8_t(width))
}

func (r *RF24) SetRetries(delay uint8, count uint8) {
	C.rf24_setRetries(r.cptr, C.uint8_t(delay), C.uint8_t(count))
}

func (r *RF24) SetChannel(channel uint8) {
	C.rf24_setChannel(r.cptr, C.uint8_t(channel))
}

func (r *RF24) GetChannel(channel uint8) uint8 {
	return uint8(C.rf24_getChannel(r.cptr))
}

func (r *RF24) SetPayloadSize(size uint8) {
	C.rf24_setPayloadSize(r.cptr, C.uint8_t(size))
}

func (r *RF24) GetPayloadSize() uint8 {
	return uint8(C.rf24_getPayloadSize(r.cptr))
}

func (r *RF24) GetDynamicPayloadSize() uint8 {
	return uint8(C.rf24_getDynamicPayloadSize(r.cptr))
}

func (r *RF24) EnableAckPayload() {
	C.rf24_enableAckPayload(r.cptr)
}

func (r *RF24) EnableDynamicPayloads() {
	C.rf24_enableDynamicPayloads(r.cptr)
}

func (r *RF24) DisableDynamicPayloads() {
	C.rf24_disableDynamicPayloads(r.cptr)
}

func (r *RF24) EnableDynamicAck() {
	C.rf24_enableDynamicAck(r.cptr)
}

func (r *RF24) IsPVariant() bool {
	return gobool(C.rf24_isPVariant(r.cptr))
}

func (r *RF24) SetAutoAck(enable bool) {
	C.rf24_setAutoAck(r.cptr, cbool(enable))
}

func (r *RF24) SetAutoAckPipe(pipe uint8, enable bool) {
	C.rf24_setAutoAck_pipe(r.cptr, C.uint8_t(pipe), cbool(enable))
}

// Is there any way to use the rf24_pa_dbm_e enum type directly
func (r *RF24) SetPALevel(level PA_DBM) {
	C.rf24_setPALevel(r.cptr, C.rf24_pa_dbm_val(level))
}

func (r *RF24) GetPALevel() PA_DBM {
	return PA_DBM(C.rf24_getPALevel(r.cptr))
}

func (r *RF24) SetDataRate(rate DATARATE) {
	C.rf24_setDataRate(r.cptr, C.rf24_datarate_val(rate))
}

func (r *RF24) GetDataRate() DATARATE {
	return DATARATE(C.rf24_getDataRate(r.cptr))
}

func (r *RF24) SetCRCLength(length CRCLENGTH) {
	C.rf24_setCRCLength(r.cptr, C.rf24_crclength_val(length))
}

func (r *RF24) GetCRCLength() CRCLENGTH {
	return CRCLENGTH(C.rf24_getCRCLength(r.cptr))
}

func (r *RF24) DisableCRC() {
	C.rf24_disableCRC(r.cptr)
}

func (r *RF24) MaskIRQ(txOk, txFail, rxReady bool) {
	C.rf24_maskIRQ(r.cptr, cbool(txOk), cbool(txFail), cbool(rxReady))
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 Jan Broer. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package main // import "github.com/janeczku/go-dnsmasq"

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/miekg/dns"

	"github.com/janeczku/go-dnsmasq/hostsfile"
	"github.com/janeczku/go-dnsmasq/resolvconf"
	"github.com/janeczku/go-dnsmasq/server"
	"github.com/janeczku/go-dnsmasq/stats"
)

// var Version string
const Version = "0.9.2"

var (
	nameservers   = []string{}
	searchDomains = []string{}
	stubzones     = ""
	hostPort      = ""
	listen        = ""
)

var exitErr error

func main() {
	app := cli.NewApp()
	app.Name = "go-dnsmasq"
	app.Usage = "Lightweight caching DNS proxy for Docker containers"
	app.Version = Version
	app.Author, app.Email = "", ""
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "listen, l",
			Value:  "127.0.0.1:53",
			Usage:  "listen address: ‘host[:port]‘",
			EnvVar: "DNSMASQ_LISTEN",
		},
		cli.BoolFlag{
			Name:   "default-resolver, d",
			Usage:  "make go-dnsmasq the default name server (updates /etc/resolv.conf)",
			EnvVar: "DNSMASQ_DEFAULT",
		},
		cli.StringFlag{
			Name:   "nameservers, n",
			Value:  "",
			Usage:  "comma-separated list of name servers: ‘host[:port]‘",
			EnvVar: "DNSMASQ_SERVERS",
		},
		cli.StringFlag{
			Name:   "stubzones, z",
			Value:  "",
			Usage:  "domains to resolve using a specific nameserver: ‘fqdn[,fqdn]/host[:port]‘",
			EnvVar: "DNSMASQ_STUB",
		},
		cli.StringFlag{
			Name:   "hostsfile, f",
			Value:  "",
			Usage:  "full path to hostsfile (e.g. ‘/etc/hosts‘)",
			EnvVar: "DNSMASQ_HOSTSFILE",
		},
		cli.IntFlag{
			Name:   "hostsfile-poll, p",
			Value:  0,
			Usage:  "how frequently to poll hostsfile (in seconds, ‘0‘ to disable)",
			EnvVar: "DNSMASQ_POLL",
		},
		cli.StringFlag{
			Name:   "search-domains, s",
			Value:  "",
			Usage:  "Specify SEARCH domains taking precedence over /etc/resolv.conf: ‘fqdn[,fqdn]‘",
			EnvVar: "DNSMASQ_SEARCH",
		},
		cli.BoolFlag{
			Name:   "append-search-domains, a",
			Usage:  "enable suffixing single-label queries with SEARCH domain",
			EnvVar: "DNSMASQ_APPEND",
		},
		cli.IntFlag{
			Name:   "rcache, r",
			Value:  0,
			Usage:  "capacity of the response cache (‘0‘ to disable caching)",
			EnvVar: "DNSMASQ_RCACHE",
		},
		cli.IntFlag{
			Name:   "rcache-ttl",
			Value:  server.RCacheTtl,
			Usage:  "TTL of entries in the response cache",
			EnvVar: "DNSMASQ_RCACHE_TTL",
		},
		cli.BoolFlag{
			Name:   "no-rec",
			Usage:  "disable recursion",
			EnvVar: "DNSMASQ_NOREC",
		},
		cli.BoolFlag{
			Name:   "round-robin",
			Usage:  "enable round robin of A/AAAA replies",
			EnvVar: "DNSMASQ_RR",
		},
		cli.BoolFlag{
			Name:   "systemd",
			Usage:  "bind to socket(s) activated by systemd (ignores --listen)",
			EnvVar: "DNSMASQ_SYSTEMD",
		},
		cli.BoolFlag{
			Name:   "verbose",
			Usage:  "enable verbose logging",
			EnvVar: "DNSMASQ_VERBOSE",
		},
	}
	app.Action = func(c *cli.Context) {
		exitReason := make(chan error)
		go func() {
			c := make(chan os.Signal, 1)
			signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
			sig := <-c
			log.Println("go-dnsmasq: exit requested by signal:", sig)
			exitReason <- nil
		}()

		if ns := c.String("nameservers"); ns != "" {
			for _, hostPort := range strings.Split(ns, ",") {
				if !strings.Contains(hostPort, ":") {
					hostPort += ":53"
				}

				if err := validateHostPort(hostPort); err != nil {
					log.Fatalf("go-dnsmasq: nameserver is invalid: %s", err)
				}

				nameservers = append(nameservers, hostPort)
			}
		}

		if sd := c.String("search-domains"); sd != "" {
			for _, domain := range strings.Split(sd, ",") {

				if dns.CountLabel(domain) < 2 {
					log.Fatalf("go-dnsmasq: SEARCH domain is not a FQDN: %s", domain)
				}
				domain = dns.Fqdn(strings.ToLower(domain))
				searchDomains = append(searchDomains, domain)
			}
		}

		if listen = c.String("listen"); !strings.Contains(listen, ":") {
			listen += ":53"
		}

		if err := validateHostPort(listen); err != nil {
			log.Fatalf("go-dnsmasq: listen address is invalid: %s", err)
		}

		config := &server.Config{
			DnsAddr:         listen,
			DefaultResolver: c.Bool("default-resolver"),
			Nameservers:     nameservers,
			Systemd:         c.Bool("systemd"),
			SearchDomains:   searchDomains,
			AppendDomain:    c.Bool("append-search-domains"),
			Hostsfile:       c.String("hostsfile"),
			PollInterval:    c.Int("hostsfile-poll"),
			RoundRobin:      c.Bool("round-robin"),
			NoRec:           c.Bool("no-rec"),
			ReadTimeout:     0,
			RCache:          c.Int("rcache"),
			RCacheTtl:       c.Int("rcache-ttl"),
			Verbose:         c.Bool("verbose"),
		}

		if err := server.SetDefaults(config); err != nil {
			if !config.NoRec && len(config.Nameservers) == 0 {
				log.Fatalf("go-dnsmasq: found no nameservers in resolv.conf and --nameservers flag not supplied: %s", err)
			} else if config.AppendDomain && len(config.SearchDomains) == 0 {
				log.Fatalf("go-dnsmasq: found no SEARCH domains in resolv.conf and --search-domains flag not supplied: %s", err)
			} else {
				log.Printf("go-dnsmasq: error parsing resolv.conf: %s", err)
			}
		}

		if stubzones = c.String("stubzones"); stubzones != "" {
			stubmap := make(map[string][]string)
			segments := strings.Split(stubzones, "/")
			if len(segments) != 2 || len(segments[0]) == 0 || len(segments[1]) == 0 {
				log.Fatalf("go-dnsmasq: stubzones argument is invalid")
			}

			hostPort = segments[1]
			if !strings.Contains(hostPort, ":") {
				hostPort += ":53"
			}

			if err := validateHostPort(hostPort); err != nil {
				log.Fatalf("go-dnsmasq: stubzones server address invalid: %s", err)
			}

			for _, sdomain := range strings.Split(segments[0], ",") {
				if dns.CountLabel(sdomain) < 2 {
					log.Fatalf("go-dnsmasq: stubzones domain is not a FQDN: %s", sdomain)
				}
				sdomain = dns.Fqdn(sdomain)
				stubmap[sdomain] = append(stubmap[sdomain], hostPort)
			}

			config.Stub = &stubmap
		}

		log.Printf("starting go-dnsmasq %s ...", Version)

		hf, err := hosts.NewHostsfile(config.Hostsfile, &hosts.Config{
			Poll:    config.PollInterval,
			Verbose: config.Verbose,
		})
		if err != nil {
			log.Fatalf("go-dnsmasq: error loading hostsfile: %s", err)
		}

		s := server.New(hf, config, Version)

		defer s.Stop()

		stats.Collect()

		if config.DefaultResolver {
			address, _, _ := net.SplitHostPort(config.DnsAddr)
			err := resolvconf.StoreAddress(address)
			if err != nil {
				log.Printf("go-dnsmasq: failed to register as default resolver: %s", err)
			}
			defer resolvconf.Clean()
		}

		go func() {
			if err := s.Run(); err != nil {
				exitReason <- err
			}
		}()

		exitErr = <-exitReason
		if exitErr != nil {
			log.Fatalf("go-dnsmasq: %s", err)
		}
	}

	app.Run(os.Args)
}

func validateHostPort(hostPort string) error {
	host, port, err := net.SplitHostPort(hostPort)
	if err != nil {
		return err
	}
	if ip := net.ParseIP(host); ip == nil {
		return fmt.Errorf("bad IP address: %s", host)
	}

	if p, _ := strconv.Atoi(port); p < 1 || p > 65535 {
		return fmt.Errorf("bad port number %s", port)
	}
	return nil
}
<commit_msg>Bump version 0.9.3<commit_after>// Copyright (c) 2015 Jan Broer. All rights reserved.
// Use of this source code is governed by The MIT License (MIT) that can be
// found in the LICENSE file.

package main // import "github.com/janeczku/go-dnsmasq"

import (
	"fmt"
	"log"
	"net"
	"os"
	"os/signal"
	"strconv"
	"strings"
	"syscall"

	"github.com/codegangsta/cli"
	"github.com/miekg/dns"

	"github.com/janeczku/go-dnsmasq/hostsfile"
	"github.com/janeczku/go-dnsmasq/resolvconf"
	"github.com/janeczku/go-dnsmasq/server"
	"github.com/janeczku/go-dnsmasq/stats"
)

// var Version string
const Version = "0.9.3"

var (
	nameservers   = []string{}
	searchDomains = []string{}
	stubzones     = ""
	hostPort      = ""
	listen        = ""
)

var exitErr error

func main() {
	app := cli.NewApp()
	app.Name = "go-dnsmasq"
	app.Usage = "Lightweight caching DNS proxy for Docker containers"
	app.Version = Version
	app.Author, app.Email = "", ""
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:   "listen, l",
			Value:  "127.0.0.1:53",
			Usage:  "listen address: ‘host[:port]‘",
			EnvVar: "DNSMASQ_LISTEN",
		},
		cli.BoolFlag{
			Name:   "default-resolver, d",
			Usage:  "make go-dnsmasq the default name server (updates /etc/resolv.conf)",
			EnvVar: "DNSMASQ_DEFAULT",
		},
		cli.StringFlag{
			Name:   "nameservers, n",
			Value:  "",
			Usage:  "comma-separated list of name servers: ‘host[:port]‘",
			EnvVar: "DNSMASQ_SERVERS",
		},
		cli.StringFlag{
			Name:   "stubzones, z",
			Value:  "",
			Usage:  "domains to resolve using a specific nameserver: ‘fqdn[,fqdn]/host[:port]‘",
			EnvVar: "DNSMASQ_STUB",
		},
		cli.StringFlag{
			Name:   "hostsfile, f",
			Value:  "",
			Usage:  "full path to hostsfile (e.g. ‘/etc/hosts‘)",
			EnvVar: "DNSMASQ_HOSTSFILE",
		},
		cli.IntFlag{
			Name:   "hostsfile-poll, p",
			Value:  0,
			Usage:  "how frequently to poll hostsfile (in seconds, ‘0‘ to disable)",
			EnvVar: "DNSMASQ_POLL",
		},
		cli.StringFlag{
			Name:   "search-domains, s",
			Value:  "",
			Usage:  "Specify SEARCH domains taking precedence over /etc/resolv.conf: ‘fqdn[,fqdn]‘",
			EnvVar: "DNSMASQ_SEARCH",
		},
		cli.BoolFlag{
			Name:   "append-search-domains, a",
			Usage:  "enable suffixing single-label queries with SEARCH domain",
			EnvVar: "DNSMASQ_APPEND",
		},
		cli.IntFlag{
			Name:   "rcache, r",
			Value:  0,
			Usage:  "capacity of the response cache (‘0‘ to disable caching)",
			EnvVar: "DNSMASQ_RCACHE",
		},
		cli.IntFlag{
			Name:   "rcache-ttl",
			Value:  server.RCacheTtl,
			Usage:  "TTL of entries in the response cache",
			EnvVar: "DNSMASQ_RCACHE_TTL",
		},
		cli.BoolFlag{
			Name:   "no-rec",
			Usage:  "disable recursion",
			EnvVar: "DNSMASQ_NOREC",
		},
		cli.BoolFlag{
			Name:   "round-robin",
			Usage:  "enable round robin of A/AAAA replies",
			EnvVar: "DNSMASQ_RR",
		},
		cli.BoolFlag{
			Name:   "systemd",
			Usage:  "bind to socket(s) activated by systemd (ignores --listen)",
			EnvVar: "DNSMASQ_SYSTEMD",
		},
		cli.BoolFlag{
			Name:   "verbose",
			Usage:  "enable verbose logging",
			EnvVar: "DNSMASQ_VERBOSE",
		},
	}
	app.Action = func(c *cli.Context) {
		exitReason := make(chan error)
		go func() {
			c := make(chan os.Signal, 1)
			signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
			sig := <-c
			log.Println("go-dnsmasq: exit requested by signal:", sig)
			exitReason <- nil
		}()

		if ns := c.String("nameservers"); ns != "" {
			for _, hostPort := range strings.Split(ns, ",") {
				if !strings.Contains(hostPort, ":") {
					hostPort += ":53"
				}

				if err := validateHostPort(hostPort); err != nil {
					log.Fatalf("go-dnsmasq: nameserver is invalid: %s", err)
				}

				nameservers = append(nameservers, hostPort)
			}
		}

		if sd := c.String("search-domains"); sd != "" {
			for _, domain := range strings.Split(sd, ",") {

				if dns.CountLabel(domain) < 2 {
					log.Fatalf("go-dnsmasq: SEARCH domain is not a FQDN: %s", domain)
				}
				domain = dns.Fqdn(strings.ToLower(domain))
				searchDomains = append(searchDomains, domain)
			}
		}

		if listen = c.String("listen"); !strings.Contains(listen, ":") {
			listen += ":53"
		}

		if err := validateHostPort(listen); err != nil {
			log.Fatalf("go-dnsmasq: listen address is invalid: %s", err)
		}

		config := &server.Config{
			DnsAddr:         listen,
			DefaultResolver: c.Bool("default-resolver"),
			Nameservers:     nameservers,
			Systemd:         c.Bool("systemd"),
			SearchDomains:   searchDomains,
			AppendDomain:    c.Bool("append-search-domains"),
			Hostsfile:       c.String("hostsfile"),
			PollInterval:    c.Int("hostsfile-poll"),
			RoundRobin:      c.Bool("round-robin"),
			NoRec:           c.Bool("no-rec"),
			ReadTimeout:     0,
			RCache:          c.Int("rcache"),
			RCacheTtl:       c.Int("rcache-ttl"),
			Verbose:         c.Bool("verbose"),
		}

		if err := server.SetDefaults(config); err != nil {
			if !config.NoRec && len(config.Nameservers) == 0 {
				log.Fatalf("go-dnsmasq: found no nameservers in resolv.conf and --nameservers flag not supplied: %s", err)
			} else if config.AppendDomain && len(config.SearchDomains) == 0 {
				log.Fatalf("go-dnsmasq: found no SEARCH domains in resolv.conf and --search-domains flag not supplied: %s", err)
			} else {
				log.Printf("go-dnsmasq: error parsing resolv.conf: %s", err)
			}
		}

		if stubzones = c.String("stubzones"); stubzones != "" {
			stubmap := make(map[string][]string)
			segments := strings.Split(stubzones, "/")
			if len(segments) != 2 || len(segments[0]) == 0 || len(segments[1]) == 0 {
				log.Fatalf("go-dnsmasq: stubzones argument is invalid")
			}

			hostPort = segments[1]
			if !strings.Contains(hostPort, ":") {
				hostPort += ":53"
			}

			if err := validateHostPort(hostPort); err != nil {
				log.Fatalf("go-dnsmasq: stubzones server address invalid: %s", err)
			}

			for _, sdomain := range strings.Split(segments[0], ",") {
				if dns.CountLabel(sdomain) < 2 {
					log.Fatalf("go-dnsmasq: stubzones domain is not a FQDN: %s", sdomain)
				}
				sdomain = dns.Fqdn(sdomain)
				stubmap[sdomain] = append(stubmap[sdomain], hostPort)
			}

			config.Stub = &stubmap
		}

		log.Printf("starting go-dnsmasq %s ...", Version)

		hf, err := hosts.NewHostsfile(config.Hostsfile, &hosts.Config{
			Poll:    config.PollInterval,
			Verbose: config.Verbose,
		})
		if err != nil {
			log.Fatalf("go-dnsmasq: error loading hostsfile: %s", err)
		}

		s := server.New(hf, config, Version)

		defer s.Stop()

		stats.Collect()

		if config.DefaultResolver {
			address, _, _ := net.SplitHostPort(config.DnsAddr)
			err := resolvconf.StoreAddress(address)
			if err != nil {
				log.Printf("go-dnsmasq: failed to register as default resolver: %s", err)
			}
			defer resolvconf.Clean()
		}

		go func() {
			if err := s.Run(); err != nil {
				exitReason <- err
			}
		}()

		exitErr = <-exitReason
		if exitErr != nil {
			log.Fatalf("go-dnsmasq: %s", err)
		}
	}

	app.Run(os.Args)
}

func validateHostPort(hostPort string) error {
	host, port, err := net.SplitHostPort(hostPort)
	if err != nil {
		return err
	}
	if ip := net.ParseIP(host); ip == nil {
		return fmt.Errorf("bad IP address: %s", host)
	}

	if p, _ := strconv.Atoi(port); p < 1 || p > 65535 {
		return fmt.Errorf("bad port number %s", port)
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"flag"
	"github.com/zenazn/goji"
	"github.com/zenazn/goji/web"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"time"
)

var resourceManagerURL = flag.String("resource-manager-url", "http://localhost:8088", "The HTTP URL to access the resource manager.")
var historyServerURL = flag.String("history-server-url", "http://localhost:19888", "The HTTP URL to access the history server.")
var proxyServerURL = flag.String("proxy-server-url", "", "The HTTP URL to access the proxy server, if separate from the resource manager.")
var namenodeAddress = flag.String("namenode-address", "localhost:9000", "The host:port to access the Namenode metadata service.")
var yarnLogDir = flag.String("yarn-logs-dir", "/tmp/logs", "The HDFS path where YARN stores logs. This is the controlled by the hadoop property yarn.nodemanager.remote-app-log-dir.")
var yarnHistoryDir = flag.String("yarn-history-dir", "/tmp/staging/history/done", "The HDFS path where YARN stores finished job history files. This is the controlled by the hadoop property mapreduce.jobhistory.done-dir.")
var httpTimeout = flag.Duration("http-timeout", time.Second*2, "The timeout used for connecting to YARN API. Pass values like: 2s")
var pollInterval = flag.Duration("poll-interval", time.Second*2, "How often should we poll the job APIs. Pass values like: 2s")

var jt *jobTracker

var rootPath, staticPath string

func index(c web.C, w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, filepath.Join(rootPath, "index.html"))
}

func getJobs(c web.C, w http.ResponseWriter, r *http.Request) {
	// We only need the details for listing pages.
	var jobs []*job
	for _, j := range jt.jobs {
		jobs = append(jobs, &job{Details: j.Details, Conf: j.Conf})
	}

	jsonBytes, err := json.Marshal(jobs)
	if err != nil {
		log.Println("error:", err)
		w.WriteHeader(500)
		return
	}

	w.Write(jsonBytes)
}

func getJob(c web.C, w http.ResponseWriter, r *http.Request) {
	if !jt.hasJob(c.URLParams["id"]) {
		w.WriteHeader(404)
		return
	}

	job := jt.reifyJob(c.URLParams["id"])

	jsonBytes, err := json.Marshal(job)
	if err != nil {
		log.Println("error:", err)
		w.WriteHeader(500)
		return
	}

	w.Write(jsonBytes)
}

func getLogs(c web.C, w http.ResponseWriter, r *http.Request) {
	if !jt.hasJob(c.URLParams["id"]) {
		w.WriteHeader(404)
		return
	}

	lines, err := jt.fetchLogs(c.URLParams["id"])

	if err != nil {
		log.Println("error:", err)
		w.WriteHeader(500)
		return
	}

	jsonBytes, err := json.Marshal(lines)
	if err != nil {
		log.Println("error:", err)
		w.WriteHeader(500)
		return
	}

	w.Write(jsonBytes)
}

func killJob(c web.C, w http.ResponseWriter, r *http.Request) {
	if !jt.hasJob(c.URLParams["id"]) {
		w.WriteHeader(404)
		return
	}

	id := c.URLParams["id"]
	err := jt.killJob(id)
	if err != nil {
		log.Println("error: ", err)
		w.WriteHeader(500)
	}
}

func init() {
	binPath, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatal(err)
	}

	rootPath = filepath.Join(binPath, "..")
	staticPath = filepath.Join(rootPath, "static")
}

func main() {
	flag.Parse()

	if *proxyServerURL == "" {
		proxyServerURL = resourceManagerURL
	}

	jt = newJobTracker(*resourceManagerURL, *historyServerURL, *proxyServerURL)
	go jt.Loop()

	if err := jt.testLogsDir(); err != nil {
		log.Printf("WARNING: Could not read yarn logs directory. Error message: `%s`\n", err)
		log.Println("\tYou can change the path with --yarn-logs-dir=HDFS_PATH.")
		log.Println("\tTo talk to HDFS, Timberlake needs to be able to access the namenode (--namenode-address) and datanodes.")
	}

	sse := newSSE()
	go sse.Loop()

	static := http.StripPrefix("/static/", http.FileServer(http.Dir(staticPath)))
	log.Println("serving static files from", staticPath)

	goji.Get("/static/*", static)
	goji.Get("/", index)
	goji.Get("/jobs/", getJobs)
	goji.Get("/sse", sse)
	goji.Get("/jobs/:id", getJob)
	goji.Get("/jobs/:id/logs", getLogs)
	goji.Post("/jobs/:id/kill", killJob)

	go func() {
		for job := range jt.updates {
			jsonBytes, err := json.Marshal(job)
			if err != nil {
				log.Println("json error: ", err)
			} else {
				sse.events <- jsonBytes
			}
		}
	}()

	goji.Serve()
}
<commit_msg>Add -pprof, to enable runtime profiling<commit_after>package main

import (
	"encoding/json"
	"flag"
	"log"
	"net/http"
	"net/http/pprof"
	"os"
	"path/filepath"
	"time"

	"github.com/zenazn/goji/bind"
	"github.com/zenazn/goji/web"
	"github.com/zenazn/goji/web/middleware"
)

var resourceManagerURL = flag.String("resource-manager-url", "http://localhost:8088", "The HTTP URL to access the resource manager.")
var historyServerURL = flag.String("history-server-url", "http://localhost:19888", "The HTTP URL to access the history server.")
var proxyServerURL = flag.String("proxy-server-url", "", "The HTTP URL to access the proxy server, if separate from the resource manager.")
var namenodeAddress = flag.String("namenode-address", "localhost:9000", "The host:port to access the Namenode metadata service.")
var yarnLogDir = flag.String("yarn-logs-dir", "/tmp/logs", "The HDFS path where YARN stores logs. This is the controlled by the hadoop property yarn.nodemanager.remote-app-log-dir.")
var yarnHistoryDir = flag.String("yarn-history-dir", "/tmp/staging/history/done", "The HDFS path where YARN stores finished job history files. This is the controlled by the hadoop property mapreduce.jobhistory.done-dir.")
var httpTimeout = flag.Duration("http-timeout", time.Second*2, "The timeout used for connecting to YARN API. Pass values like: 2s")
var pollInterval = flag.Duration("poll-interval", time.Second*2, "How often should we poll the job APIs. Pass values like: 2s")
var enableDebug = flag.Bool("pprof", false, "Enable pprof debugging tools at /debug.")

var jt *jobTracker

var rootPath, staticPath string

var mux *web.Mux

func init() {
	bind.WithFlag()
	mux = web.New()
	mux.Use(middleware.RequestID)
	mux.Use(middleware.Logger)
	mux.Use(middleware.Recoverer)
	mux.Use(middleware.AutomaticOptions)
}

func index(c web.C, w http.ResponseWriter, r *http.Request) {
	http.ServeFile(w, r, filepath.Join(rootPath, "index.html"))
}

func getJobs(c web.C, w http.ResponseWriter, r *http.Request) {
	// We only need the details for listing pages.
	var jobs []*job
	for _, j := range jt.jobs {
		jobs = append(jobs, &job{Details: j.Details, Conf: j.Conf})
	}

	jsonBytes, err := json.Marshal(jobs)
	if err != nil {
		log.Println("error:", err)
		w.WriteHeader(500)
		return
	}

	w.Write(jsonBytes)
}

func getJob(c web.C, w http.ResponseWriter, r *http.Request) {
	if !jt.hasJob(c.URLParams["id"]) {
		w.WriteHeader(404)
		return
	}

	job := jt.reifyJob(c.URLParams["id"])

	jsonBytes, err := json.Marshal(job)
	if err != nil {
		log.Println("error:", err)
		w.WriteHeader(500)
		return
	}

	w.Write(jsonBytes)
}

func getLogs(c web.C, w http.ResponseWriter, r *http.Request) {
	if !jt.hasJob(c.URLParams["id"]) {
		w.WriteHeader(404)
		return
	}

	lines, err := jt.fetchLogs(c.URLParams["id"])

	if err != nil {
		log.Println("error:", err)
		w.WriteHeader(500)
		return
	}

	jsonBytes, err := json.Marshal(lines)
	if err != nil {
		log.Println("error:", err)
		w.WriteHeader(500)
		return
	}

	w.Write(jsonBytes)
}

func killJob(c web.C, w http.ResponseWriter, r *http.Request) {
	if !jt.hasJob(c.URLParams["id"]) {
		w.WriteHeader(404)
		return
	}

	id := c.URLParams["id"]
	err := jt.killJob(id)
	if err != nil {
		log.Println("error: ", err)
		w.WriteHeader(500)
	}
}

func init() {
	binPath, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		log.Fatal(err)
	}

	rootPath = filepath.Join(binPath, "..")
	staticPath = filepath.Join(rootPath, "static")
}

func main() {
	flag.Parse()

	if *proxyServerURL == "" {
		proxyServerURL = resourceManagerURL
	}

	jt = newJobTracker(*resourceManagerURL, *historyServerURL, *proxyServerURL)
	go jt.Loop()

	if err := jt.testLogsDir(); err != nil {
		log.Printf("WARNING: Could not read yarn logs directory. Error message: `%s`\n", err)
		log.Println("\tYou can change the path with --yarn-logs-dir=HDFS_PATH.")
		log.Println("\tTo talk to HDFS, Timberlake needs to be able to access the namenode (--namenode-address) and datanodes.")
	}

	sse := newSSE()
	go sse.Loop()

	static := http.StripPrefix("/static/", http.FileServer(http.Dir(staticPath)))
	log.Println("serving static files from", staticPath)

	mux.Get("/static/*", static)
	mux.Get("/", index)
	mux.Get("/jobs/", getJobs)
	mux.Get("/sse", sse)
	mux.Get("/jobs/:id", getJob)
	mux.Get("/jobs/:id/logs", getLogs)
	mux.Post("/jobs/:id/kill", killJob)

	if *enableDebug {
		mux.Get("/debug/pprof/*", pprof.Index)
		mux.Get("/debug/pprof/cmdline", pprof.Cmdline)
		mux.Get("/debug/pprof/profile", pprof.Profile)
		mux.Get("/debug/pprof/symbol", pprof.Symbol)
		mux.Get("/debug/pprof/trace", pprof.Trace)
	}

	go func() {
		for job := range jt.updates {
			jsonBytes, err := json.Marshal(job)
			if err != nil {
				log.Println("json error: ", err)
			} else {
				sse.events <- jsonBytes
			}
		}
	}()

	http.Serve(bind.Default(), mux)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/gorilla/mux"
	"github.com/spf13/viper"
)

type Program struct {
	URL      string
	Duration time.Duration
}

// Loads a list of programs.
// A program consists of a list things to display on the rotator along
// with a number of seconds to display each one before moving on.
func loadProgramList(filename string) []Program {

	fmt.Printf("Loading programs from %s\n", filename)

	var list []Program

	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}
	webpages := string(bytes)

	r := csv.NewReader(strings.NewReader(webpages))

	for {
		var p Program
		record, err := r.Read()
		if err == io.EOF {
			fmt.Printf("Finished loading programs.\n\n")
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		p.URL = record[0]
		p.Duration, err = time.ParseDuration(record[1])
		fmt.Printf("  Loaded program %.50s to show for %s.\n", p.URL, p.Duration)
		list = append(list, p)
	}

	return list
}

func runProgram(program Program, abort chan struct{}) {

	// Does this leak goroutines over time because they are created more than they are consumed?
	// This will need to be revisited when a more elaborate API and/or console UI
	go func() {
		os.Stdin.Read(make([]byte, 1)) // read a single byte
		fmt.Printf(" >> Got keyboard input, that means you want to move to the next program.  Can do! << \n\n")
		abort <- struct{}{}
	}()

	ip := viper.Get("IP")
	port := viper.GetInt("PORT")

	constr := fmt.Sprintf("%s:%d", ip, port)

	conn, err := net.Dial("tcp", constr)
	if err != nil {
		fmt.Printf("Error making network connection to: %s\n", constr)
		fmt.Println("Pausing for 30s")
		time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
		return
	}

	fmt.Printf("Running program for %s:  %s\n", program.Duration, program.URL)
	fmt.Fprintf(conn, "window.location='%s'\n", program.URL)
	status, err := bufio.NewReader(conn).ReadString('\n')
	fmt.Printf("  %s", status)

	select {
	case <-time.After(program.Duration):
		// Do nothing.
	case <-abort:
		fmt.Println("Current program aborted")
		return
	}
}

// InitializeConfig loads our configuration using Viper package.
func InitializeConfig(abort chan<- struct{}) {

	viper.SetConfigType("yaml")
	// Set config file
	viper.SetConfigName("config")

	// Add config path
	//	viper.AddConfigPath("$HOME/.gorotator")
	viper.AddConfigPath(".")

	// Read in the config
	err := viper.ReadInConfig() // Find and read the config file
	if err != nil {             // Handle errors reading the config file
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	// Load default settings
	viper.SetDefault("debug", false)

	viper.SetEnvPrefix("gorotator") // will be uppercased automatically
	viper.BindEnv("debug")
	viper.BindEnv("ip")
	viper.BindEnv("port")

	// Do some flag handling and any complicated config logic
	if !viper.IsSet("ip") || !viper.IsSet("port") {
		fmt.Println("Configuration error.  Both IP and PORT must be set via either config or environment.")
		os.Exit(1)
	}

	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("\nConfig file changed:", e.Name)
		abort <- struct{}{}
		fmt.Printf("Content will change immediately.\n\n")
	})

}

func LoadAndRunLoop(abort chan struct{}) {

	// Load and run the acctive program_file indefinately
	for {
		// We pull filename inside the loop because the
		// configuration can change while our program is running.
		filename := viper.GetString("program_file")
		pl := loadProgramList(filename)

		for _, p := range pl {
			runProgram(p, abort)
		}

		fmt.Printf("\nLooping back to play program list from beginning\n\n")
	}

}

func PlayHandler(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()
	var p Program
	p.URL = r.Form.Get("url")
	fmt.Printf("URL: %s\n", p.URL)

	d := r.Form.Get("duration")
	fmt.Printf("Duration: %s\n", d)

	var err error
	p.Duration, err = time.ParseDuration(r.Form.Get("duration"))
	if err != nil {
		fmt.Println("Unable to parse postdata as Program.  Invalid duration")
		fmt.Println(r.FormValue("duration"))
	}

	// Needs validation...

	// Now do something with the program.. play it?

}

func main() {

	// Control channel to stop running programs immediately
	abort := make(chan struct{})

	InitializeConfig(abort)

	go LoadAndRunLoop(abort)

	r := mux.NewRouter()
	r.HandleFunc("/play", PlayHandler)

	go log.Fatal(http.ListenAndServe(":8080", r))

}
<commit_msg>Made the abort channel be global<commit_after>package main

import (
	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net"
	"net/http"
	"os"
	"strings"
	"time"

	"github.com/fsnotify/fsnotify"
	"github.com/gorilla/mux"
	"github.com/spf13/viper"
)

type Program struct {
	URL      string
	Duration time.Duration
}

// Loads a list of programs.
// A program consists of a list things to display on the rotator along
// with a number of seconds to display each one before moving on.
func loadProgramList(filename string) []Program {

	fmt.Printf("Loading programs from %s\n", filename)

	var list []Program

	bytes, err := ioutil.ReadFile(filename)
	if err != nil {
		log.Fatal(err)
	}
	webpages := string(bytes)

	r := csv.NewReader(strings.NewReader(webpages))

	for {
		var p Program
		record, err := r.Read()
		if err == io.EOF {
			fmt.Printf("Finished loading programs.\n\n")
			break
		}
		if err != nil {
			log.Fatal(err)
		}
		p.URL = record[0]
		p.Duration, err = time.ParseDuration(record[1])
		fmt.Printf("  Loaded program %.50s to show for %s.\n", p.URL, p.Duration)
		list = append(list, p)
	}

	return list
}

func runProgram(program Program) {

	// Does this leak goroutines over time because they are created more than they are consumed?
	// This will need to be revisited when a more elaborate API and/or console UI
	go func() {
		os.Stdin.Read(make([]byte, 1)) // read a single byte
		fmt.Printf(" >> Got keyboard input, that means you want to move to the next program.  Can do! << \n\n")
		abort <- struct{}{}
	}()

	ip := viper.Get("IP")
	port := viper.GetInt("PORT")

	constr := fmt.Sprintf("%s:%d", ip, port)

	conn, err := net.Dial("tcp", constr)
	if err != nil {
		fmt.Printf("Error making network connection to: %s\n", constr)
		fmt.Println("Pausing for 30s")
		time.Sleep(30 * time.Second) // wait 30 seconds to slow retries
		return
	}

	fmt.Printf("Running program for %s:  %s\n", program.Duration, program.URL)
	fmt.Fprintf(conn, "window.location='%s'\n", program.URL)
	status, err := bufio.NewReader(conn).ReadString('\n')
	fmt.Printf("  %s", status)

	select {
	case <-time.After(program.Duration):
		// Do nothing.
	case <-abort:
		fmt.Println("Current program aborted")
		return
	}
}

// InitializeConfig loads our configuration using Viper package.
func InitializeConfig() {

	viper.SetConfigType("yaml")
	// Set config file
	viper.SetConfigName("config")

	// Add config path
	//	viper.AddConfigPath("$HOME/.gorotator")
	viper.AddConfigPath(".")

	// Read in the config
	err := viper.ReadInConfig() // Find and read the config file
	if err != nil {             // Handle errors reading the config file
		panic(fmt.Errorf("Fatal error config file: %s \n", err))
	}

	// Load default settings
	viper.SetDefault("debug", false)

	viper.SetEnvPrefix("gorotator") // will be uppercased automatically
	viper.BindEnv("debug")
	viper.BindEnv("ip")
	viper.BindEnv("port")

	// Do some flag handling and any complicated config logic
	if !viper.IsSet("ip") || !viper.IsSet("port") {
		fmt.Println("Configuration error.  Both IP and PORT must be set via either config or environment.")
		os.Exit(1)
	}

	viper.WatchConfig()
	viper.OnConfigChange(func(e fsnotify.Event) {
		fmt.Println("\nConfig file changed:", e.Name)
		abort <- struct{}{}
		fmt.Printf("Content will change immediately.\n\n")
	})

}

func LoadAndRunLoop() {

	// Load and run the acctive program_file indefinately
	for {
		// We pull filename inside the loop because the
		// configuration can change while our program is running.
		filename := viper.GetString("program_file")
		pl := loadProgramList(filename)

		for _, p := range pl {
			runProgram(p)
		}

		fmt.Printf("\nLooping back to play program list from beginning\n\n")
	}

}

func PlayHandler(w http.ResponseWriter, r *http.Request) {

	r.ParseForm()
	var p Program
	p.URL = r.Form.Get("url")
	fmt.Printf("URL: %s\n", p.URL)

	d := r.Form.Get("duration")
	fmt.Printf("Duration: %s\n", d)

	var err error
	p.Duration, err = time.ParseDuration(r.Form.Get("duration"))
	if err != nil {
		fmt.Println("Unable to parse postdata as Program.  Invalid duration")
		fmt.Println(r.FormValue("duration"))
	}

	// Needs validation...

	// Now do something with the program.. play it?

}

// Control channel to stop running programs immediately
var abort = make(chan struct{})

func main() {

	InitializeConfig()

	go LoadAndRunLoop()

	r := mux.NewRouter()
	r.HandleFunc("/play", PlayHandler)

	go log.Fatal(http.ListenAndServe(":8080", r))

}
<|endoftext|>


<commit_before>package main

import (
	"github.com/praqma/git-phlow/gitwrapper"
	"fmt"
	"strconv"
)

func main() {
	//cmd.Execute()

	var branch *gitwrapper.Branch
	branch = &gitwrapper.Branch{}
	_, err := branch.Branch()

	if err != nil{
		fmt.Println(err)
	}

	for i, val := range branch.Branches {
		fmt.Println(strconv.Itoa(i) + " bbbb " + val)
	}

}<commit_msg>Added cobra again<commit_after>package main

import (
	"github.com/praqma/git-phlow/gitwrapper"
	"fmt"
	"strconv"
	"github.com/spf13/cobra/cobra/cmd"
)

func main() {
	cmd.Execute()

	var branch *gitwrapper.Branch
	branch = &gitwrapper.Branch{}
	_, err := branch.Branch()

	if err != nil{
		fmt.Println(err)
	}

	for i, val := range branch.Branches {
		fmt.Println(strconv.Itoa(i) + " bbbb " + val)
	}

}<|endoftext|>


<commit_before>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/open-falcon/graph/api"
	"github.com/open-falcon/graph/cron"
	"github.com/open-falcon/graph/db"
	"github.com/open-falcon/graph/g"
	"github.com/open-falcon/graph/http"
	"github.com/open-falcon/graph/index"
	"github.com/open-falcon/graph/rrdtool"
	"github.com/toolkits/logger"
)

var pid int

var conf g.GlobalConfig

func start_signal() {
	sigs := make(chan os.Signal, 1)
	log.Println(pid, "register signal notify")
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

	for {
		s := <-sigs
		log.Println("recv", s)

		switch s {
		case syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
			log.Println("gracefull shut down")
			http.Close_chan <- 1
			api.Close_chan <- 1
			cron.Out_done_chan <- 1
			<-http.Close_done_chan
			<-api.Close_done_chan
			log.Println(pid, "remove ", conf.Pid)
			os.Remove(conf.Pid)
			rrdtool.FlushAll()
			log.Println(pid, "flush done, exiting")
			os.Exit(0)
		}
	}
}

func main() {
	pid = os.Getpid()

	cfg := flag.String("c", "cfg.json", "configuration file")
	version := flag.Bool("v", false, "show version")
	versionGit := flag.Bool("vg", false, "show version")
	flag.Parse()
	g.ParseConfig(*cfg)

	conf = *g.Config()

	if *version {
		fmt.Println(g.VERSION)
		os.Exit(0)
	}

	if *versionGit {
		fmt.Println(g.VERSION, g.COMMIT)
		os.Exit(0)
	}

	// 只在启动的时候初始化一次，而ParseConfig可以被多次调用
	logger.SetLevelWithDefault(g.Config().Log, "info")
	db.Init()

	go api.Start()

	// 刷硬盘
	go cron.SyncDisk()

	// 索引更新2.0
	index.Start()

	// http
	go http.Start()

	start_signal()

}
<commit_msg>rm dirtty log when control version called<commit_after>package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/open-falcon/graph/api"
	"github.com/open-falcon/graph/cron"
	"github.com/open-falcon/graph/db"
	"github.com/open-falcon/graph/g"
	"github.com/open-falcon/graph/http"
	"github.com/open-falcon/graph/index"
	"github.com/open-falcon/graph/rrdtool"
	"github.com/toolkits/logger"
)

func start_signal(pid int, conf g.GlobalConfig) {
	sigs := make(chan os.Signal, 1)
	log.Println(pid, "register signal notify")
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)

	for {
		s := <-sigs
		log.Println("recv", s)

		switch s {
		case syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
			log.Println("gracefull shut down")
			http.Close_chan <- 1
			api.Close_chan <- 1
			cron.Out_done_chan <- 1
			<-http.Close_done_chan
			<-api.Close_done_chan
			log.Println(pid, "remove ", conf.Pid)
			os.Remove(conf.Pid)
			rrdtool.FlushAll()
			log.Println(pid, "flush done, exiting")
			os.Exit(0)
		}
	}
}

func main() {

	cfg := flag.String("c", "cfg.json", "configuration file")
	version := flag.Bool("v", false, "show version")
	versionGit := flag.Bool("vg", false, "show version")
	flag.Parse()

	if *version {
		fmt.Println(g.VERSION)
		os.Exit(0)
	}

	if *versionGit {
		fmt.Println(g.VERSION, g.COMMIT)
		os.Exit(0)
	}

	// global config
	g.ParseConfig(*cfg)

	// 只在启动的时候初始化一次，而ParseConfig可以被多次调用
	logger.SetLevelWithDefault(g.Config().Log, "info")
	db.Init()

	go api.Start()

	// 刷硬盘
	go cron.SyncDisk()

	// 索引更新2.0
	index.Start()

	// http
	go http.Start()

	start_signal(os.Getpid(), *g.Config())

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"strconv"
	"strings"
	"syscall"

	"github.com/boltdb/bolt"
	"github.com/cenkalti/boltbrowser/boltbrowser"
	clog "github.com/cenkalti/log"
	"github.com/cenkalti/rain/internal/console"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/rainrpc"
	"github.com/cenkalti/rain/torrent"
	"github.com/hokaccha/go-prettyjson"
	"github.com/mitchellh/go-homedir"
	"github.com/urfave/cli"
	"github.com/zeebo/bencode"
	"gopkg.in/yaml.v2"
)

var (
	app = cli.NewApp()
	clt *rainrpc.Client
	log = logger.New("rain")
)

func main() {
	app.Version = torrent.Version
	app.Usage = "BitTorrent client"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Usage: "read config from `FILE`",
		},
		cli.StringFlag{
			Name:   "cpuprofile",
			Hidden: true,
			Usage:  "write cpu profile to `FILE`",
		},
		cli.StringFlag{
			Name:   "memprofile",
			Hidden: true,
			Usage:  "write memory profile to `FILE`",
		},
		cli.IntFlag{
			Name:   "blockprofile",
			Hidden: true,
			Usage:  "enable blocking profiler",
		},
		cli.StringFlag{
			Name:   "pprof",
			Hidden: true,
			Usage:  "run pprof server on `ADDR`",
		},
		cli.BoolFlag{
			Name:  "debug, d",
			Usage: "enable debug log",
		},
		cli.StringFlag{
			Name:  "logfile",
			Usage: "write log to `FILE`",
		},
	}
	app.Before = handleBeforeCommand
	app.After = handleAfterCommand
	app.Commands = []cli.Command{
		{
			Name:  "server",
			Usage: "run rpc server and torrent client",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "config",
					Usage: "path to the config file",
					Value: "~/rain/config.yaml",
				},
			},
			Action: handleServer,
		},
		{
			Name:  "client",
			Usage: "send rpc request to server",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "url",
					Usage: "URL of RPC server",
					Value: "http://127.0.0.1:" + strconv.Itoa(torrent.DefaultConfig.RPCPort),
				},
			},
			Before: handleBeforeClient,
			Subcommands: []cli.Command{
				{
					Name:   "version",
					Usage:  "server version",
					Action: handleVersion,
				},
				{
					Name:   "list",
					Usage:  "list torrents",
					Action: handleList,
				},
				{
					Name:   "add",
					Usage:  "add torrent or magnet",
					Action: handleAdd,
					Flags: []cli.Flag{
						cli.BoolFlag{
							Name: "stopped",
						},
						cli.StringFlag{
							Name: "id",
						},
					},
				},
				{
					Name:   "remove",
					Usage:  "remove torrent",
					Action: handleRemove,
				},
				{
					Name:   "stats",
					Usage:  "get stats of torrent",
					Action: handleStats,
				},
				{
					Name:   "session-stats",
					Usage:  "get stats of session",
					Action: handleSessionStats,
				},
				{
					Name:   "trackers",
					Usage:  "get trackers of torrent",
					Action: handleTrackers,
				},
				{
					Name:   "peers",
					Usage:  "get peers of torrent",
					Action: handlePeers,
				},
				{
					Name:   "add-peer",
					Usage:  "add peer to torrent",
					Action: handleAddPeer,
				},
				{
					Name:   "add-tracker",
					Usage:  "add tracker to torrent",
					Action: handleAddTracker,
				},
				{
					Name:   "start",
					Usage:  "start torrent",
					Action: handleStart,
				},
				{
					Name:   "stop",
					Usage:  "stop torrent",
					Action: handleStop,
				},
				{
					Name:   "start-all",
					Usage:  "start all torrents",
					Action: handleStartAll,
				},
				{
					Name:   "stop-all",
					Usage:  "stop all torrents",
					Action: handleStopAll,
				},
				{
					Name:   "console",
					Usage:  "show client console",
					Action: handleConsole,
				},
			},
		},
		{
			Name:   "boltbrowser",
			Hidden: true,
			Action: handleBoltBrowser,
		},
		{
			Name:  "torrent",
			Usage: "manage torrent files",
			Subcommands: []cli.Command{
				{
					Name:   "show",
					Usage:  "show contents of the torrent file",
					Action: handleTorrentShow,
				},
			},
		},
	}
	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}

func handleBoltBrowser(c *cli.Context) error {
	db, err := bolt.Open(c.Args().Get(0), 0600, nil)
	if err != nil {
		return err
	}
	boltbrowser.Browse(db, false)
	return db.Close()
}

func handleBeforeCommand(c *cli.Context) error {
	cpuprofile := c.GlobalString("cpuprofile")
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatal("could not create CPU profile: ", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal("could not start CPU profile: ", err)
		}
	}
	pprofFlag := c.GlobalString("pprof")
	if pprofFlag != "" {
		go func() {
			log.Notice(http.ListenAndServe(pprofFlag, nil))
		}()
	}
	logFile := c.GlobalString("logfile")
	if logFile != "" {
		f, err := os.Create(logFile)
		if err != nil {
			log.Fatal("could not create log file: ", err)
		}
		logger.SetHandler(clog.NewFileHandler(f))
	}
	blockProfile := c.GlobalInt("blockprofile")
	if blockProfile != 0 {
		runtime.SetBlockProfileRate(blockProfile)
	}
	if c.GlobalBool("debug") {
		logger.SetLevel(clog.DEBUG)
	}
	return nil
}

func handleAfterCommand(c *cli.Context) error {
	if c.GlobalString("cpuprofile") != "" {
		pprof.StopCPUProfile()
	}
	return nil
}

func handleServer(c *cli.Context) error {
	cfg := torrent.DefaultConfig

	configPath := c.String("config")
	if configPath != "" {
		cp, err := homedir.Expand(configPath)
		if err != nil {
			return err
		}
		b, err := ioutil.ReadFile(cp) // nolint: gosec
		switch {
		case os.IsNotExist(err):
			log.Noticef("config file not found at %q, using default config", cp)
		case err != nil:
			return err
		default:
			err = yaml.Unmarshal(b, &cfg)
			if err != nil {
				return err
			}
			log.Infoln("config loaded from:", cp)
			b, err = yaml.Marshal(&cfg)
			if err != nil {
				return err
			}
			log.Debug("\n" + string(b))
		}
	}

	ses, err := torrent.NewSession(cfg)
	if err != nil {
		return err
	}
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	s := <-ch
	log.Noticef("received %s, stopping server", s)

	memprofile := c.GlobalString("memprofile")
	if memprofile != "" {
		f, err := os.Create(memprofile)
		if err != nil {
			log.Fatal(err)
		}
		err = pprof.WriteHeapProfile(f)
		if err != nil {
			log.Fatal(err)
		}
		err = f.Close()
		if err != nil {
			log.Fatal(err)
		}
	}

	return ses.Close()
}

func handleBeforeClient(c *cli.Context) error {
	clt = rainrpc.NewClient(c.String("url"))
	return nil
}

func handleVersion(c *cli.Context) error {
	version, err := clt.ServerVersion()
	if err != nil {
		return err
	}
	_, _ = os.Stdout.WriteString(version)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleList(c *cli.Context) error {
	resp, err := clt.ListTorrents()
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleAdd(c *cli.Context) error {
	var b []byte
	var marshalErr error
	arg := c.Args().Get(0)
	addOpt := &rainrpc.AddTorrentOptions{
		Stopped: c.Bool("stopped"),
		ID:      c.String("id"),
	}
	if strings.HasPrefix(arg, "magnet:") || strings.HasPrefix(arg, "http://") || strings.HasPrefix(arg, "https://") {
		resp, err := clt.AddURI(arg, addOpt)
		if err != nil {
			return err
		}
		b, marshalErr = prettyjson.Marshal(resp)
	} else {
		f, err := os.Open(arg) // nolint: gosec
		if err != nil {
			return err
		}
		resp, err := clt.AddTorrent(f, addOpt)
		_ = f.Close()
		if err != nil {
			return err
		}
		b, marshalErr = prettyjson.Marshal(resp)
	}
	if marshalErr != nil {
		return marshalErr
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleRemove(c *cli.Context) error {
	id := c.Args().Get(0)
	return clt.RemoveTorrent(id)
}

func handleStats(c *cli.Context) error {
	id := c.Args().Get(0)
	resp, err := clt.GetTorrentStats(id)
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleSessionStats(c *cli.Context) error {
	resp, err := clt.GetSessionStats()
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleTrackers(c *cli.Context) error {
	id := c.Args().Get(0)
	resp, err := clt.GetTorrentTrackers(id)
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handlePeers(c *cli.Context) error {
	id := c.Args().Get(0)
	resp, err := clt.GetTorrentPeers(id)
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleAddPeer(c *cli.Context) error {
	id := c.Args().Get(0)
	addr := c.Args().Get(1)
	return clt.AddPeer(id, addr)
}

func handleAddTracker(c *cli.Context) error {
	id := c.Args().Get(0)
	uri := c.Args().Get(1)
	return clt.AddTracker(id, uri)
}

func handleStart(c *cli.Context) error {
	id := c.Args().Get(0)
	return clt.StartTorrent(id)
}

func handleStop(c *cli.Context) error {
	id := c.Args().Get(0)
	return clt.StopTorrent(id)
}

func handleStartAll(c *cli.Context) error {
	return clt.StartAllTorrents()
}

func handleStopAll(c *cli.Context) error {
	return clt.StopAllTorrents()
}

func handleConsole(c *cli.Context) error {
	con := console.New(clt)
	return con.Run()
}

func handleTorrentShow(c *cli.Context) error {
	arg := c.Args().Get(0)
	f, err := os.Open(arg) // nolint: gosec
	if err != nil {
		return err
	}
	defer f.Close()

	val := make(map[string]interface{})
	err = bencode.NewDecoder(f).Decode(&val)
	if err != nil {
		return err
	}
	if info, ok := val["info"].(map[string]interface{}); ok {
		if pieces, ok := info["pieces"].(string); ok {
			info["pieces"] = fmt.Sprintf("<<< %d bytes of data >>>", len(pieces))
		}
	}
	b, err := prettyjson.Marshal(val)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}
<commit_msg>remove logfile flag<commit_after>package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	_ "net/http/pprof"
	"os"
	"os/signal"
	"runtime"
	"runtime/pprof"
	"strconv"
	"strings"
	"syscall"

	"github.com/boltdb/bolt"
	"github.com/cenkalti/boltbrowser/boltbrowser"
	clog "github.com/cenkalti/log"
	"github.com/cenkalti/rain/internal/console"
	"github.com/cenkalti/rain/internal/logger"
	"github.com/cenkalti/rain/rainrpc"
	"github.com/cenkalti/rain/torrent"
	"github.com/hokaccha/go-prettyjson"
	"github.com/mitchellh/go-homedir"
	"github.com/urfave/cli"
	"github.com/zeebo/bencode"
	"gopkg.in/yaml.v2"
)

var (
	app = cli.NewApp()
	clt *rainrpc.Client
	log = logger.New("rain")
)

func main() {
	app.Version = torrent.Version
	app.Usage = "BitTorrent client"
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Usage: "read config from `FILE`",
		},
		cli.StringFlag{
			Name:   "cpuprofile",
			Hidden: true,
			Usage:  "write cpu profile to `FILE`",
		},
		cli.StringFlag{
			Name:   "memprofile",
			Hidden: true,
			Usage:  "write memory profile to `FILE`",
		},
		cli.IntFlag{
			Name:   "blockprofile",
			Hidden: true,
			Usage:  "enable blocking profiler",
		},
		cli.StringFlag{
			Name:   "pprof",
			Hidden: true,
			Usage:  "run pprof server on `ADDR`",
		},
		cli.BoolFlag{
			Name:  "debug, d",
			Usage: "enable debug log",
		},
	}
	app.Before = handleBeforeCommand
	app.After = handleAfterCommand
	app.Commands = []cli.Command{
		{
			Name:  "server",
			Usage: "run rpc server and torrent client",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "config",
					Usage: "path to the config file",
					Value: "~/rain/config.yaml",
				},
			},
			Action: handleServer,
		},
		{
			Name:  "client",
			Usage: "send rpc request to server",
			Flags: []cli.Flag{
				cli.StringFlag{
					Name:  "url",
					Usage: "URL of RPC server",
					Value: "http://127.0.0.1:" + strconv.Itoa(torrent.DefaultConfig.RPCPort),
				},
			},
			Before: handleBeforeClient,
			Subcommands: []cli.Command{
				{
					Name:   "version",
					Usage:  "server version",
					Action: handleVersion,
				},
				{
					Name:   "list",
					Usage:  "list torrents",
					Action: handleList,
				},
				{
					Name:   "add",
					Usage:  "add torrent or magnet",
					Action: handleAdd,
					Flags: []cli.Flag{
						cli.BoolFlag{
							Name: "stopped",
						},
						cli.StringFlag{
							Name: "id",
						},
					},
				},
				{
					Name:   "remove",
					Usage:  "remove torrent",
					Action: handleRemove,
				},
				{
					Name:   "stats",
					Usage:  "get stats of torrent",
					Action: handleStats,
				},
				{
					Name:   "session-stats",
					Usage:  "get stats of session",
					Action: handleSessionStats,
				},
				{
					Name:   "trackers",
					Usage:  "get trackers of torrent",
					Action: handleTrackers,
				},
				{
					Name:   "peers",
					Usage:  "get peers of torrent",
					Action: handlePeers,
				},
				{
					Name:   "add-peer",
					Usage:  "add peer to torrent",
					Action: handleAddPeer,
				},
				{
					Name:   "add-tracker",
					Usage:  "add tracker to torrent",
					Action: handleAddTracker,
				},
				{
					Name:   "start",
					Usage:  "start torrent",
					Action: handleStart,
				},
				{
					Name:   "stop",
					Usage:  "stop torrent",
					Action: handleStop,
				},
				{
					Name:   "start-all",
					Usage:  "start all torrents",
					Action: handleStartAll,
				},
				{
					Name:   "stop-all",
					Usage:  "stop all torrents",
					Action: handleStopAll,
				},
				{
					Name:   "console",
					Usage:  "show client console",
					Action: handleConsole,
				},
			},
		},
		{
			Name:   "boltbrowser",
			Hidden: true,
			Action: handleBoltBrowser,
		},
		{
			Name:  "torrent",
			Usage: "manage torrent files",
			Subcommands: []cli.Command{
				{
					Name:   "show",
					Usage:  "show contents of the torrent file",
					Action: handleTorrentShow,
				},
			},
		},
	}
	err := app.Run(os.Args)
	if err != nil {
		log.Fatal(err)
	}
}

func handleBoltBrowser(c *cli.Context) error {
	db, err := bolt.Open(c.Args().Get(0), 0600, nil)
	if err != nil {
		return err
	}
	boltbrowser.Browse(db, false)
	return db.Close()
}

func handleBeforeCommand(c *cli.Context) error {
	cpuprofile := c.GlobalString("cpuprofile")
	if cpuprofile != "" {
		f, err := os.Create(cpuprofile)
		if err != nil {
			log.Fatal("could not create CPU profile: ", err)
		}
		if err := pprof.StartCPUProfile(f); err != nil {
			log.Fatal("could not start CPU profile: ", err)
		}
	}
	pprofFlag := c.GlobalString("pprof")
	if pprofFlag != "" {
		go func() {
			log.Notice(http.ListenAndServe(pprofFlag, nil))
		}()
	}
	blockProfile := c.GlobalInt("blockprofile")
	if blockProfile != 0 {
		runtime.SetBlockProfileRate(blockProfile)
	}
	if c.GlobalBool("debug") {
		logger.SetLevel(clog.DEBUG)
	}
	return nil
}

func handleAfterCommand(c *cli.Context) error {
	if c.GlobalString("cpuprofile") != "" {
		pprof.StopCPUProfile()
	}
	return nil
}

func handleServer(c *cli.Context) error {
	cfg := torrent.DefaultConfig

	configPath := c.String("config")
	if configPath != "" {
		cp, err := homedir.Expand(configPath)
		if err != nil {
			return err
		}
		b, err := ioutil.ReadFile(cp) // nolint: gosec
		switch {
		case os.IsNotExist(err):
			log.Noticef("config file not found at %q, using default config", cp)
		case err != nil:
			return err
		default:
			err = yaml.Unmarshal(b, &cfg)
			if err != nil {
				return err
			}
			log.Infoln("config loaded from:", cp)
			b, err = yaml.Marshal(&cfg)
			if err != nil {
				return err
			}
			log.Debug("\n" + string(b))
		}
	}

	ses, err := torrent.NewSession(cfg)
	if err != nil {
		return err
	}
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM)
	s := <-ch
	log.Noticef("received %s, stopping server", s)

	memprofile := c.GlobalString("memprofile")
	if memprofile != "" {
		f, err := os.Create(memprofile)
		if err != nil {
			log.Fatal(err)
		}
		err = pprof.WriteHeapProfile(f)
		if err != nil {
			log.Fatal(err)
		}
		err = f.Close()
		if err != nil {
			log.Fatal(err)
		}
	}

	return ses.Close()
}

func handleBeforeClient(c *cli.Context) error {
	clt = rainrpc.NewClient(c.String("url"))
	return nil
}

func handleVersion(c *cli.Context) error {
	version, err := clt.ServerVersion()
	if err != nil {
		return err
	}
	_, _ = os.Stdout.WriteString(version)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleList(c *cli.Context) error {
	resp, err := clt.ListTorrents()
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleAdd(c *cli.Context) error {
	var b []byte
	var marshalErr error
	arg := c.Args().Get(0)
	addOpt := &rainrpc.AddTorrentOptions{
		Stopped: c.Bool("stopped"),
		ID:      c.String("id"),
	}
	if strings.HasPrefix(arg, "magnet:") || strings.HasPrefix(arg, "http://") || strings.HasPrefix(arg, "https://") {
		resp, err := clt.AddURI(arg, addOpt)
		if err != nil {
			return err
		}
		b, marshalErr = prettyjson.Marshal(resp)
	} else {
		f, err := os.Open(arg) // nolint: gosec
		if err != nil {
			return err
		}
		resp, err := clt.AddTorrent(f, addOpt)
		_ = f.Close()
		if err != nil {
			return err
		}
		b, marshalErr = prettyjson.Marshal(resp)
	}
	if marshalErr != nil {
		return marshalErr
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleRemove(c *cli.Context) error {
	id := c.Args().Get(0)
	return clt.RemoveTorrent(id)
}

func handleStats(c *cli.Context) error {
	id := c.Args().Get(0)
	resp, err := clt.GetTorrentStats(id)
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleSessionStats(c *cli.Context) error {
	resp, err := clt.GetSessionStats()
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleTrackers(c *cli.Context) error {
	id := c.Args().Get(0)
	resp, err := clt.GetTorrentTrackers(id)
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handlePeers(c *cli.Context) error {
	id := c.Args().Get(0)
	resp, err := clt.GetTorrentPeers(id)
	if err != nil {
		return err
	}
	b, err := prettyjson.Marshal(resp)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}

func handleAddPeer(c *cli.Context) error {
	id := c.Args().Get(0)
	addr := c.Args().Get(1)
	return clt.AddPeer(id, addr)
}

func handleAddTracker(c *cli.Context) error {
	id := c.Args().Get(0)
	uri := c.Args().Get(1)
	return clt.AddTracker(id, uri)
}

func handleStart(c *cli.Context) error {
	id := c.Args().Get(0)
	return clt.StartTorrent(id)
}

func handleStop(c *cli.Context) error {
	id := c.Args().Get(0)
	return clt.StopTorrent(id)
}

func handleStartAll(c *cli.Context) error {
	return clt.StartAllTorrents()
}

func handleStopAll(c *cli.Context) error {
	return clt.StopAllTorrents()
}

func handleConsole(c *cli.Context) error {
	con := console.New(clt)
	return con.Run()
}

func handleTorrentShow(c *cli.Context) error {
	arg := c.Args().Get(0)
	f, err := os.Open(arg) // nolint: gosec
	if err != nil {
		return err
	}
	defer f.Close()

	val := make(map[string]interface{})
	err = bencode.NewDecoder(f).Decode(&val)
	if err != nil {
		return err
	}
	if info, ok := val["info"].(map[string]interface{}); ok {
		if pieces, ok := info["pieces"].(string); ok {
			info["pieces"] = fmt.Sprintf("<<< %d bytes of data >>>", len(pieces))
		}
	}
	b, err := prettyjson.Marshal(val)
	if err != nil {
		return err
	}
	_, _ = os.Stdout.Write(b)
	_, _ = os.Stdout.WriteString("\n")
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"code.google.com/p/go.exp/fsnotify"
)

func handleArgs(args []string) (path string, recursive bool)  {
	// Exists with a status code of 1 on parsing error with a message
	var err error = nil

	if len(args) != 2 {
		fmt.Println("Not enough args")
		os.Exit(1)
	}

	// Like python's os.path.exists(path)
	if _, err = os.Stat(args[0]); os.IsNotExist(err) {
		fmt.Printf("no such file or directory: %s\n", args[0])
		//fmt.Println(err)
		os.Exit(1)
	} else {
		path = args[0]
	}

	if args[1] == "true" {
		recursive = true
	} else if args[1] == "false" {
		recursive = false
	} else {
		fmt.Println("Second argument must be 'true' or 'false'")
		os.Exit(1)
	}

	return path, recursive
}

type Command struct {
	path         string
	removeWatchP bool
	addWatchP    bool
	exitP        bool
}

func main() {

	path, recursive := handleArgs(os.Args[1:])

	manager := make(chan *Command)

	AddWatch(path, recursive, manager)

	//HandleEvents? or do this in the above and have main deal with SIGNALS and etc

}
<commit_msg>Event handling is in main while I work on a more complex event handling function.<commit_after>package main

import (
	"fmt"
	"os"

	//"code.google.com/p/go.exp/fsnotify"
)

func handleArgs(args []string) (path string, recursive bool)  {
	// Exists with a status code of 1 on parsing error with a message
	var err error = nil

	if len(args) != 2 {
		fmt.Println("Not enough args")
		os.Exit(1)
	}

	// Like python's os.path.exists(path)
	if _, err = os.Stat(args[0]); os.IsNotExist(err) {
		fmt.Printf("no such file or directory: %s\n", args[0])
		//fmt.Println(err)
		os.Exit(1)
	} else {
		path = args[0]
	}

	if args[1] == "true" {
		recursive = true
	} else if args[1] == "false" {
		recursive = false
	} else {
		fmt.Println("Second argument must be 'true' or 'false'")
		os.Exit(1)
	}

	return path, recursive
}

type Command struct {
	path         string
	// should status codes be used or should the function be passed?
	removeWatchP bool
	addWatchP    bool
	exitP        bool
}

func main() {

	path, recursive := handleArgs(os.Args[1:])

	//manager := make(chan *Command)

	watcher, watchCount, err := StartWatch(path, recursive)
	if err != nil {
		fmt.Println("Error with watcher, main.go line 59:", err)
	}
	fmt.Println(watchCount)

	//go HandleWatch(watcher, manager)

	for {
		select {
		case ev := <-watcher.Event:
			fmt.Println(ev)
		case err := <- watcher.Error:
			fmt.Println(err)
		}
	}
	//HandleEvents? or do this in the above and have main deal with SIGNALS and etc

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"

	"strings"

	"github.com/hackebrot/go-librariesio/librariesio"
)

func loadFromEnv(keys ...string) (map[string]string, error) {
	env := make(map[string]string)

	for _, key := range keys {
		v := os.Getenv(key)
		if v == "" {
			return nil, fmt.Errorf("environment variable %q is required", key)
		}
		env[key] = v
	}

	return env, nil
}

func main() {
	env, err := loadFromEnv("LIBRARIESIO_API_KEY")

	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	c := librariesio.NewClient(strings.TrimSpace(env["LIBRARIESIO_API_KEY"]))
	project, _, err := c.GetProject("pypi", "cookiecutter")

	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	fmt.Fprintf(os.Stdout, "%+v\n", project)
}
<commit_msg>Update cmd to pass context to request<commit_after>package main

import (
	"context"
	"fmt"
	"os"
	"time"

	"strings"

	"github.com/hackebrot/go-librariesio/librariesio"
)

func loadFromEnv(keys ...string) (map[string]string, error) {
	env := make(map[string]string)

	for _, key := range keys {
		v := os.Getenv(key)
		if v == "" {
			return nil, fmt.Errorf("environment variable %q is required", key)
		}
		env[key] = v
	}

	return env, nil
}

func main() {
	env, err := loadFromEnv("LIBRARIESIO_API_KEY")

	if err != nil {
		fmt.Fprintf(os.Stderr, "error: %v\n", err)
		os.Exit(1)
	}

	c := librariesio.NewClient(strings.TrimSpace(env["LIBRARIESIO_API_KEY"]))

	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()

	project, _, err := c.GetProject(ctx, "pypi", "cookiecutter")

	if err != nil {
		fmt.Fprintf(os.Stderr, "%v\n", err)
		os.Exit(1)
	}
	fmt.Fprintf(os.Stdout, "%+v\n", project)
}
<|endoftext|>


<commit_before>package main

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

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
)

var (
	logging    = flag.Bool("log", false, "Enable logging")
	filepath   = flag.String("path", "", "Path to file")
	bucket     = flag.String("bucket", "", "Specify S3 bucket")
	region     = flag.String("region", "us-east-1", "Set S3 region")
	rename     = flag.String("rename", "", "Set a new name for file")
	uploadpath = flag.String("uploadto", "/", "Set a specific path for a file inside S3 bucket")
)

func main() {
	flag.Parse()
	if *filepath == "" || *bucket == "" {
		fmt.Println("Please specify correct parameters!")
		fmt.Println("You should specify:")
		fmt.Println("-path with path to file you want to upload")
		fmt.Println("-bucket name of bucket in S3 where you want to upload")
		os.Exit(1)
	}

	file, err := os.Open(*filepath)
	if err != nil {
		log.Fatal("Failed to open a file with an error: ", err)
	}

	session := session.New(createConfig())
	service := s3manager.NewUploader(session)

	uploadFile(*service, *bucket, *uploadpath + getFileName(*filepath), file)
}

func uploadFile(uploader s3manager.Uploader, bucket, key string, file io.Reader) {
	resp, err := uploader.Upload(&s3manager.UploadInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
		Body:   file,
	})
	if err != nil {
		log.Println("Failed to upload a file because of: ", err)
		return
	}
	fmt.Println("File was successfully uploaded! Location: ", resp.Location)
}

func getFileName(filepath string) string {
	if *rename != "" {
		return *rename
	} else {
		index := strings.LastIndex(filepath, "/")
		if index != -1 {
			return filepath[index+1:]
		} else {
			return ""
		}
	}
}

func createConfig() *aws.Config {
	config := aws.NewConfig()
	config.WithCredentials(credentials.NewEnvCredentials())
	config.WithRegion(*region)
	if *logging {
		config.WithLogLevel(aws.LogDebugWithHTTPBody)
	}
	return config
}
<commit_msg>go fmt fixes<commit_after>package main

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

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/credentials"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/s3/s3manager"
)

var (
	logging    = flag.Bool("log", false, "Enable logging")
	filepath   = flag.String("path", "", "Path to file")
	bucket     = flag.String("bucket", "", "Specify S3 bucket")
	region     = flag.String("region", "us-east-1", "Set S3 region")
	rename     = flag.String("rename", "", "Set a new name for file")
	uploadpath = flag.String("uploadto", "/", "Set a specific path for a file inside S3 bucket")
)

func main() {
	flag.Parse()
	if *filepath == "" || *bucket == "" {
		fmt.Println("Please specify correct parameters!")
		fmt.Println("You should specify:")
		fmt.Println("-path with path to file you want to upload")
		fmt.Println("-bucket name of bucket in S3 where you want to upload")
		os.Exit(1)
	}

	file, err := os.Open(*filepath)
	if err != nil {
		log.Fatal("Failed to open a file with an error: ", err)
	}

	session := session.New(createConfig())
	service := s3manager.NewUploader(session)

	uploadFile(*service, *bucket, *uploadpath+getFileName(*filepath), file)
}

func uploadFile(uploader s3manager.Uploader, bucket, key string, file io.Reader) {
	resp, err := uploader.Upload(&s3manager.UploadInput{
		Bucket: aws.String(bucket),
		Key:    aws.String(key),
		Body:   file,
	})
	if err != nil {
		log.Println("Failed to upload a file because of: ", err)
		return
	}
	fmt.Println("File was successfully uploaded! Location: ", resp.Location)
}

func getFileName(filepath string) string {
	if *rename != "" {
		return *rename
	} else {
		index := strings.LastIndex(filepath, "/")
		if index != -1 {
			return filepath[index+1:]
		} else {
			return ""
		}
	}
}

func createConfig() *aws.Config {
	config := aws.NewConfig()
	config.WithCredentials(credentials.NewEnvCredentials())
	config.WithRegion(*region)
	if *logging {
		config.WithLogLevel(aws.LogDebugWithHTTPBody)
	}
	return config
}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"github.com/libgit2/git2go"
	"github.com/urfave/cli"
	"os"
)

var gs *gitSeekret

func main() {
	app := cli.NewApp()

	app.Name = "git-seekret"
	app.Version = "0.0.1"
	app.Usage = "TBD"

	app.Author = "Albert Puigsech Galicia"
	app.Email = "albert@puigsech.com"

	app.EnableBashCompletion = false

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name: "global",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:	"config",
			Usage:  "TBD",
			Action:   GitSeekretConfig,
			Flags: 	[]cli.Flag {
				cli.BoolFlag{
					Name: "init",
					Usage: "TBD",
				},
				cli.StringFlag{
					Name:  "set, s",
					Usage: "TBD",
					Value: "",
				},
			},
		},
		{
			Name: "rules",
			Usage: "Manage rules",
			Action: GitSeekretRules,
			Flags: 	[]cli.Flag {
				cli.StringFlag{
					Name:  "enable, e",
					Usage: "TBD",
					Value: "",
				},
				cli.StringFlag{
					Name:  "disable, d",
					Usage: "TBD",
					Value: "",
				},
			},
		},
		{
			Name:     "check",
			Usage:    "TBD",
			Action:   GitSeekretCheck,
			Flags: 	[]cli.Flag {
				cli.IntFlag{
					Name:  "commit, c",
					Usage: "inspect commited files. Argument is the number of commits to inspect (0 = all)",
					Value: 0,
				},
				cli.BoolFlag{
					Name:  "staged, s",
					Usage: "inspect staged files",
				},
			},
		},
		{
			Name: "hook",
			Usage: "TBD",
			Action:   GitSeekretHook,
			Flags: 	[]cli.Flag {
				cli.StringFlag{
					Name:  "run, r",
					Usage: "TBD",
					Value: "",
				},
				cli.StringFlag{
					Name:  "enable, e",
					Usage: "TBD",
					Value: "",
				},
				cli.StringFlag{
					Name:  "disable, d",
					Usage: "TBD",
					Value: "",
				},
				cli.BoolFlag{
					Name:  "enable-all",
					Usage: "TBD",
				},
				cli.BoolFlag{
					Name:  "disable-all",
					Usage: "TBD",
				},
			},
		},
	}

	app.Before = gitSeekretBefore
	app.After = gitSeekretAfter

	app.Run(os.Args)
}

func gitSeekretBefore(c *cli.Context) error {
	var configLevel git.ConfigLevel
	var err error

	if c.Bool("global") {
		configLevel = git.ConfigLevelGlobal
	} else {
		configLevel = git.ConfigLevelLocal
	}

	_ = configLevel

	gs,err = NewGitSeekret(".")
	if err != nil {
		log.Panic(err)
	}

	return nil
}

func gitSeekretAfter(c *cli.Context) error {
	return nil
}<commit_msg>add usage for most common actions and parameters<commit_after>package main

import (
	"log"
	"github.com/libgit2/git2go"
	"github.com/urfave/cli"
	"os"
)

var gs *gitSeekret

func main() {
	app := cli.NewApp()

	app.Name = "git-seekret"
	app.Version = "0.0.1"
	app.Usage = "TBD"

	app.Author = "Albert Puigsech Galicia"
	app.Email = "albert@puigsech.com"

	app.EnableBashCompletion = false

	app.Flags = []cli.Flag{
		cli.BoolFlag{
			Name: "global",
		},
	}
	app.Commands = []cli.Command{
		{
			Name:	"config",
			Usage:  "manage configuration seetings",
			Action:   GitSeekretConfig,
			Flags: 	[]cli.Flag {
				cli.BoolFlag{
					Name: "init",
					Usage: "initialize configuration with default values",
				},
				cli.StringFlag{
					Name:  "set, s",
					Usage: "set value for specific setting",
					Value: "",
				},
			},
		},
		{
			Name: "rules",
			Usage: "manage rules",
			Action: GitSeekretRules,
			Flags: 	[]cli.Flag {
				cli.StringFlag{
					Name:  "enable, e",
					Usage: "enable rules",
					Value: "",
				},
				cli.StringFlag{
					Name:  "disable, d",
					Usage: "disable rule",
					Value: "",
				},
			},
		},
		{
			Name:     "check",
			Usage:    "inspect git repository",
			Action:   GitSeekretCheck,
			Flags: 	[]cli.Flag {
				cli.IntFlag{
					Name:  "commit, c",
					Usage: "include commited files. Argument is the number of commits to inspect (0 = all)",
					Value: 0,
				},
				cli.BoolFlag{
					Name:  "staged, s",
					Usage: "include staged files",
				},
			},
		},
		{
			Name: "hook",
			Usage: "TBD",
			Action:   GitSeekretHook,
			Flags: 	[]cli.Flag {
				cli.StringFlag{
					Name:  "run, r",
					Usage: "TBD",
					Value: "",
				},
				cli.StringFlag{
					Name:  "enable, e",
					Usage: "TBD",
					Value: "",
				},
				cli.StringFlag{
					Name:  "disable, d",
					Usage: "TBD",
					Value: "",
				},
				cli.BoolFlag{
					Name:  "enable-all",
					Usage: "TBD",
				},
				cli.BoolFlag{
					Name:  "disable-all",
					Usage: "TBD",
				},
			},
		},
	}

	app.Before = gitSeekretBefore
	app.After = gitSeekretAfter

	app.Run(os.Args)
}

func gitSeekretBefore(c *cli.Context) error {
	var configLevel git.ConfigLevel
	var err error

	if c.Bool("global") {
		configLevel = git.ConfigLevelGlobal
	} else {
		configLevel = git.ConfigLevelLocal
	}

	_ = configLevel

	gs,err = NewGitSeekret(".")
	if err != nil {
		log.Panic(err)
	}

	return nil
}

func gitSeekretAfter(c *cli.Context) error {
	return nil
}<|endoftext|>