Files
Alma/command/link.go

181 lines
4.2 KiB
Go

package command
import (
"alma/config"
"alma/helpers"
"os"
"path/filepath"
"strings"
"github.com/samber/lo"
)
type LinkCommand struct {
}
type itemToLink struct {
source string
target string
}
func (LinkCommand) GetName() string {
return "link"
}
func (LinkCommand) GetHelpText() {
println(
`Usage:
alma link [module]
alma link [repository] [module]
Options:
--help Show this message
-d, --dry-run Show what would be linked without actually linking`)
}
func (LinkCommand) Run(args []string) {
moduleInfo, err := helpers.GetModuleInfo(args)
if err != nil {
println(err.Error())
return
}
moduleDirectory := moduleInfo.ModuleDirectory
targetDirectory := moduleInfo.TargetDirectory
dryRun := lo.ContainsBy(args, func(item string) bool { return (item == "-d" || item == "--dry-run") })
almaConfigFilePath, err := os.Stat(filepath.Join(moduleDirectory, ".alma-config.json"))
moduleConfiguration := &config.ModuleConfiguration{}
if err == nil && !almaConfigFilePath.IsDir() {
moduleConfiguration = config.LoadModuleConfiguration(filepath.Join(moduleDirectory, ".alma-config.json"))
targetDirectory = helpers.ResolvePath(moduleConfiguration.Target)
}
itemsToLink := TraverseTree(
&moduleDirectory,
&targetDirectory,
&moduleDirectory,
&targetDirectory,
moduleConfiguration,
)
filteredItemsToLink := lo.Filter(itemsToLink, func(item itemToLink, index int) bool {
for _, exclude := range moduleConfiguration.Exclude {
sourceRelative := item.source[len(moduleDirectory)+1:]
if strings.HasPrefix(sourceRelative, exclude) {
return false
}
}
return true
})
if dryRun {
println("Dry run. No links will be created. The following links would be created:")
}
linkItems(filteredItemsToLink, dryRun)
// Not yet used things
_ = targetDirectory
_ = moduleConfiguration
}
func TraverseTree(
currentDirectory *string,
currentTargetDirectory *string,
moduleDirectory *string,
targetDirectory *string,
moduleConfiguration *config.ModuleConfiguration) []itemToLink {
content, err := os.ReadDir(*currentDirectory)
if err != nil {
return nil
}
itemsToLink := make([]itemToLink, 0, len(content))
for _, item := range content {
if item.IsDir() {
continue
}
if currentDirectory == moduleDirectory && item.Name() == ".alma-config.json" {
continue
}
itemConfigTargetPath := moduleConfiguration.Links[item.Name()]
var targetPath string
if itemConfigTargetPath != "" {
targetPath = helpers.ResolvePathWithDefault(moduleConfiguration.Links[item.Name()], *targetDirectory)
} else {
targetPath = filepath.Join(*currentTargetDirectory, item.Name())
}
itemsToLink = append(itemsToLink, itemToLink{
source: filepath.Join(*currentDirectory, item.Name()),
target: targetPath,
})
}
for _, item := range content {
if !item.IsDir() {
continue
}
relativePath := getRelativePath(filepath.Join(*currentDirectory, item.Name()), *moduleDirectory)
itemConfigTargetPath := moduleConfiguration.Links[relativePath]
if itemConfigTargetPath != "" {
itemsToLink = append(itemsToLink, itemToLink{
source: filepath.Join(*currentDirectory, item.Name()),
target: helpers.ResolvePathWithDefault(itemConfigTargetPath, *targetDirectory),
})
} else {
newCurrentDirectory := filepath.Join(*currentDirectory, item.Name())
newTargetDirectory := filepath.Join(*currentTargetDirectory, item.Name())
items := TraverseTree(
&newCurrentDirectory,
&newTargetDirectory,
moduleDirectory,
targetDirectory,
moduleConfiguration,
)
if items != nil {
itemsToLink = append(itemsToLink, items...)
}
}
}
return itemsToLink
}
func linkItems(itemsToLink []itemToLink, dryRun bool) {
for _, item := range itemsToLink {
_, err := os.Stat(item.target)
if err == nil {
println("Target already exists", item.target)
continue
}
if dryRun {
println("Linking", item.source, item.target)
continue
}
err = os.Symlink(item.source, item.target)
if err != nil {
println("Error while linking", item.source, item.target)
}
}
}
func getRelativePath(full string, parent string) string {
return strings.TrimPrefix(full[len(parent):], string(filepath.Separator))
}