Skip to content

Commit

Permalink
Merge pull request #39 from csaunders/refactor/improve_console_loggin…
Browse files Browse the repository at this point in the history
…g_and_errors

Refactor/improve console logging and errors
  • Loading branch information
csaunders committed Mar 17, 2015
2 parents 0ef2ee8 + f51ff18 commit 037c6c1
Show file tree
Hide file tree
Showing 12 changed files with 455 additions and 183 deletions.
19 changes: 18 additions & 1 deletion cmd/theme/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (

const commandDefault string = "download [<file> ...]"

var globalEventLog chan phoenix.ThemeEvent

var permittedZeroArgCommands = map[string]bool{
"download": true,
"replace": true,
Expand Down Expand Up @@ -45,7 +47,7 @@ var parserMapping = map[string]CommandParser{
"bootstrap": BootstrapParser,
}

type Command func(map[string]interface{}) (done chan bool)
type Command func(map[string]interface{}) chan bool

var commandMapping = map[string]Command{
"upload": commands.UploadCommand,
Expand Down Expand Up @@ -81,15 +83,30 @@ func setupErrorReporter() {
phoenix.SetErrorReporter(phoenix.HaltExecutionReporter{})
}

func setupGlobalEventLog() {
globalEventLog = make(chan phoenix.ThemeEvent)
}

func main() {
setupGlobalEventLog()
setupErrorReporter()
command, rest := SetupAndParseArgs(os.Args[1:])
verifyCommand(command, rest)

args, _ := parserMapping[command](command, rest)
args["eventLog"] = globalEventLog

operation := commandMapping[command]
done := operation(args)
go func() {
for {
event, more := <-globalEventLog
if !more {
return
}
fmt.Println(event)
}
}()
<-done
}

Expand Down
137 changes: 88 additions & 49 deletions commands/bootstrap.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package commands

import (
"fmt"
"bytes"
"errors"
"github.com/csaunders/phoenix"
"log"
"net/http"
"os"
)
Expand All @@ -15,90 +15,129 @@ const (
TimberFeedPath = "https://github.com/Shopify/Timber/releases.atom"
)

func BootstrapCommand(args map[string]interface{}) (done chan bool) {
var client phoenix.ThemeClient
var version, dir, env, prefix string
var setThemeId bool
extractString(&version, "version", args)
extractString(&dir, "directory", args)
extractString(&env, "environment", args)
extractString(&prefix, "prefix", args)
extractBool(&setThemeId, "setThemeId", args)
extractThemeClient(&client, args)

return Bootstrap(client, prefix, version, dir, env, setThemeId)
type BootstrapOptions struct {
BasicOptions
Version string
Directory string
Environment string
Prefix string
SetThemeId bool
}

func Bootstrap(client phoenix.ThemeClient, prefix, version, directory, environment string, setThemeId bool) (done chan bool) {
var zipLocation string
func BootstrapCommand(args map[string]interface{}) chan bool {
options := BootstrapOptions{}

extractString(&options.Version, "version", args)
extractString(&options.Directory, "directory", args)
extractString(&options.Environment, "environment", args)
extractString(&options.Prefix, "prefix", args)
extractBool(&options.SetThemeId, "setThemeId", args)
extractThemeClient(&options.Client, args)
extractEventLog(&options.EventLog, args)

return Bootstrap(options)
}

func Bootstrap(options BootstrapOptions) chan bool {
done := make(chan bool)
go func() {
doneCh := doBootstrap(options)
done <- <-doneCh
}()
return done
}

func doBootstrap(options BootstrapOptions) chan bool {
pwd, _ := os.Getwd()
if pwd != directory {
os.Chdir(directory)
if pwd != options.Directory {
os.Chdir(options.Directory)
}

if version == MasterBranch {
zipLocation = zipPath(MasterBranch)
} else {
zipLocation = zipPathForVersion(version)
zipLocation, err := zipPathForVersion(options.Version)
if err != nil {
phoenix.NotifyError(err)
done := make(chan bool)
close(done)
return done
}
name := "Timber-" + version
if len(prefix) > 0 {
name = prefix + "-" + name

name := "Timber-" + options.Version
if len(options.Prefix) > 0 {
name = options.Prefix + "-" + name
}
clientForNewTheme := client.CreateTheme(name, zipLocation)
if setThemeId {
AddConfiguration(directory, environment, clientForNewTheme.GetConfiguration())
clientForNewTheme, themeEvents := options.Client.CreateTheme(name, zipLocation)
mergeEvents(options.getEventLog(), []chan phoenix.ThemeEvent{themeEvents})
if options.SetThemeId {
AddConfiguration(options.Directory, options.Environment, clientForNewTheme.GetConfiguration())
}

os.Chdir(pwd)
return Download(clientForNewTheme, []string{})

downloadOptions := DownloadOptions{}
downloadOptions.Client = clientForNewTheme
downloadOptions.EventLog = options.getEventLog()

done := Download(downloadOptions)

return done
}

func zipPath(version string) string {
return ThemeZipRoot + version + ".zip"
}

func zipPathForVersion(version string) string {
feed := downloadAtomFeed()
entry := findReleaseWith(feed, version)
return zipPath(entry.Title)
func zipPathForVersion(version string) (string, error) {
if version == MasterBranch {
return zipPath(MasterBranch), nil
}

feed, err := downloadAtomFeed()
if err != nil {
return "", err
}

entry, err := findReleaseWith(feed, version)
if err != nil {
return "", err
}

return zipPath(entry.Title), nil
}

func downloadAtomFeed() phoenix.Feed {
func downloadAtomFeed() (phoenix.Feed, error) {
resp, err := http.Get(TimberFeedPath)
if err != nil {
log.Fatal(err)
return phoenix.Feed{}, err
}
defer resp.Body.Close()

feed, err := phoenix.LoadFeed(resp.Body)
if err != nil {
log.Fatal(err)
return phoenix.Feed{}, err
}
return feed
return feed, nil
}

func findReleaseWith(feed phoenix.Feed, version string) phoenix.Entry {
func findReleaseWith(feed phoenix.Feed, version string) (phoenix.Entry, error) {
if version == LatestRelease {
return feed.LatestEntry()
return feed.LatestEntry(), nil
}
for _, entry := range feed.Entries {
if entry.Title == version {
return entry
return entry, nil
}
}
logAndDie(feed, version)
return phoenix.Entry{}
return phoenix.Entry{Title: "Invalid Feed"}, buildInvalidVersionError(feed, version)
}

func logAndDie(feed phoenix.Feed, version string) {
fmt.Println(phoenix.RedText("Invalid Timber Version: " + version))
fmt.Println("Available Versions Are:")
fmt.Println(" - master")
fmt.Println(" - latest")
func buildInvalidVersionError(feed phoenix.Feed, version string) error {
buff := bytes.NewBuffer([]byte{})
buff.Write([]byte(phoenix.RedText("Invalid Timber Version: " + version)))
buff.Write([]byte("\nAvailable Versions Are:"))
buff.Write([]byte("\n - master"))
buff.Write([]byte("\n - latest"))
for _, entry := range feed.Entries {
fmt.Println(" - " + entry.Title)
buff.Write([]byte("\n - " + entry.Title))
}
os.Exit(1)
return errors.New(buff.String())
}
95 changes: 95 additions & 0 deletions commands/common.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
package commands

import (
"encoding/json"
"errors"
"fmt"
"github.com/csaunders/phoenix"
)

type BasicOptions struct {
Client phoenix.ThemeClient
Filenames []string
EventLog chan phoenix.ThemeEvent
}

func (bo *BasicOptions) getEventLog() chan phoenix.ThemeEvent {
if bo.EventLog == nil {
bo.EventLog = make(chan phoenix.ThemeEvent)
}
return bo.EventLog
}

func extractString(s *string, key string, args map[string]interface{}) {
var ok bool
if args[key] == nil {
Expand All @@ -18,6 +32,16 @@ func extractString(s *string, key string, args map[string]interface{}) {
}
}

func extractStringSlice(key string, args map[string]interface{}) []string {
var ok bool
var strs []string
if strs, ok = args[key].([]string); !ok {
errMsg := fmt.Sprintf("%s is not of valid type", key)
phoenix.NotifyError(errors.New(errMsg))
}
return strs
}

func extractInt(s *int, key string, args map[string]interface{}) {
var ok bool
if args[key] == nil {
Expand Down Expand Up @@ -53,6 +77,22 @@ func extractThemeClient(t *phoenix.ThemeClient, args map[string]interface{}) {
}
}

func extractEventLog(el *chan phoenix.ThemeEvent, args map[string]interface{}) {
var ok bool

if *el, ok = args["eventLog"].(chan phoenix.ThemeEvent); !ok {
phoenix.NotifyError(errors.New("eventLog is not of a valid type"))
}
}

func extractBasicOptions(args map[string]interface{}) BasicOptions {
options := BasicOptions{}
extractThemeClient(&options.Client, args)
extractEventLog(&options.EventLog, args)
options.Filenames = extractStringSlice("filenames", args)
return options
}

func toClientAndFilesAsync(args map[string]interface{}, fn func(phoenix.ThemeClient, []string) chan bool) chan bool {
var ok bool
var themeClient phoenix.ThemeClient
Expand All @@ -69,6 +109,61 @@ func drainErrors(errs chan error) {
for {
if err := <-errs; err != nil {
phoenix.NotifyError(err)
} else {
break
}
}
}

func mergeEvents(dest chan phoenix.ThemeEvent, chans []chan phoenix.ThemeEvent) {
go func() {
for _, ch := range chans {
var ok = true
for ok {
if ev, ok := <-ch; ok {
dest <- ev
}
}
close(ch)
}
}()
}

func logEvent(event phoenix.ThemeEvent, eventLog chan phoenix.ThemeEvent) {
go func() {
eventLog <- event
}()
}

type basicEvent struct {
Formatter func(b basicEvent) string
EventType string `json:"event_type"`
Target string `json:"target"`
Title string `json:"title"`
etype string `json:"type"`
}

func message(content string) phoenix.ThemeEvent {
return basicEvent{
Formatter: func(b basicEvent) string { return content },
EventType: "message",
Title: "Notice",
etype: "basicEvent",
}
}

func (b basicEvent) String() string {
return b.Formatter(b)
}

func (b basicEvent) Successful() bool {
return true
}

func (b basicEvent) Error() error {
return nil
}

func (b basicEvent) AsJSON() ([]byte, error) {
return json.Marshal(b)
}
Loading

0 comments on commit 037c6c1

Please sign in to comment.