Skip to content

Commit

Permalink
Merge pull request #13 from DrakeW/develop
Browse files Browse the repository at this point in the history
v0.2.1 develop to master
  • Loading branch information
junyu-w committed Jun 8, 2018
2 parents e742c9d + 5b6e7e2 commit f85db99
Show file tree
Hide file tree
Showing 17 changed files with 471 additions and 97 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@
*.test

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

# build
build/*
19 changes: 19 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
.PHONY: all dep build build-darwin build-linux

VERSION := $(shell git describe --tags --abbrev=0)

all: dep build

dep:
dep ensure

prep-build:
mkdir -p build

build-darwin: main.go dep prep-build
env GOOS=darwin GOARCH=amd64 go build -o build/corgi_$(VERSION)_darwin_amd64

build-linux: main.go dep prep-build
env GOOS=linux GOARCH=amd64 go build -o build/corgi_$(VERSION)_linux_amd64

build: build-darwin build-linux
97 changes: 73 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

Corgi is a command-line tool that helps with your repetitive command usages by organizing them into reusable snippet. See usage by simply running `corgi` or `corgi --help`

Current version: **v0.2.0-alpha**
Current version: **v0.2.1**
## Examples

Create a new snippet to automate the commands you run repetitively
Expand All @@ -18,24 +18,40 @@ Execute an existing snippet knowing what command is being run and its output
# Table of Contents

- [Installation](#installation)
- [Install corgi](#install-corgi)
- [Binary](#binary)
- [Homebrew](#homebrew)
- [Install a fuzzy-finder](#install-a-fuzzy-finder)
- [Features](#features)
- [Create a snippet](#create-a-snippet)
- [List snippets](#list-snippets)
- [Describe a snippet](#describe-a-snippet)
- [Execute a snippet](#execute-a-snippet)
- [Use default value without prompt](#use-default-value-without-prompt)
- [Select steps to execute](#select-steps-to-execute)
- [Interactive snippet selection](#interactive-snippet-selection)
- [Edit a snippet](#edit-a-snippet)
- [Describe a snippet](#describe-a-snippet)
- [Share snippets](#share-snippets)
- [Remove a snippet](#remove-a-snippet)
- [Configure corgi](#configure-corgi)
- [Roadmap](#roadmap)
- [Note](#note)

## Installation
## Installation

### Install `corgi`

#### Binary
Since this project is still in its very early phase, installation via package managers like `brew` or `apt-get` is not supported. Here are the steps to follow if you would like to try it out:
1. Download the latest `corgi` executable from releases tab
2. `chmod a+x ./corgi` to give execution permission to all users & groups
3. (Optional) If you already have a previous release of corgi installed, remove the soft link in your `bin` folder first
4. Create a soft link of the `corgi` executable to your local `bin` folder - (if you are on Mac, you can use `ln -s $(pwd)/corgi /usr/local/bin/corgi`)
5. Start `Corgi`ing
1. Download the latest executable from [releases](https://github.com/DrakeW/corgi/releases) based on your system (currently support linux and macOS).
2. Rename it to `corgi` and make sure the execution bit is turned on (`chmod u+x ./corgi`)
3. Put it into your `bin` folder or create a softlink with `ln -s $(pwd)/corgi <your bin folder>/bin`

#### Homebrew
Corgi is still sprinting towards Homebrew, stay tuned

### Install a fuzzy-finder
`corgi` will enable interactive selection if you install a fuzzy finder, the currently supported two are [fzf](https://github.com/junegunn/fzf) and [peco](https://github.com/peco/peco).

## Features
To view usage of a specific action, run `corgi <action> --help`
Expand All @@ -49,51 +65,84 @@ If you would like to quickly combine the last couple commands you just executed
```
corgi new --last <number of commands to look back>
```
Furthermore, you could also save a command template (with or without default value) as part of the snippet and reuse the same parameter, for example:
Furthermore, you could also add template fields (with or without default value) to command of a step and reuse the same field, for example:
```
tar -xzf <project>.tgz && scp <project> <user=ec2-user>@<ec2-instance-address>:~/
```
And you can enter the values for those parameters when the snippet executes.
And you will be prompted to enter values for those fields when the snippet executes. The value set for the same field name will be applied to **all steps** in a snippet, so you don't have to enter multiple times.

Also if you have field with **multiple default values**, the latest appearance will take precedence over the previous values.


### List snippets
To view all snippets saved on your system, run
```
corgi list
```

### Describe a snippet
To see the details of a snippet, you can run
```
corgi describe <title of the snippet>
```
And it will print out each step of the snippet so that you don't have to memorize them.

### Execute a snippet
### Execute a snippet
To execute a snippet, simply run
```
corgi exec <title of the snippet>
corgi exec [<title of the snippet>] [--use-default] [--step <step range>]
```
Your commands will run smoothly just as they were being run on a terminal directly, and any prompt that asks for input (for example, password prompt when you `ssh` into a remote server) will work seamlessly as well.

Also note that if you run `cd` command in one of the steps, the current working directory will not change for subsequent steps. But you can always put `cd <target dir> && <do something else>` to get commands executed inside of your target directory.

Also note that if you run `cd` command in one of the steps, the current working directory will not change for subsequent steps. But you can always put `cd <target dir> && <do something else>` to get commands executed inside of your target directory.

#### Use default value without prompt
if `--use-default` is set, then the snippet will execute without asking explicitly for user to set a value for template fields defined, but if there are missing default values, the snippet will fail fast and tell you what fields are missed.

#### Select steps to execute
You can use the `--step` (or `-s`) flag to specify the steps (starting from index 1) you want to execute, for example
```
--step 3 # will only execute step 3
--step 3-5 # will execute step 3 to 5
--step 3- # will execute step 3 to the last step
```
This can be particularly useful when your workflow fail midway, but you don't want to start the whole workflow from step 1 again.

#### Interactive snippet selection
This feature will guide you through the darkness if you don't have the title of your snippet memorized. Simply type
```
corgi exec [with or without options]
```
and you will be presented an interactive interface to fuzzy-find your snippet (To enable this feature, see [installation instruction](#install-a-fuzzy-finder))

<img src="images/corgi-fuzzy-select.gif" width="700">


### Edit a snippet
To edit a snippet, run
```
corgi edit <title of the snippet>
corgi edit [<title of the snippet>]
```
You'll be able to edit the snippet json file directly with your preferred editor (configurable via `corgi config` command, details see below)

Furthermore, `edit` also provides [fuzzy finding capabilities](#interactive-snippet-selection) when you omit the snippet title.

### Describe a snippet
To see the details of a snippet, you can run (without title will yield interactive title selection)
```
corgi describe [<title of the snippet>]
```
And it will print out each step of the snippet so that you don't have to memorize them.

### Share snippets
If someone shares his/her snippet json file(s) with you, you can import it by running
```
corgi import <snippet json file 1> [<snippet json file 2>...]
```
And similarly, if you already have a workflow defined in a snippet, you can easily share it by exporting via
And similarly, if you already have a workflow defined in a snippet, you can easily share it by exporting via (without title will yield interactive title selection)
```
corgi export <title of the snippet> [-o <output file path>]
corgi export [<title of the snippet>] [-o <output file path>]
```
and send the json file to another person

### Remove a snippet
You can remove a snippet by running (without title will yield interactive title selection)
```
corgi remove [<title of the snippet>]
```

### Configure `corgi`
Currently the only editable option is your text editor choice (default is `vim`), to configure the corgi CLI, run
Expand Down
16 changes: 13 additions & 3 deletions cmd/describe.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,26 @@ import "github.com/spf13/cobra"
var describeCmd = &cobra.Command{
Use: "describe",
Short: "Describe a snippet",
Args: cobra.ExactArgs(1),
Args: cobra.MaximumNArgs(1),
RunE: describe,
}

func describe(cmd *cobra.Command, args []string) error {
title := args[0]
_, snippetsMeta, err := loadConfigAndSnippetsMeta()
conf, snippetsMeta, err := loadConfigAndSnippetsMeta()
if err != nil {
return err
}
// find snippet title
var title string
if len(args) == 0 {
title, err = filterSnippetTitle(conf.FilterCmd, snippetsMeta.GetSnippetTitles())
if err != nil {
return err
}
} else {
title = args[0]
}
// find snippet
s, err := snippetsMeta.FindSnippet(title)
if err != nil {
return err
Expand Down
24 changes: 16 additions & 8 deletions cmd/edit.go
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
package cmd

import (
"corgi/util"
"fmt"
"github.com/spf13/cobra"
"os"
"os/exec"
)

var editCmd = &cobra.Command{
Use: "edit",
Short: "Edit a snippet",
Args: cobra.ExactArgs(1),
Args: cobra.MaximumNArgs(1),
RunE: edit,
}

func edit(cmd *cobra.Command, args []string) error {
title := args[0]
// load config & snippets
config, snippets, err := loadConfigAndSnippetsMeta()
conf, snippets, err := loadConfigAndSnippetsMeta()
if err != nil {
return err
}
// find snippet title
var title string
if len(args) == 0 {
title, err = filterSnippetTitle(conf.FilterCmd, snippets.GetSnippetTitles())
if err != nil {
return err
}
} else {
title = args[0]
}
// find snippet
s, err := snippets.FindSnippet(title)
if err != nil {
return err
}
editFileCmd := exec.Command(config.Editor, s.GetFilePath())
editFileCmd.Stdin = os.Stdin
editFileCmd.Stdout = os.Stdout
if err := editFileCmd.Run(); err != nil {
command := fmt.Sprintf("%s %s", conf.Editor, s.GetFilePath())
if err := util.Execute(command, os.Stdin, os.Stdout); err != nil {
return err
}
return nil
Expand Down
24 changes: 19 additions & 5 deletions cmd/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,40 @@ import (
var execCmd = &cobra.Command{
Use: "exec",
Short: "Execute a snippet",
Args: cobra.ExactArgs(1),
Args: cobra.MaximumNArgs(1),
RunE: execute,
}

var useDefaultParamValue bool
var stepRange string

func execute(cmd *cobra.Command, args []string) error {
title := args[0]
// load config & snippets
_, snippets, err := loadConfigAndSnippetsMeta()
conf, snippetsMeta, err := loadConfigAndSnippetsMeta()
if err != nil {
return err
}
// find snippet title
var title string
if len(args) == 0 {
title, err = filterSnippetTitle(conf.FilterCmd, snippetsMeta.GetSnippetTitles())
if err != nil {
return err
}
} else {
title = args[0]
}
// find snippet corresponds to title
s, err := snippets.FindSnippet(title)
s, err := snippetsMeta.FindSnippet(title)
if err != nil {
return fmt.Errorf("%s, run \"corgi list\" to view all snippets", err.Error())
}
s.Execute()
s.Execute(useDefaultParamValue, stepRange)
return nil
}

func init() {
execCmd.Flags().StringVarP(&stepRange, "step", "s", "", "Select a single step to execute with \"-s <step>\" or a range of steps to execute with \"-s <start>-<end>\", end is optional")
execCmd.Flags().BoolVar(&useDefaultParamValue, "use-default", false, "Add this flag if you would like to use the default values for your defined template fields without being asked to enter a value")
rootCmd.AddCommand(execCmd)
}
16 changes: 13 additions & 3 deletions cmd/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,28 @@ import (
var exportCmd = &cobra.Command{
Use: "export",
Short: "Export a snippet to json file",
Args: cobra.ExactArgs(1),
Args: cobra.MaximumNArgs(1),
RunE: export,
}

var outputFile string

func export(cmd *cobra.Command, args []string) error {
title := args[0]
_, snippetsMeta, err := loadConfigAndSnippetsMeta()
conf, snippetsMeta, err := loadConfigAndSnippetsMeta()
if err != nil {
return err
}
// find snippet title
var title string
if len(args) == 0 {
title, err = filterSnippetTitle(conf.FilterCmd, snippetsMeta.GetSnippetTitles())
if err != nil {
return err
}
} else {
title = args[0]
}
// find snippet
s, err := snippetsMeta.FindSnippet(title)
if err != nil {
return err
Expand Down
35 changes: 35 additions & 0 deletions cmd/remove.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package cmd

import "github.com/spf13/cobra"

var removeCmd = &cobra.Command{
Use: "remove",
Short: "Remove a snippet",
Args: cobra.MaximumNArgs(1),
RunE: remove,
}

func remove(cmd *cobra.Command, args []string) error {
conf, snippetsMeta, err := loadConfigAndSnippetsMeta()
if err != nil {
return err
}
// find snippet title
var title string
if len(args) == 0 {
title, err = filterSnippetTitle(conf.FilterCmd, snippetsMeta.GetSnippetTitles())
if err != nil {
return err
}
} else {
title = args[0]
}
if err = snippetsMeta.DeleteSnippet(title); err != nil {
return err
}
return nil
}

func init() {
rootCmd.AddCommand(removeCmd)
}
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"os"
)

var appVersion = "v0.2.0-alpha"
var appVersion = "v0.2.1"

var rootCmd = &cobra.Command{
Use: "corgi",
Expand Down
Loading

0 comments on commit f85db99

Please sign in to comment.