Skip to content

Commit

Permalink
Release v1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Nguyen Le Anh Tuan committed Jun 9, 2024
1 parent d7787e5 commit b3364ab
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
.vscode/
tmp/
12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,33 +43,29 @@ new folder2/{{file2,file3}.go,file4.txt}

# Installation

```go
```sh
go install github.com/dynonguyen/new-cli/cmd/new@latest
```

# Usage

### Create file

```sh
# Create file
new file.go
new file.go file2.go file3.js
new {file,file2}.go file3.js

# Create directory (end with /)
new dir/
new dir/sub1/sub2/ dir2/
new "dir/[sub1,sub2]/" # Equivalent: new dir/sub1/ dir/sub2/

# Create file in directory
new dir/file.go
new dir/sub1/file.go
new dir/sub1/sub2/{file,file2}.go
new dir/sub1/sub2/{{file,file2}.go,file3.js}
new "dir/sub1/[file.go,file2.go]" # Equivalent: new dir/sub1/file1.go dir/sub2/file2.go

# Space character (surrounded by double quotes)
new "dir/orange cat/cat.go"

# Combination
new dir/{file,file2}.go dir/sub1/file.go file3.js
new "dir/[file.go,file2.go]" dir/sub1/file.go file3.js
```
23 changes: 21 additions & 2 deletions cmd/new/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,26 @@
package main

import newcli "github.com/dynonguyen/new-cli"
import (
"flag"
"fmt"
"os"

newcli "github.com/dynonguyen/new-cli"
)

func main() {
newcli.Run()
var verbose bool

flag.BoolVar(&verbose, "verbose", false, "Verbose output")
flag.BoolVar(&verbose, "v", false, "Verbose output")

flag.Parse()
args := flag.Args()

if len(args) == 0 {
fmt.Fprintf(os.Stderr, "No paths provided\n")
os.Exit(1)
}

newcli.NewCli(args, verbose)
}
118 changes: 115 additions & 3 deletions new.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,119 @@
package newcli

import "fmt"
import (
"fmt"
"os"
"regexp"
"slices"
"strings"
)

func Run() {
fmt.Println("HELLO NEW CLI")
// path = 'abc/xyz/[a.go,b.go]' => ['abc/xyz/a.go', 'abc/xyz/b.go']
// path = 'abc/xyz/[sub,sub2]/' => ['abc/xyz/sub/', 'abc/xyz/sub2/']
// path = 'abc/xyz/a.go' => ['abc/xyz/a.go']
func expandPaths(path string) []string {
if matched, _ := regexp.MatchString(`^.*\/+\[.*\]\/?$`, path); matched {
isDir := strings.HasSuffix(path, "/")

ss := strings.Split(path, "/")
var last, preDir string

if isDir {
last = ss[len(ss)-2]
preDir = strings.Join(ss[:len(ss)-2], "/")
} else {
last = ss[len(ss)-1]
preDir = strings.Join(ss[:len(ss)-1], "/")
}

items := strings.Split(strings.TrimFunc(last, func(r rune) bool {
return r == '[' || r == ']'
}), ",")

paths := []string{}

for _, item := range items {
if isDir {
paths = append(paths, preDir+"/"+item+"/")
} else {
paths = append(paths, preDir+"/"+item)
}
}

return paths
}

return []string{path}
}

func getDirFile(path string) (dir, file string) {
if strings.HasSuffix(path, "/") {
dir = path
return
}

splits := strings.Split(path, "/")

if len(splits) == 1 {
file = path
return
}

file = splits[len(splits)-1]
dir = strings.Replace(path, file, "", 1)
return
}

func newFile(path string) error {
dir, filename := getDirFile(strings.TrimSpace(path))

if _, err := os.Stat(path); err == nil {
if filename != "" {
return fmt.Errorf("file already exists: %v", path)
} else {
return fmt.Errorf("directory already exists: %v", path)
}
}

if dir != "" {
if err := os.MkdirAll(dir, os.ModePerm); err != nil {
return fmt.Errorf("failed to create a directory: %v", err)
}
}

if filename != "" {
if f, err := os.Create(path); err != nil {
return fmt.Errorf("failed to create a file: %v", err)
} else {
f.Close()
}
}

return nil
}

func getPaths(args *[]string) (paths []string) {
for _, arg := range *args {
for _, path := range expandPaths(arg) {
if !slices.Contains(paths, path) {
paths = append(paths, path)
}
}
}

return paths
}

func NewCli(args []string, verbose bool) {
for _, path := range getPaths(&args) {
err := newFile(path)

if verbose {
if err != nil {
fmt.Println(err)
} else {
fmt.Println("Created: " + path)
}
}
}
}
59 changes: 57 additions & 2 deletions new_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,62 @@
package newcli

import "testing"
import (
"slices"
"testing"
)

func TestNew(t *testing.T) {
func TestGetDirFile(t *testing.T) {
testCases := []struct {
path, dir, file string
}{
{path: "", dir: "", file: ""},
{path: "/", dir: "/", file: ""},
{path: "main.go", dir: "", file: "main.go"},
{path: "~/main.go", dir: "~/", file: "main.go"},
{path: "dir/sub1/sub2/", dir: "dir/sub1/sub2/", file: ""},
{path: "dir/sub1/sub2/main.go", dir: "dir/sub1/sub2/", file: "main.go"},
}

for _, tc := range testCases {
if dir, file := getDirFile(tc.path); dir != tc.dir || file != tc.file {
t.Errorf("FAIL => Input: %v, Expected: '%v', '%v' - Actual: '%v', '%v'", tc.path, tc.dir, tc.file, dir, file)
}
}
}

func TestGetPaths(t *testing.T) {
testCases := []struct {
args []string
paths []string
}{
{args: []string{}, paths: []string{}},
{
args: []string{
"tmp.js",
"tmp/",
"tmp/main.js",
"dir/sub1/sub2/",
"dir/[nested1,nested2]/",
"dir/sub1/[file.go,file2.go]",
"dir/sub1/[file.go,file2.go,file3.go]",
},
paths: []string{
"tmp.js",
"tmp/",
"tmp/main.js",
"dir/sub1/sub2/",
"dir/nested1/",
"dir/nested2/",
"dir/sub1/file.go",
"dir/sub1/file2.go",
"dir/sub1/file3.go",
},
},
}

for _, tc := range testCases {
if paths := getPaths(&tc.args); !slices.Equal(paths, tc.paths) {
t.Errorf("FAIL => Input: %v, Expected: '%v' - Actual: '%v'", tc.args, tc.paths, paths)
}
}
}

0 comments on commit b3364ab

Please sign in to comment.