<commit_before>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/gumieri/act/lib/editor"
	"github.com/gumieri/act/lib/git"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func commit(activity ActivityStruct) (timeEntry TimeEntryStruct, err error) {
	duration := activity.StoppedAt.Sub(activity.StartedAt)
	durationHour := float64(duration) / float64(time.Hour)

	timeEntry.IssueID = activity.IssueID
	timeEntry.ActivityID = activity.ActivityID
	timeEntry.Date = activity.StartedAt.Format("2006-01-02")
	timeEntry.Time = strconv.FormatFloat(durationHour, 'f', 2, 64)
	timeEntry.Comment = activity.Comment

	editorPath := viper.Get("editor")
	if editorPath != nil && timeEntry.Comment == "" {
		fileName := fmt.Sprintf("%d-comment", timeEntry.IssueID)

		helperText := fmt.Sprintf("\n\n# Issue #%d\n# Date: %s\n# Time elapsed: %s\n# Activity ID: %d", timeEntry.IssueID, timeEntry.Date, timeEntry.Time, timeEntry.ActivityID)

		timeEntry.Comment, err = editor.Open(editorPath.(string), fileName, helperText, true)

		if err != nil {
			return
		}
	}

	if timeEntry.ActivityID == 0 {
		timeEntry.ActivityID = viper.GetInt("default.activity_id")
	}

	// Validating ActivityID
	if timeEntry.ActivityID == 0 {
		err = errors.New("activity_id is missing")
		return
	}

	// Validating ActivityID
	if strings.Trim(timeEntry.Comment, "\n ") == "" {
		err = errors.New("You must inform a comment/description to the activity")
		return
	}

	// Sending the data to the Redmine
	payload := new(PayloadStruct)
	payload.TimeEntry = timeEntry

	marshal, err := json.Marshal(payload)

	if err != nil {
		return
	}

	url := fmt.Sprintf("http://%s/time_entries.json", viper.Get("redmine.url"))
	payloadMarshal := bytes.NewBuffer(marshal)
	request, err := http.NewRequest(http.MethodPost, url, payloadMarshal)

	if err != nil {
		return
	}

	request.Header.Add("X-Redmine-API-Key", viper.GetString("redmine.access_key"))
	request.Header.Add("Content-Type", "application/json")

	client := &http.Client{}

	response, err := client.Do(request)

	if err != nil {
		return
	}

	defer response.Body.Close()

	if response.StatusCode != http.StatusCreated {
		err = fmt.Errorf("%d", response.StatusCode)
	}

	return
}

func pushRun(cmd *cobra.Command, args []string) {
	var activities []ActivityStruct
	var loadPath string
	var err error

	gitPath := viper.Get("git.path")
	if gitPath != nil {
		loadPath, _ = git.TopLevelPath(gitPath.(string))
	}

	if loadPath == "" {
		loadPath = filepath.Dir(os.Args[0])
	}

	activitiesPath := path.Join(loadPath, ".activities")

	err = Load(activitiesPath, &activities)

	if err != nil {
		return
	}

	if len(activities) == 0 {
		return
	}

	for index, activity := range activities {
		timeEntry, err := commit(activity)

		if err != nil {
			log.Fatal(err)
		}

		activities = append(activities[:index], activities[index+1:]...)

		err = Save(activitiesPath, activities)

		if err != nil {
			log.Fatal(err)
		}

		log.Printf("Added %s hour(s) to the Issue #%d.", timeEntry.Time, timeEntry.IssueID)
	}
}

// pushCmd represents the push command
var pushCmd = &cobra.Command{
	Use:   "push",
	Short: "Update all stopped activities tracked by start/stop",
	Long:  `All activities that was started and stopped by 'act start' and 'act stop will be pushed.`,
	Run:   pushRun,
}

func init() {
	RootCmd.AddCommand(pushCmd)
}
<commit_msg>cmd push: Fix helper comment with the activity ID<commit_after>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// 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 cmd

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"log"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"github.com/gumieri/act/lib/editor"
	"github.com/gumieri/act/lib/git"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

func commit(activity ActivityStruct) (timeEntry TimeEntryStruct, err error) {
	duration := activity.StoppedAt.Sub(activity.StartedAt)
	durationHour := float64(duration) / float64(time.Hour)

	timeEntry.IssueID = activity.IssueID
	timeEntry.ActivityID = activity.ActivityID
	timeEntry.Date = activity.StartedAt.Format("2006-01-02")
	timeEntry.Time = strconv.FormatFloat(durationHour, 'f', 2, 64)
	timeEntry.Comment = activity.Comment

	if timeEntry.ActivityID == 0 {
		timeEntry.ActivityID = viper.GetInt("default.activity_id")
	}

	if timeEntry.ActivityID == 0 {
		err = errors.New("activity_id is missing")
		return
	}

	if strings.Trim(timeEntry.Comment, "\n ") == "" {
		err = errors.New("You must inform a comment/description to the activity")
		return
	}

	editorPath := viper.Get("editor")
	if editorPath != nil && timeEntry.Comment == "" {
		fileName := fmt.Sprintf("%d-comment", timeEntry.IssueID)

		helperText := fmt.Sprintf("\n\n# Issue #%d\n# Date: %s\n# Time elapsed: %s\n# Activity ID: %d", timeEntry.IssueID, timeEntry.Date, timeEntry.Time, timeEntry.ActivityID)

		timeEntry.Comment, err = editor.Open(editorPath.(string), fileName, helperText, true)

		if err != nil {
			return
		}
	}

	// Sending the data to the Redmine
	payload := new(PayloadStruct)
	payload.TimeEntry = timeEntry

	marshal, err := json.Marshal(payload)

	if err != nil {
		return
	}

	url := fmt.Sprintf("http://%s/time_entries.json", viper.Get("redmine.url"))
	payloadMarshal := bytes.NewBuffer(marshal)
	request, err := http.NewRequest(http.MethodPost, url, payloadMarshal)

	if err != nil {
		return
	}

	request.Header.Add("X-Redmine-API-Key", viper.GetString("redmine.access_key"))
	request.Header.Add("Content-Type", "application/json")

	client := &http.Client{}

	response, err := client.Do(request)

	if err != nil {
		return
	}

	defer response.Body.Close()

	if response.StatusCode != http.StatusCreated {
		err = fmt.Errorf("%d", response.StatusCode)
	}

	return
}

func pushRun(cmd *cobra.Command, args []string) {
	var activities []ActivityStruct
	var loadPath string
	var err error

	gitPath := viper.Get("git.path")
	if gitPath != nil {
		loadPath, _ = git.TopLevelPath(gitPath.(string))
	}

	if loadPath == "" {
		loadPath = filepath.Dir(os.Args[0])
	}

	activitiesPath := path.Join(loadPath, ".activities")

	err = Load(activitiesPath, &activities)

	if err != nil {
		return
	}

	if len(activities) == 0 {
		return
	}

	for index, activity := range activities {
		timeEntry, err := commit(activity)

		if err != nil {
			log.Fatal(err)
		}

		activities = append(activities[:index], activities[index+1:]...)

		err = Save(activitiesPath, activities)

		if err != nil {
			log.Fatal(err)
		}

		log.Printf("Added %s hour(s) to the Issue #%d.", timeEntry.Time, timeEntry.IssueID)
	}
}

// pushCmd represents the push command
var pushCmd = &cobra.Command{
	Use:   "push",
	Short: "Update all stopped activities tracked by start/stop",
	Long:  `All activities that was started and stopped by 'act start' and 'act stop will be pushed.`,
	Run:   pushRun,
}

func init() {
	RootCmd.AddCommand(pushCmd)
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "casper",
	Short: "Casper",
	Long: `Configuration Automation for Safe and Painless Environment Releases

     .-----.
   .' -   - '.
  /  .-. .-.  \
  |  | | | |  |
   \ \o/ \o/ /
  _/    ^    \_
 | \  '---'  / |
 / /'--. .--'\ \
/ /'---' '---'\ \
'.__.       .__.'
    '|     |'
     |     \
     \      '--.
      '.        '\
        ''---.   |
           ,__) /
            '..'
	`,
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	RootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.AddConfigPath(".")
	viper.AutomaticEnv() // read in environment variables that match

	// Read config file
	if err := viper.ReadInConfig(); err != nil {
		fmt.Println("Error parsing config file:", err)
	}
}
<commit_msg>Stop looking for cfg in the current dir if explicitly passed<commit_after>package cmd

import (
	"fmt"
	"os"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "casper",
	Short: "Casper",
	Long: `Configuration Automation for Safe and Painless Environment Releases

     .-----.
   .' -   - '.
  /  .-. .-.  \
  |  | | | |  |
   \ \o/ \o/ /
  _/    ^    \_
 | \  '---'  / |
 / /'--. .--'\ \
/ /'---' '---'\ \
'.__.       .__.'
    '|     |'
     |     \
     \      '--.
      '.        '\
        ''---.   |
           ,__) /
            '..'
	`,
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	RootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	} else {
		viper.AddConfigPath(".")
	}

	viper.AutomaticEnv() // read in environment variables that match

	// Read config file
	if err := viper.ReadInConfig(); err != nil {
		fmt.Println("Error parsing config file:", err)
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"gitlab.com/littledot/mockhiato/lib"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "mockhiato",
	Short: "A mocking framework for Go",
	Long:  `A mocking framework for Go.`,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	// Run: func(cmd *cobra.Command, args []string) {
	// 	spew.Dump(viper.AllSettings())
	// },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		log.Fatal(err)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.
	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is mockhiato.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.PersistentFlags().BoolP("Verbose", "v", false, "Make some noise!")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName("mockhiato") // name of config file (without extension)
	viper.AddConfigPath(".")

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		log.Infof("Configuring mockhiato with %s", viper.ConfigFileUsed())
	}
}

func getConfig(cmd *cobra.Command) lib.Config {
	if err := viper.BindPFlags(cmd.Flags()); err != nil {
		panic(err)
	}
	config := lib.Config{}
	if err := viper.Unmarshal(&config); err != nil {
		panic(err)
	}
	if config.Verbose {
		log.SetLevel(log.DebugLevel)
	}
	log.Debugf("Configs: %#v", config)
	return config
}
<commit_msg>Ensure generated file names end with “.go”.<commit_after>package cmd

import (
	"strings"

	"gitlab.com/littledot/mockhiato/lib"

	log "github.com/sirupsen/logrus"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "mockhiato",
	Short: "A mocking framework for Go",
	Long:  `A mocking framework for Go.`,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	// Run: func(cmd *cobra.Command, args []string) {
	// 	spew.Dump(viper.AllSettings())
	// },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		log.Fatal(err)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	// Here you will define your flags and configuration settings.
	// Cobra supports Persistent Flags, which, if defined here,
	// will be global for your application.
	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is mockhiato.yaml)")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.PersistentFlags().BoolP("Verbose", "v", false, "Make some noise!")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" { // enable ability to specify config file via flag
		viper.SetConfigFile(cfgFile)
	}

	viper.SetConfigName("mockhiato") // name of config file (without extension)
	viper.AddConfigPath(".")

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		log.Infof("Configuring mockhiato with %s", viper.ConfigFileUsed())
	}
}

func getConfig(cmd *cobra.Command) lib.Config {
	if err := viper.BindPFlags(cmd.Flags()); err != nil {
		panic(err)
	}
	config := lib.Config{}
	if err := viper.Unmarshal(&config); err != nil {
		panic(err)
	}
	if config.Verbose {
		log.SetLevel(log.DebugLevel)
	}
	if !strings.HasSuffix(config.MockFileName, ".go") { // Ensure mock files end with ".go"
		config.MockFileName += ".go"
	}
	log.Debugf("Configs: %#v", config)
	return config
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"

	"github.com/cozy/cozy-stack/config"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "cozy",
	Short: "cozy is the main command",
	Long: `Cozy is a platform that brings all your web services in the same private space.
With it, your web apps and your devices can share data easily, providing you
with a new experience. You can install Cozy on your own hardware where no one
profiles you.`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := Configure(); err != nil {
			return err
		}

		// Display the usage/help by default
		return cmd.Help()
	},
	// Do not display usage on error
	SilenceUsage: true,
}

var cfgFile string

func init() {
	RootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is $HOME/.cozy.yaml)")

	RootCmd.PersistentFlags().StringP("mode", "m", "development", "server mode: development or production")
	viper.BindPFlag("mode", RootCmd.PersistentFlags().Lookup("mode"))

	RootCmd.PersistentFlags().StringP("address", "a", "localhost", "Address on which the server will listen")
	viper.BindPFlag("address", RootCmd.PersistentFlags().Lookup("address"))

	RootCmd.PersistentFlags().IntP("port", "p", 8080, "Port on which the server will listen")
	viper.BindPFlag("port", RootCmd.PersistentFlags().Lookup("port"))

	RootCmd.PersistentFlags().StringP("databaseUrl", "d", "http://localhost:5984", "Database to connect to")
	viper.BindPFlag("databaseUrl", RootCmd.PersistentFlags().Lookup("databaseUrl"))
}

// Configure Viper to read the environment and the optional config file
func Configure() error {
	viper.SetEnvPrefix("cozy")
	viper.AutomaticEnv()

	if cfgFile != "" {
		// Read given config file and skip other paths
		viper.SetConfigFile(cfgFile)
	} else {
		viper.SetConfigName(".cozy")
		viper.AddConfigPath("/etc/cozy")
		viper.AddConfigPath("$HOME")
		viper.AddConfigPath(".")
	}

	err := viper.ReadInConfig()

	if err != nil {
		if _, ok := err.(viper.ConfigParseError); ok {
			return err
		}

		if cfgFile != "" {
			return fmt.Errorf("Unable to locate config file: %s\n", cfgFile)
		}
	}

	if viper.ConfigFileUsed() != "" {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}

	config.UseViper(viper.GetViper())

	return nil
}
<commit_msg>Rename the command name from `cozy` to `cozy-stack`<commit_after>package cmd

import (
	"fmt"

	"github.com/cozy/cozy-stack/config"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "cozy-stack",
	Short: "cozy-stack is the main command",
	Long: `Cozy is a platform that brings all your web services in the same private space.
With it, your web apps and your devices can share data easily, providing you
with a new experience. You can install Cozy on your own hardware where no one
profiles you.`,
	RunE: func(cmd *cobra.Command, args []string) error {
		if err := Configure(); err != nil {
			return err
		}

		// Display the usage/help by default
		return cmd.Help()
	},
	// Do not display usage on error
	SilenceUsage: true,
}

var cfgFile string

func init() {
	RootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "config file (default is $HOME/.cozy.yaml)")

	RootCmd.PersistentFlags().StringP("mode", "m", "development", "server mode: development or production")
	viper.BindPFlag("mode", RootCmd.PersistentFlags().Lookup("mode"))

	RootCmd.PersistentFlags().StringP("address", "a", "localhost", "Address on which the server will listen")
	viper.BindPFlag("address", RootCmd.PersistentFlags().Lookup("address"))

	RootCmd.PersistentFlags().IntP("port", "p", 8080, "Port on which the server will listen")
	viper.BindPFlag("port", RootCmd.PersistentFlags().Lookup("port"))

	RootCmd.PersistentFlags().StringP("databaseUrl", "d", "http://localhost:5984", "Database to connect to")
	viper.BindPFlag("databaseUrl", RootCmd.PersistentFlags().Lookup("databaseUrl"))
}

// Configure Viper to read the environment and the optional config file
func Configure() error {
	viper.SetEnvPrefix("cozy")
	viper.AutomaticEnv()

	if cfgFile != "" {
		// Read given config file and skip other paths
		viper.SetConfigFile(cfgFile)
	} else {
		viper.SetConfigName(".cozy")
		viper.AddConfigPath("/etc/cozy")
		viper.AddConfigPath("$HOME")
		viper.AddConfigPath(".")
	}

	err := viper.ReadInConfig()

	if err != nil {
		if _, ok := err.(viper.ConfigParseError); ok {
			return err
		}

		if cfgFile != "" {
			return fmt.Errorf("Unable to locate config file: %s\n", cfgFile)
		}
	}

	if viper.ConfigFileUsed() != "" {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}

	config.UseViper(viper.GetViper())

	return nil
}
<|endoftext|>


<commit_before>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
// 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 cmd

import (
	"fmt"
	"os"

	homedir "github.com/mitchellh/go-homedir"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "json2yaml",
	Short: "Convert json to yaml",
	Long: `Convert json to yaml either from stdin or from a file`,
	// Uncomment the following line if your bare application
	// has an action associated with it:
	Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)

	// Here you will define your flags and configuration settings.
	// Cobra supports persistent flags, which, if defined here,
	// will be global for your application.
	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.json2yaml.yaml)")

	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("compact", "c", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if cfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(cfgFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		// Search config in home directory with name ".json2yaml" (without extension).
		viper.AddConfigPath(home)
		viper.SetConfigName(".json2yaml")
	}

	viper.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<commit_msg>Cobra comments cleanup<commit_after>// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
// 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 cmd

import (
	"fmt"
	"os"

	homedir "github.com/mitchellh/go-homedir"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

var cfgFile string

var RootCmd = &cobra.Command{
	Use:   "json2yaml",
	Short: "Convert json to yaml",
	Long: `Convert json to yaml either from stdin or from a file`,
	Run: func(cmd *cobra.Command, args []string) { },
}

func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.json2yaml.yaml)")
}

func initConfig() {
	if cfgFile != "" {
		viper.SetConfigFile(cfgFile)
	} else {
		home, err := homedir.Dir()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}

		viper.AddConfigPath(home)
		viper.SetConfigName(".json2yaml")
	}

	viper.AutomaticEnv()

	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"text/template"
)

// HookContext are the variables available during hook template evaluation
type HookContext struct {
	// SelfPath is the unescaped absolute path to direnv
	SelfPath string
}

// CmdHook is `direnv hook $0`
var CmdHook = &Cmd{
	Name:   "hook",
	Desc:   "Used to setup the shell hook",
	Args:   []string{"SHELL"},
	Action: actionSimple(cmdHookAction),
}

func cmdHookAction(env Env, args []string) (err error) {
	var target string

	if len(args) > 1 {
		target = args[1]
	}

	selfPath, err := os.Executable()
	if err != nil {
		return err
	}

	ctx := HookContext{selfPath}

	shell := DetectShell(target)
	if shell == nil {
		return fmt.Errorf("unknown target shell '%s'", target)
	}

	hookStr, err := shell.Hook()
	if err != nil {
		return err
	}

	hookTemplate, err := template.New("hook").Parse(hookStr)
	if err != nil {
		return err
	}

	err = hookTemplate.Execute(os.Stdout, ctx)
	if err != nil {
		return err
	}

	return
}
<commit_msg>Make direnv hook output work on Windows (#632)<commit_after>package main

import (
	"fmt"
	"os"
	"strings"
	"text/template"
)

// HookContext are the variables available during hook template evaluation
type HookContext struct {
	// SelfPath is the unescaped absolute path to direnv
	SelfPath string
}

// CmdHook is `direnv hook $0`
var CmdHook = &Cmd{
	Name:   "hook",
	Desc:   "Used to setup the shell hook",
	Args:   []string{"SHELL"},
	Action: actionSimple(cmdHookAction),
}

func cmdHookAction(env Env, args []string) (err error) {
	var target string

	if len(args) > 1 {
		target = args[1]
	}

	selfPath, err := os.Executable()
	if err != nil {
		return err
	}

	// Convert Windows path if needed
	selfPath = strings.Replace(selfPath, "\\", "/", -1)
	ctx := HookContext{selfPath}

	shell := DetectShell(target)
	if shell == nil {
		return fmt.Errorf("unknown target shell '%s'", target)
	}

	hookStr, err := shell.Hook()
	if err != nil {
		return err
	}

	hookTemplate, err := template.New("hook").Parse(hookStr)
	if err != nil {
		return err
	}

	err = hookTemplate.Execute(os.Stdout, ctx)
	if err != nil {
		return err
	}

	return
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/template"
	"time"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
	"github.com/gonuts/gas"
	"github.com/gonuts/logger"
	"github.com/lhcb-org/lbx/lbx"
)

func lbx_make_cmd_init() *commander.Command {
	cmd := &commander.Command{
		Run:       lbx_run_cmd_init,
		UsageLine: "init [options] <project-name> <project-version>",
		Short:     "initialize a local development project.",
		Long: `
init initialize a local development project.

ex:
 $ lbx init Gaudi trunk
 $ lbx init -name mydev Gaudi trunk
`,
		Flag: *flag.NewFlagSet("lbx-init", flag.ExitOnError),
	}
	add_output_level(cmd)
	add_search_path(cmd)
	add_platform(cmd)

	cmd.Flag.String("name", "", "name of the local project (default: <project>Dev_<version>)")
	return cmd
}

func lbx_run_cmd_init(cmd *commander.Command, args []string) error {
	var err error

	g_ctx.SetLevel(logger.Level(cmd.Flag.Lookup("lvl").Value.Get().(int)))

	proj := ""
	vers := ""

	switch len(args) {
	case 1:
		proj = args[0]
		vers = "trunk"
	case 2:
		proj = args[0]
		vers = args[1]
	default:
		g_ctx.Errorf("lbx-init: needs 2 args (project+version). got=%d\n", len(args))
		return fmt.Errorf("lbx-init: invalid number of arguments")
	}

	proj = lbx.FixProjectCase(proj)

	dirname := cmd.Flag.Lookup("name").Value.Get().(string)
	local_proj, local_vers := dirname, "HEAD"
	if dirname == "" {
		dirname = proj + "Dev_" + vers
		local_proj = proj + "Dev"
		local_vers = vers
	}

	usr_area := cmd.Flag.Lookup("user-area").Value.Get().(string)
	if usr_area == "" {
		g_ctx.Errorf("lbx-init: user area not defined (env.var. User_release_area or option -user-area)\n")
		return fmt.Errorf("lbx-init: user-area not defined")
	}
	local_projdir := filepath.Join(usr_area, dirname)
	if path_exists(local_projdir) {
		g_ctx.Errorf("lbx-init: directory %q already exists\n", local_projdir)
		return fmt.Errorf("lbx-init: invalid project dir")
	}

	platform := cmd.Flag.Lookup("c").Value.Get().(string)

	// prepend dev-dirs to the search path
	devdirs := cmd.Flag.Lookup("dev-dirs").Value.Get().(string)
	if devdirs != "" {
		g_ctx.ProjectsPath = append(strings.Split(devdirs, string(os.PathListSeparator)), g_ctx.ProjectsPath...)
	}

	g_ctx.Infof(">>> project=%q version=%q\n", proj, vers)
	g_ctx.Infof("local-proj=%q\n", local_proj)
	g_ctx.Infof("local-vers=%q\n", local_vers)
	g_ctx.Infof("local-dir=%q\n", local_projdir)
	g_ctx.Infof("platform=%q\n", platform)

	projdir, err := g_ctx.FindProject(proj, vers, platform)
	if err != nil {
		g_ctx.Errorf("lbx-init: problem finding project: %v\n", err)
		return err
	}
	g_ctx.Infof("using [%s] [%s] from [%s]\n", proj, vers, projdir)

	use_cmake := path_exists(filepath.Join(projdir, proj+"Config.cmake"))
	if !use_cmake {
		g_ctx.Warnf("%s %s does NOT seem to be a CMake-based project\n", proj, vers)
	}

	// create the local dev project
	if !path_exists(usr_area) {
		g_ctx.Debugf("creating user release area directory [%s]\n", usr_area)
		err = os.MkdirAll(usr_area, 0755)
		if err != nil {
			g_ctx.Errorf("lbx-init: problem creating user release area directory: %v\n", err)
			return err
		}
	}

	g_ctx.Debugf("creating local dev directory [%s]\n", local_projdir)
	err = os.MkdirAll(local_projdir, 0755)
	if err != nil {
		g_ctx.Errorf("lbx-init: problem creating local dev. directory: %v\n", err)
		return err
	}

	templates_dir, err := gas.Abs("github.com/lhcb-org/lbx/templates")
	if err != nil {
		g_ctx.Errorf("lbx-init: problem locating templates: %v\n", err)
		return err
	}
	templates := []string{
		"CMakeLists.txt", "toolchain.cmake", "Makefile",
		"searchPath.cmake",
	}

	data := map[string]interface{}{
		"Project":       proj,
		"Version":       vers,
		"SearchPath":    strings.Join(g_ctx.ProjectsPath, " "),
		"SearchPathEnv": strings.Join(g_ctx.ProjectsPath, string(os.PathListSeparator)),
		"UseCMake": func() string {
			if use_cmake {
				return "yes"
			}
			return ""
		}(),
		"PROJECT":      strings.ToUpper(proj),
		"LocalProject": local_proj,
		"LocalVersion": local_vers,
		"CMTProject":   dirname,
		"Slot":         "",
		"Day":          "",
	}

	if nightly := cmd.Flag.Lookup("nightly").Value.Get().(string); nightly != "" {
		templates = append(templates, "nightly.cmake")
		slice := strings.Split(nightly, ",")
		data["Slot"] = slice[0]
		if len(slice) > 1 {
			data["Day"] = slice[1]
		} else {
			data["Day"] = time.Now().Format("Mon")
		}
	}

	for _, tmpl := range templates {
		fname := filepath.Join(templates_dir, tmpl)
		t := template.Must(template.New(tmpl).ParseFiles(fname))
		oname := filepath.Join(local_projdir, tmpl)
		dest, err := os.Create(oname)
		if err != nil {
			g_ctx.Errorf("error creating file [%s]: %v\n", oname, err)
			return err
		}
		defer dest.Close()
		err = t.Execute(dest, data)
		if err != nil {
			g_ctx.Errorf("error running template: %v\n", err)
			return err
		}
	}
	return err
}
<commit_msg>init: add nightly handling<commit_after>package main

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"text/template"
	"time"

	"github.com/gonuts/commander"
	"github.com/gonuts/flag"
	"github.com/gonuts/gas"
	"github.com/gonuts/logger"
	"github.com/lhcb-org/lbx/lbx"
)

func lbx_make_cmd_init() *commander.Command {
	cmd := &commander.Command{
		Run:       lbx_run_cmd_init,
		UsageLine: "init [options] <project-name> <project-version>",
		Short:     "initialize a local development project.",
		Long: `
init initialize a local development project.

ex:
 $ lbx init Gaudi trunk
 $ lbx init -name mydev Gaudi trunk
`,
		Flag: *flag.NewFlagSet("lbx-init", flag.ExitOnError),
	}
	add_output_level(cmd)
	add_search_path(cmd)
	add_platform(cmd)

	cmd.Flag.String("name", "", "name of the local project (default: <project>Dev_<version>)")
	return cmd
}

func lbx_run_cmd_init(cmd *commander.Command, args []string) error {
	var err error

	g_ctx.SetLevel(logger.Level(cmd.Flag.Lookup("lvl").Value.Get().(int)))

	proj := ""
	vers := ""

	switch len(args) {
	case 1:
		proj = args[0]
		vers = "trunk"
	case 2:
		proj = args[0]
		vers = args[1]
	default:
		g_ctx.Errorf("lbx-init: needs 2 args (project+version). got=%d\n", len(args))
		return fmt.Errorf("lbx-init: invalid number of arguments")
	}

	proj = lbx.FixProjectCase(proj)

	dirname := cmd.Flag.Lookup("name").Value.Get().(string)
	local_proj, local_vers := dirname, "HEAD"
	if dirname == "" {
		dirname = proj + "Dev_" + vers
		local_proj = proj + "Dev"
		local_vers = vers
	}

	usr_area := cmd.Flag.Lookup("user-area").Value.Get().(string)
	if usr_area == "" {
		g_ctx.Errorf("lbx-init: user area not defined (env.var. User_release_area or option -user-area)\n")
		return fmt.Errorf("lbx-init: user-area not defined")
	}
	local_projdir := filepath.Join(usr_area, dirname)
	if path_exists(local_projdir) {
		g_ctx.Errorf("lbx-init: directory %q already exists\n", local_projdir)
		return fmt.Errorf("lbx-init: invalid project dir")
	}

	platform := cmd.Flag.Lookup("c").Value.Get().(string)

	if nightly := cmd.Flag.Lookup("nightly").Value.Get().(string); nightly != "" {
		slice := strings.Split(nightly, ",")
		slot := slice[0]
		day := time.Now().Format("Mon")
		if len(slice) > 1 {
			day = slice[1]
		}
		nightly_bases := []string{
			Getenv("LHCBNIGHTLIES", "/afs/cern.ch/lhcb/software/nightlies"),
			filepath.Clean(filepath.Join(Getenv("LCG_release_area", "/afs/cern.ch/sw/lcg/app/releases"), "..", "nightlies")),
		}
		slot_dir := ""
		for i := range nightly_bases {
			dir := filepath.Join(nightly_bases[i], slot)
			if path_exists(dir) {
				slot_dir = dir
				break
			}
		}
		if slot_dir == "" {
			err = fmt.Errorf("lbx-init: could not find slot %q in [%s].", slot, nightly_bases)
			g_ctx.Errorf("%v\n", err)
			return err
		}
		g_ctx.ProjectsPath = append([]string{filepath.Join(slot_dir, day)}, g_ctx.ProjectsPath...)
	}

	// prepend dev-dirs to the search path
	devdirs := cmd.Flag.Lookup("dev-dirs").Value.Get().(string)
	if devdirs != "" {
		g_ctx.ProjectsPath = append(strings.Split(devdirs, string(os.PathListSeparator)), g_ctx.ProjectsPath...)
	}

	g_ctx.Infof(">>> project=%q version=%q\n", proj, vers)
	g_ctx.Infof("local-proj=%q\n", local_proj)
	g_ctx.Infof("local-vers=%q\n", local_vers)
	g_ctx.Infof("local-dir=%q\n", local_projdir)
	g_ctx.Infof("platform=%q\n", platform)

	projdir, err := g_ctx.FindProject(proj, vers, platform)
	if err != nil {
		g_ctx.Errorf("lbx-init: problem finding project: %v\n", err)
		return err
	}
	g_ctx.Infof("using [%s] [%s] from [%s]\n", proj, vers, projdir)

	use_cmake := path_exists(filepath.Join(projdir, proj+"Config.cmake"))
	if !use_cmake {
		g_ctx.Warnf("%s %s does NOT seem to be a CMake-based project\n", proj, vers)
	}

	// create the local dev project
	if !path_exists(usr_area) {
		g_ctx.Debugf("creating user release area directory [%s]\n", usr_area)
		err = os.MkdirAll(usr_area, 0755)
		if err != nil {
			g_ctx.Errorf("lbx-init: problem creating user release area directory: %v\n", err)
			return err
		}
	}

	g_ctx.Debugf("creating local dev directory [%s]\n", local_projdir)
	err = os.MkdirAll(local_projdir, 0755)
	if err != nil {
		g_ctx.Errorf("lbx-init: problem creating local dev. directory: %v\n", err)
		return err
	}

	templates_dir, err := gas.Abs("github.com/lhcb-org/lbx/templates")
	if err != nil {
		g_ctx.Errorf("lbx-init: problem locating templates: %v\n", err)
		return err
	}
	templates := []string{
		"CMakeLists.txt", "toolchain.cmake", "Makefile",
		"searchPath.cmake",
	}

	data := map[string]interface{}{
		"Project":       proj,
		"Version":       vers,
		"SearchPath":    strings.Join(g_ctx.ProjectsPath, " "),
		"SearchPathEnv": strings.Join(g_ctx.ProjectsPath, string(os.PathListSeparator)),
		"UseCMake": func() string {
			if use_cmake {
				return "yes"
			}
			return ""
		}(),
		"PROJECT":      strings.ToUpper(proj),
		"LocalProject": local_proj,
		"LocalVersion": local_vers,
		"CMTProject":   dirname,
		"Slot":         "",
		"Day":          "",
	}

	if nightly := cmd.Flag.Lookup("nightly").Value.Get().(string); nightly != "" {
		templates = append(templates, "nightly.cmake")
		slice := strings.Split(nightly, ",")
		data["Slot"] = slice[0]
		if len(slice) > 1 {
			data["Day"] = slice[1]
		} else {
			data["Day"] = time.Now().Format("Mon")
		}
	}

	for _, tmpl := range templates {
		fname := filepath.Join(templates_dir, tmpl)
		t := template.Must(template.New(tmpl).ParseFiles(fname))
		oname := filepath.Join(local_projdir, tmpl)
		dest, err := os.Create(oname)
		if err != nil {
			g_ctx.Errorf("error creating file [%s]: %v\n", oname, err)
			return err
		}
		defer dest.Close()
		err = t.Execute(dest, data)
		if err != nil {
			g_ctx.Errorf("error running template: %v\n", err)
			return err
		}
	}
	return err
}
<|endoftext|>


<commit_before>package gmf

/*

#cgo pkg-config: libavcodec libavutil

#include <string.h>

#include "libavcodec/avcodec.h"
#include "libavutil/channel_layout.h"
#include "libavutil/samplefmt.h"
#include "libavutil/opt.h"
#include "libavutil/mem.h"

static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt) {
    const enum AVSampleFormat *p = codec->sample_fmts;

    while (*p != AV_SAMPLE_FMT_NONE) {
        if (*p == sample_fmt)
            return 1;
        p++;
    }
    return 0;
}

static int select_sample_rate(AVCodec *codec) {
    const int *p;
    int best_samplerate = 0;

    if (!codec->supported_samplerates)
        return 44100;

    p = codec->supported_samplerates;
    while (*p) {
        best_samplerate = FFMAX(*p, best_samplerate);
        p++;
    }
    return best_samplerate;
}

static int select_channel_layout(AVCodec *codec) {
    const uint64_t *p;
    uint64_t best_ch_layout = 0;
    int best_nb_channels    = 0;

    if (!codec->channel_layouts)
        return AV_CH_LAYOUT_STEREO;

    p = codec->channel_layouts;
    while (*p) {
        int nb_channels = av_get_channel_layout_nb_channels(*p);

        if (nb_channels > best_nb_channels) {
            best_ch_layout   = *p;
            best_nb_channels = nb_channels;
        }
        p++;
    }
    return best_ch_layout;
}

static void call_av_freep(AVCodecContext *out){
	return av_freep(&out);
}
*/
import "C"

import (
	"errors"
	"fmt"
	"unsafe"
	//	"log"
)

var (
	AV_CODEC_ID_MPEG1VIDEO int = C.AV_CODEC_ID_MPEG1VIDEO
	AV_CODEC_ID_MPEG2VIDEO int = C.AV_CODEC_ID_MPEG2VIDEO
	AV_CODEC_ID_H264       int = C.AV_CODEC_ID_H264
	AV_CODEC_ID_MPEG4      int = C.AV_CODEC_ID_MPEG4
	AV_CODEC_ID_JPEG2000   int = C.AV_CODEC_ID_JPEG2000
	AV_CODEC_ID_MJPEG      int = C.AV_CODEC_ID_MJPEG
	AV_CODEC_ID_MSMPEG4V1  int = C.AV_CODEC_ID_MSMPEG4V1
	AV_CODEC_ID_MSMPEG4V2  int = C.AV_CODEC_ID_MSMPEG4V2
	AV_CODEC_ID_MSMPEG4V3  int = C.AV_CODEC_ID_MSMPEG4V3
	AV_CODEC_ID_WMV1       int = C.AV_CODEC_ID_WMV1
	AV_CODEC_ID_WMV2       int = C.AV_CODEC_ID_WMV2
	AV_CODEC_ID_FLV1       int = C.AV_CODEC_ID_FLV1
	AV_CODEC_ID_PNG        int = C.AV_CODEC_ID_PNG
	AV_CODEC_ID_TIFF       int = C.AV_CODEC_ID_TIFF
	AV_CODEC_ID_GIF        int = C.AV_CODEC_ID_GIF

	CODEC_FLAG_GLOBAL_HEADER int   = C.CODEC_FLAG_GLOBAL_HEADER
	FF_MB_DECISION_SIMPLE    int   = C.FF_MB_DECISION_SIMPLE
	FF_MB_DECISION_BITS      int   = C.FF_MB_DECISION_BITS
	FF_MB_DECISION_RD        int   = C.FF_MB_DECISION_RD
	AV_SAMPLE_FMT_S16        int32 = C.AV_SAMPLE_FMT_S16
	AV_SAMPLE_FMT_S16P       int32 = C.AV_SAMPLE_FMT_S16P
)

type SampleFmt int

type CodecCtx struct {
	codec      *Codec
	avCodecCtx *C.struct_AVCodecContext
	CgoMemoryManage
}

func NewCodecCtx(codec *Codec, options ...[]*Option) *CodecCtx {
	result := &CodecCtx{codec: codec}

	codecctx := C.avcodec_alloc_context3(codec.avCodec)
	if codecctx == nil {
		return nil
	}

	C.avcodec_get_context_defaults3(codecctx, codec.avCodec)

	result.avCodecCtx = codecctx

	// we're really expecting only one options-array —
	// variadic arg is used for backward compatibility
	if len(options) == 1 {
		for _, option := range options[0] {
			option.Set(result.avCodecCtx)
		}
	}

	return result
}

func (this *CodecCtx) CopyExtra(ist *Stream) *CodecCtx {
	codec := this.avCodecCtx
	icodec := ist.CodecCtx().avCodecCtx

	codec.bits_per_raw_sample = icodec.bits_per_raw_sample
	codec.chroma_sample_location = icodec.chroma_sample_location

	codec.codec_id = icodec.codec_id
	codec.codec_type = icodec.codec_type

	// codec.codec_tag = icodec.codec_tag

	codec.rc_max_rate = icodec.rc_max_rate
	codec.rc_buffer_size = icodec.rc_buffer_size

	codec.field_order = icodec.field_order

	codec.extradata = (*_Ctype_uint8_t)(C.av_mallocz((_Ctype_size_t)((C.uint64_t)(icodec.extradata_size) + C.FF_INPUT_BUFFER_PADDING_SIZE)))

	C.memcpy(unsafe.Pointer(codec.extradata), unsafe.Pointer(icodec.extradata), (_Ctype_size_t)(icodec.extradata_size))
	codec.extradata_size = icodec.extradata_size
	codec.bits_per_coded_sample = icodec.bits_per_coded_sample

	codec.has_b_frames = icodec.has_b_frames

	return this
}

func (this *CodecCtx) CopyBasic(ist *Stream) *CodecCtx {
	codec := this.avCodecCtx
	icodec := ist.CodecCtx().avCodecCtx

	codec.bit_rate = icodec.bit_rate
	codec.pix_fmt = icodec.pix_fmt
	codec.width = icodec.width
	codec.height = icodec.height

	codec.time_base = icodec.time_base
	codec.time_base.num *= icodec.ticks_per_frame

	codec.sample_fmt = icodec.sample_fmt
	codec.sample_rate = icodec.sample_rate
	codec.channels = icodec.channels

	codec.channel_layout = icodec.channel_layout

	return this
}

func (this *CodecCtx) Open(dict *Dict) error {
	if this.IsOpen() {
		return nil
	}

	var avDict *C.struct_AVDictionary
	if dict != nil {
		avDict = dict.avDict
	}

	if averr := C.avcodec_open2(this.avCodecCtx, this.codec.avCodec, &avDict); averr < 0 {
		return errors.New(fmt.Sprintf("Error opening codec '%s:%s', averror: %s", this.codec.Name(), this.codec.LongName(), AvError(int(averr))))
	}

	return nil
}

func (this *CodecCtx) Close() {
	if nil != this.avCodecCtx {
		C.avcodec_close(this.avCodecCtx)
		this.avCodecCtx = nil
	}
}

func (this *CodecCtx) Free() {
	this.CloseAndRelease()
}

func (this *CodecCtx) CloseAndRelease() {
	this.Close()
	C.call_av_freep(this.avCodecCtx)
}

// @todo
func (this *CodecCtx) SetOpt() {
	// mock
	C.av_opt_set_int(unsafe.Pointer(this.avCodecCtx), C.CString("refcounted_frames"), 1, 0)
}

func (this *CodecCtx) Codec() *Codec {
	return &Codec{avCodec: this.avCodecCtx.codec}
}

func (this *CodecCtx) Id() int {
	return int(this.avCodecCtx.codec_id)
}

func (this *CodecCtx) Type() int32 {
	return int32(this.avCodecCtx.codec_type)
}

func (this *CodecCtx) Width() int {
	return int(this.avCodecCtx.width)
}

func (this *CodecCtx) Height() int {
	return int(this.avCodecCtx.height)
}

func (this *CodecCtx) PixFmt() int32 {
	return int32(this.avCodecCtx.pix_fmt)
}

func (this *CodecCtx) FrameSize() int {
	return int(this.avCodecCtx.frame_size)
}

func (this *CodecCtx) SampleFmt() int32 {
	return this.avCodecCtx.sample_fmt
}

func (this *CodecCtx) SampleRate() int {
	return int(this.avCodecCtx.sample_rate)
}

func (this *CodecCtx) Profile() int {
	return int(this.avCodecCtx.profile)
}

func (this *CodecCtx) IsOpen() bool {
	return (int(C.avcodec_is_open(this.avCodecCtx)) > 0)
}

func (this *CodecCtx) SetProfile(profile int) *CodecCtx {
	this.avCodecCtx.profile = C.int(profile)
	return this
}

func (this *CodecCtx) TimeBase() AVRational {
	return AVRational(this.avCodecCtx.time_base)
}

func (this *CodecCtx) ChannelLayout() int {
	return int(this.avCodecCtx.channel_layout)
}
func (this *CodecCtx) SetChannelLayout(channelLayout int) {
	this.avCodecCtx.channel_layout = C.uint64_t(channelLayout)
}

func (this *CodecCtx) BitRate() int {
	return int(this.avCodecCtx.bit_rate)
}

func (this *CodecCtx) Channels() int {
	return int(this.avCodecCtx.channels)
}

func (this *CodecCtx) SetBitRate(val int) *CodecCtx {
	this.avCodecCtx.bit_rate = C.int64_t(val)
	return this
}

func (this *CodecCtx) SetWidth(val int) *CodecCtx {
	this.avCodecCtx.width = C.int(val)
	return this
}

func (this *CodecCtx) SetHeight(val int) *CodecCtx {
	this.avCodecCtx.height = C.int(val)
	return this
}

func (this *CodecCtx) SetDimension(w, h int) *CodecCtx {
	this.avCodecCtx.width = C.int(w)
	this.avCodecCtx.height = C.int(h)
	return this
}

func (this *CodecCtx) SetTimeBase(val AVR) *CodecCtx {
	this.avCodecCtx.time_base.num = C.int(val.Num)
	this.avCodecCtx.time_base.den = C.int(val.Den)
	return this
}

func (this *CodecCtx) SetGopSize(val int) *CodecCtx {
	this.avCodecCtx.gop_size = C.int(val)
	return this
}

func (this *CodecCtx) SetMaxBFrames(val int) *CodecCtx {
	this.avCodecCtx.max_b_frames = C.int(val)
	return this
}

func (this *CodecCtx) SetPixFmt(val int32) *CodecCtx {
	this.avCodecCtx.pix_fmt = val
	return this
}

func (this *CodecCtx) SetFlag(flag int) *CodecCtx {
	this.avCodecCtx.flags |= C.int(flag)
	return this
}

func (this *CodecCtx) SetMbDecision(val int) *CodecCtx {
	this.avCodecCtx.mb_decision = C.int(val)
	return this
}

func (this *CodecCtx) SetSampleFmt(val int32) *CodecCtx {
	if int(C.check_sample_fmt(this.codec.avCodec, val)) == 0 {
		panic(fmt.Sprintf("encoder doesn't support sample format %s", GetSampleFmtName(val)))
	}

	this.avCodecCtx.sample_fmt = val
	return this
}

func (this *CodecCtx) SetSampleRate(val int) *CodecCtx {
	this.avCodecCtx.sample_rate = C.int(val)
	return this
}

var (
	FF_COMPLIANCE_VERY_STRICT  int = C.FF_COMPLIANCE_VERY_STRICT
	FF_COMPLIANCE_STRICT       int = C.FF_COMPLIANCE_STRICT
	FF_COMPLIANCE_NORMAL       int = C.FF_COMPLIANCE_NORMAL
	FF_COMPLIANCE_UNOFFICIAL   int = C.FF_COMPLIANCE_UNOFFICIAL
	FF_COMPLIANCE_EXPERIMENTAL int = C.FF_COMPLIANCE_EXPERIMENTAL
)

func (this *CodecCtx) SetStrictCompliance(val int) *CodecCtx {
	this.avCodecCtx.strict_std_compliance = C.int(val)
	return this
}

func (this *CodecCtx) SetHasBframes(val int) *CodecCtx {
	this.avCodecCtx.has_b_frames = C.int(val)
	return this
}

func (this *CodecCtx) SetChannels(val int) *CodecCtx {
	this.avCodecCtx.channels = C.int(val)
	return this
}

func (this *CodecCtx) SelectSampleRate() int {
	return int(C.select_sample_rate(this.codec.avCodec))
}

func (this *CodecCtx) SelectChannelLayout() int {
	return int(C.select_channel_layout(this.codec.avCodec))
}

func (this *CodecCtx) FlushBuffers() {
	C.avcodec_flush_buffers(this.avCodecCtx)
}

func (this *CodecCtx) Dump() {
	fmt.Println(this.avCodecCtx)
}
<commit_msg>Put unsafe.Pointer back in + formatting<commit_after>package gmf

/*

#cgo pkg-config: libavcodec libavutil

#include <string.h>

#include "libavcodec/avcodec.h"
#include "libavutil/channel_layout.h"
#include "libavutil/samplefmt.h"
#include "libavutil/opt.h"
#include "libavutil/mem.h"

static int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt) {
    const enum AVSampleFormat *p = codec->sample_fmts;

    while (*p != AV_SAMPLE_FMT_NONE) {
        if (*p == sample_fmt)
            return 1;
        p++;
    }
    return 0;
}

static int select_sample_rate(AVCodec *codec) {
    const int *p;
    int best_samplerate = 0;

    if (!codec->supported_samplerates)
        return 44100;

    p = codec->supported_samplerates;
    while (*p) {
        best_samplerate = FFMAX(*p, best_samplerate);
        p++;
    }
    return best_samplerate;
}

static int select_channel_layout(AVCodec *codec) {
    const uint64_t *p;
    uint64_t best_ch_layout = 0;
    int best_nb_channels    = 0;

    if (!codec->channel_layouts)
        return AV_CH_LAYOUT_STEREO;

    p = codec->channel_layouts;
    while (*p) {
        int nb_channels = av_get_channel_layout_nb_channels(*p);

        if (nb_channels > best_nb_channels) {
            best_ch_layout   = *p;
            best_nb_channels = nb_channels;
        }
        p++;
    }
    return best_ch_layout;
}

static void call_av_freep(AVCodecContext *out){
    return av_freep(&out);
}
*/
import "C"

import (
	"errors"
	"fmt"
	"unsafe"
	//	"log"
)

var (
	AV_CODEC_ID_MPEG1VIDEO int = C.AV_CODEC_ID_MPEG1VIDEO
	AV_CODEC_ID_MPEG2VIDEO int = C.AV_CODEC_ID_MPEG2VIDEO
	AV_CODEC_ID_H264       int = C.AV_CODEC_ID_H264
	AV_CODEC_ID_MPEG4      int = C.AV_CODEC_ID_MPEG4
	AV_CODEC_ID_JPEG2000   int = C.AV_CODEC_ID_JPEG2000
	AV_CODEC_ID_MJPEG      int = C.AV_CODEC_ID_MJPEG
	AV_CODEC_ID_MSMPEG4V1  int = C.AV_CODEC_ID_MSMPEG4V1
	AV_CODEC_ID_MSMPEG4V2  int = C.AV_CODEC_ID_MSMPEG4V2
	AV_CODEC_ID_MSMPEG4V3  int = C.AV_CODEC_ID_MSMPEG4V3
	AV_CODEC_ID_WMV1       int = C.AV_CODEC_ID_WMV1
	AV_CODEC_ID_WMV2       int = C.AV_CODEC_ID_WMV2
	AV_CODEC_ID_FLV1       int = C.AV_CODEC_ID_FLV1
	AV_CODEC_ID_PNG        int = C.AV_CODEC_ID_PNG
	AV_CODEC_ID_TIFF       int = C.AV_CODEC_ID_TIFF
	AV_CODEC_ID_GIF        int = C.AV_CODEC_ID_GIF

	CODEC_FLAG_GLOBAL_HEADER int   = C.CODEC_FLAG_GLOBAL_HEADER
	FF_MB_DECISION_SIMPLE    int   = C.FF_MB_DECISION_SIMPLE
	FF_MB_DECISION_BITS      int   = C.FF_MB_DECISION_BITS
	FF_MB_DECISION_RD        int   = C.FF_MB_DECISION_RD
	AV_SAMPLE_FMT_S16        int32 = C.AV_SAMPLE_FMT_S16
	AV_SAMPLE_FMT_S16P       int32 = C.AV_SAMPLE_FMT_S16P
)

type SampleFmt int

type CodecCtx struct {
	codec      *Codec
	avCodecCtx *C.struct_AVCodecContext
	CgoMemoryManage
}

func NewCodecCtx(codec *Codec, options ...[]*Option) *CodecCtx {
	result := &CodecCtx{codec: codec}

	codecctx := C.avcodec_alloc_context3(codec.avCodec)
	if codecctx == nil {
		return nil
	}

	C.avcodec_get_context_defaults3(codecctx, codec.avCodec)

	result.avCodecCtx = codecctx

	// we're really expecting only one options-array —
	// variadic arg is used for backward compatibility
	if len(options) == 1 {
		for _, option := range options[0] {
			option.Set(result.avCodecCtx)
		}
	}

	return result
}

func (this *CodecCtx) CopyExtra(ist *Stream) *CodecCtx {
	codec := this.avCodecCtx
	icodec := ist.CodecCtx().avCodecCtx

	codec.bits_per_raw_sample = icodec.bits_per_raw_sample
	codec.chroma_sample_location = icodec.chroma_sample_location

	codec.codec_id = icodec.codec_id
	codec.codec_type = icodec.codec_type

	// codec.codec_tag = icodec.codec_tag

	codec.rc_max_rate = icodec.rc_max_rate
	codec.rc_buffer_size = icodec.rc_buffer_size

	codec.field_order = icodec.field_order

	codec.extradata = (*_Ctype_uint8_t)(C.av_mallocz((_Ctype_size_t)((C.uint64_t)(icodec.extradata_size) + C.FF_INPUT_BUFFER_PADDING_SIZE)))

	C.memcpy(unsafe.Pointer(codec.extradata), unsafe.Pointer(icodec.extradata), (_Ctype_size_t)(icodec.extradata_size))
	codec.extradata_size = icodec.extradata_size
	codec.bits_per_coded_sample = icodec.bits_per_coded_sample

	codec.has_b_frames = icodec.has_b_frames

	return this
}

func (this *CodecCtx) CopyBasic(ist *Stream) *CodecCtx {
	codec := this.avCodecCtx
	icodec := ist.CodecCtx().avCodecCtx

	codec.bit_rate = icodec.bit_rate
	codec.pix_fmt = icodec.pix_fmt
	codec.width = icodec.width
	codec.height = icodec.height

	codec.time_base = icodec.time_base
	codec.time_base.num *= icodec.ticks_per_frame

	codec.sample_fmt = icodec.sample_fmt
	codec.sample_rate = icodec.sample_rate
	codec.channels = icodec.channels

	codec.channel_layout = icodec.channel_layout

	return this
}

func (this *CodecCtx) Open(dict *Dict) error {
	if this.IsOpen() {
		return nil
	}

	var avDict *C.struct_AVDictionary
	if dict != nil {
		avDict = dict.avDict
	}

	if averr := C.avcodec_open2(this.avCodecCtx, this.codec.avCodec, &avDict); averr < 0 {
		return errors.New(fmt.Sprintf("Error opening codec '%s:%s', averror: %s", this.codec.Name(), this.codec.LongName(), AvError(int(averr))))
	}

	return nil
}

func (this *CodecCtx) Close() {
	if nil != this.avCodecCtx {
		C.avcodec_close(this.avCodecCtx)
		this.avCodecCtx = nil
	}
}

func (this *CodecCtx) Free() {
	this.CloseAndRelease()
}

func (this *CodecCtx) CloseAndRelease() {
	this.Close()
	C.call_av_freep(unsafe.Pointer(this.avCodecCtx))
}

// @todo
func (this *CodecCtx) SetOpt() {
	// mock
	C.av_opt_set_int(unsafe.Pointer(this.avCodecCtx), C.CString("refcounted_frames"), 1, 0)
}

func (this *CodecCtx) Codec() *Codec {
	return &Codec{avCodec: this.avCodecCtx.codec}
}

func (this *CodecCtx) Id() int {
	return int(this.avCodecCtx.codec_id)
}

func (this *CodecCtx) Type() int32 {
	return int32(this.avCodecCtx.codec_type)
}

func (this *CodecCtx) Width() int {
	return int(this.avCodecCtx.width)
}

func (this *CodecCtx) Height() int {
	return int(this.avCodecCtx.height)
}

func (this *CodecCtx) PixFmt() int32 {
	return int32(this.avCodecCtx.pix_fmt)
}

func (this *CodecCtx) FrameSize() int {
	return int(this.avCodecCtx.frame_size)
}

func (this *CodecCtx) SampleFmt() int32 {
	return this.avCodecCtx.sample_fmt
}

func (this *CodecCtx) SampleRate() int {
	return int(this.avCodecCtx.sample_rate)
}

func (this *CodecCtx) Profile() int {
	return int(this.avCodecCtx.profile)
}

func (this *CodecCtx) IsOpen() bool {
	return (int(C.avcodec_is_open(this.avCodecCtx)) > 0)
}

func (this *CodecCtx) SetProfile(profile int) *CodecCtx {
	this.avCodecCtx.profile = C.int(profile)
	return this
}

func (this *CodecCtx) TimeBase() AVRational {
	return AVRational(this.avCodecCtx.time_base)
}

func (this *CodecCtx) ChannelLayout() int {
	return int(this.avCodecCtx.channel_layout)
}
func (this *CodecCtx) SetChannelLayout(channelLayout int) {
	this.avCodecCtx.channel_layout = C.uint64_t(channelLayout)
}

func (this *CodecCtx) BitRate() int {
	return int(this.avCodecCtx.bit_rate)
}

func (this *CodecCtx) Channels() int {
	return int(this.avCodecCtx.channels)
}

func (this *CodecCtx) SetBitRate(val int) *CodecCtx {
	this.avCodecCtx.bit_rate = C.int64_t(val)
	return this
}

func (this *CodecCtx) SetWidth(val int) *CodecCtx {
	this.avCodecCtx.width = C.int(val)
	return this
}

func (this *CodecCtx) SetHeight(val int) *CodecCtx {
	this.avCodecCtx.height = C.int(val)
	return this
}

func (this *CodecCtx) SetDimension(w, h int) *CodecCtx {
	this.avCodecCtx.width = C.int(w)
	this.avCodecCtx.height = C.int(h)
	return this
}

func (this *CodecCtx) SetTimeBase(val AVR) *CodecCtx {
	this.avCodecCtx.time_base.num = C.int(val.Num)
	this.avCodecCtx.time_base.den = C.int(val.Den)
	return this
}

func (this *CodecCtx) SetGopSize(val int) *CodecCtx {
	this.avCodecCtx.gop_size = C.int(val)
	return this
}

func (this *CodecCtx) SetMaxBFrames(val int) *CodecCtx {
	this.avCodecCtx.max_b_frames = C.int(val)
	return this
}

func (this *CodecCtx) SetPixFmt(val int32) *CodecCtx {
	this.avCodecCtx.pix_fmt = val
	return this
}

func (this *CodecCtx) SetFlag(flag int) *CodecCtx {
	this.avCodecCtx.flags |= C.int(flag)
	return this
}

func (this *CodecCtx) SetMbDecision(val int) *CodecCtx {
	this.avCodecCtx.mb_decision = C.int(val)
	return this
}

func (this *CodecCtx) SetSampleFmt(val int32) *CodecCtx {
	if int(C.check_sample_fmt(this.codec.avCodec, val)) == 0 {
		panic(fmt.Sprintf("encoder doesn't support sample format %s", GetSampleFmtName(val)))
	}

	this.avCodecCtx.sample_fmt = val
	return this
}

func (this *CodecCtx) SetSampleRate(val int) *CodecCtx {
	this.avCodecCtx.sample_rate = C.int(val)
	return this
}

var (
	FF_COMPLIANCE_VERY_STRICT  int = C.FF_COMPLIANCE_VERY_STRICT
	FF_COMPLIANCE_STRICT       int = C.FF_COMPLIANCE_STRICT
	FF_COMPLIANCE_NORMAL       int = C.FF_COMPLIANCE_NORMAL
	FF_COMPLIANCE_UNOFFICIAL   int = C.FF_COMPLIANCE_UNOFFICIAL
	FF_COMPLIANCE_EXPERIMENTAL int = C.FF_COMPLIANCE_EXPERIMENTAL
)

func (this *CodecCtx) SetStrictCompliance(val int) *CodecCtx {
	this.avCodecCtx.strict_std_compliance = C.int(val)
	return this
}

func (this *CodecCtx) SetHasBframes(val int) *CodecCtx {
	this.avCodecCtx.has_b_frames = C.int(val)
	return this
}

func (this *CodecCtx) SetChannels(val int) *CodecCtx {
	this.avCodecCtx.channels = C.int(val)
	return this
}

func (this *CodecCtx) SelectSampleRate() int {
	return int(C.select_sample_rate(this.codec.avCodec))
}

func (this *CodecCtx) SelectChannelLayout() int {
	return int(C.select_channel_layout(this.codec.avCodec))
}

func (this *CodecCtx) FlushBuffers() {
	C.avcodec_flush_buffers(this.avCodecCtx)
}

func (this *CodecCtx) Dump() {
	fmt.Println(this.avCodecCtx)
}
<|endoftext|>


<commit_before>package dmplugin

import (
	"errors"
	"fmt"
	"io"
	"sync"
	"syscall"

	"github.intel.com/hpdd/logging/alert"
	"github.intel.com/hpdd/logging/debug"
	pb "github.intel.com/hpdd/policy/pdm/pdm"
	"golang.org/x/net/context"
)

type (
	// DataMoverClient is the data mover client to the HSM agent
	DataMoverClient struct {
		plugin    Plugin
		rpcClient pb.DataMoverClient
		stop      chan struct{}
		status    chan *pb.ActionStatus
		mover     Mover
		config    *Config
	}

	// Config defines configuration for a DatamMoverClient
	Config struct {
		Mover      Mover
		NumThreads int
		ArchiveID  uint32
	}

	// Action is a data movement action
	dmAction struct {
		status       chan *pb.ActionStatus
		item         *pb.ActionItem
		fileID       []byte
		actualLength *uint64
	}

	// Action defines an interface for dm actions
	Action interface {
		// Update sends an action status update
		Update(offset, length, max uint64) error
		// Complete signals that the action has completed
		Complete() error
		// Fail signals that the action has failed
		Fail(err error) error
		// ID returns the action item's ID
		ID() uint64
		// Offset returns the current offset of the action item
		Offset() uint64
		// Length returns the expected length of the action item's file
		Length() uint64
		// Data returns a byte slice of the action item's data
		Data() []byte
		// PrimaryPath returns the action item's primary file path
		PrimaryPath() string

		// WritePath returns the action item's write path (e.g. for restores)
		WritePath() string
		// FileID returns the action item's file id
		FileID() []byte

		// SetFileID sets the action's file id
		SetFileID(id []byte)

		// SetActualLength sets the action's actual file length
		SetActualLength(length uint64)
	}

	// Mover defines an interface for data mover implementations
	Mover interface {
		Start()
	}

	// Archiver defines an interface for data movers capable of
	// fulfilling Archive requests
	Archiver interface {
		Archive(Action) error
	}

	// Restorer defines an interface for data movers capable of
	// fulfilling Restore requests
	Restorer interface {
		Restore(Action) error
	}

	// Remover defines an interface for data movers capable of
	// fulfilling Remove requests
	Remover interface {
		Remove(Action) error
	}
)

type key int

var handleKey key

const (
	defaultNumThreads = 4
)

func withHandle(ctx context.Context, handle *pb.Handle) context.Context {
	return context.WithValue(ctx, handleKey, handle)
}

func getHandle(ctx context.Context) (*pb.Handle, bool) {
	handle, ok := ctx.Value(handleKey).(*pb.Handle)
	return handle, ok
}

// Update sends an action status update
func (a *dmAction) Update(offset, length, max uint64) error {
	a.status <- &pb.ActionStatus{
		Id:     a.item.Id,
		Offset: offset,
		Length: length,
	}
	return nil
}

// Complete signals that the action has completed
func (a *dmAction) Complete() error {
	status := &pb.ActionStatus{
		Id:        a.item.Id,
		Completed: true,
		Offset:    a.item.Offset,
		Length:    a.item.Length,
		FileId:    a.fileID,
	}
	if a.actualLength != nil {
		status.Length = *a.actualLength
	}
	a.status <- status
	return nil
}

func getErrno(err error) int32 {
	if errno, ok := err.(syscall.Errno); ok {
		return int32(errno)
	}
	return -1
}

// Fail signals that the action has failed
func (a *dmAction) Fail(err error) error {
	alert.Warnf("fail: id:%d %v", a.item.Id, err)
	a.status <- &pb.ActionStatus{
		Id:        a.item.Id,
		Completed: true,

		Error: getErrno(err),
	}
	return nil
}

// ID returns the action item's ID
func (a *dmAction) ID() uint64 {
	return a.item.Id
}

// Offset returns the current offset of the action item
func (a *dmAction) Offset() uint64 {
	return a.item.Offset
}

// Length returns the expected length of the action item's file
func (a *dmAction) Length() uint64 {
	return a.item.Length
}

// Data returns a byte slice of the action item's data
func (a *dmAction) Data() []byte {
	return a.item.Data
}

// PrimaryPath returns the action item's primary file path
func (a *dmAction) PrimaryPath() string {
	return a.item.PrimaryPath
}

// WritePath returns the action item's write path (e.g. for restores)
func (a *dmAction) WritePath() string {
	return a.item.WritePath
}

// FileID returns the action item's file id
func (a *dmAction) FileID() []byte {
	return a.item.FileId
}

// SetFileID sets the action's file id
func (a *dmAction) SetFileID(id []byte) {
	a.fileID = id
}

// SetActualLength sets the action's actual file length
func (a *dmAction) SetActualLength(length uint64) {
	a.actualLength = &length
}

// NewMover returns a new *DataMoverClient
func NewMover(plugin Plugin, cli pb.DataMoverClient, config *Config) *DataMoverClient {
	return &DataMoverClient{
		plugin:    plugin,
		rpcClient: cli,
		mover:     config.Mover,
		stop:      make(chan struct{}),
		status:    make(chan *pb.ActionStatus, 2),
		config:    config,
	}
}

// Run begins listening for and processing incoming action items
func (dm *DataMoverClient) Run() {
	var wg sync.WaitGroup
	ctx, cancel := context.WithCancel(context.Background())

	handle, err := dm.registerEndpoint(ctx)
	if err != nil {
		alert.Fatal(err)
	}
	ctx = withHandle(ctx, handle)
	actions := dm.processActions(ctx)
	dm.processStatus(ctx)

	n := defaultNumThreads
	if dm.config.NumThreads > 0 {
		n = dm.config.NumThreads
	}

	for i := 0; i < n; i++ {
		wg.Add(1)
		go func(i int) {
			dm.handler(fmt.Sprintf("handler-%d", i), actions)
			wg.Done()
		}(i)
		dm.processStatus(ctx)
	}

	// Signal to the mover that it should begin any async processing
	dm.config.Mover.Start()

	<-dm.stop
	debug.Printf("Shutting down Data Mover")
	cancel()
	wg.Wait()
	close(dm.status)
}

// Stop signals to the client that it should stop processing and shut down
func (dm *DataMoverClient) Stop() {
	close(dm.stop)
}

func (dm *DataMoverClient) registerEndpoint(ctx context.Context) (*pb.Handle, error) {

	handle, err := dm.rpcClient.Register(ctx, &pb.Endpoint{
		FsUrl:   dm.plugin.FsName(),
		Archive: dm.config.ArchiveID,
	})
	if err != nil {
		return nil, err
	}
	debug.Printf("Registered archive %d,  cookie %x", dm.config.ArchiveID, handle.Id)
	return handle, nil
}

func (dm *DataMoverClient) processActions(ctx context.Context) chan *pb.ActionItem {
	actions := make(chan *pb.ActionItem)

	go func() {
		handle, ok := getHandle(ctx)
		if !ok {
			alert.Fatal("No context")
		}
		stream, err := dm.rpcClient.GetActions(ctx, handle)
		if err != nil {
			alert.Fatalf("GetActions() failed: %v", err)
		}
		for {
			action, err := stream.Recv()
			if err != nil {
				close(actions)
				if err == io.EOF {
					debug.Print("Shutting down dmclient action stream")
					return
				}
				alert.Warnf("Shutting down dmclient action stream due to error on Recv(): %v", err)
				return
			}
			// debug.Printf("Got message id:%d op: %v %v", action.Id, action.Op, action.PrimaryPath)

			actions <- action
		}
	}()

	return actions

}

func (dm *DataMoverClient) processStatus(ctx context.Context) {
	go func() {
		handle, ok := getHandle(ctx)
		if !ok {
			alert.Fatal("No context")
		}

		acks, err := dm.rpcClient.StatusStream(ctx)
		if err != nil {
			alert.Fatalf("StatusStream() failed: %v", err)
		}
		for reply := range dm.status {
			reply.Handle = handle
			// debug.Printf("Sent reply  %x error: %#v", reply.Id, reply.Error)
			err := acks.Send(reply)
			if err != nil {
				alert.Fatalf("Failed to ack message %x: %v", reply.Id, err)
			}
		}
	}()
	return
}

func (dm *DataMoverClient) handler(name string, actions chan *pb.ActionItem) {
	for item := range actions {
		var ret error
		action := &dmAction{
			status: dm.status,
			item:   item,
		}

		ret = errors.New("Command not supported")

		switch item.Op {
		case pb.Command_ARCHIVE:
			if archiver, ok := dm.mover.(Archiver); ok {
				ret = archiver.Archive(action)
			}
		case pb.Command_RESTORE:
			if restorer, ok := dm.mover.(Restorer); ok {
				ret = restorer.Restore(action)
			}
		case pb.Command_REMOVE:
			if remover, ok := dm.mover.(Remover); ok {
				ret = remover.Remove(action)
			}
		case pb.Command_CANCEL:
			// TODO: Cancel in-progress action using a context
		default:
			ret = errors.New("Unknown cmmand")
		}

		//		rate.Mark(1)
		// debug.Printf("completed (action: %v) %v ", action, ret)
		if ret != nil {
			action.Fail(ret)
		} else {
			action.Complete()
		}
	}
	debug.Printf("%s: stopping", name)
}
<commit_msg>Only start 1 goroutine to handle status updates<commit_after>package dmplugin

import (
	"errors"
	"fmt"
	"io"
	"sync"
	"syscall"

	"github.intel.com/hpdd/logging/alert"
	"github.intel.com/hpdd/logging/debug"
	pb "github.intel.com/hpdd/policy/pdm/pdm"
	"golang.org/x/net/context"
)

type (
	// DataMoverClient is the data mover client to the HSM agent
	DataMoverClient struct {
		plugin    Plugin
		rpcClient pb.DataMoverClient
		stop      chan struct{}
		status    chan *pb.ActionStatus
		mover     Mover
		config    *Config
	}

	// Config defines configuration for a DatamMoverClient
	Config struct {
		Mover      Mover
		NumThreads int
		ArchiveID  uint32
	}

	// Action is a data movement action
	dmAction struct {
		status       chan *pb.ActionStatus
		item         *pb.ActionItem
		fileID       []byte
		actualLength *uint64
	}

	// Action defines an interface for dm actions
	Action interface {
		// Update sends an action status update
		Update(offset, length, max uint64) error
		// Complete signals that the action has completed
		Complete() error
		// Fail signals that the action has failed
		Fail(err error) error
		// ID returns the action item's ID
		ID() uint64
		// Offset returns the current offset of the action item
		Offset() uint64
		// Length returns the expected length of the action item's file
		Length() uint64
		// Data returns a byte slice of the action item's data
		Data() []byte
		// PrimaryPath returns the action item's primary file path
		PrimaryPath() string

		// WritePath returns the action item's write path (e.g. for restores)
		WritePath() string
		// FileID returns the action item's file id
		FileID() []byte

		// SetFileID sets the action's file id
		SetFileID(id []byte)

		// SetActualLength sets the action's actual file length
		SetActualLength(length uint64)
	}

	// Mover defines an interface for data mover implementations
	Mover interface {
		Start()
	}

	// Archiver defines an interface for data movers capable of
	// fulfilling Archive requests
	Archiver interface {
		Archive(Action) error
	}

	// Restorer defines an interface for data movers capable of
	// fulfilling Restore requests
	Restorer interface {
		Restore(Action) error
	}

	// Remover defines an interface for data movers capable of
	// fulfilling Remove requests
	Remover interface {
		Remove(Action) error
	}
)

type key int

var handleKey key

const (
	defaultNumThreads = 4
)

func withHandle(ctx context.Context, handle *pb.Handle) context.Context {
	return context.WithValue(ctx, handleKey, handle)
}

func getHandle(ctx context.Context) (*pb.Handle, bool) {
	handle, ok := ctx.Value(handleKey).(*pb.Handle)
	return handle, ok
}

// Update sends an action status update
func (a *dmAction) Update(offset, length, max uint64) error {
	a.status <- &pb.ActionStatus{
		Id:     a.item.Id,
		Offset: offset,
		Length: length,
	}
	return nil
}

// Complete signals that the action has completed
func (a *dmAction) Complete() error {
	status := &pb.ActionStatus{
		Id:        a.item.Id,
		Completed: true,
		Offset:    a.item.Offset,
		Length:    a.item.Length,
		FileId:    a.fileID,
	}
	if a.actualLength != nil {
		status.Length = *a.actualLength
	}
	a.status <- status
	return nil
}

func getErrno(err error) int32 {
	if errno, ok := err.(syscall.Errno); ok {
		return int32(errno)
	}
	return -1
}

// Fail signals that the action has failed
func (a *dmAction) Fail(err error) error {
	alert.Warnf("fail: id:%d %v", a.item.Id, err)
	a.status <- &pb.ActionStatus{
		Id:        a.item.Id,
		Completed: true,

		Error: getErrno(err),
	}
	return nil
}

// ID returns the action item's ID
func (a *dmAction) ID() uint64 {
	return a.item.Id
}

// Offset returns the current offset of the action item
func (a *dmAction) Offset() uint64 {
	return a.item.Offset
}

// Length returns the expected length of the action item's file
func (a *dmAction) Length() uint64 {
	return a.item.Length
}

// Data returns a byte slice of the action item's data
func (a *dmAction) Data() []byte {
	return a.item.Data
}

// PrimaryPath returns the action item's primary file path
func (a *dmAction) PrimaryPath() string {
	return a.item.PrimaryPath
}

// WritePath returns the action item's write path (e.g. for restores)
func (a *dmAction) WritePath() string {
	return a.item.WritePath
}

// FileID returns the action item's file id
func (a *dmAction) FileID() []byte {
	return a.item.FileId
}

// SetFileID sets the action's file id
func (a *dmAction) SetFileID(id []byte) {
	a.fileID = id
}

// SetActualLength sets the action's actual file length
func (a *dmAction) SetActualLength(length uint64) {
	a.actualLength = &length
}

// NewMover returns a new *DataMoverClient
func NewMover(plugin Plugin, cli pb.DataMoverClient, config *Config) *DataMoverClient {
	return &DataMoverClient{
		plugin:    plugin,
		rpcClient: cli,
		mover:     config.Mover,
		stop:      make(chan struct{}),
		status:    make(chan *pb.ActionStatus, config.NumThreads),
		config:    config,
	}
}

// Run begins listening for and processing incoming action items
func (dm *DataMoverClient) Run() {
	var wg sync.WaitGroup
	ctx, cancel := context.WithCancel(context.Background())

	handle, err := dm.registerEndpoint(ctx)
	if err != nil {
		alert.Fatal(err)
	}
	ctx = withHandle(ctx, handle)
	actions := dm.processActions(ctx)
	dm.processStatus(ctx)

	n := defaultNumThreads
	if dm.config.NumThreads > 0 {
		n = dm.config.NumThreads
	}

	for i := 0; i < n; i++ {
		wg.Add(1)
		go func(i int) {
			dm.handler(fmt.Sprintf("handler-%d", i), actions)
			wg.Done()
		}(i)
	}

	// Signal to the mover that it should begin any async processing
	dm.config.Mover.Start()

	<-dm.stop
	debug.Printf("Shutting down Data Mover")
	cancel()
	wg.Wait()
	close(dm.status)
}

// Stop signals to the client that it should stop processing and shut down
func (dm *DataMoverClient) Stop() {
	close(dm.stop)
}

func (dm *DataMoverClient) registerEndpoint(ctx context.Context) (*pb.Handle, error) {

	handle, err := dm.rpcClient.Register(ctx, &pb.Endpoint{
		FsUrl:   dm.plugin.FsName(),
		Archive: dm.config.ArchiveID,
	})
	if err != nil {
		return nil, err
	}
	debug.Printf("Registered archive %d,  cookie %x", dm.config.ArchiveID, handle.Id)
	return handle, nil
}

func (dm *DataMoverClient) processActions(ctx context.Context) chan *pb.ActionItem {
	actions := make(chan *pb.ActionItem)

	go func() {
		handle, ok := getHandle(ctx)
		if !ok {
			alert.Fatal("No context")
		}
		stream, err := dm.rpcClient.GetActions(ctx, handle)
		if err != nil {
			alert.Fatalf("GetActions() failed: %v", err)
		}
		for {
			action, err := stream.Recv()
			if err != nil {
				close(actions)
				if err == io.EOF {
					debug.Print("Shutting down dmclient action stream")
					return
				}
				alert.Warnf("Shutting down dmclient action stream due to error on Recv(): %v", err)
				return
			}
			// debug.Printf("Got message id:%d op: %v %v", action.Id, action.Op, action.PrimaryPath)

			actions <- action
		}
	}()

	return actions

}

func (dm *DataMoverClient) processStatus(ctx context.Context) {
	go func() {
		handle, ok := getHandle(ctx)
		if !ok {
			alert.Fatal("No context")
		}

		acks, err := dm.rpcClient.StatusStream(ctx)
		if err != nil {
			alert.Fatalf("StatusStream() failed: %v", err)
		}
		for reply := range dm.status {
			reply.Handle = handle
			// debug.Printf("Sent reply  %x error: %#v", reply.Id, reply.Error)
			err := acks.Send(reply)
			if err != nil {
				alert.Fatalf("Failed to ack message %x: %v", reply.Id, err)
			}
		}
	}()
	return
}

func (dm *DataMoverClient) handler(name string, actions chan *pb.ActionItem) {
	for item := range actions {
		var ret error
		action := &dmAction{
			status: dm.status,
			item:   item,
		}

		ret = errors.New("Command not supported")

		switch item.Op {
		case pb.Command_ARCHIVE:
			if archiver, ok := dm.mover.(Archiver); ok {
				ret = archiver.Archive(action)
			}
		case pb.Command_RESTORE:
			if restorer, ok := dm.mover.(Restorer); ok {
				ret = restorer.Restore(action)
			}
		case pb.Command_REMOVE:
			if remover, ok := dm.mover.(Remover); ok {
				ret = remover.Remove(action)
			}
		case pb.Command_CANCEL:
			// TODO: Cancel in-progress action using a context
		default:
			ret = errors.New("Unknown command")
		}

		// debug.Printf("completed (action: %v) %v ", action, ret)
		if ret != nil {
			action.Fail(ret)
		} else {
			action.Complete()
		}
	}
	debug.Printf("%s: stopping", name)
}
<|endoftext|>


<commit_before>// Package golang implements the "golang" runtime.
package golang

import (
	"github.com/apex/apex/function"
)

func init() {
	function.RegisterPlugin("golang", &Plugin{})
}

// Plugin implementation.
type Plugin struct{}

// Run adds the shim when runtime is "golang".
func (p *Plugin) Run(hook function.Hook, fn *function.Function) error {
	if hook != function.OpenHook || fn.Runtime != "golang" {
		return nil
	}

	fn.Shim = true
	fn.Runtime = "nodejs"
	fn.Hooks.Build = "GOOS=linux GOARCH=amd64 go build -o main main.go"
	fn.Hooks.Clean = "rm -f main"

	return nil
}
<commit_msg>add support for overriding the build hook when using golang runtime<commit_after>// Package golang implements the "golang" runtime.
package golang

import (
	"github.com/apex/apex/function"
)

func init() {
	function.RegisterPlugin("golang", &Plugin{})
}

// Plugin implementation.
type Plugin struct{}

// Run adds the shim when runtime is "golang".
func (p *Plugin) Run(hook function.Hook, fn *function.Function) error {
	if hook != function.OpenHook || fn.Runtime != "golang" {
		return nil
	}

	if fn.Hooks.Build == "" {
		fn.Hooks.Build = "GOOS=linux GOARCH=amd64 go build -o main main.go"
	}

	fn.Shim = true
	fn.Runtime = "nodejs"
	fn.Hooks.Clean = "rm -f main"

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2016-2017 Joonas Kuorilehto.

// Command colorout is a colors and multiplexes output from tasks.
// Each task (external command) is executed concurrently using
// command shell and output is colored with a unique color per task.
package main

import (
	"bytes"
	"context"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"sync"

	"github.com/fatih/color"
)

var colors = []*color.Color{
	color.New(color.FgHiRed),
	color.New(color.FgHiGreen),
	color.New(color.FgHiYellow),
	color.New(color.FgHiBlue),
	color.New(color.FgHiMagenta),
	color.New(color.FgHiCyan),
	color.New(color.FgHiWhite),
	color.New(color.FgRed, color.ReverseVideo),
	color.New(color.FgGreen, color.ReverseVideo),
	color.New(color.FgYellow, color.ReverseVideo),
	color.New(color.FgBlue, color.ReverseVideo),
	color.New(color.FgMagenta, color.ReverseVideo),
	color.New(color.FgCyan, color.ReverseVideo),
	color.New(color.FgWhite, color.ReverseVideo),
}

func main() {
	fail := flag.Bool("fail", false, "terminate if any task fails with error")
	flag.Parse()
	tasks := flag.Args()

	if len(tasks) > len(colors) {
		log.Fatal("Too many tasks!")
	}

	// safeWriter protects stdout and stderr for concurrent access
	stdout := &safeWriter{W: os.Stdout}
	stderr := &safeWriter{W: os.Stderr}

	wg := &sync.WaitGroup{}
	wg.Add(len(tasks))
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	for i, command := range tasks {
		colorOut := colorize(stdout, i)
		colorErr := colorize(stderr, i)
		fmt.Fprintf(colorErr, "%d> Running: %s\n", i, command)

		go func(i int, command string) {
			if err := runCommand(ctx, command, colorOut, colorErr); err != nil {
				fmt.Fprintf(stderr, "%d> command failed with %v\n", i, err)
				if *fail { // terminate other tasks on failure
					cancel()
				}
			}
			colorOut.Close()
			colorErr.Close()
			wg.Done()
		}(i, command)
	}
	wg.Wait()
}

func runCommand(ctx context.Context, command string, stdout, stderr io.Writer) error {
	commandLine := append(shellCommand(), command)
	cmd := exec.CommandContext(ctx, commandLine[0], commandLine[1:]...)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	if err := cmd.Start(); err != nil {
		return err
	}
	if err := cmd.Wait(); err != nil {
		return err
	}
	return nil
}

func shellCommand() []string {
	return []string{"bash", "-c"}
}

func colorize(dst io.Writer, i int) io.WriteCloser {
	return &colorizer{
		W:      dst,
		Prefix: fmt.Sprintf("%d> ", i),
		Color:  colors[i],
	}
}

type colorizer struct {
	W      io.Writer
	Prefix string
	Color  *color.Color

	trailer []byte
}

func (c *colorizer) write(prev, line []byte) (err error) {
	_, err = c.Color.Fprintf(c.W, "%s%s%s\n", c.Prefix, prev, line)
	return
}

// Write writes the contents of p into W with color coding.
// Each Stream is output with an unique color.
// If p does not end with a newline, the trailing partial line
// is buffered and will be output on next write or on Close.
func (c *colorizer) Write(p []byte) (n int, err error) {
	n = len(p)
	for {
		pos := bytes.IndexByte(p, '\n')
		if pos == -1 { // incomplete last line
			c.trailer = append(c.trailer[:0], p...)
			return
		}
		line := p[:pos]
		if err := c.write(c.trailer, line); err != nil {
			return n, err
		}
		p = p[pos+1:]
		c.trailer = nil
	}
}

// Close writes trailing data not terminated with a newline.
func (c *colorizer) Close() error {
	if len(c.trailer) > 0 {
		return c.write(c.trailer, nil)
	}
	return nil
}

type safeWriter struct {
	W io.Writer

	mu sync.Mutex
}

func (s *safeWriter) Write(data []byte) (n int, err error) {
	s.mu.Lock()
	n, err = s.W.Write(data)
	s.mu.Unlock()
	return
}
<commit_msg>Fix output locking<commit_after>// Copyright 2016-2017 Joonas Kuorilehto.

// Command colorout is a colors and multiplexes output from tasks.
// Each task (external command) is executed concurrently using
// command shell and output is colored with a unique color per task.
package main

import (
	"bytes"
	"context"
	"flag"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"sync"

	"github.com/fatih/color"
)

var colors = []*color.Color{
	color.New(color.FgHiRed),
	color.New(color.FgHiGreen),
	color.New(color.FgHiYellow),
	color.New(color.FgHiBlue),
	color.New(color.FgHiMagenta),
	color.New(color.FgHiCyan),
	color.New(color.FgHiWhite),
	color.New(color.FgRed, color.ReverseVideo),
	color.New(color.FgGreen, color.ReverseVideo),
	color.New(color.FgYellow, color.ReverseVideo),
	color.New(color.FgBlue, color.ReverseVideo),
	color.New(color.FgMagenta, color.ReverseVideo),
	color.New(color.FgCyan, color.ReverseVideo),
	color.New(color.FgWhite, color.ReverseVideo),
}

func main() {
	fail := flag.Bool("fail", false, "terminate if any task fails with error")
	flag.Parse()
	tasks := flag.Args()

	if len(tasks) > len(colors) {
		log.Fatalf("Too many tasks! I only know %d colors.", len(colors))
	}

	wg := &sync.WaitGroup{}
	wg.Add(len(tasks))
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	for i, command := range tasks {
		colorOut := colorize(os.Stdout, i)
		colorErr := colorize(os.Stderr, i)
		fmt.Fprintf(colorErr, "Starting %q\n", command)

		go func(i int, command string) {
			if err := runCommand(ctx, command, colorOut, colorErr); err != nil {
				fmt.Fprintf(colorErr, "command failed with %v\n", err)
				if *fail { // terminate other tasks on failure
					cancel()
				}
			}
			colorOut.Close()
			colorErr.Close()
			wg.Done()
		}(i, command)
	}
	wg.Wait()
}

func runCommand(ctx context.Context, command string, stdout, stderr io.Writer) error {
	commandLine := append(shellCommand(), command)
	cmd := exec.CommandContext(ctx, commandLine[0], commandLine[1:]...)
	cmd.Stdout = stdout
	cmd.Stderr = stderr
	if err := cmd.Start(); err != nil {
		return err
	}
	if err := cmd.Wait(); err != nil {
		return err
	}
	return nil
}

func shellCommand() []string {
	return []string{"bash", "-c"}
}

func colorize(dst io.Writer, i int) io.WriteCloser {
	return &colorizer{
		W:      dst,
		Prefix: fmt.Sprintf("%d> ", i),
		Color:  colors[i],
	}
}

// mu protects writes to stdout and stderr
var mu sync.Mutex

type colorizer struct {
	W      io.Writer
	Prefix string
	Color  *color.Color

	trailer []byte
}

func (c *colorizer) write(prev, line []byte) (err error) {
	mu.Lock()
	_, err = c.Color.Fprintf(c.W, "%s%s%s\n", c.Prefix, prev, line)
	mu.Unlock()
	return
}

// Write writes the contents of p into W with color coding.
// Each Stream is output with an unique color.
// If p does not end with a newline, the trailing partial line
// is buffered and will be output on next write or on Close.
func (c *colorizer) Write(p []byte) (n int, err error) {
	n = len(p)
	for {
		pos := bytes.IndexByte(p, '\n')
		if pos == -1 { // incomplete last line
			c.trailer = append(c.trailer[:0], p...)
			return
		}
		line := p[:pos]
		if err := c.write(c.trailer, line); err != nil {
			return n, err
		}
		p = p[pos+1:]
		c.trailer = nil
	}
}

// Close writes trailing data not terminated with a newline.
func (c *colorizer) Close() error {
	if len(c.trailer) > 0 {
		return c.write(c.trailer, nil)
	}
	return nil
}
<|endoftext|>


<commit_before>package popularpost

import (
	"fmt"
	"socialapi/config"
	"socialapi/models"
	"time"

	"github.com/koding/logging"
	"github.com/koding/redis"
	"github.com/streadway/amqp"
)

var (
	PopularPostKeyName = "popularpost"
)

type Controller struct {
	log   logging.Logger
	redis *redis.RedisSession
}

func (t *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	if delivery.Redelivered {
		t.log.Error("Redelivered message gave error again, putting to maintenance queue", err)
		delivery.Ack(false)
		return true
	}

	t.log.Error("an error occured putting message back to queue", err)
	delivery.Nack(false, true)
	return false
}

func New(log logging.Logger, redis *redis.RedisSession) *Controller {
	return &Controller{
		log:   log,
		redis: redis,
	}
}

func (f *Controller) InteractionSaved(i *models.Interaction) error {
	return f.handleInteraction(1, i)
}

func (f *Controller) InteractionDeleted(i *models.Interaction) error {
	return f.handleInteraction(-1, i)
}

func (f *Controller) handleInteraction(incrementCount int, i *models.Interaction) error {
	cm, err := models.ChannelMessageById(i.MessageId)
	if err != nil {
		return err
	}

	c, err := models.ChannelById(cm.InitialChannelId)
	if err != nil {
		return err
	}

	if notEligibleForPopularPost(c, cm) {
		f.log.Error(fmt.Sprintf("Not eligible Interaction Id:%d", i.Id))
		return nil
	}

	if createdMoreThan7DaysAgo(cm.CreatedAt) {
		f.log.Debug(fmt.Sprintf("Post created more than 7 days ago: %v, %v", i.Id, i.CreatedAt))
		return nil
	}

	err = f.saveToDailyBucket(c, cm, i, incrementCount)
	if err != nil {
		return err
	}

	err = f.saveToSevenDayBucket(c, cm, i, incrementCount)
	if err != nil {
		return err
	}

	return nil
}

func (f *Controller) saveToDailyBucket(c *models.Channel, cm *models.ChannelMessage, i *models.Interaction, incrementCount int) error {
	key := getDailyKey(c, cm.CreatedAt)
	_, err := f.redis.SortedSetIncrBy(key, incrementCount, cm.Id)

	return err
}

func (f *Controller) saveToSevenDayBucket(c *models.Channel, cm *models.ChannelMessage, i *models.Interaction, incrementCount int) error {
	key := getSevenDayKey(c, cm)
	from := getStartOfDay(cm.CreatedAt)

	exists := f.redis.Exists(key)
	if exists {
		_, err := f.redis.SortedSetIncrBy(key, incrementCount, cm.Id)
		return err
	}

	err := f.createSevenDayCombinedBucket(c, cm, key, from)
	if err != nil {
		return err
	}

	return nil
}

func (f *Controller) createSevenDayCombinedBucket(c *models.Channel, cm *models.ChannelMessage, key string, from time.Time) error {
	keys, weights := []interface{}{}, []interface{}{}
	aggregate := "SUM"
	from = getStartOfDay(from)

	for i := 0; i <= 6; i++ {
		currentDate := getXDaysAgo(from, i)
		key := getDailyKey(c, currentDate)
		keys = append(keys, key)

		// add by 1 to prevent divide by 0 errors
		weight := float64(i + 1)
		weights = append(weights, float64(1/weight))
	}

	_, err := f.redis.SortedSetsUnion(key, keys, weights, aggregate)

	return err
}

//----------------------------------------------------------
// Key helpers
//----------------------------------------------------------

func getDailyKey(c *models.Channel, date time.Time) string {
	if date.IsZero() {
		date = time.Now().UTC()
	}

	unix := getStartOfDay(date).Unix()

	return fmt.Sprintf("%s:%s:%s:%s:%d",
		config.MustGet().Environment, c.GroupName, PopularPostKeyName, c.Name, unix,
	)
}

func getSevenDayKey(c *models.Channel, cm *models.ChannelMessage) string {
	date := getStartOfDay(cm.CreatedAt)
	return PopularPostKey(c.GroupName, c.Name, date)
}

func PopularPostKey(group, channelName string, current time.Time) string {
	sevenDaysAgo := getXDaysAgo(current, 7)

	return fmt.Sprintf("%s:%s:%s:%s:%d-%d",
		config.MustGet().Environment, group, PopularPostKeyName, channelName,
		current.Unix(), sevenDaysAgo.Unix(),
	)
}

//----------------------------------------------------------
// helpers
//----------------------------------------------------------

func notEligibleForPopularPost(c *models.Channel, cm *models.ChannelMessage) bool {
	if c.MetaBits.Is(models.Troll) {
		return true
	}

	if c.PrivacyConstant != models.Channel_PRIVACY_PUBLIC {
		return true
	}

	if cm.MetaBits.Is(models.Troll) {
		return true
	}

	if cm.TypeConstant != models.ChannelMessage_TYPE_POST {
		return true
	}

	return false
}

//----------------------------------------------------------
// Time helpers
//----------------------------------------------------------

func createdMoreThan7DaysAgo(createdAt time.Time) bool {
	delta := time.Now().Sub(createdAt)
	return delta.Hours()/24 > 7
}

func getStartOfDay(t time.Time) time.Time {
	start := time.Duration(-t.Hour()) * time.Hour         // subtract hour
	start = start - time.Duration(t.Minute())*time.Minute // subtract minutes
	start = start - time.Duration(t.Second())*time.Second // substract seconds

	return t.Add(start)
}

func getXDaysAgo(t time.Time, days int) time.Time {
	daysAgo := -time.Hour * 24 * time.Duration(days)
	return t.Add(daysAgo)
}
<commit_msg>popularpost: convert client time to utc<commit_after>package popularpost

import (
	"fmt"
	"socialapi/config"
	"socialapi/models"
	"time"

	"github.com/koding/logging"
	"github.com/koding/redis"
	"github.com/streadway/amqp"
)

var (
	PopularPostKeyName = "popularpost"
)

type Controller struct {
	log   logging.Logger
	redis *redis.RedisSession
}

func (t *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	if delivery.Redelivered {
		t.log.Error("Redelivered message gave error again, putting to maintenance queue", err)
		delivery.Ack(false)
		return true
	}

	t.log.Error("an error occured putting message back to queue", err)
	delivery.Nack(false, true)
	return false
}

func New(log logging.Logger, redis *redis.RedisSession) *Controller {
	return &Controller{
		log:   log,
		redis: redis,
	}
}

func (f *Controller) InteractionSaved(i *models.Interaction) error {
	return f.handleInteraction(1, i)
}

func (f *Controller) InteractionDeleted(i *models.Interaction) error {
	return f.handleInteraction(-1, i)
}

func (f *Controller) handleInteraction(incrementCount int, i *models.Interaction) error {
	cm, err := models.ChannelMessageById(i.MessageId)
	if err != nil {
		return err
	}

	c, err := models.ChannelById(cm.InitialChannelId)
	if err != nil {
		return err
	}

	if notEligibleForPopularPost(c, cm) {
		f.log.Error(fmt.Sprintf("Not eligible Interaction Id:%d", i.Id))
		return nil
	}

	if createdMoreThan7DaysAgo(cm.CreatedAt) {
		f.log.Debug(fmt.Sprintf("Post created more than 7 days ago: %v, %v", i.Id, i.CreatedAt))
		return nil
	}

	err = f.saveToDailyBucket(c, cm, i, incrementCount)
	if err != nil {
		return err
	}

	err = f.saveToSevenDayBucket(c, cm, i, incrementCount)
	if err != nil {
		return err
	}

	return nil
}

func (f *Controller) saveToDailyBucket(c *models.Channel, cm *models.ChannelMessage, i *models.Interaction, incrementCount int) error {
	key := getDailyKey(c, cm.CreatedAt)
	_, err := f.redis.SortedSetIncrBy(key, incrementCount, cm.Id)

	return err
}

func (f *Controller) saveToSevenDayBucket(c *models.Channel, cm *models.ChannelMessage, i *models.Interaction, incrementCount int) error {
	key := getSevenDayKey(c, cm)
	from := getStartOfDay(cm.CreatedAt)

	exists := f.redis.Exists(key)
	if exists {
		_, err := f.redis.SortedSetIncrBy(key, incrementCount, cm.Id)
		return err
	}

	err := f.createSevenDayCombinedBucket(c, cm, key, from)
	if err != nil {
		return err
	}

	return nil
}

func (f *Controller) createSevenDayCombinedBucket(c *models.Channel, cm *models.ChannelMessage, key string, from time.Time) error {
	keys, weights := []interface{}{}, []interface{}{}
	aggregate := "SUM"
	from = getStartOfDay(from)

	for i := 0; i <= 6; i++ {
		currentDate := getXDaysAgo(from, i)
		key := getDailyKey(c, currentDate)
		keys = append(keys, key)

		// add by 1 to prevent divide by 0 errors
		weight := float64(i + 1)
		weights = append(weights, float64(1/weight))
	}

	_, err := f.redis.SortedSetsUnion(key, keys, weights, aggregate)

	return err
}

//----------------------------------------------------------
// Key helpers
//----------------------------------------------------------

func getDailyKey(c *models.Channel, date time.Time) string {
	if date.IsZero() {
		date = time.Now().UTC()
	}

	unix := getStartOfDay(date).Unix()

	return fmt.Sprintf("%s:%s:%s:%s:%d",
		config.MustGet().Environment, c.GroupName, PopularPostKeyName, c.Name, unix,
	)
}

func getSevenDayKey(c *models.Channel, cm *models.ChannelMessage) string {
	date := getStartOfDay(cm.CreatedAt)
	return PopularPostKey(c.GroupName, c.Name, date)
}

func PopularPostKey(group, channelName string, current time.Time) string {
	current = getStartOfDay(current.UTC())
	sevenDaysAgo := getXDaysAgo(current, 7)

	return fmt.Sprintf("%s:%s:%s:%s:%d-%d",
		config.MustGet().Environment, group, PopularPostKeyName, channelName,
		current.Unix(), sevenDaysAgo.Unix(),
	)
}

//----------------------------------------------------------
// helpers
//----------------------------------------------------------

func notEligibleForPopularPost(c *models.Channel, cm *models.ChannelMessage) bool {
	if c.MetaBits.Is(models.Troll) {
		return true
	}

	if c.PrivacyConstant != models.Channel_PRIVACY_PUBLIC {
		return true
	}

	if cm.MetaBits.Is(models.Troll) {
		return true
	}

	if cm.TypeConstant != models.ChannelMessage_TYPE_POST {
		return true
	}

	return false
}

//----------------------------------------------------------
// Time helpers
//----------------------------------------------------------

func createdMoreThan7DaysAgo(createdAt time.Time) bool {
	delta := time.Now().Sub(createdAt)
	return delta.Hours()/24 > 7
}

func getStartOfDay(t time.Time) time.Time {
	start := time.Duration(-t.Hour()) * time.Hour         // subtract hour
	start = start - time.Duration(t.Minute())*time.Minute // subtract minutes
	start = start - time.Duration(t.Second())*time.Second // substract seconds

	return t.Add(start)
}

func getXDaysAgo(t time.Time, days int) time.Time {
	daysAgo := -time.Hour * 24 * time.Duration(days)
	return t.Add(daysAgo)
}
<|endoftext|>