%PDF- %PDF-
| Direktori : /home/waritko/go/src/github.com/odeke-em/drive/drive-google/ |
| Current File : //home/waritko/go/src/github.com/odeke-em/drive/drive-google/main.go |
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package contains the main entry point of gd.
package main
import (
"encoding/json"
"flag"
"fmt"
"io"
"os"
"os/signal"
"path/filepath"
"runtime"
"strconv"
"strings"
"github.com/odeke-em/command"
"github.com/odeke-em/drive/config"
"github.com/odeke-em/drive/gen"
"github.com/odeke-em/drive/src"
"github.com/odeke-em/drive/src/dcrypto"
)
var context *config.Context
type errorer func() error
func bindCommandWithAliases(key, description string, cmd command.Cmd, requiredFlags []string) {
command.On(key, description, cmd, requiredFlags)
aliases, ok := drive.Aliases[key]
if ok {
for _, alias := range aliases {
command.On(alias, description, cmd, requiredFlags)
}
}
}
func translateKeyChecks(definedFlags map[string]*flag.Flag) map[string]bool {
keysOnly := map[string]bool{}
for k, _ := range definedFlags {
keysOnly[k] = true
}
return keysOnly
}
type defaultsFiller struct {
command string
from, to interface{}
rcSourcePath string
definedFlags map[string]*flag.Flag
}
func fillWithDefaults(df defaultsFiller) error {
alreadyDefined := translateKeyChecks(df.definedFlags)
jsonStringified, err := drive.JSONStringifySiftedCLITags(df.from, df.rcSourcePath, alreadyDefined, df.command)
if err != nil {
return err
}
return json.Unmarshal([]byte(jsonStringified), df.to)
}
func main() {
maxProcs, err := strconv.ParseInt(os.Getenv(drive.GoMaxProcsKey), 10, 0)
if err != nil || maxProcs < 1 {
maxProcs = int64(drive.DefaultMaxProcs)
}
runtime.GOMAXPROCS(int(maxProcs))
bindCommandWithAliases(drive.AboutKey, drive.DescAbout, &aboutCmd{}, []string{})
bindCommandWithAliases(drive.CopyKey, drive.DescCopy, ©Cmd{}, []string{})
bindCommandWithAliases(drive.DiffKey, drive.DescDiff, &diffCmd{}, []string{})
bindCommandWithAliases(drive.EmptyTrashKey, drive.DescEmptyTrash, &emptyTrashCmd{}, []string{})
bindCommandWithAliases(drive.FeaturesKey, drive.DescFeatures, &featuresCmd{}, []string{})
bindCommandWithAliases(drive.InitKey, drive.DescInit, &initCmd{}, []string{})
bindCommandWithAliases(drive.DeInitKey, drive.DescDeInit, &deInitCmd{}, []string{})
bindCommandWithAliases(drive.HelpKey, drive.DescHelp, &helpCmd{}, []string{})
bindCommandWithAliases(drive.ListKey, drive.DescList, &listCmd{}, []string{})
bindCommandWithAliases(drive.MoveKey, drive.DescMove, &moveCmd{}, []string{})
bindCommandWithAliases(drive.PullKey, drive.DescPull, &pullCmd{}, []string{})
bindCommandWithAliases(drive.PushKey, drive.DescPush, &pushCmd{}, []string{})
bindCommandWithAliases(drive.PubKey, drive.DescPublish, &publishCmd{}, []string{})
bindCommandWithAliases(drive.RenameKey, drive.DescRename, &renameCmd{}, []string{})
bindCommandWithAliases(drive.QuotaKey, drive.DescQuota, "aCmd{}, []string{})
bindCommandWithAliases(drive.ShareKey, drive.DescShare, &shareCmd{}, []string{})
bindCommandWithAliases(drive.StatKey, drive.DescStat, &statCmd{}, []string{})
bindCommandWithAliases(drive.Md5sumKey, drive.DescMd5sum, &md5SumCmd{}, []string{})
bindCommandWithAliases(drive.UnshareKey, drive.DescUnshare, &unshareCmd{}, []string{})
bindCommandWithAliases(drive.TouchKey, drive.DescTouch, &touchCmd{}, []string{})
bindCommandWithAliases(drive.TrashKey, drive.DescTrash, &trashCmd{}, []string{})
bindCommandWithAliases(drive.UntrashKey, drive.DescUntrash, &untrashCmd{}, []string{})
bindCommandWithAliases(drive.DeleteKey, drive.DescDelete, &deleteCmd{}, []string{})
bindCommandWithAliases(drive.UnpubKey, drive.DescUnpublish, &unpublishCmd{}, []string{})
bindCommandWithAliases(drive.VersionKey, drive.Version, &versionCmd{}, []string{})
bindCommandWithAliases(drive.NewKey, drive.DescNew, &newCmd{}, []string{})
bindCommandWithAliases(drive.IndexKey, drive.DescIndex, &indexCmd{}, []string{})
bindCommandWithAliases(drive.UrlKey, drive.DescUrl, &urlCmd{}, []string{})
bindCommandWithAliases(drive.OpenKey, drive.DescOpen, &openCmd{}, []string{})
bindCommandWithAliases(drive.EditDescriptionKey, drive.DescEdit, &editDescriptionCmd{}, []string{})
bindCommandWithAliases(drive.QRLinkKey, drive.DescQR, &qrLinkCmd{}, []string{})
bindCommandWithAliases(drive.DuKey, drive.DescDu, &duCmd{}, []string{})
bindCommandWithAliases(drive.StarKey, drive.DescStar, &starCmd{}, []string{})
bindCommandWithAliases(drive.UnStarKey, drive.DescUnStar, &unstarCmd{}, []string{})
bindCommandWithAliases(drive.ClashesKey, drive.DescFixClashes, &clashesCmd{}, []string{})
bindCommandWithAliases(drive.IdKey, drive.DescId, &idCmd{}, []string{})
bindCommandWithAliases(drive.ReportIssueKey, drive.DescReportIssue, &issueCmd{}, []string{})
command.DefineHelp(&helpCmd{})
command.ParseAndRun()
}
type helpCmd struct {
args []string
}
func (cmd *helpCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
return fs
}
func (cmd *helpCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
drive.ShowDescriptions(args...)
exitWithError(nil)
}
type featuresCmd struct{}
func (cmd *featuresCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
return fs
}
func (cmd *featuresCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
context, path := discoverContext(args)
exitWithError(drive.New(context, &drive.Options{
Path: path,
}).About(drive.AboutFeatures))
}
type versionCmd struct{}
func (cmd *versionCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
return fs
}
func (cmd *versionCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
drive.StdoutPrintf("drive version: %s\n%s\n", drive.Version, generated.PkgInfo)
exitWithError(nil)
}
type initCmd struct {
ServiceAccountJSONFile *string `json:"-"`
}
func (cmd *initCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.ServiceAccountJSONFile = fs.String(drive.ServiceAccountJSONFileKey, "", "points the Google Service Account JSON file")
return fs
}
func (cmd *initCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
comm := drive.New(initContext(args), nil)
gcsJSONFile := *cmd.ServiceAccountJSONFile
if gcsJSONFile == "" {
exitWithError(comm.Init())
} else {
exitWithError(comm.InitWithServiceAccount(gcsJSONFile))
}
}
type deInitCmd struct {
noPrompt *bool
}
func (cmd *deInitCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.noPrompt = fs.Bool(drive.NoPromptKey, false, "disables the prompt")
return fs
}
func (cmd *deInitCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
_, context, path := preprocessArgsByToggle(args, true)
opts := &drive.Options{
NoPrompt: *cmd.noPrompt,
Path: path,
}
exitWithError(drive.New(context, opts).DeInit())
}
type quotaCmd struct{}
func (cmd *quotaCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
return fs
}
func (cmd *quotaCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
context, path := discoverContext(args)
exitWithError(drive.New(context, &drive.Options{
Path: path,
}).About(drive.AboutQuota))
}
type openCmd struct {
ById *bool `json:"by-id"`
FileBrowser *bool `json:"file-browser"`
WebBrowser *bool `json:"web-browser"`
}
func (cmd *openCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.ById = fs.Bool(drive.CLIOptionId, false, "open by id instead of path")
cmd.FileBrowser = fs.Bool(drive.CLIOptionFileBrowser, true, "open file with the local file manager")
cmd.WebBrowser = fs.Bool(drive.CLIOptionWebBrowser, true, "open file in default browser")
return fs
}
func (ocmd *openCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *ocmd.ById)
absEntryPath := context.AbsPathOf(path)
cmd := new(openCmd)
df := defaultsFiller{
command: drive.OpenKey,
from: *ocmd, to: cmd,
rcSourcePath: absEntryPath,
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
opts := drive.Options{
Path: path,
Sources: sources,
}
openType := drive.OpenNone
if *cmd.ById {
openType |= drive.IdOpen
}
if *cmd.WebBrowser {
openType |= drive.BrowserOpen
}
if *cmd.FileBrowser {
openType |= drive.FileManagerOpen
}
exitWithError(drive.New(context, &opts).Open(openType))
}
type editDescriptionCmd struct {
ById *bool `json:"by-id"`
Description *string `json:"description"`
Piped *bool `json:"piped"`
}
func (cmd *editDescriptionCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.ById = fs.Bool(drive.CLIOptionId, false, "open by id instead of path")
cmd.Description = fs.String(drive.CLIOptionDescription, "", drive.DescDescription)
cmd.Piped = fs.Bool(drive.CLIOptionPiped, false, drive.DescPiped)
return fs
}
func (cmd *editDescriptionCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *cmd.ById)
meta := map[string][]string{
drive.EditDescriptionKey: []string{*cmd.Description},
}
if *cmd.Piped {
meta[drive.PipedKey] = []string{fmt.Sprintf("%v", *cmd.Piped)}
}
opts := drive.Options{
Meta: &meta,
Path: path,
Sources: sources,
}
exitWithError(drive.New(context, &opts).EditDescription(*cmd.ById))
}
type urlCmd struct {
ById *bool `json:"by-id"`
}
func (cmd *urlCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.ById = fs.Bool(drive.CLIOptionId, false, "resolve url by id instead of path")
return fs
}
func (cmd *urlCmd) Run(args []string, definedArgs map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *cmd.ById)
opts := drive.Options{
Path: path,
Sources: sources,
}
exitWithError(drive.New(context, &opts).Url(*cmd.ById))
}
type listCmd struct {
ById *bool `json:"by-id"`
Hidden *bool `json:"hidden"`
Recursive *bool `json:"recursive"`
Files *bool `json:"files"`
Directories *bool `json:"directories"`
Depth *int `json:"depth"`
PageSize *int64 `json:"page-size"`
LongFmt *bool `json:"long"`
NoPrompt *bool `json:"no-prompt"`
Shared *bool `json:"shared"`
InTrash *bool `json:"trashed"`
Version *bool `json:"version"`
Matches *bool `json:"matches"`
Owners *bool `json:"owners"`
Quiet *bool `json:"quiet"`
SkipMimeKey *string `json:"skip-mime"`
MatchMimeKey *string `json:"match-mime"`
ExactTitle *string `json:"exact-title"`
MatchOwner *string `json:"match-owner"`
ExactOwner *string `json:"exact-owner"`
NotOwner *string `json:"not-owner"`
Sort *string `json:"sort"`
}
func (cmd *listCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Depth = fs.Int(drive.DepthKey, 1, "maximum recursion depth")
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "list all paths even hidden ones")
cmd.Files = fs.Bool(drive.CLIOptionFiles, false, "list only files")
cmd.Directories = fs.Bool(drive.CLIOptionDirectories, false, "list all directories")
cmd.LongFmt = fs.Bool(drive.CLIOptionLongFmt, false, "long listing of contents")
cmd.PageSize = fs.Int64(drive.PageSizeKey, 100, "number of results per pagination")
cmd.Shared = fs.Bool("shared", false, "show files that are shared with me")
cmd.InTrash = fs.Bool(drive.CLIOptionTrashed, false, "list content in the trash")
cmd.Version = fs.Bool("version", false, "show the number of times that the file has been modified on \n\t\tthe server even with changes not visible to the user")
cmd.NoPrompt = fs.Bool(drive.NoPromptKey, false, "shows no prompt before pagination")
cmd.Owners = fs.Bool("owners", false, "shows the owner names per file")
cmd.Recursive = fs.Bool(drive.RecursiveKey, false, "recursively list subdirectories")
cmd.Sort = fs.String(drive.SortKey, "", drive.DescSort)
cmd.Matches = fs.Bool(drive.MatchesKey, false, "list by prefix")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.SkipMimeKey = fs.String(drive.CLIOptionSkipMime, "", drive.DescSkipMime)
cmd.MatchMimeKey = fs.String(drive.CLIOptionMatchMime, "", drive.DescMatchMime)
cmd.ExactTitle = fs.String(drive.CLIOptionExactTitle, "", drive.DescExactTitle)
cmd.MatchOwner = fs.String(drive.CLIOptionMatchOwner, "", drive.DescMatchOwner)
cmd.ExactOwner = fs.String(drive.CLIOptionExactOwner, "", drive.DescExactOwner)
cmd.NotOwner = fs.String(drive.CLIOptionNotOwner, "", drive.DescNotOwner)
cmd.ById = fs.Bool(drive.CLIOptionId, false, "list by id instead of path")
return fs
}
func (lCmd *listCmd) _run(args []string, definedFlags map[string]*flag.Flag, diskUsageSubset bool) error {
sources, context, path := preprocessArgsByToggle(args, (*lCmd.ById || *lCmd.Matches))
cmd := listCmd{}
df := defaultsFiller{
command: drive.ListKey,
from: *lCmd, to: &cmd,
rcSourcePath: context.AbsPathOf(path),
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
typeMask := 0
if *cmd.Directories {
typeMask |= drive.Folder
}
if *cmd.Shared {
typeMask |= drive.Shared
}
if *cmd.Owners {
typeMask |= drive.Owners
}
if *cmd.Version {
typeMask |= drive.CurrentVersion
}
if *cmd.Files {
typeMask |= drive.NonFolder
}
if *cmd.InTrash {
typeMask |= drive.InTrash
}
if diskUsageSubset {
typeMask |= drive.DiskUsageOnly
}
if !*cmd.LongFmt {
typeMask |= drive.Minimal
}
depth := *cmd.Depth
if *cmd.Recursive {
depth = drive.InfiniteDepth
}
meta := map[string][]string{
drive.SortKey: drive.NonEmptyTrimmedStrings(*cmd.Sort),
drive.SkipMimeKeyKey: drive.NonEmptyTrimmedStrings(strings.Split(*cmd.SkipMimeKey, ",")...),
drive.MatchMimeKeyKey: drive.NonEmptyTrimmedStrings(strings.Split(*cmd.MatchMimeKey, ",")...),
drive.ExactTitleKey: drive.NonEmptyTrimmedStrings(strings.Split(*cmd.ExactTitle, ",")...),
drive.MatchOwnerKey: drive.NonEmptyTrimmedStrings(strings.Split(*cmd.MatchOwner, ",")...),
drive.ExactOwnerKey: drive.NonEmptyTrimmedStrings(strings.Split(*cmd.ExactOwner, ",")...),
drive.NotOwnerKey: drive.NonEmptyTrimmedStrings(strings.Split(*cmd.NotOwner, ",")...),
}
opts := &drive.Options{
Path: path,
Sources: sources,
Depth: depth,
Hidden: *cmd.Hidden,
InTrash: *cmd.InTrash,
PageSize: *cmd.PageSize,
NoPrompt: *cmd.NoPrompt,
Recursive: *cmd.Recursive,
TypeMask: typeMask,
Quiet: *cmd.Quiet,
Meta: &meta,
Match: *cmd.Matches,
}
if *cmd.Shared {
return drive.New(context, opts).ListShared()
} else if *cmd.Matches {
return drive.New(context, opts).ListMatches()
} else {
return drive.New(context, opts).List(*cmd.ById)
}
return nil
}
type duCmd struct {
listCmd
}
func (lCmd *listCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
exitWithError(lCmd._run(args, definedFlags, false))
}
func (dCmd *duCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
exitWithError(dCmd._run(args, definedFlags, true))
}
type md5SumCmd struct {
ById *bool `json:"by-id"`
Depth *int `json:"depth"`
Hidden *bool `json:"hidden"`
Recursive *bool `json:"recursive"`
Quiet *bool `json:"quiet"`
}
func (cmd *md5SumCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Depth = fs.Int(drive.DepthKey, 1, "max traversal depth")
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "discover hidden paths")
cmd.Recursive = fs.Bool(drive.RecursiveKey, false, "recursively discover folders")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "stat by id instead of path")
return fs
}
func (mcmd *md5SumCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *mcmd.ById)
absEntryPath := context.AbsPathOf(path)
cmd := new(md5SumCmd)
df := defaultsFiller{
command: drive.Md5sumKey,
from: *mcmd, to: cmd,
rcSourcePath: absEntryPath,
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
depth := *cmd.Depth
if *cmd.Recursive {
depth = drive.InfiniteDepth
}
opts := drive.Options{
Path: path,
Sources: sources,
Depth: depth,
Hidden: *cmd.Hidden,
Recursive: *cmd.Recursive,
Quiet: *cmd.Quiet,
Md5sum: true,
}
if *cmd.ById {
exitWithError(drive.New(context, &opts).StatById())
} else {
exitWithError(drive.New(context, &opts).Stat())
}
}
type statCmd struct {
ById *bool `json:"by-id"`
Depth *int `json:"depth"`
Hidden *bool `json:"hidden"`
Recursive *bool `json:"recursive"`
Quiet *bool `json:"quiet"`
Md5sum *bool `json:"md5sum"`
}
func (cmd *statCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Depth = fs.Int(drive.DepthKey, 1, "max traversal depth")
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "discover hidden paths")
cmd.Recursive = fs.Bool(drive.RecursiveKey, false, "recursively discover folders")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "stat by id instead of path")
cmd.Md5sum = fs.Bool(drive.Md5sumKey, false, "produce output compatible with md5sum(1)")
return fs
}
func (scmd *statCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *scmd.ById)
absEntryPath := context.AbsPathOf(path)
cmd := new(statCmd)
df := defaultsFiller{
command: drive.StatKey,
from: *scmd, to: cmd,
rcSourcePath: absEntryPath,
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
depth := *cmd.Depth
if *cmd.Recursive {
depth = drive.InfiniteDepth
}
opts := drive.Options{
Depth: depth,
Path: path,
Sources: sources,
Hidden: *cmd.Hidden,
Recursive: *cmd.Recursive,
Quiet: *cmd.Quiet,
Md5sum: *cmd.Md5sum,
}
if *cmd.ById {
exitWithError(drive.New(context, &opts).StatById())
} else {
exitWithError(drive.New(context, &opts).Stat())
}
}
type indexCmd struct {
ById *bool `json:"by-id"`
IgnoreConflict *bool `json:"ignore-conflict"`
Recursive *bool `json:"recursive"`
NoPrompt *bool `json:"no-prompt"`
Hidden *bool `json:"hidden"`
Force *bool `json:"force"`
IgnoreNameClashes *bool `json:"ignore-name-clashes"`
Quiet *bool `json:"quiet"`
ExcludeOps *string `json:"exclude-ops"`
SkipMimeKey *string `json:"skip-mime"`
IgnoreChecksum *bool `json:"ignore-checksum"`
NoClobber *bool `json:"no-clobber"`
Prune *bool `json:"prune"`
AllOps *bool `json:"all-ops"`
Matches *bool `json:"matches"`
}
func (cmd *indexCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.ById = fs.Bool(drive.CLIOptionId, false, "fetch by id instead of path")
cmd.IgnoreConflict = fs.Bool(drive.CLIOptionIgnoreConflict, true, drive.DescIgnoreConflict)
cmd.Recursive = fs.Bool(drive.RecursiveKey, true, "fetch recursively for children")
cmd.NoPrompt = fs.Bool(drive.NoPromptKey, false, "shows no prompt before applying the fetch action")
cmd.Hidden = fs.Bool(drive.HiddenKey, true, "allows fetching of hidden paths")
cmd.Force = fs.Bool(drive.ForceKey, false, "forces a fetch even if no changes present")
cmd.IgnoreNameClashes = fs.Bool(drive.CLIOptionIgnoreNameClashes, true, drive.DescIgnoreNameClashes)
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ExcludeOps = fs.String(drive.CLIOptionExcludeOperations, "", drive.DescExcludeOps)
cmd.SkipMimeKey = fs.String(drive.CLIOptionSkipMime, "", drive.DescSkipMime)
cmd.IgnoreChecksum = fs.Bool(drive.CLIOptionIgnoreChecksum, true, drive.DescIgnoreChecksum)
cmd.NoClobber = fs.Bool(drive.CLIOptionNoClobber, false, "prevents overwriting of old content")
cmd.Prune = fs.Bool(drive.CLIOptionPruneIndices, false, drive.DescPruneIndices)
cmd.AllOps = fs.Bool(drive.CLIOptionAllIndexOperations, false, drive.DescAllIndexOperations)
cmd.Matches = fs.Bool(drive.MatchesKey, false, "search by prefix")
return fs
}
func (icmd *indexCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
byId := *icmd.ById
byMatches := *icmd.Matches
sources, context, path := preprocessArgsByToggle(args, byMatches || byId)
absEntryPath := context.AbsPathOf(path)
cmd := new(indexCmd)
df := defaultsFiller{
command: drive.IndexKey,
from: *icmd, to: cmd,
rcSourcePath: absEntryPath,
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
options := &drive.Options{
Path: path,
Sources: sources,
Hidden: *cmd.Hidden,
IgnoreChecksum: *cmd.IgnoreChecksum,
IgnoreConflict: *cmd.IgnoreConflict,
NoPrompt: *cmd.NoPrompt,
NoClobber: *cmd.NoClobber,
Recursive: *cmd.Recursive,
Quiet: *cmd.Quiet,
Force: *cmd.Force,
IgnoreNameClashes: *cmd.IgnoreNameClashes,
Match: *cmd.Matches,
}
dr := drive.New(context, options)
fetchFn := dr.Fetch
if byId {
fetchFn = dr.FetchById
} else if *cmd.Matches {
fetchFn = dr.FetchMatches
}
scheduling := []errorer{}
if *cmd.AllOps {
scheduling = append(scheduling, dr.Prune, fetchFn)
} else if *cmd.Prune {
scheduling = append(scheduling, dr.Prune)
} else {
scheduling = append(scheduling, fetchFn)
}
for _, fn := range scheduling {
exitWithError(fn())
}
}
type pullCmd struct {
ById *bool `json:"by-id"`
Files *bool `json:"files"`
Piped *bool `json:"piped"`
Quiet *bool `json:"quiet"`
Force *bool `json:"force"`
Depth *int `json:"depth"`
Hidden *bool `json:"hidden"`
Export *string `json:"export"`
FixMode *string `json:"fix-mode"`
Starred *bool `json:"starred"`
Verbose *bool `json:"verbose"`
InTrash *bool `json:"trashed"`
Matches *bool `json:"matches"`
NoPrompt *bool `json:"no-prompt"`
NoClobber *bool `json:"no-clobber"`
Recursive *bool `json:"recursive"`
AllStarred *bool `json:"all-starred"`
FixClashes *bool `json:"fix-clashes"`
Directories *bool `json:"directories"`
ExportsDir *string `json:"exports-dir"`
ExcludeOps *string `json:"exclude-ops"`
SkipMimeKey *string `json:"skip-mime"`
IgnoreChecksum *bool `json:"ignore-checksum"`
IgnoreConflict *bool `json:"ignore-conflict"`
ExplicitlyExport *bool `json:"explicitly-export"`
IgnoreNameClashes *bool `json:"ignore-name-clashes"`
DecryptionPassword *string `json:"decryption-password"`
ExponentialBackoffRetryCount *int `json:"retry-count"`
ExportsDumpToSameDirectory *bool `json:"same-exports-dir"`
AllowURLLinkedFiles *bool `json:"desktop-links"`
}
func (cmd *pullCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.AllStarred = fs.Bool(drive.CLIOptionAllStarred, false, drive.DescAllStarred)
cmd.NoClobber = fs.Bool(drive.CLIOptionNoClobber, false, "prevents overwriting of old content")
cmd.Export = fs.String(
drive.ExportsKey, "", "comma separated list of formats to export your docs + sheets files")
cmd.Recursive = fs.Bool(drive.RecursiveKey, true, "performs the pull action recursively")
cmd.NoPrompt = fs.Bool(drive.NoPromptKey, false, "shows no prompt before applying the pull action")
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "allows pulling of hidden paths")
cmd.Force = fs.Bool(drive.ForceKey, false, "forces a pull even if no changes present")
cmd.IgnoreChecksum = fs.Bool(drive.CLIOptionIgnoreChecksum, true, drive.DescIgnoreChecksum)
cmd.IgnoreConflict = fs.Bool(drive.CLIOptionIgnoreConflict, false, drive.DescIgnoreConflict)
cmd.IgnoreNameClashes = fs.Bool(drive.CLIOptionIgnoreNameClashes, false, drive.DescIgnoreNameClashes)
cmd.FixMode = fs.String(drive.CLIOptionFixClashesMode, "rename", drive.DescFixClashesMode)
cmd.ExportsDir = fs.String(drive.ExportsDirKey, "", "directory to place exports")
cmd.ExportsDumpToSameDirectory = fs.Bool(drive.CLIOptionExportsDumpToSameDirectory, false, "exports are put in the same directory")
cmd.Matches = fs.Bool(drive.MatchesKey, false, "search by prefix")
cmd.Piped = fs.Bool(drive.CLIOptionPiped, false, drive.DescPiped)
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ExcludeOps = fs.String(drive.CLIOptionExcludeOperations, "", drive.DescExcludeOps)
cmd.ById = fs.Bool(drive.CLIOptionId, false, "pull by id instead of path")
cmd.SkipMimeKey = fs.String(drive.CLIOptionSkipMime, "", drive.DescSkipMime)
cmd.ExplicitlyExport = fs.Bool(drive.CLIOptionExplicitlyExport, false, drive.DescExplicitylPullExports)
cmd.Verbose = fs.Bool(drive.CLIOptionVerboseKey, false, drive.DescVerbose)
cmd.Depth = fs.Int(drive.DepthKey, drive.DefaultMaxTraversalDepth, "max traversal depth")
cmd.FixClashes = fs.Bool(drive.CLIOptionFixClashesKey, false, drive.DescFixClashes)
cmd.Starred = fs.Bool(drive.CLIOptionStarred, false, drive.DescStarred)
cmd.InTrash = fs.Bool(drive.TrashedKey, false, "pull content in the trash")
cmd.ExponentialBackoffRetryCount = fs.Int(drive.CLIOptionRetryCount, drive.MaxFailedRetryCount, drive.DescExponentialBackoffRetryCount)
cmd.DecryptionPassword = fs.String(drive.CLIDecryptionPassword, "", drive.DescDecryptionPassword)
cmd.Files = fs.Bool(drive.CLIOptionFiles, false, "pull only files")
cmd.Directories = fs.Bool(drive.CLIOptionDirectories, false, "pull only directories")
cmd.AllowURLLinkedFiles = fs.Bool(drive.CLIOptionDesktopLinks, true, drive.DescAllowDesktopLinks)
return fs
}
func (pCmd *pullCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, (*pCmd.ById || *pCmd.Matches || *pCmd.Starred))
cmd := pullCmd{}
df := defaultsFiller{
command: drive.PullKey,
from: *pCmd, to: &cmd,
rcSourcePath: context.AbsPathOf(path),
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
excludes := drive.NonEmptyTrimmedStrings(strings.Split(*cmd.ExcludeOps, ",")...)
excludeCrudMask := drive.CrudAtoi(excludes...)
if excludeCrudMask == drive.AllCrudOperations {
exitWithError(fmt.Errorf("all CRUD operations forbidden"))
}
meta := map[string][]string{
drive.SkipMimeKeyKey: drive.NonEmptyTrimmedStrings(strings.Split(*cmd.SkipMimeKey, ",")...),
}
// Filter out empty strings.
exports := drive.NonEmptyTrimmedStrings(strings.Split(*cmd.Export, ",")...)
retryCount := drive.MaxFailedRetryCount
if cmd.ExponentialBackoffRetryCount != nil {
retryCount = *(cmd.ExponentialBackoffRetryCount)
}
var decryptFn func(io.Reader) (io.ReadCloser, error)
if cmd.DecryptionPassword != nil {
passStr := *(cmd.DecryptionPassword)
if passStr != "" {
passwordAsBytes := []byte(passStr)
decryptFn = func(r io.Reader) (io.ReadCloser, error) {
return dcrypto.NewDecrypter(r, passwordAsBytes)
}
}
}
typeMask := 0
if *cmd.Directories {
typeMask |= drive.Folder
}
if *cmd.Files {
typeMask |= drive.NonFolder
}
exitIfIllogicalFileAndFolder(typeMask)
fixMode, ok := translateFixMode(*cmd.FixMode)
if !ok {
exitWithError(fmt.Errorf("Unknown fix mode: %s", *cmd.FixMode))
}
options := &drive.Options{
Path: path,
Sources: sources,
Exports: uniqOrderedStr(exports),
ExportsDir: strings.TrimSpace(*cmd.ExportsDir),
Force: *cmd.Force,
Hidden: *cmd.Hidden,
NoPrompt: *cmd.NoPrompt,
NoClobber: *cmd.NoClobber,
Recursive: *cmd.Recursive,
Piped: *cmd.Piped,
Quiet: *cmd.Quiet,
Meta: &meta,
Verbose: *cmd.Verbose,
Depth: *cmd.Depth,
FixClashes: *cmd.FixClashes,
Starred: *cmd.Starred,
Match: *cmd.Matches,
InTrash: *cmd.InTrash,
Decrypter: decryptFn,
TypeMask: typeMask,
FixClashesMode: fixMode,
IgnoreChecksum: *cmd.IgnoreChecksum,
IgnoreConflict: *cmd.IgnoreConflict,
ExcludeCrudMask: excludeCrudMask,
ExplicitlyExport: *cmd.ExplicitlyExport,
IgnoreNameClashes: *cmd.IgnoreNameClashes,
AllowURLLinkedFiles: *cmd.AllowURLLinkedFiles,
ExportsDumpToSameDirectory: *cmd.ExportsDumpToSameDirectory,
ExponentialBackoffRetryCount: retryCount,
}
if *cmd.Matches || *cmd.Starred {
if *cmd.AllStarred {
exitWithError(drive.New(context, options).PullAllStarred())
} else {
exitWithError(drive.New(context, options).PullMatchLike())
}
} else if *cmd.Piped {
exitWithError(drive.New(context, options).PullPiped(*cmd.ById))
} else if *cmd.ById {
exitWithError(drive.New(context, options).PullById())
} else {
exitWithError(drive.New(context, options).Pull())
}
}
type pushCmd struct {
NoClobber *bool `json:"no-clobber"`
Hidden *bool `json:"hidden"`
Force *bool `json:"force"`
FixMode *string `json:"fix-mode"`
NoPrompt *bool `json:"no-prompt"`
Recursive *bool `json:"recursive"`
Piped *bool `json:"piped"`
MountedPush *bool `json:"m"`
// convert when set tells Google drive to convert the document into
// its appropriate Google Docs format
Convert *bool `json:"convert"`
// ocr when set indicates that Optical Character Recognition should be
// attempted on .[gif, jpg, pdf, png] uploads
Ocr *bool `json:"ocr"`
IgnoreChecksum *bool `json:"ignore-checksum"`
IgnoreConflict *bool `json:"ignore-conflict"`
IgnoreNameClashes *bool `json:"ignore-name-clashes"`
Quiet *bool `json:"quiet"`
CoercedMimeKey *string `json:"coerced-mime"`
ExcludeOps *string `json:"exclude-ops"`
SkipMimeKey *string `json:"skip-mime"`
Verbose *bool `json:"verbose"`
Depth *int `json:"depth"`
FixClashes *bool `json:"fix-clashes"`
Destination *string `json:"dest"`
ExponentialBackoffRetryCount *int `json:"retry-count"`
EncryptionPassword *string `json:"encryption-password"`
Files *bool `json:"files"`
Directories *bool `json:"directories"`
UploadChunkSize *int `json:"upload-chunk-size"`
}
func (cmd *pushCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.NoClobber = fs.Bool(drive.CLIOptionNoClobber, false, "prevents overwriting of old content")
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "allows pushing of hidden paths")
cmd.Recursive = fs.Bool(drive.RecursiveKey, true, "performs the push action recursively")
cmd.FixMode = fs.String(drive.CLIOptionFixClashesMode, "rename", drive.DescFixClashesMode)
cmd.NoPrompt = fs.Bool(drive.NoPromptKey, false, "shows no prompt before applying the push action")
cmd.Force = fs.Bool(drive.ForceKey, false, "forces a push even if no changes present")
cmd.MountedPush = fs.Bool("m", false, "allows pushing of mounted paths")
cmd.Convert = fs.Bool(drive.ConvertKey, false, "toggles conversion of the file to its appropriate Google Doc format")
cmd.Ocr = fs.Bool(drive.OcrKey, false, "if true, attempt OCR on gif, jpg, pdf and png uploads")
cmd.Piped = fs.Bool(drive.CLIOptionPiped, false, drive.DescPiped)
cmd.IgnoreChecksum = fs.Bool(drive.CLIOptionIgnoreChecksum, true, drive.DescIgnoreChecksum)
cmd.IgnoreConflict = fs.Bool(drive.CLIOptionIgnoreConflict, false, drive.DescIgnoreConflict)
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.CoercedMimeKey = fs.String(drive.CoercedMimeKeyKey, "", "the mimeType you are trying to coerce this file to be")
cmd.IgnoreNameClashes = fs.Bool(drive.CLIOptionIgnoreNameClashes, false, drive.DescIgnoreNameClashes)
cmd.ExcludeOps = fs.String(drive.CLIOptionExcludeOperations, "", drive.DescExcludeOps)
cmd.SkipMimeKey = fs.String(drive.CLIOptionSkipMime, "", drive.DescSkipMime)
cmd.Verbose = fs.Bool(drive.CLIOptionVerboseKey, false, drive.DescVerbose)
cmd.Depth = fs.Int(drive.DepthKey, drive.DefaultMaxTraversalDepth, "max traversal depth")
cmd.FixClashes = fs.Bool(drive.CLIOptionFixClashesKey, false, drive.DescFixClashes)
cmd.Destination = fs.String(drive.CLIOptionPushDestination, "", drive.DescPushDestination)
cmd.ExponentialBackoffRetryCount = fs.Int(drive.CLIOptionRetryCount, drive.MaxFailedRetryCount, drive.DescExponentialBackoffRetryCount)
cmd.EncryptionPassword = fs.String(drive.CLIEncryptionPassword, "", drive.DescEncryptionPassword)
cmd.Files = fs.Bool(drive.CLIOptionFiles, false, "push only files")
cmd.Directories = fs.Bool(drive.CLIOptionDirectories, false, "push only directories")
cmd.UploadChunkSize = fs.Int(drive.CLIOptionUploadChunkSize, 0, "specifies the size of each data chunk to be uploaded. Only set it if you want a custom chunk size. Otherwise the default value of googleapi.DefaultUploadChunkSize ie 8MiB will be used. However it must be at least googleapi.MinUploadChunkSize ie 256KiB. See https://godoc.org/google.golang.org/api/googleapi#pkg-constants")
return fs
}
func (cmd *pushCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
if *cmd.MountedPush {
exitWithError(cmd.pushMounted(args, definedFlags))
return
}
sources, context, path := preprocessArgs(args)
options, err := cmd.createPushOptions(context.AbsPathOf(path), definedFlags)
if err != nil {
exitWithError(err)
}
options.Path = path
options.Sources = sources
if *cmd.Piped {
exitWithError(drive.New(context, options).PushPiped())
} else {
exitWithError(drive.New(context, options).Push())
}
}
type qrLinkCmd struct {
Address *string `json:"address"`
ById *bool `json:"by-id"`
Verbose *bool `json:"verbose"`
}
func (cmd *qrLinkCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Address = fs.String(drive.AddressKey, drive.DefaultQRShareServer, "address on which the QR code generator is running")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "share by id instead of path")
cmd.Verbose = fs.Bool(drive.CLIOptionVerboseKey, true, drive.DescVerbose)
return fs
}
func (qCmd *qrLinkCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *qCmd.ById)
cmd := qrLinkCmd{}
df := defaultsFiller{
command: drive.QRLinkKey,
from: *qCmd, to: &cmd,
rcSourcePath: path,
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
meta := map[string][]string{
drive.AddressKey: []string{*cmd.Address},
}
opts := drive.Options{
Path: path,
Sources: sources,
Meta: &meta,
Verbose: *cmd.Verbose,
}
exitWithError(drive.New(context, &opts).QR(*cmd.ById))
}
type touchCmd struct {
ById *bool `json:"by-id"`
Depth *int `json:"depth"`
Hidden *bool `json:"hidden"`
Recursive *bool `json:"recursive"`
Matches *bool `json:"matches"`
Quiet *bool `json:"quiet"`
Verbose *bool `json:"verbose"`
TouchTimeStr *string `json:"time"`
OffsetDurationStr *string `json:"duration"`
TimeFormatSpecifier *string `json:"format"`
}
func (cmd *touchCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "allows pushing of hidden paths")
cmd.Recursive = fs.Bool(drive.RecursiveKey, false, "toggles recursive touching")
cmd.Matches = fs.Bool(drive.MatchesKey, false, "search by prefix and touch")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "share by id instead of path")
cmd.Depth = fs.Int(drive.DepthKey, drive.DefaultMaxTraversalDepth, "max traversal depth")
cmd.Verbose = fs.Bool(drive.CLIOptionVerboseKey, true, drive.DescVerbose)
cmd.TouchTimeStr = fs.String(drive.TouchModTimeKey, "", drive.DescTouchTimeStr)
cmd.OffsetDurationStr = fs.String(drive.TouchOffsetDurationKey, "", drive.DescTouchOffsetDuration)
cmd.TimeFormatSpecifier = fs.String(drive.TouchTimeFmtSpecifierKey, drive.DefaultTouchTimeSpecifier, drive.DescTouchTimeFmtSpecifier)
return fs
}
func (tcmd *touchCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *tcmd.Matches || *tcmd.ById)
absEntryPath := context.AbsPathOf(path)
cmd := new(touchCmd)
df := defaultsFiller{
command: drive.TouchKey,
from: *tcmd, to: cmd,
rcSourcePath: absEntryPath,
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
depth := *cmd.Depth
if *cmd.Recursive {
depth = drive.InfiniteDepth
}
opts := drive.Options{
Path: path,
Sources: sources,
Hidden: *cmd.Hidden,
Recursive: *cmd.Recursive,
Depth: depth,
Quiet: *cmd.Quiet,
Match: *cmd.Matches,
Verbose: *cmd.Verbose,
}
meta := map[string][]string{
drive.TouchModTimeKey: drive.NonEmptyTrimmedStrings(*cmd.TouchTimeStr),
drive.TouchOffsetDurationKey: drive.NonEmptyTrimmedStrings(*cmd.OffsetDurationStr),
drive.TouchTimeFmtSpecifierKey: drive.NonEmptyTrimmedStrings(*cmd.TimeFormatSpecifier),
}
opts.Meta = &meta
if *cmd.Matches {
exitWithError(drive.New(context, &opts).TouchByMatch())
} else {
exitWithError(drive.New(context, &opts).Touch(*cmd.ById))
}
}
func exitIfIllogicalFileAndFolder(mask int) {
fileAndFolder := drive.NonFolder | drive.Folder
if (mask & fileAndFolder) == fileAndFolder {
exitWithError(fmt.Errorf("cannot request for both file and folder"))
}
}
func (pCmd *pushCmd) createPushOptions(absEntryPath string, definedFlags map[string]*flag.Flag) (*drive.Options, error) {
cmd := pushCmd{}
df := defaultsFiller{
command: drive.PushKey,
from: *pCmd, to: &cmd,
rcSourcePath: absEntryPath,
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
mask := drive.OptNone
if *cmd.Convert {
mask |= drive.OptConvert
}
if *cmd.Ocr {
mask |= drive.OptOCR
}
if *cmd.Directories {
mask |= drive.Folder
}
if *cmd.Files {
mask |= drive.NonFolder
}
exitIfIllogicalFileAndFolder(mask)
meta := map[string][]string{
drive.CoercedMimeKeyKey: drive.NonEmptyTrimmedStrings(*cmd.CoercedMimeKey),
drive.SkipMimeKeyKey: drive.NonEmptyTrimmedStrings(strings.Split(*cmd.SkipMimeKey, ",")...),
}
excludes := drive.NonEmptyTrimmedStrings(strings.Split(*cmd.ExcludeOps, ",")...)
excludeCrudMask := drive.CrudAtoi(excludes...)
if excludeCrudMask == drive.AllCrudOperations {
exitWithError(fmt.Errorf("all CRUD operations forbidden yet asking to push"))
}
retryCount := drive.MaxFailedRetryCount
if cmd.ExponentialBackoffRetryCount != nil {
retryCount = *(cmd.ExponentialBackoffRetryCount)
}
var encryptFn func(io.Reader) (io.Reader, error)
if cmd.EncryptionPassword != nil {
passStr := *(cmd.EncryptionPassword)
if passStr != "" {
passwordAsBytes := []byte(passStr)
encryptFn = func(r io.Reader) (io.Reader, error) {
return dcrypto.NewEncrypter(r, passwordAsBytes)
}
}
}
fixMode, ok := translateFixMode(*cmd.FixMode)
if !ok {
exitWithError(fmt.Errorf("Unknown fix mode: %s", *cmd.FixMode))
}
opts := &drive.Options{
Force: *cmd.Force,
Hidden: *cmd.Hidden,
IgnoreChecksum: *cmd.IgnoreChecksum,
IgnoreConflict: *cmd.IgnoreConflict,
NoClobber: *cmd.NoClobber,
NoPrompt: *cmd.NoPrompt,
Recursive: *cmd.Recursive,
Piped: *cmd.Piped,
Quiet: *cmd.Quiet,
Meta: &meta,
TypeMask: mask,
ExcludeCrudMask: excludeCrudMask,
IgnoreNameClashes: *cmd.IgnoreNameClashes,
Verbose: *cmd.Verbose,
Depth: *cmd.Depth,
FixClashes: *cmd.FixClashes,
Destination: *cmd.Destination,
Encrypter: encryptFn,
ExponentialBackoffRetryCount: retryCount,
UploadChunkSize: *cmd.UploadChunkSize,
FixClashesMode: fixMode,
}
return opts, nil
}
func (cmd *pushCmd) pushMounted(args []string, definedFlags map[string]*flag.Flag) error {
argc := len(args)
var err error
var contextArgs, rest, sources []string
// Expectation is that at least one path has to be passed in
if argc < 2 {
cwd, cerr := os.Getwd()
if cerr == nil {
contextArgs = append(contextArgs, cwd)
}
rest = args
} else {
endIndex := argc - 1
contextArgs = append(contextArgs, args[endIndex:]...)
rest = append(rest, args[:endIndex]...)
}
rest = drive.NonEmptyStrings(rest...)
context, path := discoverContext(contextArgs)
if path == "." {
path = ""
}
root := context.AbsPathOf("")
contextAbsPath := filepath.Join(root, path)
mount, auxSrcs := config.MountPoints(path, contextAbsPath, rest, *cmd.Hidden)
sources, err = relativePathsOpt(root, auxSrcs, true)
exitWithError(err)
options, err := cmd.createPushOptions(path, definedFlags)
if err != nil {
exitWithError(err)
}
options.Path = path
options.Mount = mount
options.Sources = sources
return drive.New(context, options).Push()
}
type aboutCmd struct {
Features *bool `json:"features"`
Filesize *bool `json:"filesize"`
Quiet *bool `json:"quiet"`
Quota *bool `json:"quota"`
}
func (cmd *aboutCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Features = fs.Bool("features", false, "gives information on features present on this drive")
cmd.Filesize = fs.Bool("filesize", false, "prints out information about file sizes e.g the max upload size for a specific file size")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.Quota = fs.Bool("quota", false, "prints out quota information for this drive")
return fs
}
func (acmd *aboutCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
_, context, path := preprocessArgs(args)
absEntryPath := context.AbsPathOf(path)
cmd := new(aboutCmd)
df := defaultsFiller{
command: drive.AboutKey,
from: *acmd, to: cmd,
rcSourcePath: absEntryPath,
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
mask := drive.AboutNone
if *cmd.Features {
mask |= drive.AboutFeatures
}
if *cmd.Quota {
mask |= drive.AboutQuota
}
if *cmd.Filesize {
mask |= drive.AboutFileSizes
}
if mask == drive.AboutNone { // No option set
mask = drive.AboutQuota | drive.AboutFeatures | drive.AboutFileSizes
}
exitWithError(drive.New(context, &drive.Options{
Quiet: *cmd.Quiet,
}).About(mask))
}
type diffCmd struct {
Hidden *bool `json:"hidden"`
IgnoreConflict *bool `json:"ignore-conflict"`
IgnoreChecksum *bool `json:"ignore-checksum"`
IgnoreNameClashes *bool `json:"ignore-name-clashes"`
Quiet *bool `json:"quiet"`
Depth *int `json:"depth"`
Recursive *bool `json:"recursive"`
Unified *bool `json:"unified"`
BaseLocal *bool `json:"base-local"`
SkipContentCheck *bool `json:"skip-content-check"`
}
func (cmd *diffCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "allows pulling of hidden paths")
cmd.IgnoreChecksum = fs.Bool(drive.CLIOptionIgnoreChecksum, true, drive.DescIgnoreChecksum)
cmd.IgnoreConflict = fs.Bool(drive.CLIOptionIgnoreConflict, false, drive.DescIgnoreConflict)
cmd.IgnoreNameClashes = fs.Bool(drive.CLIOptionIgnoreNameClashes, false, drive.DescIgnoreNameClashes)
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.Depth = fs.Int(drive.DepthKey, drive.DefaultMaxTraversalDepth, "max traversal depth")
cmd.Recursive = fs.Bool(drive.RecursiveKey, true, "recursively diff")
cmd.Unified = fs.Bool(drive.CLIOptionUnifiedShortKey, true, drive.DescUnifiedDiff)
cmd.BaseLocal = fs.Bool(drive.CLIOptionDiffBaseLocal, true, drive.DescDiffBaseLocal)
cmd.SkipContentCheck = fs.Bool(drive.SkipContentCheckKey, false, drive.DescSkipContentCheck)
return fs
}
func (cmd *diffCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgs(args)
mask := drive.DiffNone
if *cmd.Unified {
mask |= drive.DiffUnified
}
var metaPtr *map[string][]string
if *cmd.SkipContentCheck {
meta := map[string][]string{
drive.SkipContentCheckKey: []string{drive.SkipContentCheckKey},
}
metaPtr = &meta
}
exitWithError(drive.New(context, &drive.Options{
Path: path,
Sources: sources,
Hidden: *cmd.Hidden,
Recursive: *cmd.Recursive,
IgnoreChecksum: *cmd.IgnoreChecksum,
IgnoreNameClashes: *cmd.IgnoreNameClashes,
IgnoreConflict: *cmd.IgnoreConflict,
Quiet: *cmd.Quiet,
Depth: *cmd.Depth,
BaseLocal: *cmd.BaseLocal,
Meta: metaPtr,
TypeMask: mask,
}).Diff())
}
type unpublishCmd struct {
Hidden *bool `json:"hidden"`
Quiet *bool `json:"quiet"`
ById *bool `json:"by-id"`
}
func (cmd *unpublishCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "allows pulling of hidden paths")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "unpublish by id instead of path")
return fs
}
func (uCmd *unpublishCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *uCmd.ById)
cmd := unpublishCmd{}
df := defaultsFiller{
command: drive.UnpubKey,
from: *uCmd, to: &cmd,
rcSourcePath: context.AbsPathOf(path),
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
exitWithError(drive.New(context, &drive.Options{
Path: path,
Sources: sources,
Quiet: *cmd.Quiet,
}).Unpublish(*cmd.ById))
}
type emptyTrashCmd struct {
NoPrompt *bool `json:"no-prompt"`
Quiet *bool `json:"quiet"`
}
func (cmd *emptyTrashCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.NoPrompt = fs.Bool(drive.NoPromptKey, false, "shows no prompt before emptying the trash")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
return fs
}
func (cmd *emptyTrashCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
_, context, _ := preprocessArgs(args)
exitWithError(drive.New(context, &drive.Options{
NoPrompt: *cmd.NoPrompt,
Quiet: *cmd.Quiet,
}).EmptyTrash())
}
type deleteCmd struct {
Hidden *bool `json:"hidden"`
Matches *bool `json:"matches"`
Quiet *bool `json:"quiet"`
ById *bool `json:"by-id"`
NoPrompt *bool `json:"no-prompt"`
}
func (cmd *deleteCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "allows trashing hidden paths")
cmd.Matches = fs.Bool(drive.MatchesKey, false, "search by prefix and delete")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "delete by id instead of path")
cmd.NoPrompt = fs.Bool(drive.NoPromptKey, false, "disables the prompt")
return fs
}
func (cmd *deleteCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
if *cmd.NoPrompt {
exitWithError(drive.PermanentDeletionNoPromptError)
}
sources, context, path := preprocessArgsByToggle(args, *cmd.Matches || *cmd.ById)
opts := drive.Options{
Path: path,
Sources: sources,
Quiet: *cmd.Quiet,
Match: *cmd.Matches,
}
if !*cmd.Matches {
exitWithError(drive.New(context, &opts).Delete(*cmd.ById))
} else {
exitWithError(drive.New(context, &opts).DeleteByMatch())
}
}
type trashCmd struct {
Hidden *bool `json:"hidden"`
Matches *bool `json:"matches"`
Quiet *bool `json:"quiet"`
ById *bool `json:"by-id"`
Verbose *bool `json:"verbose"`
}
func (cmd *trashCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "allows trashing hidden paths")
cmd.Matches = fs.Bool(drive.MatchesKey, false, "search by prefix and trash")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "trash by id instead of path")
cmd.Verbose = fs.Bool(drive.CLIOptionVerboseKey, false, drive.DescVerbose)
return fs
}
func (cmd *trashCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *cmd.Matches || *cmd.ById)
opts := drive.Options{
Path: path,
Sources: sources,
Quiet: *cmd.Quiet,
Match: *cmd.Matches,
Verbose: *cmd.Verbose,
}
if !*cmd.Matches {
exitWithError(drive.New(context, &opts).Trash(*cmd.ById))
} else {
exitWithError(drive.New(context, &opts).TrashByMatch())
}
}
type newCmd struct {
Folder *bool `json:"folder"`
MimeKey *string `json:"mime"`
}
func (cmd *newCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Folder = fs.Bool("folder", false, "create a folder if set otherwise create a regular file")
cmd.MimeKey = fs.String(drive.MimeKey, "", "coerce the file to this mimeType")
return fs
}
func (cmd *newCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgs(args)
opts := drive.Options{
Path: path,
Sources: sources,
}
meta := map[string][]string{
drive.MimeKey: drive.NonEmptyTrimmedStrings(strings.Split(*cmd.MimeKey, ",")...),
}
opts.Meta = &meta
if *cmd.Folder {
exitWithError(drive.New(context, &opts).NewFolder())
} else {
exitWithError(drive.New(context, &opts).NewFile())
}
}
type copyCmd struct {
Quiet *bool `json:"quiet"`
Recursive *bool `json:"recursive"`
ById *bool `json:"by-id"`
}
func (cmd *copyCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Recursive = fs.Bool(drive.RecursiveKey, false, "recursive copying")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "copy by id instead of path")
return fs
}
func (cmd *copyCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
if len(args) < 2 {
args = append(args, ".")
}
end := len(args) - 1
if end < 1 {
exitWithError(fmt.Errorf("copy: expected more than one path"))
}
dest := args[end]
sources, context, path := preprocessArgsByToggle(args, *cmd.ById)
// Unshift by the end path
sources = sources[:len(sources)-1]
destRels, err := relativePaths(context.AbsPathOf(""), dest)
exitWithError(err)
dest = destRels[0]
sources = append(sources, dest)
exitWithError(drive.New(context, &drive.Options{
Path: path,
Sources: sources,
Recursive: *cmd.Recursive,
Quiet: *cmd.Quiet,
}).Copy(*cmd.ById))
}
type untrashCmd struct {
Hidden *bool `json:"hidden"`
Matches *bool `json:"matches"`
Quiet *bool `json:"quiet"`
ById *bool `json:"by-id"`
}
func (cmd *untrashCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "allows untrashing hidden paths")
cmd.Matches = fs.Bool(drive.MatchesKey, false, "search by prefix and untrash")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "untrash by id instead of path")
return fs
}
func (cmd *untrashCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *cmd.ById || *cmd.Matches)
opts := drive.Options{
Path: path,
Sources: sources,
Quiet: *cmd.Quiet,
Match: *cmd.Matches,
}
if !*cmd.Matches {
exitWithError(drive.New(context, &opts).Untrash(*cmd.ById))
} else {
exitWithError(drive.New(context, &opts).UntrashByMatch())
}
}
type publishCmd struct {
Hidden *bool `json:"hidden"`
Quiet *bool `json:"quiet"`
ById *bool `json:"by-id"`
}
func (cmd *publishCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Hidden = fs.Bool(drive.HiddenKey, false, "allows publishing of hidden paths")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "publish by id instead of path")
return fs
}
func (cmd *publishCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *cmd.ById)
exitWithError(drive.New(context, &drive.Options{
Path: path,
Sources: sources,
Quiet: *cmd.Quiet,
}).Publish(*cmd.ById))
}
type shareCmd struct {
ById *bool `json:"by-id"`
Emails *string `json:"emails"`
Message *string `json:"message"`
Role *string `json:"role"`
AccountType *string `json:"type"`
NoPrompt *bool `json:"no-prompt"`
Notify *bool `json:"notify"`
Quiet *bool `json:"quiet"`
Verbose *bool `json:"verbose"`
WithLink *bool `json:"with-link"`
}
func (cmd *shareCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Emails = fs.String(drive.EmailsKey, "", "emails to share the file to")
cmd.Message = fs.String("message", "", "message to send receipients")
cmd.Role = fs.String(drive.RoleKey, "", "role to set to receipients of share. Possible values: "+drive.DescRoles)
cmd.AccountType = fs.String(drive.TypeKey, "", "scope of accounts to share files with. Possible values: "+drive.DescAccountTypes)
cmd.Notify = fs.Bool(drive.CLIOptionNotify, true, "toggle whether to notify receipients about share")
cmd.WithLink = fs.Bool(drive.CLIOptionWithLink, false, drive.DescWithLink)
cmd.NoPrompt = fs.Bool(drive.NoPromptKey, false, "disables the prompt")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "share by id instead of path")
cmd.Verbose = fs.Bool(drive.CLIOptionVerboseKey, true, drive.DescVerbose)
return fs
}
func (cmd *shareCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *cmd.ById)
meta := map[string][]string{
drive.EmailMessageKey: []string{*cmd.Message},
drive.EmailsKey: uniqOrderedStr(drive.NonEmptyTrimmedStrings(strings.Split(*cmd.Emails, ",")...)),
drive.RoleKey: uniqOrderedStr(drive.NonEmptyTrimmedStrings(strings.Split(*cmd.Role, ",")...)),
drive.AccountTypeKey: uniqOrderedStr(drive.NonEmptyTrimmedStrings(strings.Split(*cmd.AccountType, ",")...)),
}
mask := drive.NoopOnShare
if *cmd.Notify {
mask |= drive.Notify
}
if *cmd.WithLink {
mask |= drive.WithLink
}
exitWithError(drive.New(context, &drive.Options{
Path: path,
Sources: sources,
Meta: &meta,
TypeMask: mask,
NoPrompt: *cmd.NoPrompt,
Quiet: *cmd.Quiet,
Verbose: *cmd.Verbose,
}).Share(*cmd.ById))
}
type unshareCmd struct {
Role *string `json:"role"`
AccountType *string `json:"type"`
Quiet *bool `json:"quiet"`
ById *bool `json:"by-id"`
Emails *string `json:"emails"`
NoPrompt *bool `json:"no-prompt"`
Verbose *bool `json:"verbose"`
}
func (cmd *unshareCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.ById = fs.Bool(drive.CLIOptionId, false, "unshare by id instead of path")
cmd.Role = fs.String(drive.RoleKey, "", "role to set to receipients of share. Possible values: "+drive.DescRoles)
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.Verbose = fs.Bool(drive.CLIOptionVerboseKey, true, drive.DescVerbose)
cmd.Emails = fs.String(drive.EmailsKey, "", "emails to share the file to")
cmd.NoPrompt = fs.Bool(drive.NoPromptKey, false, "disables the prompt")
cmd.AccountType = fs.String(drive.TypeKey, "", "scope of account to revoke access to")
return fs
}
func (cmd *unshareCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *cmd.ById)
meta := map[string][]string{
drive.EmailsKey: uniqOrderedStr(drive.NonEmptyTrimmedStrings(strings.Split(*cmd.Emails, ",")...)),
drive.RoleKey: uniqOrderedStr(drive.NonEmptyTrimmedStrings(strings.Split(*cmd.Role, ",")...)),
drive.AccountTypeKey: uniqOrderedStr(drive.NonEmptyTrimmedStrings(strings.Split(*cmd.AccountType, ",")...)),
}
exitWithError(drive.New(context, &drive.Options{
Meta: &meta,
Path: path,
Sources: sources,
NoPrompt: *cmd.NoPrompt,
Quiet: *cmd.Quiet,
Verbose: *cmd.Verbose,
}).Unshare(*cmd.ById))
}
type moveCmd struct {
Quiet *bool `json:"quiet"`
ById *bool `json:"by-id"`
KeepParent *bool `json:"keep-parent"`
}
func (cmd *moveCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "move by id instead of path")
cmd.KeepParent = fs.Bool(drive.CLIOptionKeepParent, false, drive.DescKeepParent)
return fs
}
func (cmd *moveCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
argc := len(args)
if argc < 1 {
exitWithError(fmt.Errorf("move: expecting a path or more"))
}
sources, context, path := preprocessArgsByToggle(args, *cmd.ById)
// Unshift by the end path
sources = sources[:len(sources)-1]
dest := args[argc-1]
destRels, err := relativePaths(context.AbsPathOf(""), dest)
exitWithError(err)
sources = append(sources, destRels[0])
exitWithError(drive.New(context, &drive.Options{
Path: path,
Sources: sources,
Quiet: *cmd.Quiet,
}).Move(*cmd.ById, *cmd.KeepParent))
}
type renameCmd struct {
Force *bool `json:"force"`
Quiet *bool `json:"quiet"`
ById *bool `json:"by-id"`
RenameLocal *bool `json:"rename-local"`
RenameRemote *bool `json:"rename-local"`
}
func (cmd *renameCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Force = fs.Bool(drive.ForceKey, false, "coerce rename even if remote already exists")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
cmd.ById = fs.Bool(drive.CLIOptionId, false, "unshare by id instead of path")
cmd.RenameLocal = fs.Bool(drive.CLIOptionRenameLocal, true, "rename local as well")
cmd.RenameRemote = fs.Bool(drive.CLIOptionRenameRemote, true, "rename remote as well")
return fs
}
func boolDeref(boolPtr *bool) bool {
return boolPtr != nil && *boolPtr
}
func (cmd *renameCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
argc := len(args)
if argc < 2 {
exitWithError(fmt.Errorf("rename: expecting <src> <dest>"))
}
rest, last := args[:argc-1], args[argc-1]
sources, context, path := preprocessArgsByToggle(rest, *cmd.ById)
var renameMode drive.RenameMode
if boolDeref(cmd.RenameLocal) {
renameMode |= drive.RenameLocal
}
if boolDeref(cmd.RenameRemote) {
renameMode |= drive.RenameRemote
}
sources = append(sources, last)
exitWithError(drive.New(context, &drive.Options{
Path: path,
Sources: sources,
Force: *cmd.Force,
Quiet: *cmd.Quiet,
RenameMode: renameMode,
}).Rename(*cmd.ById))
}
type starCmd struct {
ById *bool `json:"by-id"`
Quiet *bool `json:"quiet"`
NoPrompt *bool `json:"no-prompt"`
}
func (cmd *starCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.ById = fs.Bool(drive.CLIOptionId, false, "open by id instead of path")
cmd.NoPrompt = fs.Bool(drive.NoPromptKey, false, "disables the prompt")
cmd.Quiet = fs.Bool(drive.QuietKey, false, "if set, do not log anything but errors")
return fs
}
func (cmd *starCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *cmd.ById)
opts := &drive.Options{
Path: path,
Sources: sources,
Quiet: *cmd.Quiet,
}
exitWithError(drive.New(context, opts).Star(*cmd.ById))
}
type unstarCmd struct {
starCmd
}
func (cmd *unstarCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *cmd.ById)
opts := &drive.Options{
Path: path,
Sources: sources,
}
exitWithError(drive.New(context, opts).UnStar(*cmd.ById))
}
type idCmd struct {
Depth *int `json:"depth"`
Hidden *bool `json:"hidden"`
}
func (cmd *idCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Depth = fs.Int(drive.DepthKey, 1, "maximum recursion depth")
cmd.Hidden = fs.Bool(drive.HiddenKey, true, "allows operation on hidden paths")
return fs
}
func (icmd *idCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgs(args)
cmd := idCmd{}
df := defaultsFiller{
command: drive.IdKey,
from: *icmd, to: &cmd,
rcSourcePath: context.AbsPathOf(path),
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
opts := &drive.Options{
Path: path,
Sources: sources,
Depth: *cmd.Depth,
Hidden: *cmd.Hidden,
}
exitWithError(drive.New(context, opts).Id())
}
type clashesCmd struct {
Fix *bool `json:"fix"`
FixMode *string `json:"fix-mode"`
List *bool `json:"list"`
ById *bool `json:"by-id"`
Depth *int `json:"depth"`
Hidden *bool `json:"hidden"`
NoPrompt *bool `json:"no-prompt"`
}
func (cmd *clashesCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
cmd.Fix = fs.Bool(drive.CLIOptionFixClashes, false, drive.DescFixClashes)
cmd.FixMode = fs.String(drive.CLIOptionFixClashesMode, "rename", drive.DescFixClashesMode)
cmd.List = fs.Bool(drive.CLIOptionListClashes, true, drive.DescListClashes)
cmd.ById = fs.Bool(drive.CLIOptionId, false, drive.DescClashesOpById)
cmd.Depth = fs.Int(drive.DepthKey, drive.InfiniteDepth, "maximum recursion depth")
cmd.Hidden = fs.Bool(drive.HiddenKey, true, "allows operation on hidden paths")
cmd.NoPrompt = fs.Bool(drive.NoPromptKey, false, "shows no prompt before fixing clashes")
return fs
}
func translateFixMode(strFixMode string) (drive.FixClashesMode, bool) {
switch strings.ToLower(strFixMode) {
case "rename":
return drive.FixClashesRename, true
case "trash":
return drive.FixClashesTrash, true
default:
return 0, false
}
}
func (ccmd *clashesCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgsByToggle(args, *ccmd.ById)
cmd := clashesCmd{}
df := defaultsFiller{
command: drive.ClashesKey,
from: *ccmd, to: &cmd,
rcSourcePath: context.AbsPathOf(path),
definedFlags: definedFlags,
}
if err := fillWithDefaults(df); err != nil {
exitWithError(err)
}
fixMode, ok := translateFixMode(*cmd.FixMode)
if !ok {
exitWithError(fmt.Errorf("Unknown fix mode: %s", *cmd.FixMode))
}
opts := &drive.Options{
Path: path,
Sources: sources,
Depth: *cmd.Depth,
Hidden: *cmd.Hidden,
NoPrompt: *cmd.NoPrompt,
FixClashesMode: fixMode,
}
driveInstance := drive.New(context, opts)
fn := driveInstance.ListClashes
if *cmd.Fix {
fn = driveInstance.FixClashes
}
exitWithError(fn(*cmd.ById))
}
type issueCmd struct {
Piped *bool
Title *string
Body *string
}
func (ic *issueCmd) Flags(fs *flag.FlagSet) *flag.FlagSet {
ic.Piped = fs.Bool(drive.CLIOptionPiped, false, drive.DescPiped)
ic.Title = fs.String(drive.IssueTitleKey, "", drive.DescIssueTitle)
ic.Body = fs.String(drive.IssueBodyKey, "", drive.DescIssueBody)
return fs
}
func (cmd *issueCmd) Run(args []string, definedFlags map[string]*flag.Flag) {
sources, context, path := preprocessArgs(args)
meta := map[string][]string{
drive.IssueTitleKey: []string{*cmd.Title},
drive.IssueBodyKey: []string{*cmd.Body},
}
if *cmd.Piped {
meta[drive.PipedKey] = []string{fmt.Sprintf("%v", *cmd.Piped)}
}
opts := &drive.Options{
Path: path,
Sources: sources,
Meta: &meta,
}
exitWithError(drive.New(context, opts).FileIssue())
}
func initContext(args []string) *config.Context {
var err error
var gdPath string
var firstInit bool
gdPath, firstInit, context, err = config.Initialize(getContextPath(args))
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
// The signal handler should clean up the .gd path if this is the first time
go func() {
_ = <-c
if firstInit {
os.RemoveAll(gdPath)
}
os.Exit(1)
}()
exitWithError(err)
return context
}
func discoverContext(args []string) (*config.Context, string) {
var err error
ctxPath := getContextPath(args)
context, err = config.Discover(ctxPath)
drive.DebugPrintf("contextPath: %q", ctxPath)
exitWithError(err)
relPath := ""
if len(args) > 0 {
var headAbsArg string
headAbsArg, err = filepath.Abs(args[0])
if err == nil {
relPath, err = filepath.Rel(context.AbsPath, headAbsArg)
}
}
drive.DebugPrintf("driveRoot: %q relToRoot: %q\n\n", context.AbsPath, relPath)
exitWithError(err)
// relPath = strings.Join([]string{"", relPath}, "/")
return context, relPath
}
func getContextPath(args []string) (contextPath string) {
if len(args) > 0 {
contextPath, _ = filepath.Abs(args[0])
}
if contextPath == "" {
contextPath, _ = os.Getwd()
}
return
}
func uniqOrderedStr(sources []string) []string {
cache := map[string]bool{}
var uniqPaths []string
for _, p := range sources {
ok := cache[p]
if ok {
continue
}
uniqPaths = append(uniqPaths, p)
cache[p] = true
}
return uniqPaths
}
func exitWithError(err error) {
if err == nil {
return
}
msg := err.Error()
code := -1
if codedErr, ok := err.(*drive.Error); ok {
code = codedErr.Code()
}
drive.FprintfShadow(os.Stderr, "%s\n", msg)
os.Exit(code)
}
func relativePaths(root string, args ...string) ([]string, error) {
return relativePathsOpt(root, args, false)
}
func relativePathsOpt(root string, args []string, leastNonExistant bool) ([]string, error) {
var err error
var relPath string
var relPaths []string
for _, p := range args {
p, err = filepath.Abs(p)
if err != nil {
drive.FprintfShadow(os.Stderr, "%s %v\n", p, err)
continue
}
if leastNonExistant {
sRoot := config.LeastNonExistantRoot(p)
if sRoot != "" {
p = sRoot
}
}
relPath, err = filepath.Rel(root, p)
if err != nil {
break
}
if relPath == "." {
relPath = ""
}
relPath = "/" + relPath
relPaths = append(relPaths, relPath)
}
return relPaths, err
}
func preprocessArgs(args []string) ([]string, *config.Context, string) {
context, path := discoverContext(args)
root := context.AbsPathOf("")
if len(args) < 1 {
args = []string{"."}
}
relPaths, err := relativePaths(root, args...)
exitWithError(err)
return uniqOrderedStr(relPaths), context, path
}
func preprocessArgsByToggle(args []string, skipArgPreprocess bool) (sources []string, context *config.Context, path string) {
if !skipArgPreprocess {
return preprocessArgs(args)
}
cwd, err := os.Getwd()
exitWithError(err)
_, context, path = preprocessArgs([]string{cwd})
sources = uniqOrderedStr(args)
return sources, context, path
}