Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ajbosco committed Sep 27, 2018
0 parents commit dfac4f1
Show file tree
Hide file tree
Showing 32 changed files with 1,371 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

.envrc
2 changes: 2 additions & 0 deletions .goosarch
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
darwin/amd64
darwin/386
21 changes: 21 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2018 Adam Boscarino

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
68 changes: 68 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.EXPORT_ALL_VARIABLES:
NAME := reads
PKG := github.com/ajbosco/reads/cmd/reads
BUILD_DIR := $(shell pwd)/build
TARGET := ${BUILD_DIR}/${NAME}
VERSION := $(shell cat VERSION.txt)
LDFLAGS ?= -X github.com/ajbosco/reads/version.VERSION=${VERSION}

# List the GOOS and GOARCH to build
GOOSARCHES = $(shell cat .goosarch)

.PHONY: fmt
fmt: ## Verifies all files have been `gofmt`ed.
@gofmt -s -l .

.PHONY: lint
lint: ## Verifies `golint` passes.
@golint ./...

.PHONY: test
test: ## Runs the go tests.
@go test -cover -race ./...

.PHONY: vet
vet: ## Verifies `go vet` passes.
@go vet ./...

.PHONY: build-native
build-native: ## run go build for current OS
@go build -ldflags "$(LDFLAGS)" -o "${TARGET}" ${PKG}

define buildrelease
GOOS=$(1) GOARCH=$(2) go build \
-ldflags "$(LDFLAGS)" \
-o $(BUILD_DIR)/$(NAME)-$(1)-$(2) ${PKG};
md5sum $(BUILD_DIR)/$(NAME)-$(1)-$(2) > $(BUILD_DIR)/$(NAME)-$(1)-$(2).md5;
sha256sum $(BUILD_DIR)/$(NAME)-$(1)-$(2) > $(BUILD_DIR)/$(NAME)-$(1)-$(2).sha256;
endef

.PHONY: release
release: VERSION.txt ## Builds the cross-compiled binaries, naming them in such a way for release (eg. binary-GOOS-GOARCH).
@$(foreach GOOSARCH,$(GOOSARCHES), $(call buildrelease,$(subst /,,$(dir $(GOOSARCH))),$(notdir $(GOOSARCH))))

.PHONY: bump-version
BUMP := patch
bump-version: ## Bump the version in the version file. Set BUMP to [ patch | major | minor ].
@go get -u github.com/jessfraz/junk/sembump # update sembump tool
$(eval NEW_VERSION = $(shell sembump --kind $(BUMP) $(VERSION)))
@echo "Bumping VERSION.txt from $(VERSION) to $(NEW_VERSION)"
echo $(NEW_VERSION) > VERSION.txt
@echo "Updating links to download binaries in README.md"
sed -i s/$(VERSION)/$(NEW_VERSION)/g README.md
git add VERSION.txt README.md
git commit -vsam "Bump version to $(NEW_VERSION)"
@echo "Run make tag to create and push the tag for new version $(NEW_VERSION)"

.PHONY: tag
tag: ## Create a new git tag to prepare to build a release.
git tag -sa $(VERSION) -m "$(VERSION)"
@echo "Run git push origin $(VERSION) to push your new tag to GitHub and trigger a travis build."

.PHONY: clean
clean: ## Cleanup any build binaries or packages.
$(RM) -r $(BUILD_DIR)

.PHONY: help
help:
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | sed 's/^[^:]*://g' | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
111 changes: 111 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# reads

Command line tool to interact with [Goodreads](https://www.goodreads.com).

- [Installation](#installation)
+ [Binaries](#binaries)
+ [With Go](#with-go)
- [Authentication](#authentication)
- [Usage](#usage)
* [Search for Book](#search-for-book)
* [List Shelves](#list-shelves)
* [Show Books on Shelf](#show-books-on-shelf)
* [Add Book to Shelf](#add-book-to-shelf)

## Installation

#### Binaries

For installation instructions from binaries please visit the [Releases Page](https://github.com/ajbosco/reads/releases).

#### With Go

```console
$ go get github.com/ajbosco/reads
```

## Authentication

1. Create a Developer Key with [Goodreads](https://www.goodreads.com/api/keys)
2. Create a `config.yml` file
```console
DeveloperKey: your-developer-key
DeveloperSecret: your-developer-secret
```
3. Set the config filepath as `GOODREADS_CLI_CONFIG` environment variable.
```console
export GOODREADS_CLI_CONFIG=path/to/your/config.yml
```

## Usage

```console
$ reads -h
NAME:
reads - Command line tool to interact with Goodreads

USAGE:
reads [global options] command [command options] [arguments...]

COMMANDS:
search search for a book by title, author, or id
shelves view shelves and add books to them
help, h Shows a list of commands or help for one command

GLOBAL OPTIONS:
--config value, -c value Goodreads CLI config file [$GOODREADS_CLI_CONFIG]
--debug, -d enable debug logging
--help, -h show help
--version, -v print the version
```

### Search for Book

```console
$ reads search -h
NAME:
reads search - search for a book by title, author, or id

USAGE:
reads search [arguments...]
```

### List Shelves

```console
$ reads list -h
NAME:
reads shelves list - list your shelves

USAGE:
reads shelves list [arguments...]
```

### Show Books on Shelf

```console
$ reads shelves show -h
NAME:
reads shelves show - show books on shelf

USAGE:
reads shelves show [command options] [arguments...]

OPTIONS:
--shelf value, -s value -s=shelf-name
```

### Add Book to Shelf

```console
$ reads shelves add -h
NAME:
reads shelves add - add a book to shelf

USAGE:
reads shelves add [command options] [arguments...]

OPTIONS:
--shelf value, -s value -s=shelf-name
--book-id value, -b value -b=book-id
```
1 change: 1 addition & 0 deletions VERSION.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v0.1.0
94 changes: 94 additions & 0 deletions cmd/reads/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package main

import (
"errors"
"fmt"
"os"

"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"github.com/ajbosco/reads/goodreads"
"github.com/ajbosco/reads/version"
)

var (
configFile string
debug bool

client *goodreads.Client
)

func main() {

app := cli.NewApp()
app.Name = "reads"
app.Usage = "Command line tool to interact with Goodreads"
app.Version = version.VERSION

// Setup the global flags.
app.Flags = []cli.Flag{
cli.StringFlag{
Name: "config, c",
Usage: "Goodreads CLI config file",
EnvVar: "GOODREADS_CLI_CONFIG",
Destination: &configFile,
},
cli.BoolFlag{
Name: "debug, d",
Usage: "enable debug logging",
Destination: &debug,
},
}

// Build the list of available commands.
app.Commands = []cli.Command{
searchCommand,
shelvesCommand,
}

// Set the before function.
app.Before = func(c *cli.Context) error {
// Set the log level.
if debug {
logrus.SetLevel(logrus.DebugLevel)
fmt.Println("Debug logging is enabled")
}

if len(configFile) <= 0 {
return errors.New("Goodreads config file cannot be empty")
}

cfg := new(goodreads.Config)
cfg, err := goodreads.ReadConfig(configFile)
if err != nil {
logrus.Debug(err)
return errors.New("Could not read Goodreads config file")
}
if cfg.DeveloperKey == "" || cfg.DeveloperSecret == "" {
return errors.New("Goodreads config file requires Developer Key and Developer Secret")
}

// Get OAuth tokens if they are not in config.
if cfg.AccessToken == "" || cfg.AccessSecret == "" {
token, err := goodreads.GetAccessToken(cfg.DeveloperKey, cfg.DeveloperSecret)
if err != nil {
logrus.Debug(err)
return errors.New("Could not get Goodreads access token")
}
cfg.AccessToken = token.Token
cfg.AccessSecret = token.Secret
goodreads.WriteConfig(cfg, configFile)
}

// Create the Goodreads client.
client, err = goodreads.NewClient(cfg)
if err != nil {
logrus.Debug(err)
return errors.New("Could not create Goodreads client")
}

return nil
}

app.Run(os.Args)
}
43 changes: 43 additions & 0 deletions cmd/reads/search.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"fmt"
"strings"

"github.com/sirupsen/logrus"
"github.com/urfave/cli"
"github.com/ajbosco/reads/utils"
)

var (
searchCommand = cli.Command{
Name: "search",
Usage: "search for a book by title, author, or id",
Action: searchBooks,
}
)

const baseBookURI = "https://www.goodreads.com/book/show"

func searchBooks(c *cli.Context) error {
if len(c.Args()) <= 0 {
fmt.Println("You didn't search for anything!")
return nil
}
args := append([]string{c.Args().First()}, c.Args().Tail()...)
searchText := strings.Join(args, " ")
books, err := client.SearchBooks(searchText)
if err != nil {
logrus.Fatal(err)
}

table := utils.NewTable("ID", "Title", "Author", "Average Rating", "Ratings Count", "URI")

for _, b := range books {
uri := fmt.Sprintf("%s/%s", baseBookURI, b.ID)
table.Append([]string{b.ID, b.Title, b.Author, b.AvgRating, b.RatingsCount, uri})
}
fmt.Fprintf(c.App.Writer, "Results for %q\n", searchText)
table.Render()
return nil
}
Loading

0 comments on commit dfac4f1

Please sign in to comment.