mirror of
https://github.com/yarlson/lnk.git
synced 2025-09-25 21:18:57 +02:00
Compare commits
2 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
92f2575090 | ||
|
0f74723a03 |
16
README.md
16
README.md
@@ -55,7 +55,7 @@ lnk add ~/.vimrc ~/.config/nvim ~/.gitconfig
|
|||||||
|
|
||||||
# Add host-specific files
|
# Add host-specific files
|
||||||
lnk add --host laptop ~/.ssh/config
|
lnk add --host laptop ~/.ssh/config
|
||||||
lnk add --host work ~/.aws/credentials
|
lnk add --host work ~/.gitconfig
|
||||||
|
|
||||||
# List managed files
|
# List managed files
|
||||||
lnk list # Common config only
|
lnk list # Common config only
|
||||||
@@ -101,13 +101,11 @@ Lnk supports both **common configurations** (shared across all machines) and **h
|
|||||||
├── laptop.lnk/ # Laptop-specific storage
|
├── laptop.lnk/ # Laptop-specific storage
|
||||||
│ ├── .ssh/
|
│ ├── .ssh/
|
||||||
│ │ └── config
|
│ │ └── config
|
||||||
│ └── .aws/
|
│ └── .tmux.conf
|
||||||
│ └── credentials
|
|
||||||
└── work.lnk/ # Work-specific storage
|
└── work.lnk/ # Work-specific storage
|
||||||
├── .ssh/
|
├── .ssh/
|
||||||
│ └── config
|
│ └── config
|
||||||
└── .company/
|
└── .gitconfig
|
||||||
└── config
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Usage Patterns
|
### Usage Patterns
|
||||||
@@ -118,7 +116,7 @@ lnk add ~/.vimrc ~/.bashrc ~/.gitconfig
|
|||||||
|
|
||||||
# Host-specific config (unique per machine)
|
# Host-specific config (unique per machine)
|
||||||
lnk add --host $(hostname) ~/.ssh/config
|
lnk add --host $(hostname) ~/.ssh/config
|
||||||
lnk add --host work ~/.aws/credentials
|
lnk add --host work ~/.gitconfig
|
||||||
|
|
||||||
# List configurations
|
# List configurations
|
||||||
lnk list # Common only
|
lnk list # Common only
|
||||||
@@ -150,7 +148,7 @@ lnk init -r git@github.com:you/dotfiles.git
|
|||||||
lnk add ~/.bashrc ~/.vimrc ~/.gitconfig
|
lnk add ~/.bashrc ~/.vimrc ~/.gitconfig
|
||||||
|
|
||||||
# Add host-specific config
|
# Add host-specific config
|
||||||
lnk add --host $(hostname) ~/.ssh/config ~/.aws/credentials
|
lnk add --host $(hostname) ~/.ssh/config ~/.tmux.conf
|
||||||
|
|
||||||
lnk push "initial setup"
|
lnk push "initial setup"
|
||||||
```
|
```
|
||||||
@@ -188,8 +186,8 @@ lnk push "laptop ssh config"
|
|||||||
|
|
||||||
# On your work machine
|
# On your work machine
|
||||||
lnk pull # Get common config
|
lnk pull # Get common config
|
||||||
lnk add --host work ~/.aws/credentials
|
lnk add --host work ~/.gitconfig
|
||||||
lnk push "work aws config"
|
lnk push "work git config"
|
||||||
|
|
||||||
# Back on laptop
|
# Back on laptop
|
||||||
lnk pull # Get updates (work config won't affect laptop)
|
lnk pull # Get updates (work config won't affect laptop)
|
||||||
|
@@ -33,10 +33,10 @@ func newAddCmd() *cobra.Command {
|
|||||||
basename := filepath.Base(filePath)
|
basename := filepath.Base(filePath)
|
||||||
if host != "" {
|
if host != "" {
|
||||||
printf(cmd, "✨ \033[1mAdded %s to lnk (host: %s)\033[0m\n", basename, host)
|
printf(cmd, "✨ \033[1mAdded %s to lnk (host: %s)\033[0m\n", basename, host)
|
||||||
printf(cmd, " 🔗 \033[90m%s\033[0m → \033[36m~/.config/lnk/%s.lnk/%s\033[0m\n", filePath, host, basename)
|
printf(cmd, " 🔗 \033[90m%s\033[0m → \033[36m~/.config/lnk/%s.lnk/%s\033[0m\n", filePath, host, filePath)
|
||||||
} else {
|
} else {
|
||||||
printf(cmd, "✨ \033[1mAdded %s to lnk\033[0m\n", basename)
|
printf(cmd, "✨ \033[1mAdded %s to lnk\033[0m\n", basename)
|
||||||
printf(cmd, " 🔗 \033[90m%s\033[0m → \033[36m~/.config/lnk/%s\033[0m\n", filePath, basename)
|
printf(cmd, " 🔗 \033[90m%s\033[0m → \033[36m~/.config/lnk/%s\033[0m\n", filePath, filePath)
|
||||||
}
|
}
|
||||||
printf(cmd, " 📝 Use \033[1mlnk push\033[0m to sync to remote\n")
|
printf(cmd, " 📝 Use \033[1mlnk push\033[0m to sync to remote\n")
|
||||||
return nil
|
return nil
|
||||||
|
@@ -5,7 +5,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
@@ -107,19 +106,10 @@ func (suite *CLITestSuite) TestAddCommand() {
|
|||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.Equal(os.ModeSymlink, info.Mode()&os.ModeSymlink)
|
suite.Equal(os.ModeSymlink, info.Mode()&os.ModeSymlink)
|
||||||
|
|
||||||
// Verify some file exists in repo with .bashrc in the name
|
// Verify the file exists in repo with preserved directory structure
|
||||||
lnkDir := filepath.Join(suite.tempDir, "lnk")
|
lnkDir := filepath.Join(suite.tempDir, "lnk")
|
||||||
entries, err := os.ReadDir(lnkDir)
|
repoFile := filepath.Join(lnkDir, suite.tempDir, ".bashrc")
|
||||||
suite.NoError(err)
|
suite.FileExists(repoFile)
|
||||||
|
|
||||||
found := false
|
|
||||||
for _, entry := range entries {
|
|
||||||
if strings.Contains(entry.Name(), ".bashrc") && entry.Name() != ".lnk" {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
suite.True(found, "Repository should contain a file with .bashrc in the name")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *CLITestSuite) TestRemoveCommand() {
|
func (suite *CLITestSuite) TestRemoveCommand() {
|
||||||
@@ -397,19 +387,10 @@ func (suite *CLITestSuite) TestAddDirectory() {
|
|||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
suite.Equal(os.ModeSymlink, info.Mode()&os.ModeSymlink)
|
suite.Equal(os.ModeSymlink, info.Mode()&os.ModeSymlink)
|
||||||
|
|
||||||
// Verify some directory exists in repo with .config in the name
|
// Verify the directory exists in repo with preserved directory structure
|
||||||
lnkDir := filepath.Join(suite.tempDir, "lnk")
|
lnkDir := filepath.Join(suite.tempDir, "lnk")
|
||||||
entries, err := os.ReadDir(lnkDir)
|
repoDir := filepath.Join(lnkDir, suite.tempDir, ".config")
|
||||||
suite.NoError(err)
|
suite.DirExists(repoDir)
|
||||||
|
|
||||||
found := false
|
|
||||||
for _, entry := range entries {
|
|
||||||
if strings.Contains(entry.Name(), ".config") && entry.Name() != ".lnk" {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
suite.True(found, "Repository should contain a directory with .config in the name")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *CLITestSuite) TestSameBasenameFilesBug() {
|
func (suite *CLITestSuite) TestSameBasenameFilesBug() {
|
||||||
|
@@ -67,18 +67,11 @@ func getRepoPath() string {
|
|||||||
|
|
||||||
// generateRepoName creates a repository path from a relative path
|
// generateRepoName creates a repository path from a relative path
|
||||||
func generateRepoName(relativePath string, host string) string {
|
func generateRepoName(relativePath string, host string) string {
|
||||||
if host != "" {
|
// Always preserve the directory structure for consistency
|
||||||
// For host-specific files, preserve the directory structure
|
// Both common and host-specific files should maintain their path structure
|
||||||
return relativePath
|
return relativePath
|
||||||
}
|
}
|
||||||
|
|
||||||
// For common files, replace slashes and backslashes with underscores to create valid filename
|
|
||||||
repoName := strings.ReplaceAll(relativePath, "/", "_")
|
|
||||||
repoName = strings.ReplaceAll(repoName, "\\", "_")
|
|
||||||
|
|
||||||
return repoName
|
|
||||||
}
|
|
||||||
|
|
||||||
// getHostStoragePath returns the storage path for host-specific or common files
|
// getHostStoragePath returns the storage path for host-specific or common files
|
||||||
func (l *Lnk) getHostStoragePath() string {
|
func (l *Lnk) getHostStoragePath() string {
|
||||||
if l.host == "" {
|
if l.host == "" {
|
||||||
|
@@ -82,19 +82,11 @@ func (suite *CoreTestSuite) TestCoreFileOperations() {
|
|||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
suite.Equal(os.ModeSymlink, info.Mode()&os.ModeSymlink)
|
suite.Equal(os.ModeSymlink, info.Mode()&os.ModeSymlink)
|
||||||
|
|
||||||
// The repository file will have a generated name based on the relative path
|
// The repository file will preserve the directory structure
|
||||||
lnkDir := filepath.Join(suite.tempDir, "lnk")
|
lnkDir := filepath.Join(suite.tempDir, "lnk")
|
||||||
entries, err := os.ReadDir(lnkDir)
|
|
||||||
suite.Require().NoError(err)
|
|
||||||
|
|
||||||
var repoFile string
|
// Find the .bashrc file in the repository (it should be at the relative path)
|
||||||
for _, entry := range entries {
|
repoFile := filepath.Join(lnkDir, suite.tempDir, ".bashrc")
|
||||||
if strings.Contains(entry.Name(), ".bashrc") && entry.Name() != ".lnk" {
|
|
||||||
repoFile = filepath.Join(lnkDir, entry.Name())
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
suite.NotEmpty(repoFile, "Repository should contain a file with .bashrc in the name")
|
|
||||||
suite.FileExists(repoFile)
|
suite.FileExists(repoFile)
|
||||||
|
|
||||||
// Verify content is preserved
|
// Verify content is preserved
|
||||||
@@ -141,19 +133,11 @@ func (suite *CoreTestSuite) TestCoreDirectoryOperations() {
|
|||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
suite.Equal(os.ModeSymlink, info.Mode()&os.ModeSymlink)
|
suite.Equal(os.ModeSymlink, info.Mode()&os.ModeSymlink)
|
||||||
|
|
||||||
// Check that some repository directory exists with testdir in the name
|
// Check that the repository directory preserves the structure
|
||||||
lnkDir := filepath.Join(suite.tempDir, "lnk")
|
lnkDir := filepath.Join(suite.tempDir, "lnk")
|
||||||
entries, err := os.ReadDir(lnkDir)
|
|
||||||
suite.Require().NoError(err)
|
|
||||||
|
|
||||||
var repoDir string
|
// The directory should be at the relative path
|
||||||
for _, entry := range entries {
|
repoDir := filepath.Join(lnkDir, suite.tempDir, "testdir")
|
||||||
if strings.Contains(entry.Name(), "testdir") && entry.Name() != ".lnk" {
|
|
||||||
repoDir = filepath.Join(lnkDir, entry.Name())
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
suite.NotEmpty(repoDir, "Repository should contain a directory with testdir in the name")
|
|
||||||
suite.DirExists(repoDir)
|
suite.DirExists(repoDir)
|
||||||
|
|
||||||
// Remove the directory
|
// Remove the directory
|
||||||
|
Reference in New Issue
Block a user