-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Nguyen Le Anh Tuan
committed
Jun 9, 2024
1 parent
d7787e5
commit b3364ab
Showing
5 changed files
with
198 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
.vscode/ | ||
tmp/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
} | ||
} |