Skip to content

Commit

Permalink
Merge pull request #3 from kernle32dll/tagging
Browse files Browse the repository at this point in the history
Implement tag adding and removal via commands
  • Loading branch information
kernle32dll authored Oct 14, 2020
2 parents db6bdb9 + 8620e90 commit d1c6cc7
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 33 deletions.
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
ew - short for `(run things) e(very)w(here)` is a tool for grouping folders by tags,
and executing tasks in all folders via these tags.

**Note**: Currently it is not possible to add or remove folders to tags via the cli.
See paragraph "Config" below, to see how to do this manually.

## Quickstart

You need a working installation of the Go tooling for installation:
Expand Down Expand Up @@ -49,10 +46,10 @@ ew paths | list all paths (alias for ew paths list)
ew paths list | list all paths
ew tags | list all tags (alias for ew tags list)
ew tags list | list all tags
ew tags add @some-tag | add current directory to tag "some-tag" (NOT YET IMPLEMENTED)
ew tags add \some\path @some-tag | add \some\path to tag "some-tag" (NOT YET IMPLEMENTED)
ew tags rm @some-tag | add current directory to tag "some-tag" (NOT YET IMPLEMENTED)
ew tags rm \some\path @some-tag | add \some\path to tag "some-tag" (NOT YET IMPLEMENTED)
ew tags add @some-tag | add current directory to tag "some-tag"
ew tags add \some\path @some-tag | add \some\path to tag "some-tag"
ew tags rm @some-tag | add current directory to tag "some-tag"
ew tags rm \some\path @some-tag | add \some\path to tag "some-tag"
ew status | show quick git status for all paths
ew @tag1 status | show quick git status for all paths of tag1 (supports multiple tags)
ew @tag1 some-cmd | executes some-cmd in all paths of tag1 (supports multiple tags)
Expand Down
89 changes: 89 additions & 0 deletions internal/cmd/cmd_add_paths.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package cmd

import (
"github.com/kernle32dll/ew/internal"

"errors"
"fmt"
"io"
"os"
"strings"
)

// AddPathsCommand adds one or multiple paths to a tag.
type AddPathsCommand struct {
output io.Writer
config internal.Config
args []string
}

// NewAddPathsCommand creates a new AddPathsCommand.
func NewAddPathsCommand(
output io.Writer,
config internal.Config,
args []string,
) *AddPathsCommand {
return &AddPathsCommand{
output: output,
config: config,
args: args,
}
}

func (c AddPathsCommand) Execute() error {
if len(c.args) == 0 {
return errors.New("missing @tag to add path to")
}

// Current path to tag
if len(c.args) == 1 {
return c.addCurrentPath()
}

// Multiple paths
return c.addPaths()
}

func (c AddPathsCommand) addPaths() error {
tag := c.args[len(c.args)-1]
if !strings.HasPrefix(tag, "@") {
return fmt.Errorf("expected @tag for last argument, got %q", tag)
}
tag = strings.TrimPrefix(tag, "@")

paths := c.args[:1]

c.config.AddPathsToTag(tag, paths...)

if _, err := c.config.ReWriteConfig(); err != nil {
return err
}

fmt.Fprintf(c.output, "Added paths to tag @%s:\n", tag)
for _, path := range paths {
fmt.Fprintf(c.output, " %s\n", path)
}
return nil
}

func (c AddPathsCommand) addCurrentPath() error {
tag := c.args[0]
if !strings.HasPrefix(tag, "@") {
return fmt.Errorf("expected @tag, got %q", tag)
}
tag = strings.TrimPrefix(tag, "@")

path, err := os.Getwd()
if err != nil {
return err
}

c.config.AddPathsToTag(tag, path)

if _, err := c.config.ReWriteConfig(); err != nil {
return err
}

fmt.Fprintf(c.output, "Added path %s to tag @%s\n", path, tag)
return nil
}
11 changes: 4 additions & 7 deletions internal/cmd/cmd_help.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package cmd

import (
"github.com/fatih/color"

"fmt"
"io"
"strings"
Expand Down Expand Up @@ -32,7 +30,6 @@ func (c HelpCommand) Execute() error {
fmt.Fprintln(c.output)
fmt.Fprintln(c.output, "Available commands:")

nyi := color.RedString(" (NOT YET IMPLEMENTED)")
cmds := [][]string{
{"ew", "list all paths, grouped by their tags"},
{"ew help", "displays this help"},
Expand All @@ -45,10 +42,10 @@ func (c HelpCommand) Execute() error {
{"ew paths list", "list all paths"},
{"ew tags", "list all tags (alias for ew tags list)"},
{"ew tags list", "list all tags"},
{"ew tags add @some-tag", "add current directory to tag \"some-tag\"" + nyi},
{"ew tags add \\some\\path @some-tag", "add \\some\\path to tag \"some-tag\"" + nyi},
{"ew tags rm @some-tag", "add current directory to tag \"some-tag\"" + nyi},
{"ew tags rm \\some\\path @some-tag", "add \\some\\path to tag \"some-tag\"" + nyi},
{"ew tags add @some-tag", "add current directory to tag \"some-tag\""},
{"ew tags add \\some\\path @some-tag", "add \\some\\path to tag \"some-tag\""},
{"ew tags rm @some-tag", "add current directory to tag \"some-tag\""},
{"ew tags rm \\some\\path @some-tag", "add \\some\\path to tag \"some-tag\""},
{"ew status", "show quick git status for all paths"},
{"ew @tag1 status", "show quick git status for all paths of tag1 (supports multiple tags)"},
{"ew @tag1 some-cmd", "executes some-cmd in all paths of tag1 (supports multiple tags)"},
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/cmd_migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func (c MigrateCommand) Execute() error {
conf.Source = internal.YamlSrc
}

migratedPath, err := conf.WriteConfig(home)
migratedPath, err := conf.ReWriteConfig()
if err != nil {
return err
}
Expand Down
89 changes: 89 additions & 0 deletions internal/cmd/cmd_rm_paths.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package cmd

import (
"github.com/kernle32dll/ew/internal"

"errors"
"fmt"
"io"
"os"
"strings"
)

// RmPathsCommand removes one or multiple paths from a tag.
type RmPathsCommand struct {
output io.Writer
config internal.Config
args []string
}

// NewRmPathsCommand creates a new RmPathsCommand.
func NewRmPathsCommand(
output io.Writer,
config internal.Config,
args []string,
) *RmPathsCommand {
return &RmPathsCommand{
output: output,
config: config,
args: args,
}
}

func (c RmPathsCommand) Execute() error {
if len(c.args) == 0 {
return errors.New("missing @tag to remove path from")
}

// Current path from tag
if len(c.args) == 1 {
return c.rmCurrentPath()
}

// Multiple paths
return c.rmPaths()
}

func (c RmPathsCommand) rmPaths() error {
tag := c.args[len(c.args)-1]
if !strings.HasPrefix(tag, "@") {
return fmt.Errorf("expected @tag for last argument, got %q", tag)
}
tag = strings.TrimPrefix(tag, "@")

paths := c.args[:1]

c.config.RemovePathsFromTag(tag, paths...)

if _, err := c.config.ReWriteConfig(); err != nil {
return err
}

fmt.Fprintf(c.output, "Removed paths from tag @%s:\n", tag)
for _, path := range paths {
fmt.Fprintf(c.output, " %s\n", path)
}
return nil
}

func (c RmPathsCommand) rmCurrentPath() error {
tag := c.args[0]
if !strings.HasPrefix(tag, "@") {
return fmt.Errorf("expected @tag, got %q", tag)
}
tag = strings.TrimPrefix(tag, "@")

path, err := os.Getwd()
if err != nil {
return err
}

c.config.RemovePathsFromTag(tag, path)

if _, err := c.config.ReWriteConfig(); err != nil {
return err
}

fmt.Fprintf(c.output, "Removing path %s from tag @%s\n", path, tag)
return nil
}
7 changes: 2 additions & 5 deletions internal/cmd/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cmd
import (
"github.com/kernle32dll/ew/internal"

"errors"
"io"
"strings"
)
Expand Down Expand Up @@ -40,12 +39,10 @@ func ParseCommand(output io.Writer, conf internal.Config, args []string) (Comman
}

if args[1] == "add" {
//&ListPathsCommand{config: conf}.Execute()
return nil, errors.New("tag adding not implemented yet")
return NewAddPathsCommand(output, conf, args[2:]), nil
}
if args[1] == "rm" {
//&ListPathsCommand{config: conf}.Execute()
return nil, errors.New("tag adding not implemented yet")
return NewRmPathsCommand(output, conf, args[2:]), nil
}
}

Expand Down
75 changes: 70 additions & 5 deletions internal/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package internal

import (
"encoding/json"
"errors"
"os"
"path/filepath"
"sort"
Expand All @@ -25,13 +26,63 @@ type encodable interface {
// Config contains all runtime configuration for ew, such as
// available tags.
type Config struct {
Source ReadSource `json:"-" yaml:"-"`
Tags Tags `json:"tags" yaml:"tags"`
Source ReadSource `json:"-" yaml:"-"`
LoadedFrom string `json:"-" yaml:"-"`
Tags Tags `json:"tags" yaml:"tags"`
}

// Tags is a convenience wrapper around map[string][]string
type Tags map[string][]string

// AddPathsToTag adds a list of paths to a tag.
func (c *Config) AddPathsToTag(tag string, paths ...string) {
if len(paths) == 0 {
return
}

c.Tags[tag] = deDuplicateAndSort(append(c.Tags[tag], paths...))
}

// RemovePathsFromTag removes a list of paths from a tag.
func (c *Config) RemovePathsFromTag(tag string, paths ...string) {
if len(paths) == 0 {
return
}

// Prepare full array size, and splice later
newTags := make([]string, len(c.Tags[tag]))
i, rmCount := 0, 0
for _, path := range c.Tags[tag] {
if contains(paths, path) {
rmCount++
continue
}

newTags[i] = path
i++
}

c.Tags[tag] = newTags[:len(newTags)-rmCount]
}

func deDuplicateAndSort(keys []string) []string {
table := make(map[string]struct{}, len(keys))
for _, key := range keys {
table[key] = struct{}{}
}

deduped := make([]string, len(table))
i := 0
for key := range table {
deduped[i] = key
i++
}

sort.Strings(deduped)

return deduped
}

// GetTagsSorted returns a sorted list of configured tags.
func (c Config) GetTagsSorted() []string {
if len(c.Tags) == 0 {
Expand Down Expand Up @@ -153,7 +204,7 @@ func ParseConfigFromFolder(path string) Config {
}

// If no config is found, use default yaml
return Config{Source: YamlSrc}
return Config{Source: YamlSrc, LoadedFrom: path}
}

func parseConfigFromYaml(path string) (Config, error) {
Expand All @@ -166,7 +217,8 @@ func parseConfigFromYaml(path string) (Config, error) {
decoder := yaml.NewDecoder(f)

config := Config{
Source: YamlSrc,
Source: YamlSrc,
LoadedFrom: path,
}
if err := decoder.Decode(&config); err != nil {
return Config{}, err
Expand All @@ -185,7 +237,8 @@ func parseConfigFromJson(path string) (Config, error) {
decoder := json.NewDecoder(f)

config := Config{
Source: JsonSrc,
Source: JsonSrc,
LoadedFrom: path,
}
if err := decoder.Decode(&config); err != nil {
return Config{}, err
Expand All @@ -194,6 +247,16 @@ func parseConfigFromJson(path string) (Config, error) {
return config, nil
}

// ReWriteConfig re-writes the config from the path it was
// loaded from.
func (c *Config) ReWriteConfig() (string, error) {
if c.LoadedFrom == "" {
return "", errors.New("loaded path not set, cannot re-write")
}

return c.WriteConfig(c.LoadedFrom)
}

// WriteConfig writes the config to the given folder.
// Naming of the file is derived from the read source of
// the config.
Expand Down Expand Up @@ -230,5 +293,7 @@ func (c *Config) WriteConfig(path string) (string, error) {
return "", err
}

c.LoadedFrom = path

return f.Name(), nil
}
Loading

0 comments on commit d1c6cc7

Please sign in to comment.