<commit_before>package cli

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

	log "github.com/Sirupsen/logrus"

	"github.com/bitrise-io/go-utils/cmdex"
	"github.com/bitrise-io/go-utils/colorstring"
	"github.com/bitrise-io/go-utils/fileutil"
	"github.com/bitrise-io/go-utils/pathutil"
	"github.com/bitrise-io/goinp/goinp"
	"github.com/bitrise-tools/codesigndoc/osxkeychain"
	"github.com/bitrise-tools/codesigndoc/provprofile"
	"github.com/bitrise-tools/codesigndoc/utils"
	"github.com/bitrise-tools/codesigndoc/xcode"
	"github.com/codegangsta/cli"
)

const (
	confExportOutputDirPath = "./codesigndoc_exports"
)

func printFinished() {
	fmt.Println()
	fmt.Println(colorstring.Green("That's all."))
	fmt.Println("You just have to upload the found code signing files and you'll be good to go!")
}

func scan(c *cli.Context) {
	absExportOutputDirPath, err := pathutil.AbsPath(confExportOutputDirPath)
	log.Debugf("absExportOutputDirPath: %s", absExportOutputDirPath)
	if err != nil {
		log.Fatalf("Failed to determin Absolute path of export dir: %s", confExportOutputDirPath)
	}
	if exist, err := pathutil.IsDirExists(absExportOutputDirPath); err != nil {
		log.Fatalf("Failed to determin whether the export directory already exists: %s", err)
	} else if !exist {
		if err := os.Mkdir(absExportOutputDirPath, 0777); err != nil {
			log.Fatalf("Failed to create export output directory at path: %s | error: %s", absExportOutputDirPath, err)
		}
	} else {
		log.Infof("Export output dir already exists at path: %s", absExportOutputDirPath)
	}

	projectPath := c.String(FileParamKey)
	if projectPath == "" {
		askText := `Please drag-and-drop your Xcode Project (` + colorstring.Green(".xcodeproj") + `)
   or Workspace (` + colorstring.Green(".xcworkspace") + `) file, the one you usually open in Xcode,
   then hit Enter.

  (Note: if you have a Workspace file you should most likely use that)`
		fmt.Println()
		projpth, err := goinp.AskForPath(askText)
		if err != nil {
			log.Fatalf("Failed to read input: %s", err)
		}
		projectPath = projpth
	}
	log.Debugf("projectPath: %s", projectPath)
	xcodeCmd := xcode.CommandModel{
		ProjectFilePath: projectPath,
	}

	schemeToUse := c.String(SchemeParamKey)
	if schemeToUse == "" {
		log.Println("🔦  Scanning Schemes ...")
		schemes, err := xcodeCmd.ScanSchemes()
		if err != nil {
			log.Fatalf("Failed to scan Schemes: %s", err)
		}
		log.Debugf("schemes: %v", schemes)

		fmt.Println()
		selectedScheme, err := goinp.SelectFromStrings("Select the Scheme you usually use in Xcode", schemes)
		if err != nil {
			log.Fatalf("Failed to select Scheme: %s", err)
		}
		log.Debugf("selected scheme: %v", selectedScheme)
		schemeToUse = selectedScheme
	}
	xcodeCmd.Scheme = schemeToUse

	fmt.Println()
	fmt.Println()
	log.Println("🔦  Running an Xcode Archive, to get all the required code signing settings...")
	codeSigningSettings, xcodebuildOutput, err := xcodeCmd.ScanCodeSigningSettings()
	// save the xcodebuild output into a debug log file
	{
		xcodebuildOutputFilePath := filepath.Join(absExportOutputDirPath, "xcodebuild-output.log")
		log.Infof("  💡  Saving xcodebuild output into file: %s", xcodebuildOutputFilePath)
		if err := fileutil.WriteStringToFile(xcodebuildOutputFilePath, xcodebuildOutput); err != nil {
			log.Errorf("Failed to save xcodebuild output into file (%s), error: %s", xcodebuildOutputFilePath, err)
		}
	}
	if err != nil {
		log.Fatalf("Failed to detect code signing settings: %s", err)
	}
	log.Debugf("codeSigningSettings: %#v", codeSigningSettings)

	fmt.Println()
	fmt.Println()
	utils.Printlnf("=== Required Identities/Certificates (%d) ===", len(codeSigningSettings.Identities))
	for idx, anIdentity := range codeSigningSettings.Identities {
		utils.Printlnf(" * (%d): %s", idx+1, anIdentity.Title)
	}
	fmt.Println("============================================")

	fmt.Println()
	utils.Printlnf("=== Required Provisioning Profiles (%d) ===", len(codeSigningSettings.ProvProfiles))
	for idx, aProvProfile := range codeSigningSettings.ProvProfiles {
		utils.Printlnf(" * (%d): %s (UUID: %s)", idx+1, aProvProfile.Title, aProvProfile.UUID)
	}
	fmt.Println("==========================================")

	fmt.Println()
	utils.Printlnf("=== Team IDs (%d) ===", len(codeSigningSettings.TeamIDs))
	for idx, aTeamID := range codeSigningSettings.TeamIDs {
		utils.Printlnf(" * (%d): %s", idx+1, aTeamID)
	}
	fmt.Println("==========================================")

	fmt.Println()
	utils.Printlnf("=== App/Bundle IDs (%d) ===", len(codeSigningSettings.AppBundleIDs))
	for idx, anAppBundleID := range codeSigningSettings.AppBundleIDs {
		utils.Printlnf(" * (%d): %s", idx+1, anAppBundleID)
	}
	fmt.Println("==========================================")
	fmt.Println()

	//
	// --- Code Signing issue checks / report
	//

	if len(codeSigningSettings.Identities) < 1 {
		log.Fatal("No Code Signing Identity detected!")
	}
	if len(codeSigningSettings.Identities) > 1 {
		log.Warning(colorstring.Yellow("More than one Code Signing Identity (certificate) is required to sign your app!"))
		log.Warning("You should check your settings and make sure a single Identity/Certificate can be used")
		log.Warning(" for Archiving your app!")
	}

	if len(codeSigningSettings.ProvProfiles) < 1 {
		log.Fatal("No Provisioning Profiles detected!")
	}

	//
	// --- Export
	//

	if !c.Bool(AllowExportParamKey) {
		isShouldExport, err := goinp.AskForBoolWithDefault("Do you want to export these files?", true)
		if err != nil {
			log.Fatalf("Failed to process your input: %s", err)
		}
		if !isShouldExport {
			printFinished()
			return
		}
	} else {
		log.Debug("Allow Export flag was set - doing export without asking")
	}

	fmt.Println()
	log.Println("Collecting the required Identities (Certificates) for a base Xcode Archive ...")
	fmt.Println()

	identitiesWithKeychainRefs := []osxkeychain.IdentityWithRefModel{}
	defer osxkeychain.ReleaseIdentityWithRefList(identitiesWithKeychainRefs)

	for _, aIdentity := range codeSigningSettings.Identities {
		log.Infof(" * "+colorstring.Blue("Searching for Identity")+": %s", aIdentity.Title)
		validIdentityRefs, err := osxkeychain.FindAndValidateIdentity(aIdentity.Title, true)
		if err != nil {
			log.Fatalf("Failed to export, error: %s", err)
		}

		if len(validIdentityRefs) < 1 {
			log.Fatalf("Identity not found in the keychain, or it was invalid (expired)!")
		}
		if len(validIdentityRefs) > 1 {
			log.Warning(colorstring.Yellow("Multiple matching Identities found in Keychain! Most likely you have duplicated identities in separate Keychains, e.g. one in System.keychain and one in your Login.keychain, or you have revoked versions of the Certificate."))
		}

		identitiesWithKeychainRefs = append(identitiesWithKeychainRefs, validIdentityRefs...)
	}

	fmt.Println()
	log.Println("Collecting additional identities, for Distribution builds ...")
	fmt.Println()

	for _, aTeamID := range codeSigningSettings.TeamIDs {
		log.Infof(" * "+colorstring.Blue("Searching for Identities with Team ID")+": %s", aTeamID)
		validIdentityRefs, err := osxkeychain.FindAndValidateIdentity(fmt.Sprintf("(%s)", aTeamID), false)
		if err != nil {
			log.Fatalf("Failed to export, error: %s", err)
		}

		if len(validIdentityRefs) < 1 {
			log.Infoln("No valid identity found for this Team ID")
		}

		identitiesWithKeychainRefs = append(identitiesWithKeychainRefs, validIdentityRefs...)
	}

	fmt.Println()
	log.Println(colorstring.Green("Exporting the Identities") + " (Certificates):")
	fmt.Println()

	identityKechainRefs := osxkeychain.CreateEmptyCFTypeRefSlice()
	for _, aIdentityWithRefItm := range identitiesWithKeychainRefs {
		fmt.Println(" * "+colorstring.Blue("Identity")+":", aIdentityWithRefItm.Label)
		identityKechainRefs = append(identityKechainRefs, aIdentityWithRefItm.KeychainRef)
	}

	fmt.Println()
	log.Infoln(colorstring.Blue("Exporting from Keychain") + ", " + colorstring.Yellow("using empty Passphrase") + " ...")
	log.Info(" This means that " + colorstring.Yellow("if you want to import the file the passphrase at import should be left empty") + ",")
	log.Info(" you don't have to type in anything, just leave the passphrase input empty.")
	fmt.Println()
	log.Info(colorstring.Blue("You'll most likely see popups") + " (one for each Identity) from Keychain,")
	log.Info(colorstring.Yellow(" you will have to accept (Allow)") + " those to be able to export the Identities!")
	fmt.Println()
	if err := osxkeychain.ExportFromKeychain(identityKechainRefs, filepath.Join(absExportOutputDirPath, "Identities.p12")); err != nil {
		log.Fatalf("Failed to export from Keychain: %s", err)
	}

	fmt.Println()
	log.Println(colorstring.Green("Exporting base Provisioning Profile(s)"), "...")
	fmt.Println()

	for _, aProvProfile := range codeSigningSettings.ProvProfiles {
		log.Infof(" * "+colorstring.Blue("Exporting Provisioning Profile")+": %s (UUID: %s)", aProvProfile.Title, aProvProfile.UUID)
		filePth, err := provprofile.FindProvProfileFileByUUID(aProvProfile.UUID)
		if err != nil {
			log.Fatalf("Failed to find Provisioning Profile: %s", err)
		}
		log.Infof("   File found at: %s", filePth)

		exportFileName := provProfileExportFileName(aProvProfile.UUID, aProvProfile.Title)
		exportPth := filepath.Join(absExportOutputDirPath, exportFileName)
		if err := cmdex.RunCommand("cp", filePth, exportPth); err != nil {
			log.Fatalf("Failed to copy the Provisioning Profile into the export directory: %s", err)
		}
	}

	fmt.Println()
	log.Println(colorstring.Green("Exporting additinal, Distribution Provisioning Profile(s)"), "...")
	fmt.Println()
	for _, aAppBundleID := range codeSigningSettings.AppBundleIDs {
		log.Infof(" * "+colorstring.Blue("Searching for Provisioning Profiles with Bundle ID")+": %s", aAppBundleID)
		filePths, err := provprofile.FindProvProfilesFileByAppID(aAppBundleID)
		if err != nil {
			log.Fatalf("Failed to find Provisioning Profile: %s", err)
		}
		if len(filePths) < 1 {
			log.Warn("   No Provisioning Profile found for this Bundle ID")
			continue
		}

		for _, aFilePth := range filePths {
			log.Info("   " + colorstring.Green("Exporting Provisioning Profile:") + " " + aFilePth)
			exportFileName := provProfileExportFileName(
				strings.TrimSuffix(filepath.Base(aFilePth), ".mobileprovision"),
				aAppBundleID,
			)
			exportPth := filepath.Join(absExportOutputDirPath, exportFileName)
			if err := cmdex.RunCommand("cp", aFilePth, exportPth); err != nil {
				log.Fatalf("Failed to copy the Provisioning Profile into the export directory: %s", err)
			}
		}
	}

	fmt.Println()
	fmt.Printf(colorstring.Green("Exports finished")+" you can find the exported files at: %s\n", absExportOutputDirPath)
	if err := cmdex.RunCommand("open", absExportOutputDirPath); err != nil {
		log.Errorf("Failed to open the export directory in Finder: %s", absExportOutputDirPath)
	}
	fmt.Println("Opened the directory in Finder.")
	fmt.Println()

	printFinished()
}

func provProfileExportFileName(provProfileUUID, title string) string {
	replaceRexp, err := regexp.Compile("[^A-Za-z0-9_.-]")
	if err != nil {
		log.Warn("Invalid regex, error: %s", err)
		return ""
	}
	safeTitle := replaceRexp.ReplaceAllString(title, "")

	return provProfileUUID + "_" + safeTitle + ".mobileprovision"
}
<commit_msg>base "please create an issue" (#13)<commit_after>package cli

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

	log "github.com/Sirupsen/logrus"

	"github.com/bitrise-io/go-utils/cmdex"
	"github.com/bitrise-io/go-utils/colorstring"
	"github.com/bitrise-io/go-utils/fileutil"
	"github.com/bitrise-io/go-utils/pathutil"
	"github.com/bitrise-io/goinp/goinp"
	"github.com/bitrise-tools/codesigndoc/osxkeychain"
	"github.com/bitrise-tools/codesigndoc/provprofile"
	"github.com/bitrise-tools/codesigndoc/utils"
	"github.com/bitrise-tools/codesigndoc/xcode"
	"github.com/codegangsta/cli"
)

const (
	confExportOutputDirPath = "./codesigndoc_exports"
)

func printFinished() {
	fmt.Println()
	fmt.Println(colorstring.Green("That's all."))
	fmt.Println("You just have to upload the found code signing files and you'll be good to go!")
}

func failWithError(format string, args ...interface{}) {
	log.Errorf(colorstring.Red("Error: ")+format, args...)
	fmt.Println()
	fmt.Println("------------------------------")
	fmt.Println(colorstring.Red("Please create an issue") + " on GitHub at: https://github.com/bitrise-tools/codesigndoc/issues")
	fmt.Println("with as many details & logs as you can share!")
	fmt.Println("------------------------------")
	fmt.Println()
	os.Exit(1)
}

func scan(c *cli.Context) {
	absExportOutputDirPath, err := pathutil.AbsPath(confExportOutputDirPath)
	log.Debugf("absExportOutputDirPath: %s", absExportOutputDirPath)
	if err != nil {
		failWithError("Failed to determin Absolute path of export dir: %s", confExportOutputDirPath)
	}
	if exist, err := pathutil.IsDirExists(absExportOutputDirPath); err != nil {
		failWithError("Failed to determin whether the export directory already exists: %s", err)
	} else if !exist {
		if err := os.Mkdir(absExportOutputDirPath, 0777); err != nil {
			failWithError("Failed to create export output directory at path: %s | error: %s", absExportOutputDirPath, err)
		}
	} else {
		log.Infof("Export output dir already exists at path: %s", absExportOutputDirPath)
	}

	projectPath := c.String(FileParamKey)
	if projectPath == "" {
		askText := `Please drag-and-drop your Xcode Project (` + colorstring.Green(".xcodeproj") + `)
   or Workspace (` + colorstring.Green(".xcworkspace") + `) file, the one you usually open in Xcode,
   then hit Enter.

  (Note: if you have a Workspace file you should most likely use that)`
		fmt.Println()
		projpth, err := goinp.AskForPath(askText)
		if err != nil {
			failWithError("Failed to read input: %s", err)
		}
		projectPath = projpth
	}
	log.Debugf("projectPath: %s", projectPath)
	xcodeCmd := xcode.CommandModel{
		ProjectFilePath: projectPath,
	}

	schemeToUse := c.String(SchemeParamKey)
	if schemeToUse == "" {
		log.Println("🔦  Scanning Schemes ...")
		schemes, err := xcodeCmd.ScanSchemes()
		if err != nil {
			failWithError("Failed to scan Schemes: %s", err)
		}
		log.Debugf("schemes: %v", schemes)

		fmt.Println()
		selectedScheme, err := goinp.SelectFromStrings("Select the Scheme you usually use in Xcode", schemes)
		if err != nil {
			failWithError("Failed to select Scheme: %s", err)
		}
		log.Debugf("selected scheme: %v", selectedScheme)
		schemeToUse = selectedScheme
	}
	xcodeCmd.Scheme = schemeToUse

	fmt.Println()
	fmt.Println()
	log.Println("🔦  Running an Xcode Archive, to get all the required code signing settings...")
	codeSigningSettings, xcodebuildOutput, err := xcodeCmd.ScanCodeSigningSettings()
	// save the xcodebuild output into a debug log file
	{
		xcodebuildOutputFilePath := filepath.Join(absExportOutputDirPath, "xcodebuild-output.log")
		log.Infof("  💡  Saving xcodebuild output into file: %s", xcodebuildOutputFilePath)
		if err := fileutil.WriteStringToFile(xcodebuildOutputFilePath, xcodebuildOutput); err != nil {
			log.Errorf("Failed to save xcodebuild output into file (%s), error: %s", xcodebuildOutputFilePath, err)
		}
	}
	if err != nil {
		failWithError("Failed to detect code signing settings: %s", err)
	}
	log.Debugf("codeSigningSettings: %#v", codeSigningSettings)

	fmt.Println()
	fmt.Println()
	utils.Printlnf("=== Required Identities/Certificates (%d) ===", len(codeSigningSettings.Identities))
	for idx, anIdentity := range codeSigningSettings.Identities {
		utils.Printlnf(" * (%d): %s", idx+1, anIdentity.Title)
	}
	fmt.Println("============================================")

	fmt.Println()
	utils.Printlnf("=== Required Provisioning Profiles (%d) ===", len(codeSigningSettings.ProvProfiles))
	for idx, aProvProfile := range codeSigningSettings.ProvProfiles {
		utils.Printlnf(" * (%d): %s (UUID: %s)", idx+1, aProvProfile.Title, aProvProfile.UUID)
	}
	fmt.Println("==========================================")

	fmt.Println()
	utils.Printlnf("=== Team IDs (%d) ===", len(codeSigningSettings.TeamIDs))
	for idx, aTeamID := range codeSigningSettings.TeamIDs {
		utils.Printlnf(" * (%d): %s", idx+1, aTeamID)
	}
	fmt.Println("==========================================")

	fmt.Println()
	utils.Printlnf("=== App/Bundle IDs (%d) ===", len(codeSigningSettings.AppBundleIDs))
	for idx, anAppBundleID := range codeSigningSettings.AppBundleIDs {
		utils.Printlnf(" * (%d): %s", idx+1, anAppBundleID)
	}
	fmt.Println("==========================================")
	fmt.Println()

	//
	// --- Code Signing issue checks / report
	//

	if len(codeSigningSettings.Identities) < 1 {
		failWithError("No Code Signing Identity detected!")
	}
	if len(codeSigningSettings.Identities) > 1 {
		log.Warning(colorstring.Yellow("More than one Code Signing Identity (certificate) is required to sign your app!"))
		log.Warning("You should check your settings and make sure a single Identity/Certificate can be used")
		log.Warning(" for Archiving your app!")
	}

	if len(codeSigningSettings.ProvProfiles) < 1 {
		failWithError("No Provisioning Profiles detected!")
	}

	//
	// --- Export
	//

	if !c.Bool(AllowExportParamKey) {
		isShouldExport, err := goinp.AskForBoolWithDefault("Do you want to export these files?", true)
		if err != nil {
			failWithError("Failed to process your input: %s", err)
		}
		if !isShouldExport {
			printFinished()
			return
		}
	} else {
		log.Debug("Allow Export flag was set - doing export without asking")
	}

	fmt.Println()
	log.Println("Collecting the required Identities (Certificates) for a base Xcode Archive ...")
	fmt.Println()

	identitiesWithKeychainRefs := []osxkeychain.IdentityWithRefModel{}
	defer osxkeychain.ReleaseIdentityWithRefList(identitiesWithKeychainRefs)

	for _, aIdentity := range codeSigningSettings.Identities {
		log.Infof(" * "+colorstring.Blue("Searching for Identity")+": %s", aIdentity.Title)
		validIdentityRefs, err := osxkeychain.FindAndValidateIdentity(aIdentity.Title, true)
		if err != nil {
			failWithError("Failed to export, error: %s", err)
		}

		if len(validIdentityRefs) < 1 {
			failWithError("Identity not found in the keychain, or it was invalid (expired)!")
		}
		if len(validIdentityRefs) > 1 {
			log.Warning(colorstring.Yellow("Multiple matching Identities found in Keychain! Most likely you have duplicated identities in separate Keychains, e.g. one in System.keychain and one in your Login.keychain, or you have revoked versions of the Certificate."))
		}

		identitiesWithKeychainRefs = append(identitiesWithKeychainRefs, validIdentityRefs...)
	}

	fmt.Println()
	log.Println("Collecting additional identities, for Distribution builds ...")
	fmt.Println()

	for _, aTeamID := range codeSigningSettings.TeamIDs {
		log.Infof(" * "+colorstring.Blue("Searching for Identities with Team ID")+": %s", aTeamID)
		validIdentityRefs, err := osxkeychain.FindAndValidateIdentity(fmt.Sprintf("(%s)", aTeamID), false)
		if err != nil {
			failWithError("Failed to export, error: %s", err)
		}

		if len(validIdentityRefs) < 1 {
			log.Infoln("No valid identity found for this Team ID")
		}

		identitiesWithKeychainRefs = append(identitiesWithKeychainRefs, validIdentityRefs...)
	}

	fmt.Println()
	log.Println(colorstring.Green("Exporting the Identities") + " (Certificates):")
	fmt.Println()

	identityKechainRefs := osxkeychain.CreateEmptyCFTypeRefSlice()
	for _, aIdentityWithRefItm := range identitiesWithKeychainRefs {
		fmt.Println(" * "+colorstring.Blue("Identity")+":", aIdentityWithRefItm.Label)
		identityKechainRefs = append(identityKechainRefs, aIdentityWithRefItm.KeychainRef)
	}

	fmt.Println()
	log.Infoln(colorstring.Blue("Exporting from Keychain") + ", " + colorstring.Yellow("using empty Passphrase") + " ...")
	log.Info(" This means that " + colorstring.Yellow("if you want to import the file the passphrase at import should be left empty") + ",")
	log.Info(" you don't have to type in anything, just leave the passphrase input empty.")
	fmt.Println()
	log.Info(colorstring.Blue("You'll most likely see popups") + " (one for each Identity) from Keychain,")
	log.Info(colorstring.Yellow(" you will have to accept (Allow)") + " those to be able to export the Identities!")
	fmt.Println()
	if err := osxkeychain.ExportFromKeychain(identityKechainRefs, filepath.Join(absExportOutputDirPath, "Identities.p12")); err != nil {
		failWithError("Failed to export from Keychain: %s", err)
	}

	fmt.Println()
	log.Println(colorstring.Green("Exporting base Provisioning Profile(s)"), "...")
	fmt.Println()

	for _, aProvProfile := range codeSigningSettings.ProvProfiles {
		log.Infof(" * "+colorstring.Blue("Exporting Provisioning Profile")+": %s (UUID: %s)", aProvProfile.Title, aProvProfile.UUID)
		filePth, err := provprofile.FindProvProfileFileByUUID(aProvProfile.UUID)
		if err != nil {
			failWithError("Failed to find Provisioning Profile: %s", err)
		}
		log.Infof("   File found at: %s", filePth)

		exportFileName := provProfileExportFileName(aProvProfile.UUID, aProvProfile.Title)
		exportPth := filepath.Join(absExportOutputDirPath, exportFileName)
		if err := cmdex.RunCommand("cp", filePth, exportPth); err != nil {
			failWithError("Failed to copy the Provisioning Profile into the export directory: %s", err)
		}
	}

	fmt.Println()
	log.Println(colorstring.Green("Exporting additinal, Distribution Provisioning Profile(s)"), "...")
	fmt.Println()
	for _, aAppBundleID := range codeSigningSettings.AppBundleIDs {
		log.Infof(" * "+colorstring.Blue("Searching for Provisioning Profiles with Bundle ID")+": %s", aAppBundleID)
		filePths, err := provprofile.FindProvProfilesFileByAppID(aAppBundleID)
		if err != nil {
			failWithError("Failed to find Provisioning Profile: %s", err)
		}
		if len(filePths) < 1 {
			log.Warn("   No Provisioning Profile found for this Bundle ID")
			continue
		}

		for _, aFilePth := range filePths {
			log.Info("   " + colorstring.Green("Exporting Provisioning Profile:") + " " + aFilePth)
			exportFileName := provProfileExportFileName(
				strings.TrimSuffix(filepath.Base(aFilePth), ".mobileprovision"),
				aAppBundleID,
			)
			exportPth := filepath.Join(absExportOutputDirPath, exportFileName)
			if err := cmdex.RunCommand("cp", aFilePth, exportPth); err != nil {
				failWithError("Failed to copy the Provisioning Profile into the export directory: %s", err)
			}
		}
	}

	fmt.Println()
	fmt.Printf(colorstring.Green("Exports finished")+" you can find the exported files at: %s\n", absExportOutputDirPath)
	if err := cmdex.RunCommand("open", absExportOutputDirPath); err != nil {
		log.Errorf("Failed to open the export directory in Finder: %s", absExportOutputDirPath)
	}
	fmt.Println("Opened the directory in Finder.")
	fmt.Println()

	printFinished()
}

func provProfileExportFileName(provProfileUUID, title string) string {
	replaceRexp, err := regexp.Compile("[^A-Za-z0-9_.-]")
	if err != nil {
		log.Warn("Invalid regex, error: %s", err)
		return ""
	}
	safeTitle := replaceRexp.ReplaceAllString(title, "")

	return provProfileUUID + "_" + safeTitle + ".mobileprovision"
}
<|endoftext|>


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

package cli

import (
	"fmt"
	"os"
	"strconv"

	"github.com/cockroachdb/cockroach/config"
	"github.com/cockroachdb/cockroach/util/log"
	"github.com/gogo/protobuf/proto"
	yaml "gopkg.in/yaml.v1"

	"github.com/spf13/cobra"
)

// zoneProtoToYAMLString takes a marshalled proto and returns
// its yaml representation.
func zoneProtoToYAMLString(val []byte) (string, error) {
	var zone config.ZoneConfig
	if err := proto.Unmarshal(val, &zone); err != nil {
		return "", err
	}
	ret, err := yaml.Marshal(zone)
	if err != nil {
		return "", err
	}
	return string(ret), nil
}

// formatZone is a callback used to format the raw zone config
// protobuf in a sql.Rows column for pretty printing.
func formatZone(val interface{}) string {
	if raw, ok := val.([]byte); ok {
		if ret, err := zoneProtoToYAMLString(raw); err == nil {
			return ret
		}
	}
	// Fallback to raw string in case of problems.
	return fmt.Sprintf("%#v", val)
}

// A getZoneCmd command displays the zone config for the specified ID.
var getZoneCmd = &cobra.Command{
	Use:   "get [options] <object-ID>",
	Short: "fetches and displays the zone config",
	Long: `
Fetches and displays the zone configuration for <object-id>.
`,
	Run: runGetZone,
}

// runGetZone retrieves the zone config for a given object id,
// and if present, outputs its YAML representation.
// TODO(marc): accept db/table names rather than IDs.
func runGetZone(cmd *cobra.Command, args []string) {
	if len(args) != 1 {
		mustUsage(cmd)
		return
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		log.Errorf("could not parse object ID %s", args[0])
		return
	}

	db := makeSQLClient()
	defer func() { _ = db.Close() }()
	_, rows, err := runQueryWithFormat(db, fmtMap{"config": formatZone},
		`SELECT * FROM system.zones WHERE id=$1`, id)
	if err != nil {
		log.Error(err)
		return
	}

	if len(rows) == 0 {
		log.Errorf("Object %d: no zone config found", id)
		return
	}
	fmt.Println(rows[0][1])
}

// A lsZonesCmd command displays a list of zone configs by object ID.
var lsZonesCmd = &cobra.Command{
	Use:   "ls [options]",
	Short: "list all zone configs by object ID",
	Long: `
List zone configs.
`,
	Run: runLsZones,
}

// TODO(marc): return db/table names rather than IDs.
func runLsZones(cmd *cobra.Command, args []string) {
	if len(args) > 0 {
		mustUsage(cmd)
		return
	}
	db := makeSQLClient()
	defer func() { _ = db.Close() }()
	_, rows, err := runQueryWithFormat(db, fmtMap{"config": formatZone}, `SELECT * FROM system.zones`)
	if err != nil {
		log.Error(err)
		return
	}

	if len(rows) == 0 {
		log.Error("No zone configs founds")
		return
	}
	for _, r := range rows {
		fmt.Printf("Object %s:\n%s\n", r[0], r[1])
	}
}

// A rmZoneCmd command removes a zone config by ID.
var rmZoneCmd = &cobra.Command{
	Use:   "rm [options] <object-id>",
	Short: "remove a zone config by object ID",
	Long: `
Remove an existing zone config by object ID. No action is taken if no
zone configuration exists for the specified object ID.
`,
	Run: runRmZone,
}

// TODO(marc): accept db/table names rather than IDs.
func runRmZone(cmd *cobra.Command, args []string) {
	if len(args) != 1 {
		mustUsage(cmd)
		return
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		log.Errorf("could not parse object ID %s", args[0])
		return
	}

	db := makeSQLClient()
	defer func() { _ = db.Close() }()
	err = runPrettyQuery(db, os.Stdout, `DELETE FROM system.zones WHERE id=$1`, id)
	if err != nil {
		log.Error(err)
		return
	}
}

// A setZoneCmd command creates a new or updates an existing zone config.
var setZoneCmd = &cobra.Command{
	Use:   "set [options] <object-id> <zone-config>",
	Short: "create or update zone config for object ID",
	Long: `
Create or update a zone config for the specified object ID (first argument: <object-id>)
to the specified zone-config (second argument: <zone-config>).

The zone config format has the following YAML schema:

  replicas:
    - attrs: [comma-separated attribute list]
    - attrs:  ...
  range_min_bytes: <size-in-bytes>
  range_max_bytes: <size-in-bytes>

For example, to set the zone config for object 100, run:
cockroach zone set 100 "replicas:
- attrs: [us-east-1a, ssd]
- attrs: [us-east-1b, ssd]
- attrs: [us-west-1b, ssd]
range_min_bytes: 8388608
range_max_bytes: 67108864"
`,
	Run: runSetZone,
}

// runSetZone parses the yaml input file, converts it to proto,
// and inserts it in the system.zones table.
// TODO(marc): accept db/table names rather than IDs.
func runSetZone(cmd *cobra.Command, args []string) {
	if len(args) != 2 {
		mustUsage(cmd)
		return
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		log.Errorf("could not parse object ID %s", args[0])
		return
	}

	// Convert it to proto and marshal it again to put into the table.
	// This is a bit more tedious than taking protos directly,
	// but yaml is a more widely understood format.
	var pbZoneConfig config.ZoneConfig
	if err := yaml.Unmarshal([]byte(args[1]), &pbZoneConfig); err != nil {
		log.Errorf("unable to parse zone config file %q: %s", args[1], err)
		return
	}

	if err := pbZoneConfig.Validate(); err != nil {
		log.Error(err)
		return
	}

	buf, err := proto.Marshal(&pbZoneConfig)
	if err != nil {
		log.Errorf("unable to parse zone config file %q: %s", args[1], err)
		return
	}

	db := makeSQLClient()
	defer func() { _ = db.Close() }()
	// TODO(marc): switch to UPSERT.
	err = runPrettyQuery(db, os.Stdout, `INSERT INTO system.zones VALUES ($1, $2)`, id, buf)
	if err != nil {
		log.Error(err)
		return
	}
}

var zoneCmds = []*cobra.Command{
	getZoneCmd,
	lsZonesCmd,
	rmZoneCmd,
	setZoneCmd,
}

var zoneCmd = &cobra.Command{
	Use:   "zone",
	Short: "get, set, list and remove zones\n",
	Run: func(cmd *cobra.Command, args []string) {
		mustUsage(cmd)
	},
}

func init() {
	zoneCmd.AddCommand(zoneCmds...)
}
<commit_msg>fix typo<commit_after>// Copyright 2014 The Cockroach Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
// implied. See the License for the specific language governing
// permissions and limitations under the License.
//
// Author: Spencer Kimball (spencer.kimball@gmail.com)
// Author: Bram Gruneir (bram+code@cockroachlabs.com)

package cli

import (
	"fmt"
	"os"
	"strconv"

	"github.com/cockroachdb/cockroach/config"
	"github.com/cockroachdb/cockroach/util/log"
	"github.com/gogo/protobuf/proto"
	yaml "gopkg.in/yaml.v1"

	"github.com/spf13/cobra"
)

// zoneProtoToYAMLString takes a marshalled proto and returns
// its yaml representation.
func zoneProtoToYAMLString(val []byte) (string, error) {
	var zone config.ZoneConfig
	if err := proto.Unmarshal(val, &zone); err != nil {
		return "", err
	}
	ret, err := yaml.Marshal(zone)
	if err != nil {
		return "", err
	}
	return string(ret), nil
}

// formatZone is a callback used to format the raw zone config
// protobuf in a sql.Rows column for pretty printing.
func formatZone(val interface{}) string {
	if raw, ok := val.([]byte); ok {
		if ret, err := zoneProtoToYAMLString(raw); err == nil {
			return ret
		}
	}
	// Fallback to raw string in case of problems.
	return fmt.Sprintf("%#v", val)
}

// A getZoneCmd command displays the zone config for the specified ID.
var getZoneCmd = &cobra.Command{
	Use:   "get [options] <object-ID>",
	Short: "fetches and displays the zone config",
	Long: `
Fetches and displays the zone configuration for <object-id>.
`,
	Run: runGetZone,
}

// runGetZone retrieves the zone config for a given object id,
// and if present, outputs its YAML representation.
// TODO(marc): accept db/table names rather than IDs.
func runGetZone(cmd *cobra.Command, args []string) {
	if len(args) != 1 {
		mustUsage(cmd)
		return
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		log.Errorf("could not parse object ID %s", args[0])
		return
	}

	db := makeSQLClient()
	defer func() { _ = db.Close() }()
	_, rows, err := runQueryWithFormat(db, fmtMap{"config": formatZone},
		`SELECT * FROM system.zones WHERE id=$1`, id)
	if err != nil {
		log.Error(err)
		return
	}

	if len(rows) == 0 {
		log.Errorf("Object %d: no zone config found", id)
		return
	}
	fmt.Println(rows[0][1])
}

// A lsZonesCmd command displays a list of zone configs by object ID.
var lsZonesCmd = &cobra.Command{
	Use:   "ls [options]",
	Short: "list all zone configs by object ID",
	Long: `
List zone configs.
`,
	Run: runLsZones,
}

// TODO(marc): return db/table names rather than IDs.
func runLsZones(cmd *cobra.Command, args []string) {
	if len(args) > 0 {
		mustUsage(cmd)
		return
	}
	db := makeSQLClient()
	defer func() { _ = db.Close() }()
	_, rows, err := runQueryWithFormat(db, fmtMap{"config": formatZone}, `SELECT * FROM system.zones`)
	if err != nil {
		log.Error(err)
		return
	}

	if len(rows) == 0 {
		log.Error("No zone configs found")
		return
	}
	for _, r := range rows {
		fmt.Printf("Object %s:\n%s\n", r[0], r[1])
	}
}

// A rmZoneCmd command removes a zone config by ID.
var rmZoneCmd = &cobra.Command{
	Use:   "rm [options] <object-id>",
	Short: "remove a zone config by object ID",
	Long: `
Remove an existing zone config by object ID. No action is taken if no
zone configuration exists for the specified object ID.
`,
	Run: runRmZone,
}

// TODO(marc): accept db/table names rather than IDs.
func runRmZone(cmd *cobra.Command, args []string) {
	if len(args) != 1 {
		mustUsage(cmd)
		return
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		log.Errorf("could not parse object ID %s", args[0])
		return
	}

	db := makeSQLClient()
	defer func() { _ = db.Close() }()
	err = runPrettyQuery(db, os.Stdout, `DELETE FROM system.zones WHERE id=$1`, id)
	if err != nil {
		log.Error(err)
		return
	}
}

// A setZoneCmd command creates a new or updates an existing zone config.
var setZoneCmd = &cobra.Command{
	Use:   "set [options] <object-id> <zone-config>",
	Short: "create or update zone config for object ID",
	Long: `
Create or update a zone config for the specified object ID (first argument: <object-id>)
to the specified zone-config (second argument: <zone-config>).

The zone config format has the following YAML schema:

  replicas:
    - attrs: [comma-separated attribute list]
    - attrs:  ...
  range_min_bytes: <size-in-bytes>
  range_max_bytes: <size-in-bytes>

For example, to set the zone config for object 100, run:
cockroach zone set 100 "replicas:
- attrs: [us-east-1a, ssd]
- attrs: [us-east-1b, ssd]
- attrs: [us-west-1b, ssd]
range_min_bytes: 8388608
range_max_bytes: 67108864"
`,
	Run: runSetZone,
}

// runSetZone parses the yaml input file, converts it to proto,
// and inserts it in the system.zones table.
// TODO(marc): accept db/table names rather than IDs.
func runSetZone(cmd *cobra.Command, args []string) {
	if len(args) != 2 {
		mustUsage(cmd)
		return
	}
	id, err := strconv.Atoi(args[0])
	if err != nil {
		log.Errorf("could not parse object ID %s", args[0])
		return
	}

	// Convert it to proto and marshal it again to put into the table.
	// This is a bit more tedious than taking protos directly,
	// but yaml is a more widely understood format.
	var pbZoneConfig config.ZoneConfig
	if err := yaml.Unmarshal([]byte(args[1]), &pbZoneConfig); err != nil {
		log.Errorf("unable to parse zone config file %q: %s", args[1], err)
		return
	}

	if err := pbZoneConfig.Validate(); err != nil {
		log.Error(err)
		return
	}

	buf, err := proto.Marshal(&pbZoneConfig)
	if err != nil {
		log.Errorf("unable to parse zone config file %q: %s", args[1], err)
		return
	}

	db := makeSQLClient()
	defer func() { _ = db.Close() }()
	// TODO(marc): switch to UPSERT.
	err = runPrettyQuery(db, os.Stdout, `INSERT INTO system.zones VALUES ($1, $2)`, id, buf)
	if err != nil {
		log.Error(err)
		return
	}
}

var zoneCmds = []*cobra.Command{
	getZoneCmd,
	lsZonesCmd,
	rmZoneCmd,
	setZoneCmd,
}

var zoneCmd = &cobra.Command{
	Use:   "zone",
	Short: "get, set, list and remove zones\n",
	Run: func(cmd *cobra.Command, args []string) {
		mustUsage(cmd)
	},
}

func init() {
	zoneCmd.AddCommand(zoneCmds...)
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/grpc-ecosystem/go-grpc-middleware"
	"github.com/grpc-ecosystem/go-grpc-middleware/recovery"
	"github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
	"github.com/grpc-ecosystem/go-grpc-prometheus"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
)

func createGrpcServer(app *application) *grpc.Server {
	// TODO: separate log levels
	grpclog.SetLoggerV2(grpclog.NewLoggerV2(
		log.NewStdlibAdapter(level.Info(app.logger)),
		log.NewStdlibAdapter(level.Warn(app.logger)),
		log.NewStdlibAdapter(level.Error(app.logger)),
	))

	server := grpc.NewServer(
		grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
			grpc_opentracing.StreamServerInterceptor(grpc_opentracing.WithTracer(app.tracer)),
			grpc_prometheus.StreamServerInterceptor,
			grpc_recovery.StreamServerInterceptor(),
		)),
		grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
			grpc_opentracing.UnaryServerInterceptor(grpc_opentracing.WithTracer(app.tracer)),
			grpc_prometheus.UnaryServerInterceptor,
			grpc_recovery.UnaryServerInterceptor(),
		)),
	)

	return server
}
<commit_msg>Add grpc server context to logging<commit_after>package main

import (
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/log/level"
	"github.com/grpc-ecosystem/go-grpc-middleware"
	"github.com/grpc-ecosystem/go-grpc-middleware/recovery"
	"github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
	"github.com/grpc-ecosystem/go-grpc-prometheus"
	"google.golang.org/grpc"
	"google.golang.org/grpc/grpclog"
)

func createGrpcServer(app *application) *grpc.Server {
	logger := log.With(
		app.logger,
		"server", "grpc",
	)

	// TODO: separate log levels
	grpclog.SetLoggerV2(grpclog.NewLoggerV2(
		log.NewStdlibAdapter(level.Info(logger)),
		log.NewStdlibAdapter(level.Warn(logger)),
		log.NewStdlibAdapter(level.Error(logger)),
	))

	server := grpc.NewServer(
		grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(
			grpc_opentracing.StreamServerInterceptor(grpc_opentracing.WithTracer(app.tracer)),
			grpc_prometheus.StreamServerInterceptor,
			grpc_recovery.StreamServerInterceptor(),
		)),
		grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(
			grpc_opentracing.UnaryServerInterceptor(grpc_opentracing.WithTracer(app.tracer)),
			grpc_prometheus.UnaryServerInterceptor,
			grpc_recovery.UnaryServerInterceptor(),
		)),
	)

	return server
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"github.com/urfave/cli"
	"github.com/zrepl/zrepl/jobrun"
	"github.com/zrepl/zrepl/rpc"
	"github.com/zrepl/zrepl/sshbytestream"
	"github.com/zrepl/zrepl/zfs"
	"golang.org/x/sys/unix"
	"io"
	"log"
	"os"
	"runtime/debug"
	"sync"
	"time"
)

type Logger interface {
	Printf(format string, v ...interface{})
}

var conf Config
var runner *jobrun.JobRunner
var logFlags int = log.LUTC | log.Ldate | log.Ltime
var logOut io.Writer
var defaultLog Logger

func main() {

	defer func() {
		e := recover()
		if e != nil {
			defaultLog.Printf("panic:\n%s\n\n", debug.Stack())
			defaultLog.Printf("error: %t %s", e, e)
			os.Exit(1)
		}
	}()

	app := cli.NewApp()

	app.Name = "zrepl"
	app.Usage = "replicate zfs datasets"
	app.EnableBashCompletion = true
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "config"},
		cli.StringFlag{Name: "logfile"},
	}
	app.Before = func(c *cli.Context) (err error) {

		if c.GlobalIsSet("logfile") {
			var logFile *os.File
			logFile, err = os.OpenFile(c.String("logfile"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
			if err != nil {
				return
			}

			if err = unix.Dup2(int(logFile.Fd()), int(os.Stderr.Fd())); err != nil {
				logFile.WriteString(fmt.Sprintf("error duping logfile to stderr: %s\n", err))
				return
			}
			logOut = logFile
		} else {
			logOut = os.Stderr
		}

		defaultLog = log.New(logOut, "", logFlags)
		if !c.GlobalIsSet("config") {
			return cli.NewExitError("config flag not set", 2)
		}
		if conf, err = ParseConfig(c.GlobalString("config")); err != nil {
			return cli.NewExitError(err, 2)
		}

		jobrunLogger := log.New(os.Stderr, "jobrun ", logFlags)
		runner = jobrun.NewJobRunner(jobrunLogger)
		return
	}
	app.Commands = []cli.Command{
		{
			Name:    "stdinserver",
			Aliases: []string{"s"},
			Usage:   "start in stdin server mode (from authorized keys)",
			Flags: []cli.Flag{
				cli.StringFlag{Name: "identity"},
			},
			Action: cmdStdinServer,
		},
		{
			Name:    "run",
			Aliases: []string{"r"},
			Usage:   "do replication",
			Action:  cmdRun,
			Flags: []cli.Flag{
				cli.StringFlag{Name: "job"},
			},
		},
	}

	app.Run(os.Args)

}

func cmdStdinServer(c *cli.Context) (err error) {

	if !c.IsSet("identity") {
		return cli.NewExitError("identity flag not set", 2)
	}
	identity := c.String("identity")

	var sshByteStream io.ReadWriteCloser
	if sshByteStream, err = sshbytestream.Incoming(); err != nil {
		return
	}

	findMapping := func(cm []ClientMapping, identity string) zfs.DatasetMapping {
		for i := range cm {
			if cm[i].From == identity {
				return cm[i].Mapping
			}
		}
		return nil
	}
	sinkMapping := func(identity string) (sink zfs.DatasetMapping, err error) {
		if sink = findMapping(conf.Sinks, identity); sink == nil {
			return nil, fmt.Errorf("could not find sink for dataset")
		}
		return
	}

	sinkLogger := log.New(logOut, fmt.Sprintf("sink[%s] ", identity), logFlags)
	handler := Handler{
		Logger:          sinkLogger,
		SinkMappingFunc: sinkMapping,
		PullACL:         findMapping(conf.PullACLs, identity),
	}

	if err = rpc.ListenByteStreamRPC(sshByteStream, identity, handler, sinkLogger); err != nil {
		//os.Exit(1)
		err = cli.NewExitError(err, 1)
		defaultLog.Printf("listenbytestreamerror: %#v\n", err)
	}

	return

}

func cmdRun(c *cli.Context) error {

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		runner.Start()
	}()

	jobs := make([]jobrun.Job, len(conf.Pulls)+len(conf.Pushs))
	i := 0
	for _, pull := range conf.Pulls {
		jobs[i] = jobrun.Job{
			Name:           fmt.Sprintf("pull.%d", i),
			RepeatStrategy: pull.RepeatStrategy,
			RunFunc: func(log jobrun.Logger) error {
				log.Printf("doing pull: %v", pull)
				return jobPull(pull, c, log)
			},
		}
		i++
	}
	for _, push := range conf.Pushs {
		jobs[i] = jobrun.Job{
			Name:           fmt.Sprintf("push.%d", i),
			RepeatStrategy: push.RepeatStrategy,
			RunFunc: func(log jobrun.Logger) error {
				log.Printf("doing push: %v", push)
				return jobPush(push, c, log)
			},
		}
		i++
	}

	for _, j := range jobs {
		if c.IsSet("job") {
			if c.String("job") == j.Name {
				runner.AddJob(j)
			}
			continue
		}
		runner.AddJob(j)
	}

	for {
		select {
		case job := <-runner.NotificationChan():
			log.Printf("job %s reported error: %v\n", job.Name, job.LastError)
		}
	}

	wg.Wait()

	return nil
}

func jobPull(pull Pull, c *cli.Context, log jobrun.Logger) (err error) {

	if lt, ok := pull.From.Transport.(LocalTransport); ok {
		lt.SetHandler(Handler{
			Logger:  log,
			PullACL: pull.Mapping,
		})
		pull.From.Transport = lt
		log.Printf("fixing up local transport: %#v", pull.From.Transport)
	}

	var remote rpc.RPCRequester

	if remote, err = pull.From.Transport.Connect(log); err != nil {
		return
	}

	defer closeRPCWithTimeout(log, remote, time.Second*10, "")

	return doPull(PullContext{remote, log, pull.Mapping, pull.InitialReplPolicy})
}

func jobPush(push Push, c *cli.Context, log jobrun.Logger) (err error) {

	if _, ok := push.To.Transport.(LocalTransport); ok {
		panic("no support for local pushs")
	}

	var remote rpc.RPCRequester
	if remote, err = push.To.Transport.Connect(log); err != nil {
		return err
	}

	defer closeRPCWithTimeout(log, remote, time.Second*10, "")

	log.Printf("building handler for PullMeRequest")
	handler := Handler{
		Logger:          log,
		PullACL:         push.Filter,
		SinkMappingFunc: nil, // no need for that in the handler for PullMe
	}
	log.Printf("handler: %#v", handler)

	r := rpc.PullMeRequest{
		InitialReplPolicy: push.InitialReplPolicy,
	}
	log.Printf("doing PullMeRequest: %#v", r)

	if err = remote.PullMeRequest(r, handler); err != nil {
		log.Printf("PullMeRequest failed: %s", err)
		return
	}

	log.Printf("push job finished")
	return

}
<commit_msg>cmd: support for pprof over http<commit_after>package main

import (
	"fmt"
	"github.com/urfave/cli"
	"github.com/zrepl/zrepl/jobrun"
	"github.com/zrepl/zrepl/rpc"
	"github.com/zrepl/zrepl/sshbytestream"
	"github.com/zrepl/zrepl/zfs"
	"golang.org/x/sys/unix"
	"io"
	"log"
	"net/http"
	_ "net/http/pprof"
	"os"
	"runtime/debug"
	"sync"
	"time"
)

type Logger interface {
	Printf(format string, v ...interface{})
}

var conf Config
var runner *jobrun.JobRunner
var logFlags int = log.LUTC | log.Ldate | log.Ltime
var logOut io.Writer
var defaultLog Logger

func main() {

	defer func() {
		e := recover()
		if e != nil {
			defaultLog.Printf("panic:\n%s\n\n", debug.Stack())
			defaultLog.Printf("error: %t %s", e, e)
			os.Exit(1)
		}
	}()

	app := cli.NewApp()

	app.Name = "zrepl"
	app.Usage = "replicate zfs datasets"
	app.EnableBashCompletion = true
	app.Flags = []cli.Flag{
		cli.StringFlag{Name: "config"},
		cli.StringFlag{Name: "logfile"},
		cli.StringFlag{Name: "debug.pprof.http"},
	}
	app.Before = func(c *cli.Context) (err error) {

		// Logging
		if c.GlobalIsSet("logfile") {
			var logFile *os.File
			logFile, err = os.OpenFile(c.String("logfile"), os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
			if err != nil {
				return
			}

			if err = unix.Dup2(int(logFile.Fd()), int(os.Stderr.Fd())); err != nil {
				logFile.WriteString(fmt.Sprintf("error duping logfile to stderr: %s\n", err))
				return
			}
			logOut = logFile
		} else {
			logOut = os.Stderr
		}
		defaultLog = log.New(logOut, "", logFlags)

		// CPU profiling
		if c.GlobalIsSet("debug.pprof.http") {
			go func() {
				http.ListenAndServe(c.GlobalString("debug.pprof.http"), nil)
			}()
		}

		// Config
		if !c.GlobalIsSet("config") {
			return cli.NewExitError("config flag not set", 2)
		}
		if conf, err = ParseConfig(c.GlobalString("config")); err != nil {
			return cli.NewExitError(err, 2)
		}

		jobrunLogger := log.New(os.Stderr, "jobrun ", logFlags)
		runner = jobrun.NewJobRunner(jobrunLogger)
		return
	}
	app.Commands = []cli.Command{
		{
			Name:    "stdinserver",
			Aliases: []string{"s"},
			Usage:   "start in stdin server mode (from authorized keys)",
			Flags: []cli.Flag{
				cli.StringFlag{Name: "identity"},
			},
			Action: cmdStdinServer,
		},
		{
			Name:    "run",
			Aliases: []string{"r"},
			Usage:   "do replication",
			Action:  cmdRun,
			Flags: []cli.Flag{
				cli.StringFlag{Name: "job"},
			},
		},
	}

	app.Run(os.Args)

}

func cmdStdinServer(c *cli.Context) (err error) {

	if !c.IsSet("identity") {
		return cli.NewExitError("identity flag not set", 2)
	}
	identity := c.String("identity")

	var sshByteStream io.ReadWriteCloser
	if sshByteStream, err = sshbytestream.Incoming(); err != nil {
		return
	}

	findMapping := func(cm []ClientMapping, identity string) zfs.DatasetMapping {
		for i := range cm {
			if cm[i].From == identity {
				return cm[i].Mapping
			}
		}
		return nil
	}
	sinkMapping := func(identity string) (sink zfs.DatasetMapping, err error) {
		if sink = findMapping(conf.Sinks, identity); sink == nil {
			return nil, fmt.Errorf("could not find sink for dataset")
		}
		return
	}

	sinkLogger := log.New(logOut, fmt.Sprintf("sink[%s] ", identity), logFlags)
	handler := Handler{
		Logger:          sinkLogger,
		SinkMappingFunc: sinkMapping,
		PullACL:         findMapping(conf.PullACLs, identity),
	}

	if err = rpc.ListenByteStreamRPC(sshByteStream, identity, handler, sinkLogger); err != nil {
		//os.Exit(1)
		err = cli.NewExitError(err, 1)
		defaultLog.Printf("listenbytestreamerror: %#v\n", err)
	}

	return

}

func cmdRun(c *cli.Context) error {

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		runner.Start()
	}()

	jobs := make([]jobrun.Job, len(conf.Pulls)+len(conf.Pushs))
	i := 0
	for _, pull := range conf.Pulls {
		jobs[i] = jobrun.Job{
			Name:           fmt.Sprintf("pull.%d", i),
			RepeatStrategy: pull.RepeatStrategy,
			RunFunc: func(log jobrun.Logger) error {
				log.Printf("doing pull: %v", pull)
				return jobPull(pull, c, log)
			},
		}
		i++
	}
	for _, push := range conf.Pushs {
		jobs[i] = jobrun.Job{
			Name:           fmt.Sprintf("push.%d", i),
			RepeatStrategy: push.RepeatStrategy,
			RunFunc: func(log jobrun.Logger) error {
				log.Printf("doing push: %v", push)
				return jobPush(push, c, log)
			},
		}
		i++
	}

	for _, j := range jobs {
		if c.IsSet("job") {
			if c.String("job") == j.Name {
				runner.AddJob(j)
			}
			continue
		}
		runner.AddJob(j)
	}

	for {
		select {
		case job := <-runner.NotificationChan():
			log.Printf("job %s reported error: %v\n", job.Name, job.LastError)
		}
	}

	wg.Wait()

	return nil
}

func jobPull(pull Pull, c *cli.Context, log jobrun.Logger) (err error) {

	if lt, ok := pull.From.Transport.(LocalTransport); ok {
		lt.SetHandler(Handler{
			Logger:  log,
			PullACL: pull.Mapping,
		})
		pull.From.Transport = lt
		log.Printf("fixing up local transport: %#v", pull.From.Transport)
	}

	var remote rpc.RPCRequester

	if remote, err = pull.From.Transport.Connect(log); err != nil {
		return
	}

	defer closeRPCWithTimeout(log, remote, time.Second*10, "")

	return doPull(PullContext{remote, log, pull.Mapping, pull.InitialReplPolicy})
}

func jobPush(push Push, c *cli.Context, log jobrun.Logger) (err error) {

	if _, ok := push.To.Transport.(LocalTransport); ok {
		panic("no support for local pushs")
	}

	var remote rpc.RPCRequester
	if remote, err = push.To.Transport.Connect(log); err != nil {
		return err
	}

	defer closeRPCWithTimeout(log, remote, time.Second*10, "")

	log.Printf("building handler for PullMeRequest")
	handler := Handler{
		Logger:          log,
		PullACL:         push.Filter,
		SinkMappingFunc: nil, // no need for that in the handler for PullMe
	}
	log.Printf("handler: %#v", handler)

	r := rpc.PullMeRequest{
		InitialReplPolicy: push.InitialReplPolicy,
	}
	log.Printf("doing PullMeRequest: %#v", r)

	if err = remote.PullMeRequest(r, handler); err != nil {
		log.Printf("PullMeRequest failed: %s", err)
		return
	}

	log.Printf("push job finished")
	return

}
<|endoftext|>


<commit_before>package main

import (
	"os"
	"time"

	"github.com/go-ggz/ggz/config"
	"github.com/go-ggz/ggz/version"

	"github.com/joho/godotenv"
	_ "github.com/joho/godotenv/autoload"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"gopkg.in/urfave/cli.v2"
)

func setupLogging() {
	zerolog.SetGlobalLevel(zerolog.InfoLevel)
	if config.Debug {
		zerolog.SetGlobalLevel(zerolog.DebugLevel)
	}

	if config.Logs.Pretty {
		log.Logger = log.Output(
			zerolog.ConsoleWriter{
				Out:     os.Stderr,
				NoColor: !config.Logs.Color,
			},
		)
	}
}

func main() {
	if env := os.Getenv("GGZ_ENV_FILE"); env != "" {
		if err := godotenv.Load(env); err != nil {
			log.Fatal().Err(err).Msgf("Cannot start load config from env")
		}
	}

	app := &cli.App{
		Name:      "gzz",
		Usage:     "shorten url service",
		Copyright: "Copyright (c) 2018 Bo-Yi Wu",
		Version:   version.PrintCLIVersion(),
		Compiled:  time.Now(),
		Authors: []*cli.Author{
			{
				Name:  "Bo-Yi Wu",
				Email: "appleboy.tw@gmail.com",
			},
		},

		Flags: []cli.Flag{
			&cli.BoolFlag{
				Name:        "debug",
				Value:       false,
				Usage:       "Activate debug information",
				EnvVars:     []string{"GGZ_DEBUG"},
				Destination: &config.Debug,
				Hidden:      true,
			},
			&cli.BoolFlag{
				Name:        "color",
				Value:       false,
				Usage:       "Enable pprof debugging server",
				EnvVars:     []string{"GGZ_LOGS_COLOR"},
				Destination: &config.Logs.Color,
			},
			&cli.BoolFlag{
				Name:        "pretty",
				Value:       false,
				Usage:       "Enable pprof debugging server",
				EnvVars:     []string{"GGZ_LOGS_PRETTY"},
				Destination: &config.Logs.Pretty,
			},
		},

		Before: func(c *cli.Context) error {
			setupLogging()

			return nil
		},

		Commands: []*cli.Command{
			Server(),
			Ping(),
		},
	}

	cli.HelpFlag = &cli.BoolFlag{
		Name:    "help",
		Aliases: []string{"h"},
		Usage:   "Show the help, so what you see now",
	}

	cli.VersionFlag = &cli.BoolFlag{
		Name:    "version",
		Aliases: []string{"v"},
		Usage:   "Print the current version of that tool",
	}

	if err := app.Run(os.Args); err != nil {
		os.Exit(1)
	}
}
<commit_msg>fix error fun<commit_after>package main

import (
	"os"
	"time"

	"github.com/go-ggz/ggz/config"
	"github.com/go-ggz/ggz/version"

	"github.com/joho/godotenv"
	_ "github.com/joho/godotenv/autoload"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"gopkg.in/urfave/cli.v2"
)

func setupLogging() {
	zerolog.SetGlobalLevel(zerolog.InfoLevel)
	if config.Debug {
		zerolog.SetGlobalLevel(zerolog.DebugLevel)
	}

	if config.Logs.Pretty {
		log.Logger = log.Output(
			zerolog.ConsoleWriter{
				Out:     os.Stderr,
				NoColor: !config.Logs.Color,
			},
		)
	}
}

func main() {
	if env := os.Getenv("GGZ_ENV_FILE"); env != "" {
		if err := godotenv.Load(env); err != nil {
			log.Fatal().Err(err).Msg("Cannot start load config from env")
		}
	}

	app := &cli.App{
		Name:      "gzz",
		Usage:     "shorten url service",
		Copyright: "Copyright (c) 2018 Bo-Yi Wu",
		Version:   version.PrintCLIVersion(),
		Compiled:  time.Now(),
		Authors: []*cli.Author{
			{
				Name:  "Bo-Yi Wu",
				Email: "appleboy.tw@gmail.com",
			},
		},

		Flags: []cli.Flag{
			&cli.BoolFlag{
				Name:        "debug",
				Value:       false,
				Usage:       "Activate debug information",
				EnvVars:     []string{"GGZ_DEBUG"},
				Destination: &config.Debug,
				Hidden:      true,
			},
			&cli.BoolFlag{
				Name:        "color",
				Value:       false,
				Usage:       "Enable pprof debugging server",
				EnvVars:     []string{"GGZ_LOGS_COLOR"},
				Destination: &config.Logs.Color,
			},
			&cli.BoolFlag{
				Name:        "pretty",
				Value:       false,
				Usage:       "Enable pprof debugging server",
				EnvVars:     []string{"GGZ_LOGS_PRETTY"},
				Destination: &config.Logs.Pretty,
			},
		},

		Before: func(c *cli.Context) error {
			setupLogging()

			return nil
		},

		Commands: []*cli.Command{
			Server(),
			Ping(),
		},
	}

	cli.HelpFlag = &cli.BoolFlag{
		Name:    "help",
		Aliases: []string{"h"},
		Usage:   "Show the help, so what you see now",
	}

	cli.VersionFlag = &cli.BoolFlag{
		Name:    "version",
		Aliases: []string{"v"},
		Usage:   "Print the current version of that tool",
	}

	if err := app.Run(os.Args); err != nil {
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>// Copyright © 2016 Zhang Peihao <zhangpeihao@gmail.com>

package cmd

import (
	"flag"
	"fmt"
	"net/http"
	"os"

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

var cfgFile string
var cfgVerbose bool
var cfgVmodule, cfgLogDir string
var cfgDebug bool

// RootCmd root命令
var RootCmd = &cobra.Command{
	Use:   "zim",
	Short: "IM服务",
	Long: `IM集群服务

包括一些模块：
gateway：网关。提供TCP, UDP和WebSocket等接入方式，与客户端
         建立稳定的双向连接。
maintain：网控。实时监控集群各个服务的状态`,
}

// Execute 执行命令
func Execute() {
	if cfgDebug {
		go func() {
			fmt.Println(http.ListenAndServe("localhost:8870", nil))
		}()
	}
	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/.zim.yaml)")
	RootCmd.PersistentFlags().BoolVarP(&cfgVerbose, "verbose", "v", false, "verbose mode")
	RootCmd.PersistentFlags().BoolVarP(&cfgDebug, "debug", "d", false, "debug mode. runtime profiling data at: htpp://localhost:8766/debug/pprof")
	RootCmd.PersistentFlags().StringVar(&cfgVmodule, "vmodule", "", "vmodule for glog")
	RootCmd.PersistentFlags().StringVar(&cfgLogDir, "log_dir", "", "log path")
}

// 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.SetConfigType("yaml")
	} else {
		viper.SetConfigName(".zim")  // name of config file (without extension)
		viper.AddConfigPath("$HOME") // adding home directory as first search path
	}
	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())
		if viper.InConfig("debug") {
			cfgDebug = viper.GetBool("debug")
		}
		if viper.InConfig("verbose") {
			cfgVerbose = viper.GetBool("verbose")
		}
		if viper.InConfig("router-json") {
			cfgRouterJSON = viper.GetString("router-json")
		}
		if viper.InConfig("wss-cert-file") {
			cfgCertFile = viper.GetString("wss-cert-file")
		}
		if viper.InConfig("wss-key-file") {
			cfgKeyFile = viper.GetString("wss-key-file")
		}

	} else {
		fmt.Println("ReadInConfig error:", err)
		os.Exit(1)
	}

	if cfgVerbose {
		jww.SetStdoutThreshold(jww.LevelTrace)
		flag.Set("v", "4")
		flag.Set("alsologtostderr", "true")
	}
	if len(cfgVmodule) > 0 {
		flag.Set("vmodule", cfgVmodule)
	}
	if len(cfgLogDir) > 0 {
		flag.Set("log_dir", cfgLogDir)
	}
}
<commit_msg>Fixed bug: load config file error.<commit_after>// Copyright © 2016 Zhang Peihao <zhangpeihao@gmail.com>

package cmd

import (
	"flag"
	"fmt"
	"net/http"
	"os"

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

var cfgFile string
var cfgVerbose bool
var cfgVmodule, cfgLogDir string
var cfgDebug bool

// RootCmd root命令
var RootCmd = &cobra.Command{
	Use:   "zim",
	Short: "IM服务",
	Long: `IM集群服务

包括一些模块：
gateway：网关。提供TCP, UDP和WebSocket等接入方式，与客户端
         建立稳定的双向连接。
maintain：网控。实时监控集群各个服务的状态`,
}

// Execute 执行命令
func Execute() {
	if cfgDebug {
		go func() {
			fmt.Println(http.ListenAndServe("localhost:8870", nil))
		}()
	}
	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/.zim.yaml)")
	RootCmd.PersistentFlags().BoolVarP(&cfgVerbose, "verbose", "v", false, "verbose mode")
	RootCmd.PersistentFlags().BoolVarP(&cfgDebug, "debug", "d", false, "debug mode. runtime profiling data at: htpp://localhost:8766/debug/pprof")
	RootCmd.PersistentFlags().StringVar(&cfgVmodule, "vmodule", "", "vmodule for glog")
	RootCmd.PersistentFlags().StringVar(&cfgLogDir, "log_dir", "", "log path")
}

// 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.SetConfigType("yaml")
	} else {
		viper.SetConfigName(".zim")  // name of config file (without extension)
		viper.AddConfigPath("$HOME") // adding home directory as first search path
	}
	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())
		if viper.InConfig("debug") {
			cfgDebug = viper.GetBool("debug")
		}
		if viper.InConfig("verbose") {
			cfgVerbose = viper.GetBool("verbose")
		}
		if viper.InConfig("router-json") {
			cfgRouterJSON = viper.GetString("router-json")
		}
		if viper.InConfig("wss-cert-file") {
			cfgCertFile = viper.GetString("wss-cert-file")
		}
		if viper.InConfig("wss-key-file") {
			cfgKeyFile = viper.GetString("wss-key-file")
		}
	}

	if cfgVerbose {
		jww.SetStdoutThreshold(jww.LevelTrace)
		flag.Set("v", "4")
		flag.Set("alsologtostderr", "true")
	}
	if len(cfgVmodule) > 0 {
		flag.Set("vmodule", cfgVmodule)
	}
	if len(cfgLogDir) > 0 {
		flag.Set("log_dir", cfgLogDir)
	}
}
<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/image-server/image-server/core"
	"github.com/image-server/image-server/fetcher/http"
	"github.com/image-server/image-server/logger/logfile"
	"github.com/image-server/image-server/logger/statsd"
	"github.com/image-server/image-server/paths"
	"github.com/image-server/image-server/uploader"
	homedir "github.com/mitchellh/go-homedir"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

// configT collects all the global state of the logging setup.
type configT struct {
	port          string
	extensions    string
	localBasePath string

	remoteBaseURL  string
	remoteBasePath string

	namespace string
	outputs   string
	listen    string

	uploaderType string
	maxFileAge   int

	awsAccessKeyID string
	awsSecretKey   string
	awsBucket      string
	awsRegion      string

	mantaURL    string
	mantaUser   string
	mantaKeyID  string
	sdcIdentity string

	maximumWidth   int
	defaultQuality int

	uploaderConcurrency  int
	processorConcurrency int
	httpTimeout          int
	gomaxprocs           int

	statsdHost   string
	statsdPort   int
	statsdPrefix string
	profile      bool

	version bool
}

var cfgFile string
var config configT

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "image-server",
	Short: "image-server is an image processing server",
}

// 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/.cobra-example.yaml)")
}

// 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 ".cobra-example" (without extension).
		viper.AddConfigPath(home)
		viper.SetConfigName(".cobra-example")
	}

	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())
	}
}

func serverConfiguration() (*core.ServerConfiguration, error) {
	sc := serverConfigurationFromConfig()
	statsd.Enable(config.statsdHost, config.statsdPort, config.statsdPrefix)
	logfile.Enable()

	adapters := &core.Adapters{
		Fetcher: &http.Fetcher{},
		Paths:   &paths.Paths{LocalBasePath: sc.LocalBasePath, RemoteBasePath: sc.RemoteBasePath, RemoteBaseURL: sc.RemoteBaseURL},
	}
	sc.Adapters = adapters
	sc.CleanUpTicker = time.NewTicker(2 * time.Minute)

	return sc, nil
}

// serverConfigurationFromContext returns a core.ServerConfiguration initialized
// from command line flags or defaults.
// Command line flags preceding the Command (server, process, etc) are registered
// as globals. Flags succeeding the Command are not globals.
func serverConfigurationFromConfig() *core.ServerConfiguration {
	httpTimeout := time.Duration(config.httpTimeout) * time.Second
	var maxFileAge time.Duration
	if config.maxFileAge > 0 {
		maxFileAge = time.Duration(config.maxFileAge) * time.Minute
	} else {
		maxFileAge = time.Minute
	}

	var uploader string
	if config.uploaderType != "" {
		uploader = config.uploaderType
	} else {
		if config.awsAccessKeyID != "" {
			uploader = "s3"
		} else if config.mantaKeyID != "" {
			uploader = "manta"
		} else {
			uploader = "noop"
		}
	}

	return &core.ServerConfiguration{
		WhitelistedExtensions: strings.Split(config.extensions, ","),
		LocalBasePath:         config.localBasePath,

		MaximumWidth:   config.maximumWidth,
		RemoteBasePath: config.remoteBasePath,
		RemoteBaseURL:  config.remoteBaseURL,

		UploaderType: uploader,
		MaxFileAge:   maxFileAge,

		// AWS specific
		AWSAccessKeyID: config.awsAccessKeyID,
		AWSSecretKey:   config.awsSecretKey,
		AWSBucket:      config.awsBucket,
		AWSRegion:      config.awsRegion,

		// Manta specific
		MantaURL:    config.mantaURL,
		MantaUser:   config.mantaUser,
		MantaKeyID:  config.mantaKeyID,
		SDCIdentity: config.sdcIdentity,

		Outputs:             config.outputs,
		DefaultQuality:      uint(config.defaultQuality),
		UploaderConcurrency: uint(config.uploaderConcurrency),
		HTTPTimeout:         httpTimeout,
	}
}

// initializeUploader creates base path on destination server
func initializeUploader(sc *core.ServerConfiguration) {
	err := uploader.Initialize(sc)
	if err != nil {
		log.Println("EXITING: Unable to initialize uploader: ", err)
		os.Exit(2)
	}
}
<commit_msg>Remove cobra config<commit_after>package cmd

import (
	"fmt"
	"log"
	"os"
	"strings"
	"time"

	"github.com/image-server/image-server/core"
	"github.com/image-server/image-server/fetcher/http"
	"github.com/image-server/image-server/logger/logfile"
	"github.com/image-server/image-server/logger/statsd"
	"github.com/image-server/image-server/paths"
	"github.com/image-server/image-server/uploader"
	"github.com/spf13/cobra"
)

// configT collects all the global state of the logging setup.
type configT struct {
	port          string
	extensions    string
	localBasePath string

	remoteBaseURL  string
	remoteBasePath string

	namespace string
	outputs   string
	listen    string

	uploaderType string
	maxFileAge   int

	awsAccessKeyID string
	awsSecretKey   string
	awsBucket      string
	awsRegion      string

	mantaURL    string
	mantaUser   string
	mantaKeyID  string
	sdcIdentity string

	maximumWidth   int
	defaultQuality int

	uploaderConcurrency  int
	processorConcurrency int
	httpTimeout          int
	gomaxprocs           int

	statsdHost   string
	statsdPort   int
	statsdPrefix string
	profile      bool

	version bool
}

var config configT

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
	Use:   "image-server",
	Short: "image-server is an image processing server",
}

// 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 serverConfiguration() (*core.ServerConfiguration, error) {
	sc := serverConfigurationFromConfig()
	statsd.Enable(config.statsdHost, config.statsdPort, config.statsdPrefix)
	logfile.Enable()

	adapters := &core.Adapters{
		Fetcher: &http.Fetcher{},
		Paths:   &paths.Paths{LocalBasePath: sc.LocalBasePath, RemoteBasePath: sc.RemoteBasePath, RemoteBaseURL: sc.RemoteBaseURL},
	}
	sc.Adapters = adapters
	sc.CleanUpTicker = time.NewTicker(2 * time.Minute)

	return sc, nil
}

// serverConfigurationFromContext returns a core.ServerConfiguration initialized
// from command line flags or defaults.
// Command line flags preceding the Command (server, process, etc) are registered
// as globals. Flags succeeding the Command are not globals.
func serverConfigurationFromConfig() *core.ServerConfiguration {
	httpTimeout := time.Duration(config.httpTimeout) * time.Second
	var maxFileAge time.Duration
	if config.maxFileAge > 0 {
		maxFileAge = time.Duration(config.maxFileAge) * time.Minute
	} else {
		maxFileAge = time.Minute
	}

	var uploader string
	if config.uploaderType != "" {
		uploader = config.uploaderType
	} else {
		if config.awsAccessKeyID != "" {
			uploader = "s3"
		} else if config.mantaKeyID != "" {
			uploader = "manta"
		} else {
			uploader = "noop"
		}
	}

	return &core.ServerConfiguration{
		WhitelistedExtensions: strings.Split(config.extensions, ","),
		LocalBasePath:         config.localBasePath,

		MaximumWidth:   config.maximumWidth,
		RemoteBasePath: config.remoteBasePath,
		RemoteBaseURL:  config.remoteBaseURL,

		UploaderType: uploader,
		MaxFileAge:   maxFileAge,

		// AWS specific
		AWSAccessKeyID: config.awsAccessKeyID,
		AWSSecretKey:   config.awsSecretKey,
		AWSBucket:      config.awsBucket,
		AWSRegion:      config.awsRegion,

		// Manta specific
		MantaURL:    config.mantaURL,
		MantaUser:   config.mantaUser,
		MantaKeyID:  config.mantaKeyID,
		SDCIdentity: config.sdcIdentity,

		Outputs:             config.outputs,
		DefaultQuality:      uint(config.defaultQuality),
		UploaderConcurrency: uint(config.uploaderConcurrency),
		HTTPTimeout:         httpTimeout,
	}
}

// initializeUploader creates base path on destination server
func initializeUploader(sc *core.ServerConfiguration) {
	err := uploader.Initialize(sc)
	if err != nil {
		log.Println("EXITING: Unable to initialize uploader: ", err)
		os.Exit(2)
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gogs 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 (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/Unknwon/com"
	"github.com/urfave/cli"
	log "gopkg.in/clog.v1"

	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/models/errors"
	"github.com/gogits/gogs/pkg/setting"
	http "github.com/gogits/gogs/routes/repo"
)

const (
	_ACCESS_DENIED_MESSAGE = "Repository does not exist or you do not have access"
)

var Serv = 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{
		stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
	},
}

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

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

	os.Exit(1)
}

func setup(c *cli.Context, logPath string, connectDB bool) {
	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	} else if c.GlobalIsSet("config") {
		setting.CustomConf = c.GlobalString("config")
	}

	setting.NewContext()

	level := log.TRACE
	if setting.ProdMode {
		level = log.ERROR
	}
	log.New(log.FILE, log.FileConfig{
		Level:    level,
		Filename: filepath.Join(setting.LogRootPath, logPath),
		FileRotationConfig: log.FileRotationConfig{
			Rotate:  true,
			Daily:   true,
			MaxDays: 3,
		},
	})
	log.Delete(log.CONSOLE) // Remove primary logger

	if !connectDB {
		return
	}

	models.LoadConfigs()

	if setting.UseSQLite3 {
		workDir, _ := setting.WorkDir()
		os.Chdir(workDir)
	}

	if err := models.SetEngine(); err != nil {
		fail("Internal error", "SetEngine: %v", err)
	}
}

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

func checkDeployKey(key *models.PublicKey, repo *models.Repository) {
	// 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)
	}
}

var (
	allowedCommands = map[string]models.AccessMode{
		"git-upload-pack":    models.ACCESS_MODE_READ,
		"git-upload-archive": models.ACCESS_MODE_READ,
		"git-receive-pack":   models.ACCESS_MODE_WRITE,
	}
)

func runServ(c *cli.Context) error {
	setup(c, "serv.log", true)

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

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

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

	verb, args := parseSSHCmd(sshCmd)
	repoFullName := strings.ToLower(strings.Trim(args, "'"))
	repoFields := strings.SplitN(repoFullName, "/", 2)
	if len(repoFields) != 2 {
		fail("Invalid repository path", "Invalid repository path: %v", args)
	}
	ownerName := strings.ToLower(repoFields[0])
	repoName := strings.TrimSuffix(strings.ToLower(repoFields[1]), ".git")
	repoName = strings.TrimSuffix(repoName, ".wiki")

	owner, err := models.GetUserByName(ownerName)
	if err != nil {
		if errors.IsUserNotExist(err) {
			fail("Repository owner does not exist", "Unregistered owner: %s", ownerName)
		}
		fail("Internal error", "Fail to get repository owner '%s': %v", ownerName, err)
	}

	repo, err := models.GetRepositoryByName(owner.ID, repoName)
	if err != nil {
		if errors.IsRepoNotExist(err) {
			fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", owner.Name, repoName)
		}
		fail("Internal error", "Fail to get repository: %v", err)
	}
	repo.Owner = owner

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

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

	// Allow anonymous (user is nil) clone for public repositories.
	var user *models.User

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

	if requestMode == models.ACCESS_MODE_WRITE || repo.IsPrivate {
		// Check deploy key or user key.
		if key.IsDeployKey() {
			if key.Mode < requestMode {
				fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
			}
			checkDeployKey(key, repo)
		} else {
			user, err = models.GetUserByKeyID(key.ID)
			if err != nil {
				fail("Internal error", "Fail to get user by key ID '%d': %v", key.ID, err)
			}

			mode, err := models.AccessLevel(user.ID, repo)
			if err != nil {
				fail("Internal error", "Fail to check access: %v", err)
			}

			if mode < requestMode {
				clientMessage := _ACCESS_DENIED_MESSAGE
				if mode >= models.ACCESS_MODE_READ {
					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, requestMode, repoFullName)
			}
		}
	} else {
		setting.NewService()
		// Check if the key can access to the repository in case of it is a deploy key (a deploy keys != user key).
		// A deploy key doesn't represent a signed in user, so in a site with Service.RequireSignInView activated
		// we should give read access only in repositories where this deploy key is in use. In other case, a server
		// or system using an active deploy key can get read access to all the repositories in a Gogs service.
		if key.IsDeployKey() && setting.Service.RequireSignInView {
			checkDeployKey(key, repo)
		}
	}

	// Update user key activity.
	if key.ID > 0 {
		key, err := models.GetPublicKeyByID(key.ID)
		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)
		}
	}

	// 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], repoFullName)
	} else {
		gitCmd = exec.Command(verb, repoFullName)
	}
	if requestMode == models.ACCESS_MODE_WRITE {
		gitCmd.Env = append(os.Environ(), http.ComposeHookEnvs(http.ComposeHookEnvsOptions{
			AuthUser:  user,
			OwnerName: owner.Name,
			OwnerSalt: owner.Salt,
			RepoID:    repo.ID,
			RepoName:  repo.Name,
			RepoPath:  repo.RepoPath(),
		})...)
	}
	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", "Fail to execute git command: %v", err)
	}

	return nil
}
<commit_msg>[annex] Support git-annex-shell in serv cmd<commit_after>// Copyright 2014 The Gogs 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 (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"github.com/Unknwon/com"
	"github.com/urfave/cli"
	log "gopkg.in/clog.v1"

	"github.com/gogits/gogs/models"
	"github.com/gogits/gogs/models/errors"
	"github.com/gogits/gogs/pkg/setting"
	http "github.com/gogits/gogs/routes/repo"
)

const (
	_ACCESS_DENIED_MESSAGE = "Repository does not exist or you do not have access"
)

var Serv = 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{
		stringFlag("config, c", "custom/conf/app.ini", "Custom configuration file path"),
	},
}

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

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

	os.Exit(1)
}

func setup(c *cli.Context, logPath string, connectDB bool) {
	if c.IsSet("config") {
		setting.CustomConf = c.String("config")
	} else if c.GlobalIsSet("config") {
		setting.CustomConf = c.GlobalString("config")
	}

	setting.NewContext()

	level := log.TRACE
	if setting.ProdMode {
		level = log.ERROR
	}
	log.New(log.FILE, log.FileConfig{
		Level:    level,
		Filename: filepath.Join(setting.LogRootPath, logPath),
		FileRotationConfig: log.FileRotationConfig{
			Rotate:  true,
			Daily:   true,
			MaxDays: 3,
		},
	})
	log.Delete(log.CONSOLE) // Remove primary logger

	if !connectDB {
		return
	}

	models.LoadConfigs()

	if setting.UseSQLite3 {
		workDir, _ := setting.WorkDir()
		os.Chdir(workDir)
	}

	if err := models.SetEngine(); err != nil {
		fail("Internal error", "SetEngine: %v", err)
	}
}

func parseSSHCmd(cmd string) (string, string, []string) {
	ss := strings.Split(cmd, " ")
	if len(ss) < 2 {
		return "", "", nil
	}
	return ss[0], strings.Replace(ss[len(ss)-1], "/", "'", 1), ss
}

func checkDeployKey(key *models.PublicKey, repo *models.Repository) {
	// 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)
	}
}

var (
	allowedCommands = map[string]models.AccessMode{
		"git-upload-pack":    models.ACCESS_MODE_READ,
		"git-upload-archive": models.ACCESS_MODE_READ,
		"git-receive-pack":   models.ACCESS_MODE_WRITE,
		"git-annex-shell":    models.ACCESS_MODE_WRITE,
	}
)

func runServ(c *cli.Context) error {
	setup(c, "serv.log", true)

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

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

	sshCmd := strings.Replace(os.Getenv("SSH_ORIGINAL_COMMAND"), "'", "", -1)
	log.Info("SSH commadn:%s", sshCmd)
	if len(sshCmd) == 0 {
		println("Hi there, You've successfully authenticated, but Gogs does not provide shell access.")
		println("If this is unexpected, please log in with password and setup Gogs under another user.")
		return nil
	}

	verb, path, args := parseSSHCmd(sshCmd)
	repoFullName := strings.ToLower(strings.Trim(path, "'"))
	repoFields := strings.SplitN(repoFullName, "/", 2)
	if len(repoFields) != 2 {
		fail("Invalid repository path", "Invalid repository path: %v", path)
	}
	ownerName := strings.ToLower(repoFields[0])
	repoName := strings.TrimSuffix(strings.ToLower(repoFields[1]), ".git")
	repoName = strings.TrimSuffix(repoName, ".wiki")

	owner, err := models.GetUserByName(ownerName)
	if err != nil {
		if errors.IsUserNotExist(err) {
			fail("Repository owner does not exist", "Unregistered owner: %s", ownerName)
		}
		fail("Internal error", "Fail to get repository owner '%s': %v", ownerName, err)
	}

	repo, err := models.GetRepositoryByName(owner.ID, repoName)
	if err != nil {
		if errors.IsRepoNotExist(err) {
			fail(_ACCESS_DENIED_MESSAGE, "Repository does not exist: %s/%s", owner.Name, repoName)
		}
		fail("Internal error", "Fail to get repository: %v", err)
	}
	repo.Owner = owner

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

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

	// Allow anonymous (user is nil) clone for public repositories.
	var user *models.User

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

	if requestMode == models.ACCESS_MODE_WRITE || repo.IsPrivate {
		// Check deploy key or user key.
		if key.IsDeployKey() {
			if key.Mode < requestMode {
				fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
			}
			checkDeployKey(key, repo)
		} else {
			user, err = models.GetUserByKeyID(key.ID)
			if err != nil {
				fail("Internal error", "Fail to get user by key ID '%d': %v", key.ID, err)
			}

			mode, err := models.AccessLevel(user.ID, repo)
			if err != nil {
				fail("Internal error", "Fail to check access: %v", err)
			}

			if mode < requestMode {
				clientMessage := _ACCESS_DENIED_MESSAGE
				if mode >= models.ACCESS_MODE_READ {
					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, requestMode, repoFullName)
			}
		}
	} else {
		setting.NewService()
		// Check if the key can access to the repository in case of it is a deploy key (a deploy keys != user key).
		// A deploy key doesn't represent a signed in user, so in a site with Service.RequireSignInView activated
		// we should give read access only in repositories where this deploy key is in use. In other case, a server
		// or system using an active deploy key can get read access to all the repositories in a Gogs service.
		if key.IsDeployKey() && setting.Service.RequireSignInView {
			checkDeployKey(key, repo)
		}
	}

	// Update user key activity.
	if key.ID > 0 {
		key, err := models.GetPublicKeyByID(key.ID)
		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)
		}
	}

	// Special handle for Windows.
	// Todo will break with annex
	if setting.IsWindows {
		verb = strings.Replace(verb, "-", " ", 1)
	}
	verbs := strings.Split(verb, " ")
	var cmd []string
	if len(verbs) == 2 {
		cmd = []string{verbs[0], verbs[1], repoFullName}
	} else if (verb == "git-annex-shell") {
		cmd = args
		cmd[len(cmd)-1] = setting.RepoRootPath + "/" + repoFullName
	} else {
		cmd = []string{verb, repoFullName}
	}
	return runGit(cmd, requestMode, user, owner, repo)

}

func runGit(cmd [] string, requestMode models.AccessMode, user *models.User, owner *models.User,
	repo *models.Repository) error {
	log.Info("will exectute:%s", cmd)
	gitCmd := exec.Command(cmd[0], cmd[1:]...)
	if requestMode == models.ACCESS_MODE_WRITE {
		gitCmd.Env = append(os.Environ(), http.ComposeHookEnvs(http.ComposeHookEnvsOptions{
			AuthUser:  user,
			OwnerName: owner.Name,
			OwnerSalt: owner.Salt,
			RepoID:    repo.ID,
			RepoName:  repo.Name,
			RepoPath:  repo.RepoPath(),
		})...)
	}
	gitCmd.Dir = setting.RepoRootPath
	gitCmd.Stdout = os.Stdout
	gitCmd.Stdin = os.Stdin
	gitCmd.Stderr = os.Stderr
	log.Info("args:%s", gitCmd.Args)
	if err := gitCmd.Run(); err != nil {
		fail("Internal error", "Fail to execute git command: %v", err)
	}

	return nil
}

<|endoftext|>


<commit_before>package cmd

import (
	"fmt"
	"os"
	"os/exec"
	"strings"
	"time"

	"github.com/open-falcon/falcon-plus/g"
	"github.com/spf13/cobra"
)

var Stop = &cobra.Command{
	Use:   "stop [Module ...]",
	Short: "Stop Open-Falcon modules",
	Long: `
Stop the specified Open-Falcon modules.
A module represents a single node in a cluster.
Modules:
  ` + "all " + strings.Join(g.AllModulesInOrder, " "),
	RunE: stop,
}

func stop(c *cobra.Command, args []string) error {
	if len(args) == 0 {
		return c.Usage()
	}
	if (len(args) == 1) && (args[0] == "all") {
		args = g.AllModulesInOrder
	} else {
		for _, moduleName := range args {
			err := g.ModuleExists(moduleName)
			if err != nil {
				fmt.Println(err)
				fmt.Println("** stop failed **")
				return nil //g.Command_EX_ERR
			}
		}
	}
	for _, moduleName := range args {
		moduleStatus := g.CheckModuleStatus(moduleName)

		if moduleStatus == g.ModuleExistentNotRunning {
			// Skip stopping if the module is stopped
			continue
		}

		fmt.Print("Stopping [", g.ModuleApps[moduleName], "] ")

		pidStr, _ := g.CheckModulePid(g.ModuleApps[moduleName])

		cmd := exec.Command("kill", "-9", pidStr)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		cmd.Start()
		fmt.Println("with PID [", pidStr, "]...successfully!!")
		time.Sleep(1 * time.Second)

		moduleStatus = g.CheckModuleStatus(moduleName)
		if moduleStatus == g.ModuleRunning {
			fmt.Println("** stop failed **")
			return nil //g.Command_EX_ERR
		}
	}
	return nil //g.Command_EX_OK
}
<commit_msg>Redesign of `stop` command<commit_after>package cmd

import (
	"fmt"
	"os"
	"os/exec"
	"strings"

	"github.com/open-falcon/falcon-plus/g"
	"github.com/spf13/cobra"
)

var Stop = &cobra.Command{
	Use:   "stop [Module ...]",
	Short: "Stop Open-Falcon modules",
	Long: `
Stop the specified Open-Falcon modules.
A module represents a single node in a cluster.
Modules:
  ` + "all " + strings.Join(g.AllModulesInOrder, " "),
	RunE: stop,
}

func stop(c *cobra.Command, args []string) error {
	if len(args) == 0 {
		return c.Usage()
	}
	for _, moduleName := range args {
		if !g.HasModule(moduleName) {
			return fmt.Errorf("%s doesn't exist\n", moduleName)
		}

		if !g.IsRunning(moduleName) {
			fmt.Print("[", g.ModuleApps[moduleName], "] down\n")
			continue
		}

		cmd := exec.Command("kill", "-9", g.Pid(moduleName))
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		err := cmd.Run()
		if err == nil {
			fmt.Print("[", g.ModuleApps[moduleName], "] down\n")
			continue
		}
		return err
	}
	return nil
}
<|endoftext|>