Skip to content

Instantly share code, notes, and snippets.

@kevinlebrun
Created April 1, 2016 15:04
Show Gist options
  • Save kevinlebrun/24420270b235bcf79db875207ecd3e98 to your computer and use it in GitHub Desktop.
Save kevinlebrun/24420270b235bcf79db875207ecd3e98 to your computer and use it in GitHub Desktop.
A little script I used to reorganize one of my project tree.
package main
import (
"fmt"
"os"
"path"
"path/filepath"
"strings"
)
// MAIN
func main() {
if len(os.Args) != 2 {
fmt.Printf("Usage: %s <root_dir>\n", path.Base(os.Args[0]))
os.Exit(1)
}
modules := NewModules(GetFilenames(os.Args[1]))
for _, module := range modules {
for _, move := range module.ComputeMoves() {
Move(move[0], move[1])
}
}
}
func GetFilenames(root string) []string {
var files []string
filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if strings.HasSuffix(path, ".js") && strings.Contains(path, "modules") {
files = append(files, path)
}
return nil
})
return files
}
func Move(src, dest string) {
var err error
path := path.Dir(dest)
err = os.MkdirAll(path, 0755)
if err != nil {
fmt.Printf("error: %+v\n", err)
return
}
err = os.Rename(src, dest)
if err != nil {
fmt.Printf("error: %+v\n", err)
return
}
}
// MODULE
type Module struct {
Name string
Path string
Files []File
}
func NewModules(filenames []string) []Module {
modules := make(map[string]*Module)
for _, filename := range filenames {
index := strings.Index(filename, "modules")
file := filename[index+8 : len(filename)]
name := strings.Split(file, "/")[0]
if _, ok := modules[name]; !ok {
modules[name] = &Module{
Name: name,
Path: filename[0:index],
}
}
modules[name].Files = append(modules[name].Files, File{path.Base(file), file, path.Base(file)})
}
// extract values
result := make([]Module, 0, len(modules))
for _, value := range modules {
result = append(result, *value)
}
return result
}
func (m *Module) ComputeMoves() [][2]string {
// for each files in a module we want to find a file that match the test
var tuples [][2]File
files := m.Files
for _, test := range files {
if test.IsTest() || test.IsMock() {
var matches []File
searchee := strings.ToLower(test.GetCleanName())
for _, file := range files {
if searchee == strings.ToLower(file.Name) {
matches = append(matches, file)
}
}
match, err := FindBestMatch(matches, File{Name: searchee, Path: test.Path, RealName: test.Name})
if err != nil {
fmt.Println(err)
} else {
tuples = append(tuples, [2]File{test, *match})
}
}
}
var moves [][2]string
for _, tuple := range tuples {
dest := tuple[0].ComputeRelativeDestination(tuple[1])
if dest != tuple[0].Path {
move := [2]string{path.Join(m.Path, "modules", tuple[0].Path), path.Join(m.Path, "modules", dest)}
moves = append(moves, move)
}
}
return moves
}
func FindBestMatch(haystack []File, needle File) (*File, error) {
if len(haystack) == 0 {
return nil, fmt.Errorf("ORPHANED: %q\n", needle.RealName)
}
if len(haystack) > 1 {
context := path.Base(path.Dir(needle.Path))
if context == "test" || context == "tests" {
context = path.Base(path.Dir(path.Dir(needle.Path)))
}
var matches []File
for _, file := range haystack {
if context == path.Base(path.Dir(file.Path)) {
matches = append(matches, file)
}
}
if len(matches) == 1 {
return &File{Name: matches[0].Name, Path: matches[0].Path}, nil
}
return nil, fmt.Errorf("CONFLICT for %q:\n %v\n", needle.RealName, haystack)
}
return &haystack[0], nil
}
// FILE
type File struct {
Name string
Path string
RealName string
}
func (f File) String() string {
return f.Path
}
func (f File) IsMock() bool {
return strings.HasSuffix(f.RealName, "_mock.js")
}
func (f File) IsTest() bool {
return strings.HasSuffix(f.RealName, "_test.js")
}
func (f File) GetCleanName() string {
if f.IsMock() {
return strings.Replace(f.Name, "_mock.js", ".js", 1)
}
if f.IsTest() {
return strings.Replace(f.Name, "_test.js", ".js", 1)
}
return f.Name
}
func (f File) ComputeRelativeDestination(rel File) string {
var dest string
if !f.IsTest() && !f.IsMock() {
return f.Path
}
if f.IsTest() {
dest = strings.Replace(rel.Path, ".js", "_test.js", 1)
}
if f.IsMock() {
dest = strings.Replace(rel.Path, ".js", "_mock.js", 1)
}
parts := strings.Split(dest, "/")
if len(parts) > 2 {
dest = parts[0] + "/tests/" + strings.Join(parts[1:], "/")
}
return dest
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment