From eac80b3843dbd94de2fc00e29c885dd90e261679 Mon Sep 17 00:00:00 2001 From: Clemens Fries Date: Sun, 25 Nov 2018 11:06:32 +0100 Subject: Rename project from 'clockrotz' to 'lettersnail' You can't always wait for the right name to appear before starting a project, so I chose a strange name that wasn't good. I finally came up with a name I like. --- .gitignore | 4 +- Godeps/Godeps.json | 2 +- README.asciidoc | 84 +++++++++++----------- clockrotz.go | 197 ---------------------------------------------------- clockrotz_test.go | 34 --------- cmd/check.go | 4 +- cmd/create.go | 6 +- cmd/debug.go | 4 +- cmd/next.go | 6 +- cmd/run.go | 6 +- lettersnail.go | 197 ++++++++++++++++++++++++++++++++++++++++++++++++++++ lettersnail_test.go | 34 +++++++++ 12 files changed, 289 insertions(+), 289 deletions(-) delete mode 100644 clockrotz.go delete mode 100644 clockrotz_test.go create mode 100644 lettersnail.go create mode 100644 lettersnail_test.go diff --git a/.gitignore b/.gitignore index b3702a0..75918aa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -clockrotz -clockrotz.iml +lettersnail +lettersnail.iml README.html .idea diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 437070f..8a18949 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,5 +1,5 @@ { - "ImportPath": "github.com/githubert/clockrotz", + "ImportPath": "github.com/githubert/lettersnail", "GoVersion": "go1.5.4", "Deps": [ { diff --git a/README.asciidoc b/README.asciidoc index 9bf8bb8..25c6d5f 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -1,20 +1,20 @@ -= Clockrotz -Clemens Fries += Lettersnail +Clemens Fries :source-highlighter: pygments :toc: left -:clockrotz-ini: clockrotz.ini -:clockrotz-base: clockrotz +:lettersnail-ini: lettersnail.ini +:lettersnail-base: lettersnail :version: 0.0.1 -Clockrotz v{version} — a simple email notification helper. +lettersnail v{version} — a simple email notification helper. IMPORTANT: This program is in development and might have some rough edges. The documentation on `master` should still accurately reflect the current state of the program. -== What is `clockrotz`? +== What is `lettersnail`? -`clockrotz` is a “note to my future self” email notification tool. You write a +`lettersnail` is a “note to my future self” email notification tool. You write a simple text file, with some metadata, and it will, upon invocation, send a message when the time has come. @@ -38,7 +38,7 @@ so I would not forget them if I move to another server. You could realize most of this with `atd`, but it is a bit clumsy if want to quickly write a message, plus I'd totally forget to copy `/var/spool/at`. -`clockrotz` is not meant to be a daemon. It should be executed regularly by a +`lettersnail` is not meant to be a daemon. It should be executed regularly by a cron job or other method. For the `date` parameter it also supports having a specific time, which acts as a “not before” constraint. If you run your cron job often enough (for example: every five minutes) the message will, of course, @@ -56,15 +56,15 @@ write the following: ---- cd $(mktemp -d) export GOPATH=$PWD -git clone http://github.com/githubert/clockrotz src/github.com/githubert/clockrotz -cd src/github.com/githubert/clockrotz +git clone http://github.com/githubert/lettersnail src/github.com/githubert/lettersnail +cd src/github.com/githubert/lettersnail godep get go build ---- === Running -Create `.config/{clockrotz-ini}`: +Create `.config/{lettersnail-ini}`: [source,ini] ---- [default] @@ -76,27 +76,27 @@ from = me@example.com Create a new message: ---- -clockrotz create --to me@example.com +lettersnail create --to me@example.com ---- Add a cron job: ---- -0 6 * * * /path/to/clockrotz run +0 6 * * * /path/to/lettersnail run ---- List messages due in the next days: ---- -clockrotz next +lettersnail next ---- Run manually: ---- -clockrotz run +lettersnail run ---- == Quick Start Walkthrough -Create a file `.config/{clockrotz-ini}` and provide a server, credentials and a +Create a file `.config/{lettersnail-ini}` and provide a server, credentials and a from address: [source,ini] @@ -114,7 +114,7 @@ NOTE: `port` defaults to `587`. If it doesn't work, try setting `port` to Now ready some message to yourself: ---- -clockrotz create --to me@example.com +lettersnail create --to me@example.com ---- This will open a new file using the editor set in the `VISUAL` environment @@ -124,35 +124,35 @@ Fill in `date` in the format `YYYY-mm-dd` (for example `date: 2016-01-01`) and add a meaningful `subject`. Add a blank line between the configuration in the header and your message's body. -Save and exit the editor. `clockrotz` will ask you what to do. Press `ENTER` to -save the message to the `{clockrotz-base}/todo` folder. +Save and exit the editor. `lettersnail` will ask you what to do. Press `ENTER` to +save the message to the `{lettersnail-base}/todo` folder. If you set `date` to today's date you can test if everything works. First check -if everything is okay by running `clockrotz check`, if it reports no errors, -you can see with `clockrotz next` if the message is scheduled for being sent +if everything is okay by running `lettersnail check`, if it reports no errors, +you can see with `lettersnail next` if the message is scheduled for being sent out in the next seven days. -Finally, if you type `clockrotz run`, it will deliver all messages that were +Finally, if you type `lettersnail run`, it will deliver all messages that were due. -As `clockrotz` is not a daemon, you should run it daily by adding it as a cron +As `lettersnail` is not a daemon, you should run it daily by adding it as a cron job. Type `crontab -e` and add a entry to run the command every day at 6 in the morning: ---- -0 6 * * * /path/to/clockrotz run +0 6 * * * /path/to/lettersnail run ---- == Folder structure -The default working directory is `clockrotz`, located in the user's home +The default working directory is `lettersnail`, located in the user's home directory. There are several folders created beneath it, when the program is invoked. ---- -clockrotz/ +lettersnail/ todo/ done/ errors/ @@ -160,7 +160,7 @@ clockrotz/ ---- `todo/` is the message queue. All `.msg` files in that folder are considered -when running `clockrotz run`. +when running `lettersnail run`. `done/` contains all messages that were successfully delivered. For every message there is also a corresponding `.log` file. @@ -168,17 +168,17 @@ message there is also a corresponding `.log` file. `errors/` contains all messages that could not be delivered. For every message there is also a corresponding `.log` file. -`drafts/` contains messages that can be used with `clockrotz create --draft +`drafts/` contains messages that can be used with `lettersnail create --draft FILENAME`. Additionally, messages in this folder will also be checked with -`clockrotz check`. +`lettersnail check`. -== Global Settings File `.config/{clockrotz-ini}` +== Global Settings File `.config/{lettersnail-ini}` -Global settings can be put into the optional file `.config/{clockrotz-ini}`. +Global settings can be put into the optional file `.config/{lettersnail-ini}`. All _global_ settings can also be overridden on the command line. -`.config/{clockrotz-ini}` is a simple ini-style settings file with a `default` +`.config/{lettersnail-ini}` is a simple ini-style settings file with a `default` section, plus optional sections for every command, in order to overrule the settings in the `default` section. @@ -186,7 +186,7 @@ settings in the `default` section. [source,ini] ---- [default] -workdir = ~/clockrotz +workdir = ~/lettersnail server = smtp.example.com port = 587 from = me@example.com @@ -201,7 +201,7 @@ NOTE: Empty values are valid and mean that a setting has been un-set. ==== Global and Command Line -workdir:: The working directory, defaults to `~/clockrotz`. +workdir:: The working directory, defaults to `~/lettersnail`. server:: Address of the SMTP server. Defaults to `localhost`. port:: Port of the SMTP server. Defaults to the SMTP submission port `587`. not-before:: Do not sent messages before the specified time. (`00:00` until `not-before`) @@ -286,13 +286,13 @@ Simple, plain text. It is assumed to be in UTF-8, though. == Writing a New Message -Either edit a file, directly in `{clockrotz-base}/todo`, or use the command line tool +Either edit a file, directly in `{lettersnail-base}/todo`, or use the command line tool to initialize an empty message and start your favourite editor. The file name must end in `.msg`, otherwise it will be ignored. .Using the command line tool ---- -$ clockrotz create --to "foo@example.com" +$ lettersnail create --to "foo@example.com" ---- == Command Line Options @@ -300,7 +300,7 @@ $ clockrotz create --to "foo@example.com" Use `--help` after any command to get the full help message shown. ---- -include::clockrotz.go[tag=main] +include::lettersnail.go[tag=main] ---- === `next` command @@ -315,7 +315,7 @@ use the `--all` parameter, all pending messages will be listed. The format is simply `date subject (filename)`. ---- -$ clockrotz next --all +$ lettersnail next --all Showing all messages. 2061-07-28 00:00 Watch Halley's Comet (halley.msg) @@ -350,7 +350,7 @@ line. If you provide a file name through the `--draft` parameter, it will create a new file based on the given file name in the `drafts` folder. ---- -clockrotz create --to foo@example.com --subject "Something" +lettersnail create --to foo@example.com --subject "Something" ---- It will use the editor configured in `$VISUAL` or `$EDITOR` or `vi`, if the @@ -401,7 +401,7 @@ NOTE: `--silent` will not suppress output of errors, such as problems loading a file. ---- -$ clockrotz check +$ lettersnail check in drafts: foo.msg: @@ -427,7 +427,7 @@ message there are several places, such as the `Message-Id`, that vary from invocation to invocation as they are randomly generated. ---- -$ clockrotz debug clockrotz/todo/2061.msg +$ lettersnail debug lettersnail/todo/2061.msg Configuration ------------- config: /home/me/.config/config.ini @@ -440,7 +440,7 @@ port: 578 server: smtp.example.com subject: Watch Halley's Comet to: me@example.com -workdir: /home/me/clockrotz +workdir: /home/me/lettersnail Email message ------------- diff --git a/clockrotz.go b/clockrotz.go deleted file mode 100644 index d2edc65..0000000 --- a/clockrotz.go +++ /dev/null @@ -1,197 +0,0 @@ -/* clockrotz.go: main program - * - * Copyright (C) 2016-2018 Clemens Fries - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package main - -import ( - "fmt" - "github.com/docopt/docopt.go" - "os" - "os/user" - "path/filepath" - "github.com/githubert/clockrotz/cmd" - . "github.com/githubert/clockrotz/common" -) - - -var usageMain = -// tag::main[] -` -Usage: - clockrotz [options] [...] - -Options: - --workdir=WORKDIR Working directory, defaults to $HOME/clockrotz - --config=CONFIG Use the given INI file instead of .config/clockrotz.ini - --help Show this help. - -The following commands are available: - next Show messages due in the next days. - check Check if a message is complete. - debug Print the effective configuration for a message, and the resulting - email message. - create Open a new message in an editor. - run Send out pending messages. -` // end::main[] - -var defaultConf = Configuration{ - Data: map[string]string{ - CONF_DAYS: "7", - CONF_SMTP_PORT: "587", - CONF_SMTP_SERVER: "localhost", - CONF_NOT_BEFORE: "00:00", - CONF_NOT_AFTER: "23:59", - }, -} - - -// Retrieve the user's home directory. -func userHome() string { - u, err := user.Current() - - // I don't think we can go on without finding the user's home directory - if err != nil { - panic(err) - } - - return u.HomeDir -} - -// Retrieve the user's config home, which is either defined through the environment variable -// `XDG_CONFIG_HOME` or is assumed to be a folder called `.config` in the user's home -// directory (as retrieved by `userHome()`). -func configHome() string { - value, present := os.LookupEnv("XDG_CONFIG_HOME") - - configHome := value - - if !present || value == "" || !filepath.IsAbs(value) { - configHome = filepath.Join(userHome(), ".config") - } - - return configHome -} - -// Expand `~/`, if the working directory begins with it. -func expandTilde(conf *Configuration) { - workdir := conf.Get(CONF_WORKDIR) - - if len(workdir) > 1 && workdir[0:2] == "~/" { - conf.Set(CONF_WORKDIR, filepath.Join(userHome(), workdir[2:])) - } else if len(workdir) == 1 && workdir == "~" { - conf.Set(CONF_WORKDIR, userHome()) - } -} - -// This will create all necessary folders in the working directory. -func createFolders(workdir string) error { - for _, dir := range []string{DIR_TODO, DIR_DONE, DIR_ERRORS, DIR_DRAFTS} { - err := os.MkdirAll(filepath.Join(workdir, dir), 0777) - - if err != nil { - return err - } - } - - return nil -} - -// Complain about files in DIR_ERRORS. -func alertIfErrors(workdir string) { - errorsDir := filepath.Join(workdir, DIR_ERRORS) - - count := 0 - - filepath.Walk(errorsDir, func(_ string, info os.FileInfo, _ error) error { - if info.Mode().IsRegular() { - count++ - } - - return nil - }) - - if count > 0 { - fmt.Println("There were failed messages.") - fmt.Printf("Please inspect the contents of the %s/ directory.\n", DIR_ERRORS) - } -} - -func main() { - userHome := userHome() - - // This is the configuration that will be cobbled together from the - // default configuration ('defaultConf'), the INI and the command line - // arguments. - sessionConf := NewConfiguration() - - sessionConf.MergeWith(&defaultConf) - - args, _ := docopt.Parse(usageMain, nil, true, "", true) - - // Determine configuration file name, defaults to `clockrotz.ini` in - // the user's config home (usually `.config`). - if args["--config"] != nil { - sessionConf.Set(CONF_CONFIG_FILENAME, args["--config"].(string)) - } else { - sessionConf.Set(CONF_CONFIG_FILENAME, filepath.Join(configHome(), "clockrotz.ini")) - } - - // Determine the desired command (run, next, ...) - command := args[""].(string) - - // Load INI configuration. This will merge the '[default]' section with - // the optional section named after the desired command ('cmd'). - sessionConf.MergeWithIni(command) - - // Determine working directory, defaults to the folder `clockrotz` in - // the user's home directory. '--workdir' on the command line takes - // precedence over the 'workdir' in the INI. - if args["--workdir"] != nil { - sessionConf.Set(CONF_WORKDIR, args["--workdir"].(string)) - } else { - // If no working directory is set in the INI... - if sessionConf.Get(CONF_WORKDIR) == "" { - sessionConf.Set(CONF_WORKDIR, filepath.Join(userHome, "clockrotz")) - } - } - - // Expand the `~/` in workdir. - expandTilde(sessionConf) - - // Make sure that all necessary folders exist. - createFolders(sessionConf.Get(CONF_WORKDIR)) - - // See if there are files in DIR_ERRORS and alert the user. - alertIfErrors(sessionConf.Get(CONF_WORKDIR)) - - commandArgs := []string{command} - commandArgs = append(commandArgs, args[""].([]string)...) - - switch command { - case "next": - cmd.Next(commandArgs, sessionConf) - case "create": - cmd.Create(commandArgs, sessionConf) - case "check": - cmd.Check(commandArgs, sessionConf) - case "run": - cmd.Run(commandArgs, sessionConf) - case "debug": - cmd.Debug(commandArgs, sessionConf) - } -} \ No newline at end of file diff --git a/clockrotz_test.go b/clockrotz_test.go deleted file mode 100644 index 325438c..0000000 --- a/clockrotz_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "github.com/stretchr/testify/assert" - "testing" - . "github.com/githubert/clockrotz/common" -) - -func TestExpandTilde(t *testing.T) { - c := NewConfiguration() - - c.Set(CONF_WORKDIR, "/foo") - expandTilde(c) - assert.Equal(t, "/foo", c.Get(CONF_WORKDIR)) - - c.Set(CONF_WORKDIR, "~/foo") - expandTilde(c) - assert.Equal(t, userHome() + "/foo", c.Get(CONF_WORKDIR)) - - // Shortest possible - c.Set(CONF_WORKDIR, "~/") - expandTilde(c) - assert.Equal(t, userHome(), c.Get(CONF_WORKDIR)) - - // Single character workdir with only a tilde - c.Set(CONF_WORKDIR, "~") - expandTilde(c) - assert.Equal(t, userHome(), c.Get(CONF_WORKDIR)) - - // Ignored tilde - c.Set(CONF_WORKDIR, "~test") - expandTilde(c) - assert.Equal(t, "~test", c.Get(CONF_WORKDIR)) -} \ No newline at end of file diff --git a/cmd/check.go b/cmd/check.go index e825d29..6f8e0be 100644 --- a/cmd/check.go +++ b/cmd/check.go @@ -20,7 +20,7 @@ package cmd import ( "fmt" "github.com/docopt/docopt.go" - . "github.com/githubert/clockrotz/common" + . "github.com/githubert/lettersnail/common" "os" "path/filepath" "sort" @@ -30,7 +30,7 @@ var usageCheck = // tag::check[] ` Usage: - clockrotz check [--silent] [FILE] + lettersnail check [--silent] [FILE] Options: --silent Suppress output, useful for silent checks. diff --git a/cmd/create.go b/cmd/create.go index ee682fa..95bbdc9 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -21,7 +21,7 @@ import ( "bufio" "fmt" "github.com/docopt/docopt.go" - . "github.com/githubert/clockrotz/common" + . "github.com/githubert/lettersnail/common" "io/ioutil" "os" "os/exec" @@ -34,7 +34,7 @@ var usageCreate = // tag::create[] ` Usage: - clockrotz create [--draft=FILE] [options] + lettersnail create [--draft=FILE] [options] Options: --help Show this help. @@ -50,7 +50,7 @@ Options: func Create(argv []string, conf *Configuration) { args, _ := docopt.Parse(usageCreate, argv, true, "", false) - tmpFile, err := ioutil.TempFile("", "clockrotz") + tmpFile, err := ioutil.TempFile("", "lettersnail") if err != nil { fmt.Printf("Error while creating temporary file: %s\n", err.Error()) diff --git a/cmd/debug.go b/cmd/debug.go index 343f0be..8873ac2 100644 --- a/cmd/debug.go +++ b/cmd/debug.go @@ -20,7 +20,7 @@ package cmd import ( "fmt" "github.com/docopt/docopt.go" - . "github.com/githubert/clockrotz/common" + . "github.com/githubert/lettersnail/common" "os" ) @@ -28,7 +28,7 @@ var usageDebug = // tag::debug[] ` Usage: - clockrotz debug FILENAME + lettersnail debug FILENAME Options: --help Show this help. diff --git a/cmd/next.go b/cmd/next.go index 15464bd..ff32ec0 100644 --- a/cmd/next.go +++ b/cmd/next.go @@ -20,7 +20,7 @@ package cmd import ( "fmt" "github.com/docopt/docopt.go" - . "github.com/githubert/clockrotz/common" + . "github.com/githubert/lettersnail/common" "path/filepath" "sort" "strconv" @@ -31,7 +31,7 @@ var usageNext = // tag::next[] ` Usage: - clockrotz next [--days=DAYS | --all] + lettersnail next [--days=DAYS | --all] Options: --help Show this help. @@ -72,7 +72,7 @@ func Next(argv []string, conf *Configuration) { message.Conf.MergeWith(conf) if errs := message.Verify(); errs != nil { - fmt.Printf("Error in message \"%s\". Please run 'clockrotz check'.\n", message.Name) + fmt.Printf("Error in message \"%s\". Please run 'lettersnail check'.\n", message.Name) continue } diff --git a/cmd/run.go b/cmd/run.go index 43ca6d7..11ba560 100644 --- a/cmd/run.go +++ b/cmd/run.go @@ -21,7 +21,7 @@ import ( "crypto/tls" "fmt" "github.com/docopt/docopt.go" - . "github.com/githubert/clockrotz/common" + . "github.com/githubert/lettersnail/common" "github.com/jordan-wright/email" "net/mail" "net/textproto" @@ -35,7 +35,7 @@ var usageRun = // tag::run[] ` Usage: - clockrotz run [options] + lettersnail run [options] Options: --help Show this help. @@ -103,7 +103,7 @@ func Run(argv []string, conf *Configuration) { if verificationError { // FIXME: This suggests that other messages were not sent, but they were.... fmt.Println("There were errors when verifying one or more messages.") - fmt.Println("Please run 'clockrotz check'") + fmt.Println("Please run 'lettersnail check'") os.Exit(1) } } diff --git a/lettersnail.go b/lettersnail.go new file mode 100644 index 0000000..0a211fd --- /dev/null +++ b/lettersnail.go @@ -0,0 +1,197 @@ +/* lettersnail.go: main program + * + * Copyright (C) 2016-2018 Clemens Fries + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package main + +import ( + "fmt" + "github.com/docopt/docopt.go" + "os" + "os/user" + "path/filepath" + "github.com/githubert/lettersnail/cmd" + . "github.com/githubert/lettersnail/common" +) + + +var usageMain = +// tag::main[] +` +Usage: + lettersnail [options] [...] + +Options: + --workdir=WORKDIR Working directory, defaults to $HOME/lettersnail + --config=CONFIG Use the given INI file instead of .config/lettersnail.ini + --help Show this help. + +The following commands are available: + next Show messages due in the next days. + check Check if a message is complete. + debug Print the effective configuration for a message, and the resulting + email message. + create Open a new message in an editor. + run Send out pending messages. +` // end::main[] + +var defaultConf = Configuration{ + Data: map[string]string{ + CONF_DAYS: "7", + CONF_SMTP_PORT: "587", + CONF_SMTP_SERVER: "localhost", + CONF_NOT_BEFORE: "00:00", + CONF_NOT_AFTER: "23:59", + }, +} + + +// Retrieve the user's home directory. +func userHome() string { + u, err := user.Current() + + // I don't think we can go on without finding the user's home directory + if err != nil { + panic(err) + } + + return u.HomeDir +} + +// Retrieve the user's config home, which is either defined through the environment variable +// `XDG_CONFIG_HOME` or is assumed to be a folder called `.config` in the user's home +// directory (as retrieved by `userHome()`). +func configHome() string { + value, present := os.LookupEnv("XDG_CONFIG_HOME") + + configHome := value + + if !present || value == "" || !filepath.IsAbs(value) { + configHome = filepath.Join(userHome(), ".config") + } + + return configHome +} + +// Expand `~/`, if the working directory begins with it. +func expandTilde(conf *Configuration) { + workdir := conf.Get(CONF_WORKDIR) + + if len(workdir) > 1 && workdir[0:2] == "~/" { + conf.Set(CONF_WORKDIR, filepath.Join(userHome(), workdir[2:])) + } else if len(workdir) == 1 && workdir == "~" { + conf.Set(CONF_WORKDIR, userHome()) + } +} + +// This will create all necessary folders in the working directory. +func createFolders(workdir string) error { + for _, dir := range []string{DIR_TODO, DIR_DONE, DIR_ERRORS, DIR_DRAFTS} { + err := os.MkdirAll(filepath.Join(workdir, dir), 0777) + + if err != nil { + return err + } + } + + return nil +} + +// Complain about files in DIR_ERRORS. +func alertIfErrors(workdir string) { + errorsDir := filepath.Join(workdir, DIR_ERRORS) + + count := 0 + + filepath.Walk(errorsDir, func(_ string, info os.FileInfo, _ error) error { + if info.Mode().IsRegular() { + count++ + } + + return nil + }) + + if count > 0 { + fmt.Println("There were failed messages.") + fmt.Printf("Please inspect the contents of the %s/ directory.\n", DIR_ERRORS) + } +} + +func main() { + userHome := userHome() + + // This is the configuration that will be cobbled together from the + // default configuration ('defaultConf'), the INI and the command line + // arguments. + sessionConf := NewConfiguration() + + sessionConf.MergeWith(&defaultConf) + + args, _ := docopt.Parse(usageMain, nil, true, "", true) + + // Determine configuration file name, defaults to `lettersnail.ini` in + // the user's config home (usually `.config`). + if args["--config"] != nil { + sessionConf.Set(CONF_CONFIG_FILENAME, args["--config"].(string)) + } else { + sessionConf.Set(CONF_CONFIG_FILENAME, filepath.Join(configHome(), "lettersnail.ini")) + } + + // Determine the desired command (run, next, ...) + command := args[""].(string) + + // Load INI configuration. This will merge the '[default]' section with + // the optional section named after the desired command ('cmd'). + sessionConf.MergeWithIni(command) + + // Determine working directory, defaults to the folder `lettersnail` in + // the user's home directory. '--workdir' on the command line takes + // precedence over the 'workdir' in the INI. + if args["--workdir"] != nil { + sessionConf.Set(CONF_WORKDIR, args["--workdir"].(string)) + } else { + // If no working directory is set in the INI... + if sessionConf.Get(CONF_WORKDIR) == "" { + sessionConf.Set(CONF_WORKDIR, filepath.Join(userHome, "lettersnail")) + } + } + + // Expand the `~/` in workdir. + expandTilde(sessionConf) + + // Make sure that all necessary folders exist. + createFolders(sessionConf.Get(CONF_WORKDIR)) + + // See if there are files in DIR_ERRORS and alert the user. + alertIfErrors(sessionConf.Get(CONF_WORKDIR)) + + commandArgs := []string{command} + commandArgs = append(commandArgs, args[""].([]string)...) + + switch command { + case "next": + cmd.Next(commandArgs, sessionConf) + case "create": + cmd.Create(commandArgs, sessionConf) + case "check": + cmd.Check(commandArgs, sessionConf) + case "run": + cmd.Run(commandArgs, sessionConf) + case "debug": + cmd.Debug(commandArgs, sessionConf) + } +} \ No newline at end of file diff --git a/lettersnail_test.go b/lettersnail_test.go new file mode 100644 index 0000000..0b2bdbe --- /dev/null +++ b/lettersnail_test.go @@ -0,0 +1,34 @@ +package main + +import ( + "github.com/stretchr/testify/assert" + "testing" + . "github.com/githubert/lettersnail/common" +) + +func TestExpandTilde(t *testing.T) { + c := NewConfiguration() + + c.Set(CONF_WORKDIR, "/foo") + expandTilde(c) + assert.Equal(t, "/foo", c.Get(CONF_WORKDIR)) + + c.Set(CONF_WORKDIR, "~/foo") + expandTilde(c) + assert.Equal(t, userHome() + "/foo", c.Get(CONF_WORKDIR)) + + // Shortest possible + c.Set(CONF_WORKDIR, "~/") + expandTilde(c) + assert.Equal(t, userHome(), c.Get(CONF_WORKDIR)) + + // Single character workdir with only a tilde + c.Set(CONF_WORKDIR, "~") + expandTilde(c) + assert.Equal(t, userHome(), c.Get(CONF_WORKDIR)) + + // Ignored tilde + c.Set(CONF_WORKDIR, "~test") + expandTilde(c) + assert.Equal(t, "~test", c.Get(CONF_WORKDIR)) +} \ No newline at end of file -- cgit