func deleteGCPJob(context *cli.Context) error {
	config, err := getConfig(context)
	if err != nil {
		return err
	}
	gcp, err := getGCP(config)
	if err != nil {
		return err
	}
	err = gcp.DeleteJob(context.String("job-id"))
	if err != nil {
		return fmt.Errorf("Failed to delete GCP job %s: %s\n", context.String("job-id"), err)
	}
	fmt.Printf("Deleted GCP job %s\n", context.String("job-id"))
	return nil
}
deleteGCPJob deletes one GCP job
package main
import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"strings"
	"sync"
	"github.com/google/cloud-print-connector/cdd"
	"github.com/google/cloud-print-connector/gcp"
	"github.com/google/cloud-print-connector/lib"
	"github.com/urfave/cli"
)
var commonCommands = []*cli.Command{
	&cli.Command{
		Name:   "delete-all-gcp-printers",
		Usage:  "Delete all printers associated with this connector",
		Action: deleteAllGCPPrinters,
	},
	&cli.Command{
		Name:   "backfill-config-file",
		Usage:  "Add all keys, with default values, to the config file",
		Action: backfillConfigFile,
	},
	&cli.Command{
		Name:   "sparse-config-file",
		Usage:  "Remove all keys, with non-default values, from the config file",
		Action: sparseConfigFile,
	},
	&cli.Command{
		Name:   "delete-gcp-job",
		Usage:  "Deletes one GCP job",
		Action: deleteGCPJob,
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name: "job-id",
			},
		},
	},
	&cli.Command{
		Name:   "cancel-gcp-job",
		Usage:  "Cancels one GCP job",
		Action: cancelGCPJob,
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name: "job-id",
			},
		},
	},
	&cli.Command{
		Name:   "delete-all-gcp-printer-jobs",
		Usage:  "Delete all queued jobs associated with a printer",
		Action: deleteAllGCPPrinterJobs,
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name: "printer-id",
			},
		},
	},
	&cli.Command{
		Name:   "cancel-all-gcp-printer-jobs",
		Usage:  "Cancels all queued jobs associated with a printer",
		Action: cancelAllGCPPrinterJobs,
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name: "printer-id",
			},
		},
	},
	&cli.Command{
		Name:   "show-gcp-printer-status",
		Usage:  "Shows the current status of a printer and its jobs",
		Action: showGCPPrinterStatus,
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name: "printer-id",
			},
		},
	},
	&cli.Command{
		Name:   "share-gcp-printer",
		Usage:  "Shares a printer with user or group",
		Action: shareGCPPrinter,
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:  "printer-id",
				Usage: "Printer to share",
			},
			&cli.StringFlag{
				Name:  "email",
				Usage: "Group or user to share with",
			},
			&cli.StringFlag{
				Name:  "role",
				Value: "USER",
				Usage: "Role granted. user or manager",
			},
			&cli.BoolFlag{
				Name:  "skip-notification",
				Usage: "Skip sending email notice. Defaults to true",
				DefaultText: "1",
			},
			&cli.BoolFlag{
				Name:  "public",
				Usage: "Make the printer public (anyone can print)",
			},
		},
	},
	&cli.Command{
		Name:   "unshare-gcp-printer",
		Usage:  "Removes user or group access to printer",
		Action: unshareGCPPrinter,
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:  "printer-id",
				Usage: "Printer to unshare",
			},
			&cli.StringFlag{
				Name:  "email",
				Usage: "Group or user to remove",
			},
			&cli.BoolFlag{
				Name:  "public",
				Usage: "Remove public printer access",
			},
		},
	},
	&cli.Command{
		Name:   "update-gcp-printer",
		Usage:  "Modifies settings for a printer",
		Action: updateGCPPrinter,
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:  "printer-id",
				Usage: "Printer to update",
			},
			&cli.BoolFlag{
				Name:  "enable-quota",
				Usage: "Set a daily per-user quota",
			},
			&cli.BoolFlag{
				Name:  "disable-quota",
				Usage: "Disable daily per-user quota",
			},
			&cli.IntFlag{
				Name:  "daily-quota",
				Usage: "Pages per-user per-day",
			},
		},
	},
}
func getConfig(context *cli.Context) (*lib.Config, error) {
	config, _, err := lib.GetConfig(context)
	if err != nil {
		return nil, err
	}
	return config, nil
}
func getGCP(config *lib.Config) (*gcp.GoogleCloudPrint, error) {
	return gcp.NewGoogleCloudPrint(config.GCPBaseURL, config.RobotRefreshToken,
		config.UserRefreshToken, config.ProxyName, config.GCPOAuthClientID,
		config.GCPOAuthClientSecret, config.GCPOAuthAuthURL, config.GCPOAuthTokenURL,
		0, nil, false)
}
func backfillConfigFile(context *cli.Context) error {
	config, cfBefore, err := lib.GetConfig(context)
	if err != nil {
		return err
	}
	if cfBefore == "" {
		return fmt.Errorf("Could not find a config file to backfill")
	}
	configRaw, err := ioutil.ReadFile(cfBefore)
	if err != nil {
		return err
	}
	var configMap map[string]interface{}
	if err = json.Unmarshal(configRaw, &configMap); err != nil {
		return err
	}
	if cfWritten, err := config.Backfill(configMap).ToFile(context); err != nil {
		return fmt.Errorf("Failed to write config file: %s", err)
	} else {
		fmt.Printf("Wrote %s\n", cfWritten)
	}
	return nil
}
func sparseConfigFile(context *cli.Context) error {
	config, cfBefore, err := lib.GetConfig(context)
	if err != nil {
		return err
	}
	if cfBefore == "" {
		return errors.New("Could not find a config file to sparse")
	}
	if cfWritten, err := config.Sparse(context).ToFile(context); err != nil {
		return fmt.Errorf("Failed to write config file: %s\n", err)
	} else {
		fmt.Printf("Wrote %s\n", cfWritten)
	}
	return nil
}
func deleteAllGCPPrinters(context *cli.Context) error {
	config, err := getConfig(context)
	if err != nil {
		return err
	}
	gcp, err := getGCP(config)
	if err != nil {
		return err
	}
	printers, err := gcp.List()
	if err != nil {
		return err
	}
	var wg sync.WaitGroup
	for gcpID, name := range printers {
		wg.Add(1)
		go func(gcpID, name string) {
			defer wg.Done()
			err := gcp.Delete(gcpID)
			if err != nil {
				fmt.Printf("Failed to delete %s \"%s\": %s\n", gcpID, name, err)
			} else {
				fmt.Printf("Deleted %s \"%s\" from GCP\n", gcpID, name)
			}
		}(gcpID, name)
	}
	wg.Wait()
	return nil
}