-
Notifications
You must be signed in to change notification settings - Fork 0
feat: implement global remove command #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| /* | ||
| Copyright © 2026 laggu | ||
| */ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "github.com/laggu/git-volume/internal/gitvolume" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| // globalRemoveCmd represents the global remove command | ||
| var globalRemoveCmd = &cobra.Command{ | ||
| Use: "remove <file>...", | ||
| Short: "Remove files from global storage", | ||
| Long: `Removes files or directories from the global git-volume storage (~/.git-volume). | ||
|
|
||
| Examples: | ||
| git volume global remove .env | ||
| git volume global remove secrets/api.key`, | ||
| Args: cobra.MinimumNArgs(1), | ||
| SilenceUsage: true, | ||
| Aliases: []string{"rm"}, | ||
| RunE: func(cmd *cobra.Command, args []string) error { | ||
| gv, err := gitvolume.New(gitvolume.Options{Quiet: quiet}) | ||
| if err != nil { | ||
| return err | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to the repository's style guide, errors should be wrapped to add context. The error returned from return fmt.Errorf("failed to initialize git-volume: %w", err)References
|
||
| } | ||
|
|
||
| return gv.GlobalRemove(args) | ||
| }, | ||
| } | ||
|
|
||
| func init() { | ||
| globalCmd.AddCommand(globalRemoveCmd) | ||
| } | ||
Binary file not shown.
This file contains hidden or 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 |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| package gitvolume | ||
|
|
||
| import ( | ||
| "errors" | ||
| "fmt" | ||
| "os" | ||
| "path/filepath" | ||
| ) | ||
|
|
||
| // GlobalRemove removes files from the global git-volume directory | ||
| func (g *GitVolume) GlobalRemove(files []string) error { | ||
| if err := g.beforeAllRemove(); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| var errs []error | ||
| for _, file := range files { | ||
| target, err := g.beforeRemove(file) | ||
| if err == nil { | ||
| err = g.remove(target) | ||
| } | ||
| g.afterRemove(file, err, &errs) | ||
| } | ||
|
|
||
| return g.afterAllRemove(errs) | ||
| } | ||
|
|
||
| func (g *GitVolume) beforeAllRemove() error { | ||
| if _, err := os.Stat(g.ctx.GlobalDir); os.IsNotExist(err) { | ||
| return fmt.Errorf("global storage not initialized") | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func (g *GitVolume) afterAllRemove(errs []error) error { | ||
| if len(errs) > 0 && !g.quiet { | ||
| fmt.Printf("❌ Global remove completed with %d error(s)\n", len(errs)) | ||
| } | ||
| return errors.Join(errs...) | ||
| } | ||
|
|
||
| func (g *GitVolume) beforeRemove(file string) (string, error) { | ||
| globalDir := g.ctx.GlobalDir | ||
|
|
||
| // Target path is directly relative to globalDir | ||
| targetPath := filepath.Join(globalDir, file) | ||
|
|
||
| // Security check: ensure targetPath is within globalDir | ||
| if err := verifyPathWithinBase(targetPath, globalDir); err != nil { | ||
| return "", fmt.Errorf("invalid path %s: %w", file, err) | ||
| } | ||
|
|
||
| // Check existence | ||
| if _, err := os.Lstat(targetPath); os.IsNotExist(err) { | ||
| return "", fmt.Errorf("not found: %s", file) | ||
| } else if err != nil { | ||
| return "", fmt.Errorf("failed to stat %s: %w", file, err) | ||
| } | ||
|
|
||
| return targetPath, nil | ||
| } | ||
|
|
||
| func (g *GitVolume) remove(file string) error { | ||
| // Remove | ||
| if err := os.RemoveAll(file); err != nil { | ||
| return fmt.Errorf("failed to remove: %w", err) | ||
| } | ||
|
|
||
| // Cleanup empty parents | ||
| cleanEmptyParents(filepath.Dir(file), g.ctx.GlobalDir) | ||
|
laggu marked this conversation as resolved.
|
||
|
|
||
| return nil | ||
| } | ||
|
|
||
| func (g *GitVolume) afterRemove(file string, err error, errs *[]error) { | ||
| if err != nil { | ||
| if !g.quiet { | ||
| fmt.Printf("❌ Failed to remove %s: %v\n", file, err) | ||
| } | ||
| *errs = append(*errs, err) | ||
| return | ||
| } | ||
|
|
||
| if !g.quiet { | ||
| fmt.Printf("✓ Removed %s\n", file) | ||
| } | ||
| } | ||
This file contains hidden or 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
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The import order does not follow the standard Go convention, which is also specified in the repository's style guide. Imports should be grouped by standard library, third-party libraries, and then local packages, with blank lines between groups.
References
Imports: 표준 라이브러리, 서드파티 라이브러리, 로컬 패키지 순으로 그룹화합니다.) specifies that Go imports should be grouped in the order of: standard library, third-party libraries, and then local packages. (link)