Skip to content

Commit

Permalink
Merge pull request #80 from splitsh/excludes
Browse files Browse the repository at this point in the history
Support excluding directories
  • Loading branch information
fabpot committed Mar 8, 2024
2 parents eaede0b + bd864e2 commit 931f587
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 15 deletions.
16 changes: 12 additions & 4 deletions README.md
Expand Up @@ -128,10 +128,18 @@ splitsh-lite --prefix=lib/ --origin=origin/1.0 --path=/path/to/repo

Available options:

* `--prefix` is the prefix of the directory to split; you can put the split
contents in a sub-directory of the target repository by using the
`--prefix=from:to` syntax; split several directories by passing multiple
`--prefix` flags;
* `--prefix` is the prefix of the directory to split; the value can be one of
the following:

* `from`: the origin directory to split;

* `from:to`: move the split content to a sub-directory on the target;

* `from:to:exclude`: exclude a directory from the origin `from` directory
(use `from:to:exclude1:exclude2:...` to exclude more than one
directory).

Split several directories by passing multiple `--prefix` flags;

* `--path` is the path of the repository to split (current directory by default);

Expand Down
17 changes: 11 additions & 6 deletions main.go
Expand Up @@ -24,19 +24,24 @@ func (p *prefixesFlag) Set(value string) error {
parts := strings.Split(value, ":")
from := parts[0]
to := ""
if len(parts) > 1 {
to = parts[1]
excludes := make([]string, 0)
if len(parts) >= 2 {
to = strings.TrimRight(parts[1], "/")
if len(parts) > 2 {
for _, exclude := range parts[2:] {
excludes = append(excludes, exclude)
}
}
}

// value must be unique
for _, prefix := range []*splitter.Prefix(*p) {
// FIXME: to should be normalized (xxx vs xxx/ for instance)
for _, prefix := range *p {
if prefix.To == to {
return fmt.Errorf("cannot have two prefix splits under the same directory: %s -> %s vs %s -> %s", prefix.From, prefix.To, from, to)
}
}

*p = append(*p, &splitter.Prefix{From: from, To: to})
*p = append(*p, splitter.NewPrefix(from, to, excludes))
return nil
}

Expand Down Expand Up @@ -73,7 +78,7 @@ func main() {
config := &splitter.Config{
Path: path,
Origin: origin,
Prefixes: []*splitter.Prefix(prefixes),
Prefixes: prefixes,
Target: target,
Commit: commit,
Debug: debug,
Expand Down
3 changes: 3 additions & 0 deletions splitter/cache.go
Expand Up @@ -77,6 +77,9 @@ func key(config *Config) []byte {
for _, prefix := range config.Prefixes {
io.WriteString(h, prefix.From)
io.WriteString(h, prefix.To)
for _, exclude := range prefix.Excludes {
io.WriteString(h, exclude)
}
}

return h.Sum(nil)
Expand Down
24 changes: 22 additions & 2 deletions splitter/config.go
Expand Up @@ -3,6 +3,7 @@ package splitter
import (
"fmt"
"log"
"strings"
"sync"

git "github.com/libgit2/git2go/v34"
Expand All @@ -11,8 +12,27 @@ import (

// Prefix represents which paths to split
type Prefix struct {
From string
To string
From string
To string
Excludes []string
}

// NewPrefix returns a new prefix, sanitizing the input
func NewPrefix(from, to string, excludes []string) *Prefix {
// remove the trailing slash (to avoid duplicating cache)
from = strings.TrimRight(from, "/")
to = strings.TrimRight(to, "/")

// remove trailing slashes from excludes (as it does not mean anything)
for i, exclude := range excludes {
excludes[i] = strings.TrimRight(exclude, "/")
}

return &Prefix{
From: from,
To: to,
Excludes: excludes,
}
}

// Config represents a split configuration
Expand Down
65 changes: 62 additions & 3 deletions splitter/state.go
Expand Up @@ -61,13 +61,17 @@ func newState(config *Config, result *Result) (*state, error) {
}

if config.Debug {
state.logger.Printf("Splitting %s\n", state.originBranch)
state.logger.Printf("Splitting %s", state.originBranch)
for _, v := range config.Prefixes {
to := v.To
if to == "" {
to = "ROOT"
}
state.logger.Printf(" From \"%s\" to \"%s\"\n", v.From, to)
state.logger.Printf(` From "%s" to "%s"`, v.From, to)
if (len(v.Excludes)) == 0 {
} else {
state.logger.Printf(` Excluding "%s"`, strings.Join(v.Excludes, `", "`))
}
}
}

Expand All @@ -79,7 +83,7 @@ func newState(config *Config, result *Result) (*state, error) {

// simplePrefix contains the prefix when there is only one
// with an empty value (target)
if len(config.Prefixes) == 1 && config.Prefixes[0].To == "" {
if len(config.Prefixes) == 1 && config.Prefixes[0].To == "" && len(config.Prefixes[0].Excludes) == 0 {
state.simplePrefix = config.Prefixes[0].From
}

Expand Down Expand Up @@ -284,6 +288,14 @@ func (s *state) treeByPaths(tree *git.Tree) (*git.Tree, error) {
continue
}

if len(prefix.Excludes) > 0 {
prunedTree, err := s.pruneTree(splitTree, prefix.Excludes)
if err != nil {
return nil, err
}
splitTree = prunedTree
}

// adding the prefix
if prefix.To != "" {
prefixedTree, err = s.addPrefixToTree(splitTree, prefix.To)
Expand Down Expand Up @@ -360,6 +372,53 @@ func (s *state) addPrefixToTree(tree *git.Tree, prefix string) (*git.Tree, error
return prefixedTree, nil
}

func (s *state) pruneTree(tree *git.Tree, excludes []string) (*git.Tree, error) {
var err error
treeBuilder, err := s.repo.TreeBuilder()
if err != nil {
return nil, err
}
defer treeBuilder.Free()

err = tree.Walk(func(path string, entry *git.TreeEntry) error {
// always add files at the root directory
if entry.Type == git.ObjectBlob {
if err := treeBuilder.Insert(entry.Name, entry.Id, git.FilemodeBlob); err != nil {
return err
}
return nil
}

if entry.Type != git.ObjectTree {
// should never happen
return fmt.Errorf("Unexpected entry %s/%s (type %s)", path, entry.Name, entry.Type)
}

// exclude directory in excludes
for _, exclude := range excludes {
if entry.Name == exclude {
return git.TreeWalkSkip
}
}

if err := treeBuilder.Insert(entry.Name, entry.Id, git.FilemodeTree); err != nil {
return err
}
return git.TreeWalkSkip
})

if err != nil {
return nil, err
}

treeOid, err := treeBuilder.Write()
if err != nil {
return nil, err
}

return s.repo.LookupTree(treeOid)
}

func (s *state) copyOrSkip(rev *git.Commit, tree *git.Tree, newParents []*git.Oid) (*git.Oid, bool, error) {
var identical, nonIdentical *git.Oid
var gotParents []*git.Oid
Expand Down

0 comments on commit 931f587

Please sign in to comment.