diff --git a/cmd/gsheet/cli.go b/cmd/gsheet/cli.go index a5fa83c..765821e 100644 --- a/cmd/gsheet/cli.go +++ b/cmd/gsheet/cli.go @@ -30,10 +30,10 @@ var app = &cli.App{ Name: "range", Usage: "Sheet range to update or get (A1 notation)", }, - &cli.BoolFlag{ - Name: "append", - Usage: "If set, append to end of any data in range", - }, + &cli.BoolFlag{ + Name: "append", + Usage: "If set, append to end of any data in range", + }, &cli.StringFlag{ Name: "sep", Value: ",", @@ -41,6 +41,30 @@ var app = &cli.App{ }, }, }, + { + Name: "title", + Usage: "Get the title of a sheet by its id", + Action: titleByIdAction, + Category: "Sheets", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "id", + Usage: "id of the spreadsheet document", + EnvVars: []string{"GSHEET_ID"}, + }, + &cli.Int64Flag{ + Name: "sheetid", + Usage: "id of the sheet to get the title of", + }, + }, + }, + { + Name: "sheetInfo", + Usage: "Dump info about the spreadsheet as json", + Action: sheetInfoAction, + Category: "Sheets", + ArgsUsage: "SHEET_ID", + }, { Name: "clear", Usage: "Clear all values from given range", diff --git a/cmd/gsheet/sheets.go b/cmd/gsheet/sheets.go index 7ab9d67..9bfb391 100644 --- a/cmd/gsheet/sheets.go +++ b/cmd/gsheet/sheets.go @@ -1,6 +1,8 @@ package main import ( + "encoding/json" + "errors" "fmt" "os" "strconv" @@ -22,6 +24,43 @@ func deleteSheetAction(c *cli.Context) error { return sheetSvc.DeleteSheet(c.String("id"), c.String("name")) } +func titleByIdAction(c *cli.Context) error { + if c.String("id") == "" { + return fmt.Errorf("The --id flag is required") + } + if c.String("sheetid") == "" { + return fmt.Errorf("The --sheetid flag is required") + } + id := c.String("id") + sheetId := c.Int64("sheetid") + title, err := sheetSvc.TitleFromSheetId(id, sheetId) + if err != nil { + return err + } + if title == nil { + return fmt.Errorf("No title found for sheetid %d", sheetId) + } + fmt.Fprint(c.App.Writer, *title) + return nil +} + +func sheetInfoAction(c *cli.Context) error { + if c.NArg() < 1 { + return errors.New("SHEET_ID is required") + } + id := c.Args().Get(0) + info, err := sheetSvc.SpreadsheetsService().Get(id).Do() + if err != nil { + return err + } + jsonBytes, err := json.MarshalIndent(info, "", " ") + if err != nil { + return err + } + fmt.Fprint(c.App.Writer, string(jsonBytes)) + return nil +} + func clearSheetAction(c *cli.Context) error { return sheetSvc.Clear(c.String("id"), c.StringSlice("range")...) } diff --git a/gsheets/integration_test.go b/gsheets/integration_test.go index 7da8f2d..9c2eaa2 100644 --- a/gsheets/integration_test.go +++ b/gsheets/integration_test.go @@ -86,6 +86,15 @@ func TestSheetIntegration(t *testing.T) { } t.Logf("Created new sheet with id %d", sheetId) + sheetTitle, err := svcSheet.TitleFromSheetId(testfile.Id, *sheetId) + if err != nil { + t.Fatal(err) + } + if sheetTitle == nil || *sheetTitle!= "TEST" { + t.Fatal("New sheet not found by title") + } + t.Logf("Looked up sheet title by id and found %s", *sheetTitle) + resp, err := svcSheet.UpdateRangeCSV(testfile.Id, "TEST", strings.NewReader(testData)) if err != nil { t.Fatal(err) diff --git a/gsheets/sheets.go b/gsheets/sheets.go index 7e731e0..028ded9 100644 --- a/gsheets/sheets.go +++ b/gsheets/sheets.go @@ -97,6 +97,25 @@ func (svc *Service) SheetFromTitle(id, title string) (*int64, error) { return sheetId, nil } +// TitleFromSheetId returns the sheet title for the given 'sheetId' +// If no error is encountered and no matching sheet is found, both return +// values will be nil. +func (svc *Service) TitleFromSheetId(id string, sheetId int64) (*string, error) { + ss, err := svc.sheet.Get(id).Context(svc.ctx).Do() + if err != nil { + return nil, err + } + + var sheetTitle *string + for _, sheet := range ss.Sheets { + if sheet.Properties.SheetId == sheetId { + sheetTitle = &sheet.Properties.Title + break + } + } + return sheetTitle, nil +} + // DeleteSheet deletes the sheet with 'title' from spreadsheet doc identified // by 'id' func (svc *Service) DeleteSheet(id, title string) error { @@ -243,12 +262,12 @@ func (svc *Service) AppendRangeStrings(id, a1Range string, values [][]string) (* resp, err := svc.values.Append(id, a1Range, &sheets.ValueRange{ Values: vals, }). - ValueInputOption("USER_ENTERED"). - Context(svc.ctx). - Do() - if err != nil { - return nil, err - } + ValueInputOption("USER_ENTERED"). + Context(svc.ctx). + Do() + if err != nil { + return nil, err + } return resp, nil } diff --git a/readme.adoc b/readme.adoc index 3d7a2e1..4bc916e 100644 --- a/readme.adoc +++ b/readme.adoc @@ -90,6 +90,35 @@ To get an overview of all the commands provided by `gsheet` run: [source,sh] gsheet help +``` +NAME: + gsheet - upload and download Google Sheet data from the cli + +USAGE: + gsheet [global options] command [command options] [arguments...] + +COMMANDS: + help, h Shows a list of commands or help for one command + Files: + createFolder Creates a new folder + delete Delete file(s) from drive (careful, does not trash them!) + list List file names and ids + upload Upload a file to Google Drive. + download Download a file from google drive and send it to stdout + info Dump all file's metadata as json to stdout + Sheets: + csv Pipe csv data to range or read it from range + title Get the title of a sheet by its id + sheetInfo Dump info about the spreadsheet as json + clear Clear all values from given range + newSheet Create a new sheet + deleteSheet Delete the named sheet + sort Sort a sheet by column(s) + +GLOBAL OPTIONS: + --help, -h show help +``` + You can also run `gsheet help CMD` to get help for each command. Below are some further usage hints. @@ -133,7 +162,7 @@ sort --id SHEET_NAME -name Sheet1 --column=1 --asc These commands simply create and delete sheets from a spreadsheet document. The new sheets appear after all other visible sheets. -NOTE: sheets are deleted by name (the title of the sheet) and not by id; this is a bit fragile because if a user changes the title of a sheet in Google Docs then a script depending on `gsheet deleteSheet` may break. +NOTE: sheets are deleted by name (the title of the sheet) and not by id; this is a bit fragile because if a user changes the title of a sheet in Google Docs then a script depending on `gsheet deleteSheet` may break. For a convenient way to look up a sheet's title by its id, see the `gsheet title` command. [source,sh] ----