<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 (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/planrockr/planrockr-cli/config"
	"github.com/spf13/cobra"
	"io/ioutil"
	"net/http"
	"strings"
)

var (
	user     string
	password string
)

// authCmd represents the auth command
var authCmd = &cobra.Command{
	Use:   "auth",
	Short: "auth commands",
	Long:  "You need to use the e-mail and password that you use to log in http://planrockr.com",
	Run: func(cmd *cobra.Command, args []string) {
		token, err := doLogin(user, password)
		if err != nil {
			fmt.Println(err)
		}
		//@todo: save on ~/.planrockr-cli.yaml
		fmt.Printf("%s", token)
	},
}

func doLogin(user string, password string) (token string, err error) {
	body := strings.NewReader("parameters%5Blogin%5D=" + user + "&parameters%5Bpassword%5D=" + password)
	req, err := http.NewRequest("POST", "https://app.planrockr.com/rpc/v1/authentication/login", body)
	if err != nil {
		return "", err
	}
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Origin", "planrockr-cli")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	if err != nil || resp.Status == "404 Not Found" {
		return "", errors.New("Invalid credentials")
	}
	buf, _ := ioutil.ReadAll(resp.Body)

	err = config.Init()
	if err != nil {
		return "", errors.New("Error reading config file")
	}

	type AuthData struct {
		Token         string
		Refresh_Token string
	}
	var authData AuthData
	err = json.Unmarshal(buf, &authData)
	if err != nil {
		return "", errors.New("Error parsing authorization data")
	}
	err = config.Set("auth.token", authData.Token)
	err = config.Set("auth.refreshtoken", authData.Refresh_Token)
	if err != nil {
		return "", errors.New("Error writing config file")
	}

	return "Authorized\n", nil
}

func init() {
	RootCmd.AddCommand(authCmd)

	authCmd.Flags().StringVarP(&user, "user", "u", "", "User e-mail")
	authCmd.Flags().StringVarP(&password, "password", "p", "", "User password")

}
<commit_msg>Melhoria no doLogin<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 (
	"encoding/json"
	"errors"
	"fmt"
	"github.com/planrockr/planrockr-cli/config"
	"github.com/spf13/cobra"
	"io/ioutil"
	"net/http"
	"strings"
)

var (
	user     string
	password string
)

// authCmd represents the auth command
var authCmd = &cobra.Command{
	Use:   "auth",
	Short: "auth commands",
	Long:  "You need to use the e-mail and password that you use to log in http://planrockr.com",
	Run: func(cmd *cobra.Command, args []string) {
		err := doLogin(user, password)
		if err != nil {
			fmt.Println(err)
		}
	},
}

func doLogin(user string, password string) error {
	body := strings.NewReader("parameters%5Blogin%5D=" + user + "&parameters%5Bpassword%5D=" + password)
	req, err := http.NewRequest("POST", "https://app.planrockr.com/rpc/v1/authentication/login", body)
	if err != nil {
		return err
	}
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req.Header.Set("Origin", "planrockr-cli")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if err != nil || resp.Status == "404 Not Found" {
		return errors.New("Invalid credentials")
	}
	buf, _ := ioutil.ReadAll(resp.Body)

	err = config.Init()
	if err != nil {
		return errors.New("Error reading config file")
	}

	type AuthData struct {
		Token         string
		Refresh_Token string
	}
	var authData AuthData
	err = json.Unmarshal(buf, &authData)
	if err != nil {
		return errors.New("Error parsing authorization data")
	}
	err = config.Set("auth.token", authData.Token)
	err = config.Set("auth.refreshtoken", authData.Refresh_Token)
	if err != nil {
		return errors.New("Error writing config file")
	}

	fmt.Println("Authorized")

	return nil
}

func init() {
	RootCmd.AddCommand(authCmd)

	authCmd.Flags().StringVarP(&user, "user", "u", "", "User e-mail")
	authCmd.Flags().StringVarP(&password, "password", "p", "", "User password")

}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//     https://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 main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"

	"github.com/datacommonsorg/mixer/internal/healthcheck"
	pb "github.com/datacommonsorg/mixer/internal/proto"
	"github.com/datacommonsorg/mixer/internal/server"
	"golang.org/x/oauth2/google"

	"cloud.google.com/go/bigquery"
	"cloud.google.com/go/bigtable"
	"cloud.google.com/go/profiler"
	"google.golang.org/api/compute/v1"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/alts"
	"google.golang.org/grpc/health/grpc_health_v1"
	"google.golang.org/grpc/reflection"
)

var (
	bqDataset         = flag.String("bq_dataset", "", "DataCommons BigQuery dataset.")
	btTableName       = flag.String("bt_table", "", "DataCommons Bigtable table.")
	btProject         = flag.String("bt_project", "", "GCP project containing the BigTable instance.")
	btInstance        = flag.String("bt_instance", "", "BigTable instance.")
	projectID         = flag.String("project_id", "", "The cloud project to run the mixer instance.")
	port              = flag.Int("port", 12345, "Port on which to run the server.")
	useALTS           = flag.Bool("use_alts", false, "Whether to use ALTS server authentication")
	enableBranchCache = flag.Bool("enable_branch_cache", true, "Whether to use branch cache")
	bigqueryOnly      = flag.Bool("bigquery_only", true, "The service only serves sparql query")
)

const (
	branchCacheBucket      = "prophet_cache"
	branchCacheVersionFile = "latest_branch_cache_version.txt"
	pubsubProject          = "google.com:datcom-store-dev"
	pubsubTopic            = "branch-cache-reload"
	subscriberPrefix       = "mixer-subscriber-"
)

func main() {
	fmt.Println("Enter mixer main() function")

	flag.Parse()
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	ctx := context.Background()

	credentials, error := google.FindDefaultCredentials(ctx, compute.ComputeScope)
	if error == nil && credentials.ProjectID != "" {
		cfg := profiler.Config{
			Service:        "mixer-service",
			ServiceVersion: *btTableName,
		}
		err := profiler.Start(cfg)
		if err != nil {
			log.Printf("Failed to start profiler: %v", err)
		}
	}

	// BigQuery.
	bqClient, err := bigquery.NewClient(ctx, *projectID)
	if err != nil {
		log.Fatalf("Failed to create Bigquery client: %v", err)
	}

	var btTable *bigtable.Table
	if *bigqueryOnly {
		btTable = nil
	} else {
		// BigTable.
		btTable, err = server.NewBtTable(ctx, *btProject, *btInstance, *btTableName)
		if err != nil {
			log.Fatalf("Failed to create BigTable client: %v", err)
		}
	}

	// Metadata.
	metadata, err := server.NewMetadata(*bqDataset)
	if err != nil {
		log.Fatalf("Failed to create metadata: %v", err)
	}

	memcache := &server.Memcache{}
	if !*bigqueryOnly && *enableBranchCache {
		// Memcache
		branchCacheFolder, err := server.ReadBranchCacheFolder(
			ctx, branchCacheBucket, branchCacheVersionFile)
		if err != nil {
			log.Fatalf("Failed to read branch cache folder: %v", err)
		}
		memcache, err = server.NewMemcacheFromGCS(
			ctx, branchCacheBucket, branchCacheFolder)
		if err != nil {
			log.Fatalf("Failed to create memcache from gcs: %v", err)
		}
	}

	// Create server object
	s := server.NewServer(bqClient, btTable, memcache, metadata)

	// Subscribe to cache update
	if !*bigqueryOnly && *enableBranchCache {
		err = s.SubscribeBranchCacheUpdate(
			ctx, pubsubProject, branchCacheBucket, subscriberPrefix, pubsubTopic)
		if err != nil {
			log.Fatalf("Failed to subscribe to branch cache update: %v", err)
		}
	}

	opts := []grpc.ServerOption{}

	// Use ALTS server credential to bind to VM's private IPv6 interface.
	if *useALTS {
		altsTC := alts.NewServerCreds(alts.DefaultServerOptions())
		opts = append(opts, grpc.Creds(altsTC))
	}

	// Start mixer
	srv := grpc.NewServer(opts...)
	pb.RegisterMixerServer(srv, s)
	// Register reflection service on gRPC server.
	reflection.Register(srv)

	healthService := healthcheck.NewHealthChecker()
	grpc_health_v1.RegisterHealthServer(srv, healthService)

	// Listen on network
	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
	if err != nil {
		log.Fatalf("Failed to listen on network: %v", err)
	}
	fmt.Println("Mixer ready to serve!!")
	if err := srv.Serve(lis); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}
<commit_msg>Set bigquery_only flag to be false (#442)<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//     https://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 main

import (
	"context"
	"flag"
	"fmt"
	"log"
	"net"

	"github.com/datacommonsorg/mixer/internal/healthcheck"
	pb "github.com/datacommonsorg/mixer/internal/proto"
	"github.com/datacommonsorg/mixer/internal/server"
	"golang.org/x/oauth2/google"

	"cloud.google.com/go/bigquery"
	"cloud.google.com/go/bigtable"
	"cloud.google.com/go/profiler"
	"google.golang.org/api/compute/v1"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/alts"
	"google.golang.org/grpc/health/grpc_health_v1"
	"google.golang.org/grpc/reflection"
)

var (
	bqDataset         = flag.String("bq_dataset", "", "DataCommons BigQuery dataset.")
	btTableName       = flag.String("bt_table", "", "DataCommons Bigtable table.")
	btProject         = flag.String("bt_project", "", "GCP project containing the BigTable instance.")
	btInstance        = flag.String("bt_instance", "", "BigTable instance.")
	projectID         = flag.String("project_id", "", "The cloud project to run the mixer instance.")
	port              = flag.Int("port", 12345, "Port on which to run the server.")
	useALTS           = flag.Bool("use_alts", false, "Whether to use ALTS server authentication")
	enableBranchCache = flag.Bool("enable_branch_cache", true, "Whether to use branch cache")
	bigqueryOnly      = flag.Bool("bigquery_only", false, "The service only serves sparql query")
)

const (
	branchCacheBucket      = "prophet_cache"
	branchCacheVersionFile = "latest_branch_cache_version.txt"
	pubsubProject          = "google.com:datcom-store-dev"
	pubsubTopic            = "branch-cache-reload"
	subscriberPrefix       = "mixer-subscriber-"
)

func main() {
	fmt.Println("Enter mixer main() function")

	flag.Parse()
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	ctx := context.Background()

	credentials, error := google.FindDefaultCredentials(ctx, compute.ComputeScope)
	if error == nil && credentials.ProjectID != "" {
		cfg := profiler.Config{
			Service:        "mixer-service",
			ServiceVersion: *btTableName,
		}
		err := profiler.Start(cfg)
		if err != nil {
			log.Printf("Failed to start profiler: %v", err)
		}
	}

	// BigQuery.
	bqClient, err := bigquery.NewClient(ctx, *projectID)
	if err != nil {
		log.Fatalf("Failed to create Bigquery client: %v", err)
	}

	var btTable *bigtable.Table
	if *bigqueryOnly {
		btTable = nil
	} else {
		// BigTable.
		btTable, err = server.NewBtTable(ctx, *btProject, *btInstance, *btTableName)
		if err != nil {
			log.Fatalf("Failed to create BigTable client: %v", err)
		}
	}

	// Metadata.
	metadata, err := server.NewMetadata(*bqDataset)
	if err != nil {
		log.Fatalf("Failed to create metadata: %v", err)
	}

	memcache := &server.Memcache{}
	if !*bigqueryOnly && *enableBranchCache {
		// Memcache
		branchCacheFolder, err := server.ReadBranchCacheFolder(
			ctx, branchCacheBucket, branchCacheVersionFile)
		if err != nil {
			log.Fatalf("Failed to read branch cache folder: %v", err)
		}
		memcache, err = server.NewMemcacheFromGCS(
			ctx, branchCacheBucket, branchCacheFolder)
		if err != nil {
			log.Fatalf("Failed to create memcache from gcs: %v", err)
		}
	}

	// Create server object
	s := server.NewServer(bqClient, btTable, memcache, metadata)

	// Subscribe to cache update
	if !*bigqueryOnly && *enableBranchCache {
		err = s.SubscribeBranchCacheUpdate(
			ctx, pubsubProject, branchCacheBucket, subscriberPrefix, pubsubTopic)
		if err != nil {
			log.Fatalf("Failed to subscribe to branch cache update: %v", err)
		}
	}

	opts := []grpc.ServerOption{}

	// Use ALTS server credential to bind to VM's private IPv6 interface.
	if *useALTS {
		altsTC := alts.NewServerCreds(alts.DefaultServerOptions())
		opts = append(opts, grpc.Creds(altsTC))
	}

	// Start mixer
	srv := grpc.NewServer(opts...)
	pb.RegisterMixerServer(srv, s)
	// Register reflection service on gRPC server.
	reflection.Register(srv)

	healthService := healthcheck.NewHealthChecker()
	grpc_health_v1.RegisterHealthServer(srv, healthService)

	// Listen on network
	lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
	if err != nil {
		log.Fatalf("Failed to listen on network: %v", err)
	}
	fmt.Println("Mixer ready to serve!!")
	if err := srv.Serve(lis); err != nil {
		log.Fatalf("Failed to serve: %v", err)
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"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"
	"github.com/drud/drud-go/drudapi"
	"github.com/drud/drud-go/secrets"
	"github.com/hashicorp/vault/api"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const (
	timestampFormat = "20060102150405"
	updateFile      = ".drud-update"
	tokenFile       = ".drud-sanctuary-token"
	cliVersion      = "0.2.1"
	drudapiVersion  = "v0.1"
)

var (
	cfg                *Config
	usr                *user.User
	pwd                string
	cfgFile            string
	drudconf           string           //absolute path to cfg file
	drudclient         *drudapi.Request //client for interacting with drud api
	workdir            string
	bucket             string                   // aws s3 bucket used with file storage functionality
	region             string                   // region where the s3 bucket can be found
	creds              *credentials.Credentials // s3 related credentials
	svc                *s3.S3
	awsID              string
	vaultAddress       string // stores the vault host address
	awsSecret          string
	dbFile             string
	isDev              bool   // isDev stores boolean value to allow special functionality for devs
	homedir            string // current user's home directory
	gitToken           string
	clientCreateAccess bool
	filesAccess        bool
	drudAccess         bool
	bucketName         = "drudcli-drud-files-bucket"
	forceDelete        bool
	vaultToken         string
	vault              api.Logical // part of the vault go api
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "drud",
	Short: "A CLI for interacting with DRUD.",
	Long:  "This Command Line Interface (CLI) gives you the ability to interact with the DRUD platform to manage applications, create a local development environment, or deploy an application to production. DRUD also provides utilities for securely uploading files and secrets associated with applications.",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println(`Use "drud --help" for more information about this tool.`)
	},
}

// 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() {

	//RootCmd.RemoveCommand(SecretCmd)
	SetHomedir()
	tokenLocation := filepath.Join(homedir, tokenFile)
	if len(os.Args) == 2 && os.Args[1] != "--hrlp" {
		if _, err := os.Stat(tokenLocation); os.IsNotExist(err) {
			RootCmd.Help()
			os.Exit(0)
		}
	}

	SetConf()

	// create a blank drud config if one does not exist
	if _, err := os.Stat(drudconf); os.IsNotExist(err) {
		f, ferr := os.Create(drudconf)
		if ferr != nil {
			log.Fatal(ferr)
		}
		defer f.Close()
		//default drud.yaml contents
		f.WriteString(`Client: 1fee
Dev: false
DrudHost: drudapi.genesis.drud.io
Protocol: https
VaultHost: https://sanctuary.drud.io:8200
Version: v0.1
`)

	}

	// prepopulate tokenfile so i dont have to check for its existence everywhere
	if _, err := os.Stat(tokenLocation); os.IsNotExist(err) {
		f, ferr := os.Create(tokenLocation)
		if ferr != nil {
			log.Fatal(ferr)
		}
		defer f.Close()
		//default drud.yaml contents
		f.WriteString("placeholder")
	}

	// bind flags to viper config values...allows override by flag
	//viper.BindPFlag("vault_host", RootCmd.PersistentFlags().Lookup("vault_host"))
	viper.BindPFlag("dev", RootCmd.PersistentFlags().Lookup("dev"))
	viper.SetConfigFile(drudconf)
	viper.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	err := viper.ReadInConfig() // Find and read the config file
	if err != nil {             // Handle errors reading the config file
		log.Fatalf("Fatal error config file: %s \n", err)
	}

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

	gitToken = os.Getenv("GITHUB_TOKEN")

	// load the vault token from disk and use it to get policy information
	// if permission is denied send the user through `drud auth github` and then try again
	if len(os.Args) >= 2 && os.Args[1] != "auth" {
		for i := 0; i < 2; i++ {
			vaultToken = secrets.ConfigVault(tokenLocation, cfg.VaultHost)
			vault = secrets.GetVault()
			err = EnableAvailablePackages()
			if err != nil {
				if strings.Contains(err.Error(), "permission denied") && i == 0 {
					githubCmd.Run(RootCmd, []string{})
					continue
				}
				log.Fatal(err)
			}
			break
		}
	}

	if err := RootCmd.Execute(); err != nil {
		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/drud.yaml)")
	RootCmd.PersistentFlags().StringVar(&vaultAddress, "vault_address", "https://sanctuary.drud.io:8200", "Vault Address")
	RootCmd.PersistentFlags().BoolVarP(&isDev, "dev", "", false, "Enable Dev mode")
	// files related
	RootCmd.PersistentFlags().StringVar(&bucket, "bucket", "nmdarchive", "name of S3 bucket to work with")
	RootCmd.PersistentFlags().StringVar(&region, "region", "us-west-2", "region your bucket is in")
	RootCmd.PersistentFlags().StringVar(&workdir, "workdir", "", "directory other than cwd we are running from")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {

	if drudAccess {
		// auth with vault token if available
		eveCreds := &drudapi.Credentials{}
		if vaultToken != "" {
			eveCreds.Token = vaultToken
		} else {
			eveCreds.AdminToken = gitToken
		}

		// drud api client
		drudclient = &drudapi.Request{
			Host: cfg.EveHost(),
			Auth: eveCreds,
		}
	}

	if filesAccess {

		sobj := secrets.Secret{
			Path: "secret/shared/services/awscfg",
		}

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

		awsID = sobj.Data["accesskey"].(string)
		awsSecret = sobj.Data["secretkey"].(string)
		os.Setenv("AWS_ACCESS_KEY_ID", awsID)
		os.Setenv("AWS_SECRET_ACCESS_KEY", awsSecret)

		svc = s3.New(session.New(&aws.Config{Region: aws.String(region)}))
	}

}
<commit_msg>dont require auth for some commands (#128)<commit_after>package cmd

import (
	"fmt"
	"log"
	"os"
	"os/user"
	"path/filepath"
	"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"
	"github.com/drud/drud-go/drudapi"
	"github.com/drud/drud-go/secrets"
	"github.com/hashicorp/vault/api"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const (
	timestampFormat = "20060102150405"
	updateFile      = ".drud-update"
	tokenFile       = ".drud-sanctuary-token"
	cliVersion      = "0.2.1"
	drudapiVersion  = "v0.1"
)

var (
	cfg                *Config
	usr                *user.User
	pwd                string
	cfgFile            string
	drudconf           string           //absolute path to cfg file
	drudclient         *drudapi.Request //client for interacting with drud api
	workdir            string
	bucket             string                   // aws s3 bucket used with file storage functionality
	region             string                   // region where the s3 bucket can be found
	creds              *credentials.Credentials // s3 related credentials
	svc                *s3.S3
	awsID              string
	vaultAddress       string // stores the vault host address
	awsSecret          string
	dbFile             string
	isDev              bool   // isDev stores boolean value to allow special functionality for devs
	homedir            string // current user's home directory
	gitToken           string
	clientCreateAccess bool
	filesAccess        bool
	drudAccess         bool
	bucketName         = "drudcli-drud-files-bucket"
	forceDelete        bool
	vaultToken         string
	vault              api.Logical // part of the vault go api
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "drud",
	Short: "A CLI for interacting with DRUD.",
	Long:  "This Command Line Interface (CLI) gives you the ability to interact with the DRUD platform to manage applications, create a local development environment, or deploy an application to production. DRUD also provides utilities for securely uploading files and secrets associated with applications.",
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Println(`Use "drud --help" for more information about this tool.`)
	},
}

// 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() {

	//RootCmd.RemoveCommand(SecretCmd)
	SetHomedir()
	tokenLocation := filepath.Join(homedir, tokenFile)
	if len(os.Args) == 2 && RequiresAuth(os.Args[1]) {
		if _, err := os.Stat(tokenLocation); os.IsNotExist(err) {
			RootCmd.Help()
			os.Exit(0)
		}
	}

	SetConf()
	// create a blank drud config if one does not exist
	if _, err := os.Stat(drudconf); os.IsNotExist(err) {
		f, ferr := os.Create(drudconf)
		if ferr != nil {
			log.Fatal(ferr)
		}
		defer f.Close()
		//default drud.yaml contents
		f.WriteString(`Client: 1fee
Dev: false
DrudHost: drudapi.genesis.drud.io
Protocol: https
VaultHost: https://sanctuary.drud.io:8200
Version: v0.1
`)

	}

	// prepopulate tokenfile so i dont have to check for its existence everywhere
	if _, err := os.Stat(tokenLocation); os.IsNotExist(err) {
		f, ferr := os.Create(tokenLocation)
		if ferr != nil {
			log.Fatal(ferr)
		}
		defer f.Close()
		//default drud.yaml contents
		f.WriteString("placeholder")
	}

	// bind flags to viper config values...allows override by flag
	//viper.BindPFlag("vault_host", RootCmd.PersistentFlags().Lookup("vault_host"))
	viper.BindPFlag("dev", RootCmd.PersistentFlags().Lookup("dev"))
	viper.SetConfigFile(drudconf)
	viper.AutomaticEnv() // read in environment variables that match

	// If a config file is found, read it in.
	err := viper.ReadInConfig() // Find and read the config file
	if err != nil {             // Handle errors reading the config file
		log.Fatalf("Fatal error config file: %s \n", err)
	}

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

	gitToken = os.Getenv("GITHUB_TOKEN")

	// load the vault token from disk and use it to get policy information
	// if permission is denied send the user through `drud auth github` and then try again
	if len(os.Args) >= 2 && RequiresAuth(os.Args[1]) {
		for i := 0; i < 2; i++ {
			vaultToken = secrets.ConfigVault(tokenLocation, cfg.VaultHost)
			vault = secrets.GetVault()
			err = EnableAvailablePackages()
			if err != nil {
				if strings.Contains(err.Error(), "permission denied") && i == 0 {
					githubCmd.Run(RootCmd, []string{})
					continue
				}
				log.Fatal(err)
			}
			break
		}
	}

	if err := RootCmd.Execute(); err != nil {
		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/drud.yaml)")
	RootCmd.PersistentFlags().StringVar(&vaultAddress, "vault_address", "https://sanctuary.drud.io:8200", "Vault Address")
	RootCmd.PersistentFlags().BoolVarP(&isDev, "dev", "", false, "Enable Dev mode")
	// files related
	RootCmd.PersistentFlags().StringVar(&bucket, "bucket", "nmdarchive", "name of S3 bucket to work with")
	RootCmd.PersistentFlags().StringVar(&region, "region", "us-west-2", "region your bucket is in")
	RootCmd.PersistentFlags().StringVar(&workdir, "workdir", "", "directory other than cwd we are running from")
	// Cobra also supports local flags, which will only run
	// when this action is called directly.
	RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {

	if drudAccess {
		// auth with vault token if available
		eveCreds := &drudapi.Credentials{}
		if vaultToken != "" {
			eveCreds.Token = vaultToken
		} else {
			eveCreds.AdminToken = gitToken
		}

		// drud api client
		drudclient = &drudapi.Request{
			Host: cfg.EveHost(),
			Auth: eveCreds,
		}
	}

	if filesAccess {

		sobj := secrets.Secret{
			Path: "secret/shared/services/awscfg",
		}

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

		awsID = sobj.Data["accesskey"].(string)
		awsSecret = sobj.Data["secretkey"].(string)
		os.Setenv("AWS_ACCESS_KEY_ID", awsID)
		os.Setenv("AWS_SECRET_ACCESS_KEY", awsSecret)

		svc = s3.New(session.New(&aws.Config{Region: aws.String(region)}))
	}

}
<|endoftext|>


<commit_before>// Copyright © 2017 Max Goltzsche
//
// 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"
	"strconv"

	"github.com/mgoltzsche/cntnr/log"
	"github.com/spf13/cobra"
	//homedir "github.com/mitchellh/go-homedir"
	//"github.com/spf13/viper"
	"os"
	"path/filepath"

	"github.com/containers/image/types"
	image "github.com/mgoltzsche/cntnr/oci/image"
	istore "github.com/mgoltzsche/cntnr/oci/image/store"
	storepkg "github.com/mgoltzsche/cntnr/oci/store"
	"github.com/mitchellh/go-homedir"
)

var (
	flagVerbose     bool
	flagRootless    bool
	flagCfgFile     string
	flagStoreDir    string
	flagStateDir    string
	flagImagePolicy string

	store            storepkg.Store
	lockedImageStore image.ImageStoreRW
	errorLog         = log.NewStdLogger(os.Stderr)
	warnLog          = log.NewStdLogger(os.Stderr)
	debugLog         = log.NewNopLogger()
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "cntnr",
	Short: "a lightweight container engine",
	Long: `cntnr is a lightweight OCI-compliant container engine.
It supports single image and container operations as well as high-level service composition.`,
	PersistentPreRun: preRun,
}

// 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() {
	RootCmd.AddCommand(runCmd)
	RootCmd.AddCommand(killCmd)
	RootCmd.AddCommand(listCmd)
	RootCmd.AddCommand(imageCmd)
	RootCmd.AddCommand(bundleCmd)
	RootCmd.AddCommand(composeCmd)
	RootCmd.AddCommand(netCmd)
	RootCmd.AddCommand(commitCmd)
	RootCmd.AddCommand(gcCmd)
	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/.cntnr.yaml)")

	uid := os.Geteuid()
	homeDir, err := homedir.Dir()
	if err == nil {
		flagStoreDir = filepath.Join(homeDir, ".cntnr")
	}
	flagStateDir = "/run/cntnr"
	if uid != 0 {
		flagStateDir = "/run/user/" + strconv.Itoa(uid) + "/cntnr"
	}
	flagImagePolicy = "default"
	policyFile := "/etc/containers/policy.json"
	if _, err = os.Stat(policyFile); err == nil {
		flagImagePolicy = policyFile
	}
	f := RootCmd.PersistentFlags()
	f.BoolVar(&flagVerbose, "verbose", false, "enables verbose log output")
	f.BoolVar(&flagRootless, "rootless", uid != 0, "enables image and container management as unprivileged user")
	f.StringVar(&flagStoreDir, "store-dir", flagStoreDir, "directory to store images and containers")
	f.StringVar(&flagStateDir, "state-dir", flagStateDir, "directory to store OCI container states (should be tmpfs)")
	f.StringVar(&flagImagePolicy, "image-policy", flagImagePolicy, "image trust policy configuration file or 'insecure'")
}

func preRun(cmd *cobra.Command, args []string) {
	if flagVerbose {
		debugLog = log.NewStdLogger(os.Stderr)
	}

	// init store
	// TODO: provide CLI options
	ctx := &types.SystemContext{
		RegistriesDirPath:           "",
		DockerCertPath:              "",
		DockerInsecureSkipTLSVerify: true,
		OSTreeTmpDirPath:            "ostree-tmp-dir",
		// TODO: add docker auth
		//DockerAuthConfig: dockerAuth,
	}
	var err error
	if flagRootless && ctx.DockerCertPath == "" {
		ctx.DockerCertPath = "./docker-certs"
	}

	var imagePolicy istore.TrustPolicyContext
	if flagImagePolicy == "default" {
		imagePolicy = istore.TrustPolicyReject()
	} else if flagImagePolicy == "insecure" {
		imagePolicy = istore.TrustPolicyInsecure()
	} else if flagImagePolicy != "" {
		imagePolicy = istore.TrustPolicyFromFile(flagImagePolicy)
	} else {
		exitError(2, "empty value for --image-policy option")
	}
	store, err = storepkg.NewStore(flagStoreDir, flagRootless, ctx, imagePolicy, errorLog, debugLog)
	exitOnError(cmd, err)
}

// initConfig reads in config file and ENV variables if set.
/*func initConfig() {
	if flagCfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(flagCfgFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			exitError(1, "%s", err)
		}

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

	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>Added reject policy. Improved compatibility by using go-homedir<commit_after>// Copyright © 2017 Max Goltzsche
//
// 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"
	"strconv"

	"github.com/mgoltzsche/cntnr/log"
	"github.com/spf13/cobra"
	//homedir "github.com/mitchellh/go-homedir"
	//"github.com/spf13/viper"
	"os"
	"path/filepath"

	"github.com/containers/image/types"
	image "github.com/mgoltzsche/cntnr/oci/image"
	istore "github.com/mgoltzsche/cntnr/oci/image/store"
	storepkg "github.com/mgoltzsche/cntnr/oci/store"
	"github.com/mitchellh/go-homedir"
)

var (
	flagVerbose     bool
	flagRootless    bool
	flagCfgFile     string
	flagStoreDir    string
	flagStateDir    string
	flagImagePolicy string

	store            storepkg.Store
	lockedImageStore image.ImageStoreRW
	errorLog         = log.NewStdLogger(os.Stderr)
	warnLog          = log.NewStdLogger(os.Stderr)
	debugLog         = log.NewNopLogger()
)

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "cntnr",
	Short: "a lightweight container engine",
	Long: `cntnr is a lightweight OCI-compliant container engine.
It supports single image and container operations as well as high-level service composition.`,
	PersistentPreRun: preRun,
}

// 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() {
	RootCmd.AddCommand(runCmd)
	RootCmd.AddCommand(killCmd)
	RootCmd.AddCommand(listCmd)
	RootCmd.AddCommand(imageCmd)
	RootCmd.AddCommand(bundleCmd)
	RootCmd.AddCommand(composeCmd)
	RootCmd.AddCommand(netCmd)
	RootCmd.AddCommand(commitCmd)
	RootCmd.AddCommand(gcCmd)
	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/.cntnr.yaml)")

	uid := os.Geteuid()
	homeDir, err := homedir.Dir()
	if err == nil {
		flagStoreDir = filepath.Join(homeDir, ".cntnr")
	}
	flagStateDir = "/run/cntnr"
	if uid != 0 {
		flagStateDir = "/run/user/" + strconv.Itoa(uid) + "/cntnr"
	}
	flagImagePolicy = "insecure"
	policyFile := "/etc/containers/policy.json"
	if _, err = os.Stat(policyFile); err == nil {
		flagImagePolicy = policyFile
	}
	f := RootCmd.PersistentFlags()
	f.BoolVar(&flagVerbose, "verbose", false, "enables verbose log output")
	f.BoolVar(&flagRootless, "rootless", uid != 0, "enables image and container management as unprivileged user")
	f.StringVar(&flagStoreDir, "store-dir", flagStoreDir, "directory to store images and containers")
	f.StringVar(&flagStateDir, "state-dir", flagStateDir, "directory to store OCI container states (should be tmpfs)")
	f.StringVar(&flagImagePolicy, "image-policy", flagImagePolicy, "image trust policy configuration file or 'insecure'")
}

func preRun(cmd *cobra.Command, args []string) {
	if flagVerbose {
		debugLog = log.NewStdLogger(os.Stderr)
	}

	// init store
	// TODO: provide CLI options
	ctx := &types.SystemContext{
		RegistriesDirPath:           "",
		DockerCertPath:              "",
		DockerInsecureSkipTLSVerify: true,
		OSTreeTmpDirPath:            "ostree-tmp-dir",
		// TODO: add docker auth
		//DockerAuthConfig: dockerAuth,
	}
	var err error
	if flagRootless && ctx.DockerCertPath == "" {
		ctx.DockerCertPath = "./docker-certs"
	}

	var imagePolicy istore.TrustPolicyContext
	if flagImagePolicy == "reject" {
		imagePolicy = istore.TrustPolicyReject()
	} else if flagImagePolicy == "insecure" {
		imagePolicy = istore.TrustPolicyInsecure()
	} else if flagImagePolicy != "" {
		imagePolicy = istore.TrustPolicyFromFile(flagImagePolicy)
	} else {
		exitError(2, "empty value for --image-policy option")
	}
	store, err = storepkg.NewStore(flagStoreDir, flagRootless, ctx, imagePolicy, errorLog, debugLog)
	exitOnError(cmd, err)
}

// initConfig reads in config file and ENV variables if set.
/*func initConfig() {
	if flagCfgFile != "" {
		// Use config file from the flag.
		viper.SetConfigFile(flagCfgFile)
	} else {
		// Find home directory.
		home, err := homedir.Dir()
		if err != nil {
			exitError(1, "%s", err)
		}

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

	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())
	}
}*/
<|endoftext|>


<commit_before>// Copyright © 2017 Teppei Fukuda
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

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

	"github.com/knqyf263/pet/config"
	"github.com/spf13/cobra"
)

const (
	version = "0.1.0"
)

var configFile string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "pet",
	Short: "Simple command-line snippet manager.",
	Long:  `pet - Simple command-line snippet manager.`,
}

// Execute adds all child commands to the root command sets flags appropriately.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	RootCmd.AddCommand(versionCmd)

	RootCmd.PersistentFlags().StringVar(&configFile, "config", "", "config file (default is $HOME/.config/pet/config.toml)")
	RootCmd.PersistentFlags().BoolVarP(&config.Flag.Debug, "debug", "", false, "debug mode")
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number",
	Long:  `Print the version number`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Printf("pet version %s\n", version)
	},
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if configFile == "" {
		dir, err := config.GetDefaultConfigDir()
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v", err)
			os.Exit(1)
		}
		configFile = filepath.Join(dir, "config.toml")
	}

	if err := config.Conf.Load(configFile); err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
		os.Exit(1)
	}
}
<commit_msg>v0.2.0<commit_after>// Copyright © 2017 Teppei Fukuda
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cmd

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

	"github.com/knqyf263/pet/config"
	"github.com/spf13/cobra"
)

const (
	version = "0.2.0"
)

var configFile string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "pet",
	Short: "Simple command-line snippet manager.",
	Long:  `pet - Simple command-line snippet manager.`,
}

// Execute adds all child commands to the root command sets flags appropriately.
func Execute() {
	if err := RootCmd.Execute(); err != nil {
		fmt.Println(err)
		os.Exit(-1)
	}
}

func init() {
	cobra.OnInitialize(initConfig)
	RootCmd.AddCommand(versionCmd)

	RootCmd.PersistentFlags().StringVar(&configFile, "config", "", "config file (default is $HOME/.config/pet/config.toml)")
	RootCmd.PersistentFlags().BoolVarP(&config.Flag.Debug, "debug", "", false, "debug mode")
}

var versionCmd = &cobra.Command{
	Use:   "version",
	Short: "Print the version number",
	Long:  `Print the version number`,
	Run: func(cmd *cobra.Command, args []string) {
		fmt.Printf("pet version %s\n", version)
	},
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
	if configFile == "" {
		dir, err := config.GetDefaultConfigDir()
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v", err)
			os.Exit(1)
		}
		configFile = filepath.Join(dir, "config.toml")
	}

	if err := config.Conf.Load(configFile); err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package cmd

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/setting"
	"github.com/Unknwon/com"
	"github.com/dgrijalva/jwt-go"
	"github.com/urfave/cli"
)

const (
	accessDenied        = "Repository does not exist or you do not have access"
	lfsAuthenticateVerb = "git-lfs-authenticate"
)

// CmdServ represents the available serv sub-command.
var CmdServ = cli.Command{
	Name:        "serv",
	Usage:       "This command should only be called by SSH shell",
	Description: `Serv provide access auth for repositories`,
	Action:      runServ,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Value: "custom/conf/app.ini",
			Usage: "Custom configuration file path",
		},
	},
}

func setup(logPath string) error {
	setting.NewContext()
	log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
	models.LoadConfigs()

	if setting.UseSQLite3 || setting.UseTiDB {
		workDir, _ := setting.WorkDir()
		if err := os.Chdir(workDir); err != nil {
			log.GitLogger.Fatal(4, "Failed to change directory %s: %v", workDir, err)
		}
	}

	setting.NewXORMLogService(true)
	return models.SetEngine()
}

func parseCmd(cmd string) (string, string) {
	ss := strings.SplitN(cmd, " ", 2)
	if len(ss) != 2 {
		return "", ""
	}
	return ss[0], strings.Replace(ss[1], "'/", "'", 1)
}

var (
	allowedCommands = map[string]models.AccessMode{
		"git-upload-pack":    models.AccessModeRead,
		"git-upload-archive": models.AccessModeRead,
		"git-receive-pack":   models.AccessModeWrite,
		lfsAuthenticateVerb:  models.AccessModeNone,
	}
)

func fail(userMessage, logMessage string, args ...interface{}) {
	fmt.Fprintln(os.Stderr, "Gitea:", userMessage)

	if len(logMessage) > 0 {
		if !setting.ProdMode {
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
		}
		log.GitLogger.Fatal(3, logMessage, args...)
		return
	}

	log.GitLogger.Close()
	os.Exit(1)
}

func runServ(c *cli.Context) error {
	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	}

	if err := setup("serv.log"); err != nil {
		fail("System init failed", fmt.Sprintf("setup: %v", err))
	}

	if setting.SSH.Disabled {
		println("Gitea: SSH has been disabled")
		return nil
	}

	if len(c.Args()) < 1 {
		fail("Not enough arguments", "Not enough arguments")
	}

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if len(cmd) == 0 {
		println("Hi there, You've successfully authenticated, but Gitea does not provide shell access.")
		println("If this is unexpected, please log in with password and setup Gitea under another user.")
		return nil
	}

	verb, args := parseCmd(cmd)

	var lfsVerb string
	if verb == lfsAuthenticateVerb {
		if !setting.LFS.StartServer {
			fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
		}

		if strings.Contains(args, " ") {
			argsSplit := strings.SplitN(args, " ", 2)
			args = strings.TrimSpace(argsSplit[0])
			lfsVerb = strings.TrimSpace(argsSplit[1])
		}
	}

	repoPath := strings.ToLower(strings.Trim(args, "'"))
	rr := strings.SplitN(repoPath, "/", 2)
	if len(rr) != 2 {
		fail("Invalid repository path", "Invalid repository path: %v", args)
	}

	username := strings.ToLower(rr[0])
	reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))

	isWiki := false
	if strings.HasSuffix(reponame, ".wiki") {
		isWiki = true
		reponame = reponame[:len(reponame)-5]
	}

	os.Setenv(models.EnvRepoUsername, username)
	if isWiki {
		os.Setenv(models.EnvRepoIsWiki, "true")
	} else {
		os.Setenv(models.EnvRepoIsWiki, "false")
	}
	os.Setenv(models.EnvRepoName, reponame)

	repoUser, err := models.GetUserByName(username)
	if err != nil {
		if models.IsErrUserNotExist(err) {
			fail("Repository owner does not exist", "Unregistered owner: %s", username)
		}
		fail("Internal error", "Failed to get repository owner (%s): %v", username, err)
	}

	os.Setenv(models.EnvRepoUserSalt, repoUser.Salt)

	repo, err := models.GetRepositoryByName(repoUser.ID, reponame)
	if err != nil {
		if models.IsErrRepoNotExist(err) {
			fail(accessDenied, "Repository does not exist: %s/%s", repoUser.Name, reponame)
		}
		fail("Internal error", "Failed to get repository: %v", err)
	}

	requestedMode, has := allowedCommands[verb]
	if !has {
		fail("Unknown git command", "Unknown git command %s", verb)
	}

	if verb == lfsAuthenticateVerb {
		if lfsVerb == "upload" {
			requestedMode = models.AccessModeWrite
		} else {
			requestedMode = models.AccessModeRead
		}
	}

	// Prohibit push to mirror repositories.
	if requestedMode > models.AccessModeRead && repo.IsMirror {
		fail("mirror repository is read-only", "")
	}

	// Allow anonymous clone for public repositories.
	var (
		keyID int64
		user  *models.User
	)
	if requestedMode == models.AccessModeWrite || repo.IsPrivate {
		keys := strings.Split(c.Args()[0], "-")
		if len(keys) != 2 {
			fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
		}

		key, err := models.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64())
		if err != nil {
			fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err)
		}
		keyID = key.ID

		// Check deploy key or user key.
		if key.Type == models.KeyTypeDeploy {
			if key.Mode < requestedMode {
				fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
			}
			// Check if this deploy key belongs to current repository.
			if !models.HasDeployKey(key.ID, repo.ID) {
				fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
			}

			// Update deploy key activity.
			deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID)
			if err != nil {
				fail("Internal error", "GetDeployKey: %v", err)
			}

			deployKey.Updated = time.Now()
			if err = models.UpdateDeployKey(deployKey); err != nil {
				fail("Internal error", "UpdateDeployKey: %v", err)
			}
		} else {
			user, err = models.GetUserByKeyID(key.ID)
			if err != nil {
				fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err)
			}

			mode, err := models.AccessLevel(user.ID, repo)
			if err != nil {
				fail("Internal error", "Failed to check access: %v", err)
			} else if mode < requestedMode {
				clientMessage := accessDenied
				if mode >= models.AccessModeRead {
					clientMessage = "You do not have sufficient authorization for this action"
				}
				fail(clientMessage,
					"User %s does not have level %v access to repository %s",
					user.Name, requestedMode, repoPath)
			}

			os.Setenv(models.EnvPusherName, user.Name)
			os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
		}
	}

	//LFS token authentication
	if verb == lfsAuthenticateVerb {
		url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, repoUser.Name, repo.Name)

		now := time.Now()
		token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
			"repo": repo.ID,
			"op":   lfsVerb,
			"exp":  now.Add(5 * time.Minute).Unix(),
			"nbf":  now.Unix(),
		})

		// Sign and get the complete encoded token as a string using the secret
		tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
		if err != nil {
			fail("Internal error", "Failed to sign JWT token: %v", err)
		}

		tokenAuthentication := &models.LFSTokenResponse{
			Header: make(map[string]string),
			Href:   url,
		}
		tokenAuthentication.Header["Authorization"] = fmt.Sprintf("Bearer %s", tokenString)

		enc := json.NewEncoder(os.Stdout)
		err = enc.Encode(tokenAuthentication)
		if err != nil {
			fail("Internal error", "Failed to encode LFS json response: %v", err)
		}

		return nil
	}

	// Special handle for Windows.
	if setting.IsWindows {
		verb = strings.Replace(verb, "-", " ", 1)
	}

	var gitcmd *exec.Cmd
	verbs := strings.Split(verb, " ")
	if len(verbs) == 2 {
		gitcmd = exec.Command(verbs[0], verbs[1], repoPath)
	} else {
		gitcmd = exec.Command(verb, repoPath)
	}

	if isWiki {
		if err = repo.InitWiki(); err != nil {
			fail("Internal error", "Failed to init wiki repo: %v", err)
		}
	}

	os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", repo.ID))

	gitcmd.Dir = setting.RepoRootPath
	gitcmd.Stdout = os.Stdout
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr
	if err = gitcmd.Run(); err != nil {
		fail("Internal error", "Failed to execute git command: %v", err)
	}

	// Update user key activity.
	if keyID > 0 {
		key, err := models.GetPublicKeyByID(keyID)
		if err != nil {
			fail("Internal error", "GetPublicKeyById: %v", err)
		}

		key.Updated = time.Now()
		if err = models.UpdatePublicKey(key); err != nil {
			fail("Internal error", "UpdatePublicKey: %v", err)
		}
	}

	return nil
}
<commit_msg>LFS: Fix SSH authentication for trailing arguments (#1328)<commit_after>// Copyright 2014 The Gogs Authors. All rights reserved.
// Copyright 2016 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package cmd

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"code.gitea.io/gitea/models"
	"code.gitea.io/gitea/modules/log"
	"code.gitea.io/gitea/modules/setting"
	"github.com/Unknwon/com"
	"github.com/dgrijalva/jwt-go"
	"github.com/urfave/cli"
)

const (
	accessDenied        = "Repository does not exist or you do not have access"
	lfsAuthenticateVerb = "git-lfs-authenticate"
)

// CmdServ represents the available serv sub-command.
var CmdServ = cli.Command{
	Name:        "serv",
	Usage:       "This command should only be called by SSH shell",
	Description: `Serv provide access auth for repositories`,
	Action:      runServ,
	Flags: []cli.Flag{
		cli.StringFlag{
			Name:  "config, c",
			Value: "custom/conf/app.ini",
			Usage: "Custom configuration file path",
		},
	},
}

func setup(logPath string) error {
	setting.NewContext()
	log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
	models.LoadConfigs()

	if setting.UseSQLite3 || setting.UseTiDB {
		workDir, _ := setting.WorkDir()
		if err := os.Chdir(workDir); err != nil {
			log.GitLogger.Fatal(4, "Failed to change directory %s: %v", workDir, err)
		}
	}

	setting.NewXORMLogService(true)
	return models.SetEngine()
}

func parseCmd(cmd string) (string, string) {
	ss := strings.SplitN(cmd, " ", 2)
	if len(ss) != 2 {
		return "", ""
	}
	return ss[0], strings.Replace(ss[1], "'/", "'", 1)
}

var (
	allowedCommands = map[string]models.AccessMode{
		"git-upload-pack":    models.AccessModeRead,
		"git-upload-archive": models.AccessModeRead,
		"git-receive-pack":   models.AccessModeWrite,
		lfsAuthenticateVerb:  models.AccessModeNone,
	}
)

func fail(userMessage, logMessage string, args ...interface{}) {
	fmt.Fprintln(os.Stderr, "Gitea:", userMessage)

	if len(logMessage) > 0 {
		if !setting.ProdMode {
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
		}
		log.GitLogger.Fatal(3, logMessage, args...)
		return
	}

	log.GitLogger.Close()
	os.Exit(1)
}

func runServ(c *cli.Context) error {
	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	}

	if err := setup("serv.log"); err != nil {
		fail("System init failed", fmt.Sprintf("setup: %v", err))
	}

	if setting.SSH.Disabled {
		println("Gitea: SSH has been disabled")
		return nil
	}

	if len(c.Args()) < 1 {
		fail("Not enough arguments", "Not enough arguments")
	}

	cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
	if len(cmd) == 0 {
		println("Hi there, You've successfully authenticated, but Gitea does not provide shell access.")
		println("If this is unexpected, please log in with password and setup Gitea under another user.")
		return nil
	}

	verb, args := parseCmd(cmd)

	var lfsVerb string
	if verb == lfsAuthenticateVerb {
		if !setting.LFS.StartServer {
			fail("Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
		}

		argsSplit := strings.Split(args, " ")
		if len(argsSplit) >= 2 {
			args = strings.TrimSpace(argsSplit[0])
			lfsVerb = strings.TrimSpace(argsSplit[1])
		}
	}

	repoPath := strings.ToLower(strings.Trim(args, "'"))
	rr := strings.SplitN(repoPath, "/", 2)
	if len(rr) != 2 {
		fail("Invalid repository path", "Invalid repository path: %v", args)
	}

	username := strings.ToLower(rr[0])
	reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))

	isWiki := false
	if strings.HasSuffix(reponame, ".wiki") {
		isWiki = true
		reponame = reponame[:len(reponame)-5]
	}

	os.Setenv(models.EnvRepoUsername, username)
	if isWiki {
		os.Setenv(models.EnvRepoIsWiki, "true")
	} else {
		os.Setenv(models.EnvRepoIsWiki, "false")
	}
	os.Setenv(models.EnvRepoName, reponame)

	repoUser, err := models.GetUserByName(username)
	if err != nil {
		if models.IsErrUserNotExist(err) {
			fail("Repository owner does not exist", "Unregistered owner: %s", username)
		}
		fail("Internal error", "Failed to get repository owner (%s): %v", username, err)
	}

	os.Setenv(models.EnvRepoUserSalt, repoUser.Salt)

	repo, err := models.GetRepositoryByName(repoUser.ID, reponame)
	if err != nil {
		if models.IsErrRepoNotExist(err) {
			fail(accessDenied, "Repository does not exist: %s/%s", repoUser.Name, reponame)
		}
		fail("Internal error", "Failed to get repository: %v", err)
	}

	requestedMode, has := allowedCommands[verb]
	if !has {
		fail("Unknown git command", "Unknown git command %s", verb)
	}

	if verb == lfsAuthenticateVerb {
		if lfsVerb == "upload" {
			requestedMode = models.AccessModeWrite
		} else if lfsVerb == "download" {
			requestedMode = models.AccessModeRead
		} else {
			fail("Unknown LFS verb", "Unkown lfs verb %s", lfsVerb)
		}
	}

	// Prohibit push to mirror repositories.
	if requestedMode > models.AccessModeRead && repo.IsMirror {
		fail("mirror repository is read-only", "")
	}

	// Allow anonymous clone for public repositories.
	var (
		keyID int64
		user  *models.User
	)
	if requestedMode == models.AccessModeWrite || repo.IsPrivate {
		keys := strings.Split(c.Args()[0], "-")
		if len(keys) != 2 {
			fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
		}

		key, err := models.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64())
		if err != nil {
			fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err)
		}
		keyID = key.ID

		// Check deploy key or user key.
		if key.Type == models.KeyTypeDeploy {
			if key.Mode < requestedMode {
				fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
			}
			// Check if this deploy key belongs to current repository.
			if !models.HasDeployKey(key.ID, repo.ID) {
				fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
			}

			// Update deploy key activity.
			deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID)
			if err != nil {
				fail("Internal error", "GetDeployKey: %v", err)
			}

			deployKey.Updated = time.Now()
			if err = models.UpdateDeployKey(deployKey); err != nil {
				fail("Internal error", "UpdateDeployKey: %v", err)
			}
		} else {
			user, err = models.GetUserByKeyID(key.ID)
			if err != nil {
				fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err)
			}

			mode, err := models.AccessLevel(user.ID, repo)
			if err != nil {
				fail("Internal error", "Failed to check access: %v", err)
			} else if mode < requestedMode {
				clientMessage := accessDenied
				if mode >= models.AccessModeRead {
					clientMessage = "You do not have sufficient authorization for this action"
				}
				fail(clientMessage,
					"User %s does not have level %v access to repository %s",
					user.Name, requestedMode, repoPath)
			}

			os.Setenv(models.EnvPusherName, user.Name)
			os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
		}
	}

	//LFS token authentication
	if verb == lfsAuthenticateVerb {
		url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, repoUser.Name, repo.Name)

		now := time.Now()
		token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
			"repo": repo.ID,
			"op":   lfsVerb,
			"exp":  now.Add(5 * time.Minute).Unix(),
			"nbf":  now.Unix(),
		})

		// Sign and get the complete encoded token as a string using the secret
		tokenString, err := token.SignedString(setting.LFS.JWTSecretBytes)
		if err != nil {
			fail("Internal error", "Failed to sign JWT token: %v", err)
		}

		tokenAuthentication := &models.LFSTokenResponse{
			Header: make(map[string]string),
			Href:   url,
		}
		tokenAuthentication.Header["Authorization"] = fmt.Sprintf("Bearer %s", tokenString)

		enc := json.NewEncoder(os.Stdout)
		err = enc.Encode(tokenAuthentication)
		if err != nil {
			fail("Internal error", "Failed to encode LFS json response: %v", err)
		}

		return nil
	}

	// Special handle for Windows.
	if setting.IsWindows {
		verb = strings.Replace(verb, "-", " ", 1)
	}

	var gitcmd *exec.Cmd
	verbs := strings.Split(verb, " ")
	if len(verbs) == 2 {
		gitcmd = exec.Command(verbs[0], verbs[1], repoPath)
	} else {
		gitcmd = exec.Command(verb, repoPath)
	}

	if isWiki {
		if err = repo.InitWiki(); err != nil {
			fail("Internal error", "Failed to init wiki repo: %v", err)
		}
	}

	os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", repo.ID))

	gitcmd.Dir = setting.RepoRootPath
	gitcmd.Stdout = os.Stdout
	gitcmd.Stdin = os.Stdin
	gitcmd.Stderr = os.Stderr
	if err = gitcmd.Run(); err != nil {
		fail("Internal error", "Failed to execute git command: %v", err)
	}

	// Update user key activity.
	if keyID > 0 {
		key, err := models.GetPublicKeyByID(keyID)
		if err != nil {
			fail("Internal error", "GetPublicKeyById: %v", err)
		}

		key.Updated = time.Now()
		if err = models.UpdatePublicKey(key); err != nil {
			fail("Internal error", "UpdatePublicKey: %v", err)
		}
	}

	return nil
}
<|endoftext|>


<commit_before>// Copyright 2014 Unknwon
//
// 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 (
	"io"
	"net"
	"os"
	"path"
	"strings"
	"time"

	"github.com/Unknwon/com"
	"github.com/Unknwon/log"
	"github.com/codegangsta/cli"
	"gopkg.in/fsnotify.v1"

	"github.com/Unknwon/bra/modules/setting"
)

var CmdSync = cli.Command{
	Name:   "sync",
	Usage:  "keep syncing two end points",
	Action: runSync,
	Flags: []cli.Flag{
		cli.StringFlag{"mode, m", "", "run mode", ""},
	},
}

func receiveHandler(conn net.Conn) {
	defer conn.Close()

	remoteAddr := conn.RemoteAddr().String()
	p := make([]byte, 1024)
	n, err := conn.Read(p)
	if err != nil {
		log.Error("Cannot read header(%s): %v", remoteAddr, err)
		return
	} else if n == 0 {
		log.Error("Empty header(%s)", remoteAddr)
		return
	}

	fileName := string(p[:n])
	log.Info("File: %s", fileName)
	os.MkdirAll(path.Dir(fileName), os.ModePerm)
	f, err := os.Create(fileName)
	if err != nil {
		log.Error("Fail to create file(%s:%s): %v", remoteAddr, fileName, err)
		return
	}
	defer f.Close()

	conn.Write([]byte("ok"))

	_, err = io.Copy(f, conn)
	for {
		buffer := make([]byte, 1024*200)
		n, err := conn.Read(buffer)
		//blockSize := int64(n)
		_ = n
		if err != nil && err != io.EOF {
			log.Error("Cannot read(%s:%s): %v", remoteAddr, fileName, err)
		} else if err == io.EOF {
			break
		}
	}
	if err != nil {
		log.Error("Fail to receive file(%s:%s): %v\n", remoteAddr, fileName, err)
		return
	}
	log.Info("File received: %s", fileName)
}

func runServer(ctx *cli.Context) {
	if len(setting.Cfg.Sync.ListenAddr) == 0 {
		log.Fatal("Listen address cannot be empty")
	}

	l, err := net.Listen("tcp", setting.Cfg.Sync.ListenAddr)
	if err != nil {
		log.Fatal("Fail to start server on listening(%s): %v", setting.Cfg.Sync.ListenAddr, err)
	}

	log.Info("Listening on %s...", setting.Cfg.Sync.ListenAddr)
	for {
		conn, err := l.Accept()
		if err != nil {
			if ne, ok := err.(net.Error); !ok || !ne.Temporary() {
				log.Warn("Network error when accpet: %v", err)
			}
			continue
		}
		go receiveHandler(conn)
	}
}

func sendFile(fileName string) {
	f, err := os.Open(fileName)
	if err != nil {
		log.Error("Fail to open file: %v", err)
		return
	}
	defer f.Close()

	fi, err := os.Stat(fileName)
	if err != nil {
		log.Error("Fail to stat file: %v", err)
		return
	}

	fileName = strings.Replace(fileName, "\\", "/", -1) //path.Base()
	log.Info("File name: %s; size: %s", fileName, com.HumaneFileSize(uint64(fi.Size())))

	conn, err := net.Dial("tcp", setting.Cfg.Sync.RemoteAddr)
	if err != nil {
		log.Error("Fail to establish connection: %v", err)
		return
	}
	defer conn.Close()

	log.Info("Connection established")

	conn.Write([]byte(fileName))
	p := make([]byte, 2)
	_, err = conn.Read(p)
	if err != nil {
		log.Error("Cannot get response from server: %v", err)
		return
	} else if string(p) != "ok" {
		log.Error("Invalid response: %s", string(p))
		return
	}

	log.Info("Header sent")

	start := time.Now()
	_, err = io.Copy(conn, f)
	if err != nil {
		log.Error("Fail to send file(%s): %v", fileName, err)
		return
	}
	spend := time.Since(start)
	log.Info("File sent, speed: %s/s", com.HumaneFileSize(uint64((fi.Size()*1000000000/int64(spend))/1024)))
}

func runClient(ctx *cli.Context) {
	if len(setting.Cfg.Sync.RemoteAddr) == 0 {
		log.Fatal("Remote address cannot be empty")
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal("Fail to create new watcher: %v", err)
	}
	defer watcher.Close()

	go func() {
		for {
			select {
			case e := <-watcher.Events:
				if isTmpFile(e.Name) {
					continue
				}

				if e.Op&fsnotify.Create == fsnotify.Create ||
					e.Op&fsnotify.Write == fsnotify.Write {
					if com.IsDir(e.Name) {
						log.Warn("Hasn't support directory yet")
						continue
					}
					sendFile(strings.TrimPrefix(e.Name, setting.WorkDir+"/"))
				}
			}
		}
	}()

	if err = watcher.Add(setting.WorkDir); err != nil {
		log.Fatal("Fail to watch directory(%s): %v", setting.WorkDir, err)
	}

	dirs, err := com.GetAllSubDirs(setting.WorkDir)
	if err != nil {
		log.Fatal("Fail to get subdirectories(%s): %v", setting.WorkDir, err)
	}

	for _, dir := range dirs {
		if err = watcher.Add(path.Join(setting.WorkDir, dir)); err != nil {
			log.Fatal("Fail to watch directory(%s): %v", path.Join(setting.WorkDir, dir), err)
		}
	}

	log.Info("Start watching...")
	select {}
}

func runSync(ctx *cli.Context) {
	setup(ctx)

	switch ctx.String("mode") {
	case "server":
		runServer(ctx)
	case "client":
		runClient(ctx)
	default:
		log.Fatal("Unrecognized run mode: %s", ctx.String("mode"))
	}
}
<commit_msg>fix for latest version of cli<commit_after>// Copyright 2014 Unknwon
//
// 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 (
	"io"
	"net"
	"os"
	"path"
	"strings"
	"time"

	"github.com/Unknwon/com"
	"github.com/Unknwon/log"
	"github.com/codegangsta/cli"
	"gopkg.in/fsnotify.v1"

	"github.com/Unknwon/bra/modules/setting"
)

var CmdSync = cli.Command{
	Name:   "sync",
	Usage:  "keep syncing two end points",
	Action: runSync,
	Flags: []cli.Flag{
		cli.StringFlag{Name: "mode, m", Value: "", Usage: "run mode"},
	},
}

func receiveHandler(conn net.Conn) {
	defer conn.Close()

	remoteAddr := conn.RemoteAddr().String()
	p := make([]byte, 1024)
	n, err := conn.Read(p)
	if err != nil {
		log.Error("Cannot read header(%s): %v", remoteAddr, err)
		return
	} else if n == 0 {
		log.Error("Empty header(%s)", remoteAddr)
		return
	}

	fileName := string(p[:n])
	log.Info("File: %s", fileName)
	os.MkdirAll(path.Dir(fileName), os.ModePerm)
	f, err := os.Create(fileName)
	if err != nil {
		log.Error("Fail to create file(%s:%s): %v", remoteAddr, fileName, err)
		return
	}
	defer f.Close()

	conn.Write([]byte("ok"))

	_, err = io.Copy(f, conn)
	for {
		buffer := make([]byte, 1024*200)
		n, err := conn.Read(buffer)
		//blockSize := int64(n)
		_ = n
		if err != nil && err != io.EOF {
			log.Error("Cannot read(%s:%s): %v", remoteAddr, fileName, err)
		} else if err == io.EOF {
			break
		}
	}
	if err != nil {
		log.Error("Fail to receive file(%s:%s): %v\n", remoteAddr, fileName, err)
		return
	}
	log.Info("File received: %s", fileName)
}

func runServer(ctx *cli.Context) {
	if len(setting.Cfg.Sync.ListenAddr) == 0 {
		log.Fatal("Listen address cannot be empty")
	}

	l, err := net.Listen("tcp", setting.Cfg.Sync.ListenAddr)
	if err != nil {
		log.Fatal("Fail to start server on listening(%s): %v", setting.Cfg.Sync.ListenAddr, err)
	}

	log.Info("Listening on %s...", setting.Cfg.Sync.ListenAddr)
	for {
		conn, err := l.Accept()
		if err != nil {
			if ne, ok := err.(net.Error); !ok || !ne.Temporary() {
				log.Warn("Network error when accpet: %v", err)
			}
			continue
		}
		go receiveHandler(conn)
	}
}

func sendFile(fileName string) {
	f, err := os.Open(fileName)
	if err != nil {
		log.Error("Fail to open file: %v", err)
		return
	}
	defer f.Close()

	fi, err := os.Stat(fileName)
	if err != nil {
		log.Error("Fail to stat file: %v", err)
		return
	}

	fileName = strings.Replace(fileName, "\\", "/", -1) //path.Base()
	log.Info("File name: %s; size: %s", fileName, com.HumaneFileSize(uint64(fi.Size())))

	conn, err := net.Dial("tcp", setting.Cfg.Sync.RemoteAddr)
	if err != nil {
		log.Error("Fail to establish connection: %v", err)
		return
	}
	defer conn.Close()

	log.Info("Connection established")

	conn.Write([]byte(fileName))
	p := make([]byte, 2)
	_, err = conn.Read(p)
	if err != nil {
		log.Error("Cannot get response from server: %v", err)
		return
	} else if string(p) != "ok" {
		log.Error("Invalid response: %s", string(p))
		return
	}

	log.Info("Header sent")

	start := time.Now()
	_, err = io.Copy(conn, f)
	if err != nil {
		log.Error("Fail to send file(%s): %v", fileName, err)
		return
	}
	spend := time.Since(start)
	log.Info("File sent, speed: %s/s", com.HumaneFileSize(uint64((fi.Size()*1000000000/int64(spend))/1024)))
}

func runClient(ctx *cli.Context) {
	if len(setting.Cfg.Sync.RemoteAddr) == 0 {
		log.Fatal("Remote address cannot be empty")
	}

	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal("Fail to create new watcher: %v", err)
	}
	defer watcher.Close()

	go func() {
		for {
			select {
			case e := <-watcher.Events:
				if isTmpFile(e.Name) {
					continue
				}

				if e.Op&fsnotify.Create == fsnotify.Create ||
					e.Op&fsnotify.Write == fsnotify.Write {
					if com.IsDir(e.Name) {
						log.Warn("Hasn't support directory yet")
						continue
					}
					sendFile(strings.TrimPrefix(e.Name, setting.WorkDir+"/"))
				}
			}
		}
	}()

	if err = watcher.Add(setting.WorkDir); err != nil {
		log.Fatal("Fail to watch directory(%s): %v", setting.WorkDir, err)
	}

	dirs, err := com.GetAllSubDirs(setting.WorkDir)
	if err != nil {
		log.Fatal("Fail to get subdirectories(%s): %v", setting.WorkDir, err)
	}

	for _, dir := range dirs {
		if err = watcher.Add(path.Join(setting.WorkDir, dir)); err != nil {
			log.Fatal("Fail to watch directory(%s): %v", path.Join(setting.WorkDir, dir), err)
		}
	}

	log.Info("Start watching...")
	select {}
}

func runSync(ctx *cli.Context) {
	setup(ctx)

	switch ctx.String("mode") {
	case "server":
		runServer(ctx)
	case "client":
		runClient(ctx)
	default:
		log.Fatal("Unrecognized run mode: %s", ctx.String("mode"))
	}
}
<|endoftext|>


<commit_before>// Copyright © 2016 Marc Sutter <marc.sutter@swissflow.ch>
//
// 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"
	"github.com/msutter/nodetree/models"
	"github.com/spf13/cobra"
	"sync"
	// "time"

	tm "github.com/buger/goterm"
)

var pRepository string
var pQuiet bool
var pSilent bool

// syncCmd represents the sync command
var syncCmd = &cobra.Command{
	Use:   "sync [stage name]",
	Short: "Synchronization of pulp nodes for a given stage",
	Long: `Synchronization of pulp nodes in a given stage

Filters can be set on Fqdns and tags.`,
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) != 1 {
			ErrorExitWithUsage(cmd, "sync needs a name for the stage")
		}

		if pRepository == "" {
			ErrorExitWithUsage(cmd, "sync needs a repository name")
		}

		currentStage := stageTree.GetStageByName(args[0])

		// check for flags
		if len(pFqdns) == 0 && len(pTags) == 0 && !pAll {
			fmt.Printf("\nWARNING: This will sync the complete tree for the '%v' stage!\n", args[0])
			fmt.Println("")
			currentStage.Show()
			fmt.Println("")
			fmt.Printf("you can get rid of this warning by setting the --all flag\n")
			fmt.Printf("Are you sure you want to continue? (yes/no)\n")
			userConfirm := askForConfirmation()
			if !userConfirm {
				ErrorExit("sync canceled !")
			} else {
				pAll = true
			}
		}

		// Create a progress channel
		progressChannel := make(chan models.SyncProgress)
		// create a state map
		nodeStates := make(map[string]string)
		var wg sync.WaitGroup
		wg.Add(1)
		go func() {
			defer wg.Done()
			for sp := range progressChannel {
				switch sp.State {
				case "skipped":
					line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
					tm.Printf(tm.Color(tm.Bold(line), tm.MAGENTA))
					tm.Flush()
				case "error":
					line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
					tm.Printf(tm.Color(tm.Bold(line), tm.RED))
					tm.Flush()
				case "running":
					// only output state changes
					if nodeStates[sp.Node.Fqdn] != sp.State {
						line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
						tm.Printf(tm.Color(line, tm.BLUE))
						tm.Flush()
					}
					nodeStates[sp.Node.Fqdn] = sp.State
				case "finished":
					line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
					tm.Printf(tm.Color(tm.Bold(line), tm.GREEN))
					tm.Flush()
				}
			}
		}()

		var err models.SyncErrors

		if pAll {
			err = currentStage.Sync(pRepository, progressChannel)
		} else {
			filteredStage := currentStage.Filter(pFqdns, pTags)
			err = filteredStage.Sync(pRepository, progressChannel)
		}

		// wait on the routine to finish
		wg.Wait()

		if err.Any() {
			RenderErrorSummary(err)
		}

	},
}

func init() {
	pulpCmd.AddCommand(syncCmd)
	syncCmd.Flags().StringVarP(&pRepository, "repository", "r", "", "the repository to be synced.")
	syncCmd.Flags().BoolVarP(&pQuiet, "quiet", "q", false, "simple output")
	syncCmd.Flags().BoolVarP(&pSilent, "silent", "s", false, "no output")

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	//syncCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// syncCmd.Flags().StringSlice("fqdns", []string{}, "Filter on Fqdns")
}

func RenderErrorSummary(s models.SyncErrors) {
	titleLine := fmt.Sprintf("Found errors on %v nodes:", len(s.Nodes))
	tm.Printf("\n")
	tm.Printf(tm.Bold(titleLine))
	tm.Printf("\n")
	tm.Printf("\n")
	for _, n := range s.Nodes {
		tm.Printf(tm.Color(tm.Bold(n.Fqdn), tm.RED))
		tm.Printf("\n")
		for _, e := range n.Errors {
			tm.Printf(" - ")
			tm.Printf(e.Error())
			tm.Printf("\n")
		}
		// tm.Printf("\n")
	}
	tm.Flush()

}
<commit_msg>add views<commit_after>// Copyright © 2016 Marc Sutter <marc.sutter@swissflow.ch>
//
// 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"
	"github.com/msutter/nodetree/models"
	"github.com/spf13/cobra"
	// "sync"
	// "time"

	tm "github.com/buger/goterm"
)

var pRepository string
var pQuiet bool
var pSilent bool

// syncCmd represents the sync command
var syncCmd = &cobra.Command{
	Use:   "sync [stage name]",
	Short: "Synchronization of pulp nodes for a given stage",
	Long: `Synchronization of pulp nodes in a given stage

Filters can be set on Fqdns and tags.`,
	Run: func(cmd *cobra.Command, args []string) {
		if len(args) != 1 {
			ErrorExitWithUsage(cmd, "sync needs a name for the stage")
		}

		if pRepository == "" {
			ErrorExitWithUsage(cmd, "sync needs a repository name")
		}

		currentStage := stageTree.GetStageByName(args[0])

		// check for flags
		if len(pFqdns) == 0 && len(pTags) == 0 && !pAll {
			fmt.Printf("\nWARNING: This will sync the complete tree for the '%v' stage!\n", args[0])
			currentStage.Show()
			fmt.Println("")
			fmt.Printf("you can get rid of this warning by setting the --all flag\n")
			fmt.Printf("Are you sure you want to continue? (yes/no)\n")
			userConfirm := askForConfirmation()
			if !userConfirm {
				ErrorExit("sync canceled !")
			} else {
				pAll = true
			}
		}

		// Create a progress channel
		progressChannel := make(chan models.SyncProgress)
		// create a state map
		// nodeStates := make(map[string]string)
		// var wg sync.WaitGroup
		// wg.Add(1)
		// go func() {
		// 	defer wg.Done()
		// 	for sp := range progressChannel {
		// 		switch sp.State {
		// 		case "skipped":
		// 			line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
		// 			tm.Printf(tm.Color(tm.Bold(line), tm.MAGENTA))
		// 			tm.Flush()
		// 		case "error":
		// 			line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
		// 			tm.Printf(tm.Color(tm.Bold(line), tm.RED))
		// 			tm.Flush()
		// 		case "running":
		// 			// only output state changes
		// 			if nodeStates[sp.Node.Fqdn] != sp.State {
		// 				line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
		// 				tm.Printf(tm.Color(line, tm.BLUE))
		// 				tm.Flush()
		// 			}
		// 			nodeStates[sp.Node.Fqdn] = sp.State
		// 		case "finished":
		// 			line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
		// 			tm.Printf(tm.Color(tm.Bold(line), tm.GREEN))
		// 			tm.Flush()
		// 		}
		// 	}
		// }()

		if !pSilent {
			if pQuiet {
				go RenderSimpleView(progressChannel)
			} else {
				go RenderProgressView(progressChannel)
			}
		}

		var err models.SyncErrors

		if pAll {
			err = currentStage.Sync(pRepository, progressChannel)
		} else {
			filteredStage := currentStage.Filter(pFqdns, pTags)
			err = filteredStage.Sync(pRepository, progressChannel)
		}

		// wait on the routine to finish
		// wg.Wait()

		if err.Any() {
			RenderErrorSummary(err)
		}

	},
}

func init() {
	pulpCmd.AddCommand(syncCmd)
	syncCmd.Flags().StringVarP(&pRepository, "repository", "r", "", "the repository to be synced.")
	syncCmd.Flags().BoolVarP(&pQuiet, "quiet", "q", false, "simple output")
	syncCmd.Flags().BoolVarP(&pSilent, "silent", "s", false, "no output")

	// Here you will define your flags and configuration settings.

	// Cobra supports Persistent Flags which will work for this command
	// and all subcommands, e.g.:
	//syncCmd.PersistentFlags().String("foo", "", "A help for foo")

	// Cobra supports local flags which will only run when this command
	// is called directly, e.g.:
	// syncCmd.Flags().StringSlice("fqdns", []string{}, "Filter on Fqdns")
}

// Progress view with colors and inplace update
func RenderProgressView(progressChannel chan models.SyncProgress) {
	nodeStates := make(map[string]string)

	for sp := range progressChannel {
		switch sp.State {
		case "skipped":
			line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
			tm.Printf(tm.Color(tm.Bold(line), tm.MAGENTA))
			tm.Flush()
		case "error":
			line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
			tm.Printf(tm.Color(tm.Bold(line), tm.RED))
			tm.Flush()
		case "running":
			// only output state changes
			if nodeStates[sp.Node.Fqdn] != sp.State {
				line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
				tm.Printf(tm.Color(line, tm.BLUE))
				tm.Flush()
			}
			nodeStates[sp.Node.Fqdn] = sp.State
		case "finished":
			line := fmt.Sprintf("%v [%v]", sp.Node.GetTreeRaw(sp.Node.Fqdn), sp.State)
			tm.Printf(tm.Color(tm.Bold(line), tm.GREEN))
			tm.Flush()
		}
	}
}

// simple view. No in place updates
func RenderSimpleView(progressChannel chan models.SyncProgress) {
	nodeStates := make(map[string]string)
	for sp := range progressChannel {
		switch sp.State {
		case "skipped":
			line := fmt.Sprintf("%v [%v]", sp.Node.Fqdn, sp.State)
			tm.Printf(tm.Color(tm.Bold(line), tm.MAGENTA))
			tm.Flush()
		case "error":
			line := fmt.Sprintf("%v [%v]", sp.Node.Fqdn, sp.State)
			tm.Printf(tm.Color(tm.Bold(line), tm.RED))
			tm.Flush()
		case "running":
			// only output state changes
			if nodeStates[sp.Node.Fqdn] != sp.State {
				line := fmt.Sprintf("%v [%v]", sp.Node.Fqdn, sp.State)
				tm.Printf(tm.Color(line, tm.BLUE))
				tm.Flush()
			}
			nodeStates[sp.Node.Fqdn] = sp.State
		case "finished":
			line := fmt.Sprintf("%v [%v]", sp.Node.Fqdn, sp.State)
			tm.Printf(tm.Color(tm.Bold(line), tm.GREEN))
			tm.Flush()
		}
	}
}

func RenderErrorSummary(s models.SyncErrors) {
	titleLine := fmt.Sprintf("Found errors on %v nodes:", len(s.Nodes))
	tm.Printf("\n")
	tm.Printf(tm.Bold(titleLine))
	tm.Printf("\n")
	tm.Printf("\n")
	for _, n := range s.Nodes {
		tm.Printf(tm.Color(tm.Bold(n.Fqdn), tm.RED))
		tm.Printf("\n")
		for _, e := range n.Errors {
			tm.Printf(" - ")
			tm.Printf(e.Error())
			tm.Printf("\n")
		}
		// tm.Printf("\n")
	}
	tm.Flush()

}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"time"

	"github.com/bjyoungblood/gozw/zwave/command-class"
	"github.com/bjyoungblood/gozw/zwave/frame"
	"github.com/bjyoungblood/gozw/zwave/serial-api"
	"github.com/bjyoungblood/gozw/zwave/session"
	"github.com/bjyoungblood/gozw/zwave/transport"
	"github.com/davecgh/go-spew/spew"
)

func main() {
	transport, err := transport.NewSerialTransportLayer("/tmp/usbmodem", 115200)
	if err != nil {
		panic(err)
	}

	frameLayer := frame.NewFrameLayer(transport)
	sessionLayer := session.NewSessionLayer(frameLayer)
	apiLayer := serialapi.NewSerialAPILayer(sessionLayer)

	// apiLayer.SoftReset()

	// spew.Dump(apiLayer.GetVersion())
	nodeList, err := apiLayer.GetNodeList()
	fmt.Println(nodeList.GetNodeIds())
	// spew.Dump(apiLayer.MemoryGetId())
	spew.Dump(apiLayer.GetNodeProtocolInfo(27))
	// spew.Dump(apiLayer.GetSerialApiCapabilities())

	time.Sleep(time.Second * 1)

	txTime, err := apiLayer.SendData(27, commandclass.NewVersionGet())
	fmt.Println("TX: ", txTime)
	if err != nil {
		fmt.Println(err)
	}

	<-time.After(30 * time.Second)

	// if apiLayer.AddNode() != nil {
	// 	apiLayer.AddNode()
	// }

	// sessionLayer := zwave.NewSessionLayer(frameLayer)
	// manager := zwave.NewManager(sessionLayer)

	// defer manager.Close()

	// fmt.Printf("Home ID: 0x%x; Node ID: %d\n", manager.HomeId, manager.NodeId)
	// fmt.Println("API Version:", manager.ApiVersion)
	// fmt.Println("Library:", manager.ApiLibraryType)
	// fmt.Println("Version:", manager.Version)
	// fmt.Println("API Type:", manager.ApiType)
	// fmt.Println("Timer Functions Supported:", manager.TimerFunctionsSupported)
	// fmt.Println("Is Primary Controller:", manager.IsPrimaryController)
	// fmt.Println("Node count:", len(manager.Nodes))
	//
	// manager.SendDataSecure(15, []byte{
	// 	commandclass.CommandClassDoorLock,
	// 	0x01, // door lock operation set
	// 	0x00, // unsecured
	// })

	// manager.SetApplicationNodeInformation()
	// manager.FactoryReset()

	// for _, node := range manager.Nodes {
	// 	fmt.Println(node.String())
	// }

	// manager.SendData(3, cc.NewSwitchMultilevelCommand(0))

	// line := liner.NewLiner()
	// defer line.Close()
	//
	// for {
	// 	cmd, _ := line.Prompt("(a)dd node\n(r)emove node\n(g)et nonce\n(q)uit\n> ")
	// 	switch cmd {
	// 	case "a":
	// 		manager.AddNode()
	// 	case "r":
	// 		manager.RemoveNode()
	// 	case "s":
	// 		input, _ := line.Prompt("node id: ")
	// 		nodeId, _ := strconv.Atoi(input)
	// 		manager.SendData(uint8(nodeId), commandclass.NewSecuritySchemeGet())
	// 	case "g":
	// 		input, _ := line.Prompt("node id: ")
	// 		nodeId, _ := strconv.Atoi(input)
	// 		manager.SendData(uint8(nodeId), commandclass.NewSecurityNonceGet())
	// 	case "v":
	// 		input, _ := line.Prompt("node id: ")
	// 		nodeId, _ := strconv.Atoi(input)
	// 		manager.SendData(uint8(nodeId), commandclass.NewVersionGet())
	// 	case "q":
	// 		return
	// 	default:
	// 		fmt.Println("invalid selection")
	// 	}
	// }

}
<commit_msg>Update usage examples in test cmd<commit_after>package main

import (
	"fmt"

	"github.com/bjyoungblood/gozw/zwave/application"
	"github.com/bjyoungblood/gozw/zwave/frame"
	"github.com/bjyoungblood/gozw/zwave/serial-api"
	"github.com/bjyoungblood/gozw/zwave/session"
	"github.com/bjyoungblood/gozw/zwave/transport"
	"github.com/davecgh/go-spew/spew"
	"github.com/peterh/liner"
)

func main() {
	transport, err := transport.NewSerialTransportLayer("/tmp/usbmodem", 115200)
	if err != nil {
		panic(err)
	}

	frameLayer := frame.NewFrameLayer(transport)
	sessionLayer := session.NewSessionLayer(frameLayer)
	apiLayer := serialapi.NewSerialAPILayer(sessionLayer)
	appLayer, err := application.NewApplicationLayer(apiLayer)
	if err != nil {
		panic(err)
	}

	// spew.Dump(applicationLayer.Nodes)

	// apiLayer.SoftReset()

	// spew.Dump(apiLayer.GetVersion())
	// nodeList, err := apiLayer.GetNodeList()
	// fmt.Println(nodeList.GetNodeIds())
	// spew.Dump(apiLayer.MemoryGetId())
	// spew.Dump(apiLayer.GetNodeProtocolInfo(27))
	// spew.Dump(apiLayer.GetSerialApiCapabilities())

	// txTime, err := apiLayer.SendData(27, commandclass.NewVersionGet())
	// fmt.Println("TX: ", txTime)
	// if err != nil {
	// 	fmt.Println(err)
	// }

	// if apiLayer.AddNode() != nil {
	// 	apiLayer.AddNode()
	// }

	// sessionLayer := zwave.NewSessionLayer(frameLayer)
	// manager := zwave.NewManager(sessionLayer)

	// defer manager.Close()

	fmt.Printf("Home ID: 0x%x; Node ID: %d\n", appLayer.HomeId, appLayer.NodeId)
	fmt.Println("API Version:", appLayer.ApiVersion)
	fmt.Println("Library:", appLayer.ApiLibraryType)
	fmt.Println("Version:", appLayer.Version)
	fmt.Println("API Type:", appLayer.ApiType)
	fmt.Println("Is Primary Controller:", appLayer.IsPrimaryController)
	fmt.Println("Node count:", len(appLayer.Nodes))
	//
	// manager.SendDataSecure(15, []byte{
	// 	commandclass.CommandClassDoorLock,
	// 	0x01, // door lock operation set
	// 	0x00, // unsecured
	// })

	// manager.SetApplicationNodeInformation()
	// manager.FactoryReset()

	for _, node := range appLayer.Nodes {
		fmt.Println(node.String())
	}

	// manager.SendData(3, cc.NewSwitchMultilevelCommand(0))

	line := liner.NewLiner()
	defer line.Close()

	for {
		cmd, _ := line.Prompt("(a)dd node\n(r)emove node\n(g)et nonce\n(q)uit\n> ")
		switch cmd {
		case "a":
			spew.Dump(appLayer.AddNode())
		case "r":
			spew.Dump(appLayer.RemoveNode())
		// case "s":
		// 	input, _ := line.Prompt("node id: ")
		// 	nodeId, _ := strconv.Atoi(input)
		// 	manager.SendData(uint8(nodeId), commandclass.NewSecuritySchemeGet())
		// case "g":
		// 	input, _ := line.Prompt("node id: ")
		// 	nodeId, _ := strconv.Atoi(input)
		// 	manager.SendData(uint8(nodeId), commandclass.NewSecurityNonceGet())
		// case "v":
		// 	input, _ := line.Prompt("node id: ")
		// 	nodeId, _ := strconv.Atoi(input)
		// 	manager.SendData(uint8(nodeId), commandclass.NewVersionGet())
		case "q":
			return
		default:
			fmt.Println("invalid selection")
		}
	}

}
<|endoftext|>