Add unlink and remove commands
This commit is contained in:
157
main.go
157
main.go
@@ -4,6 +4,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -36,6 +37,10 @@ func main() {
|
|||||||
err = applyCmd(args[1:])
|
err = applyCmd(args[1:])
|
||||||
case "add":
|
case "add":
|
||||||
err = addCmd(args[1:])
|
err = addCmd(args[1:])
|
||||||
|
case "unlink":
|
||||||
|
err = unlinkCmd(args[1:])
|
||||||
|
case "remove":
|
||||||
|
err = removeCmd(args[1:])
|
||||||
case "help", "-h", "--help":
|
case "help", "-h", "--help":
|
||||||
usage()
|
usage()
|
||||||
return
|
return
|
||||||
@@ -54,6 +59,8 @@ func usage() {
|
|||||||
fmt.Println("usage:")
|
fmt.Println("usage:")
|
||||||
fmt.Println(" sigil apply [--prune]")
|
fmt.Println(" sigil apply [--prune]")
|
||||||
fmt.Println(" sigil add <path>")
|
fmt.Println(" sigil add <path>")
|
||||||
|
fmt.Println(" sigil unlink <package>")
|
||||||
|
fmt.Println(" sigil remove <package>")
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyCmd(args []string) error {
|
func applyCmd(args []string) error {
|
||||||
@@ -238,6 +245,72 @@ func addCmd(args []string) error {
|
|||||||
return applyPackage(filesDir, targetRoot)
|
return applyPackage(filesDir, targetRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func unlinkCmd(args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return errors.New("missing package name")
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgName := args[0]
|
||||||
|
repo, err := repoPath()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgDir := filepath.Join(repo, pkgName)
|
||||||
|
configPath := filepath.Join(pkgDir, configFileName)
|
||||||
|
cfg, err := loadConfig(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetRoot, err := selectTarget(cfg.targets)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
filesDir := filepath.Join(pkgDir, filesDirName)
|
||||||
|
if _, err := os.Stat(filesDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return restorePackage(filesDir, targetRoot)
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeCmd(args []string) error {
|
||||||
|
if len(args) < 1 {
|
||||||
|
return errors.New("missing package name")
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgName := args[0]
|
||||||
|
repo, err := repoPath()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
pkgDir := filepath.Join(repo, pkgName)
|
||||||
|
configPath := filepath.Join(pkgDir, configFileName)
|
||||||
|
cfg, err := loadConfig(configPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetRoot, err := selectTarget(cfg.targets)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
filesDir := filepath.Join(pkgDir, filesDirName)
|
||||||
|
if _, err := os.Stat(filesDir); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := restorePackage(filesDir, targetRoot); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return os.RemoveAll(pkgDir)
|
||||||
|
}
|
||||||
|
|
||||||
func applyPackage(filesDir, targetRoot string) error {
|
func applyPackage(filesDir, targetRoot string) error {
|
||||||
if err := ensureDir(targetRoot); err != nil {
|
if err := ensureDir(targetRoot); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -528,3 +601,87 @@ func removeLinks(paths []string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func restorePackage(filesDir, targetRoot string) error {
|
||||||
|
filesAbs, err := filepath.Abs(filesDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return filepath.WalkDir(filesDir, func(path string, entry fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if path == filesDir {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if entry.IsDir() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rel, err := filepath.Rel(filesDir, path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
targetPath := filepath.Join(targetRoot, rel)
|
||||||
|
|
||||||
|
info, err := os.Lstat(targetPath)
|
||||||
|
if errors.Is(err, os.ErrNotExist) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if info.Mode()&os.ModeSymlink == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
src, err := os.Readlink(targetPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !filepath.IsAbs(src) {
|
||||||
|
src = filepath.Join(filepath.Dir(targetPath), src)
|
||||||
|
}
|
||||||
|
src = filepath.Clean(src)
|
||||||
|
|
||||||
|
if !strings.HasPrefix(src, filesAbs+string(os.PathSeparator)) && src != filesAbs {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Remove(targetPath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return copyFile(path, targetPath)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyFile(src, dst string) error {
|
||||||
|
if err := os.MkdirAll(filepath.Dir(dst), 0o755); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
srcFile, err := os.Open(src)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer srcFile.Close()
|
||||||
|
|
||||||
|
info, err := srcFile.Stat()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dstFile, err := os.OpenFile(dst, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, info.Mode())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer dstFile.Close()
|
||||||
|
|
||||||
|
if _, err := io.Copy(dstFile, srcFile); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user