github.com/mutagen-io/mutagen@v0.18.0-rc1/pkg/synchronization/safety.go (about)

     1  package synchronization
     2  
     3  import (
     4  	"github.com/mutagen-io/mutagen/pkg/synchronization/core"
     5  )
     6  
     7  // oneEndpointEmptiedRoot determines whether or not one endpoint (but not both)
     8  // transitioned from a directory root with a non-trivial amount of content to a
     9  // directory root without any content.
    10  func oneEndpointEmptiedRoot(ancestor, alpha, beta *core.Entry) bool {
    11  	// Check that all three entries are directories. If not, then this check
    12  	// doesn't apply.
    13  	if ancestor == nil || ancestor.Kind != core.EntryKind_Directory {
    14  		return false
    15  	} else if alpha == nil || alpha.Kind != core.EntryKind_Directory {
    16  		return false
    17  	} else if beta == nil || beta.Kind != core.EntryKind_Directory {
    18  		return false
    19  	}
    20  
    21  	// Check whether or not the ancestor has a non-trivial amount of content.
    22  	// We define a non-trivial amount of content as two or more entries that are
    23  	// immediate children of the synchronization root. If that's not the case,
    24  	// then this check doesn't apply.
    25  	if len(ancestor.Contents) < 2 {
    26  		return false
    27  	}
    28  
    29  	// Check if alpha deleted all content within the root.
    30  	alphaEmptied := len(alpha.Contents) == 0
    31  
    32  	// Check if beta deleted all content within the root.
    33  	betaEmptied := len(beta.Contents) == 0
    34  
    35  	// Determine whether one (and only one) endpoint emptied root content.
    36  	return (alphaEmptied || betaEmptied) && !(alphaEmptied && betaEmptied)
    37  }
    38  
    39  // containsRootDeletion determines whether or not any of the specified changes
    40  // is a root deletion change.
    41  func containsRootDeletion(changes []*core.Change) bool {
    42  	// Look for root deletions.
    43  	for _, change := range changes {
    44  		if change.IsRootDeletion() {
    45  			return true
    46  		}
    47  	}
    48  
    49  	// Done.
    50  	return false
    51  }
    52  
    53  // containsRootTypeChange determines whether or not any of the specified changes
    54  // is a root type change.
    55  func containsRootTypeChange(changes []*core.Change) bool {
    56  	// Look for root type changes.
    57  	for _, change := range changes {
    58  		if change.IsRootTypeChange() {
    59  			return true
    60  		}
    61  	}
    62  
    63  	// Done.
    64  	return false
    65  }
    66  
    67  // filteredPathsAreSubset checks whether or not a slice of filtered paths is a
    68  // subset of a larger slice of unfiltered paths. The paths in the filtered slice
    69  // must share the same relative ordering as in the original slice.
    70  func filteredPathsAreSubset(filteredPaths, originalPaths []string) bool {
    71  	// Loop over the list of filtered paths.
    72  	for _, filtered := range filteredPaths {
    73  		// Track whether or not we find a match for this path in what remains of
    74  		// the original path list.
    75  		matched := false
    76  
    77  		// Loop over what remains of the original paths.
    78  		for o, original := range originalPaths {
    79  			if original == filtered {
    80  				originalPaths = originalPaths[o+1:]
    81  				matched = true
    82  				break
    83  			}
    84  		}
    85  
    86  		// Check if we found a match.
    87  		if !matched {
    88  			return false
    89  		}
    90  	}
    91  
    92  	// Success.
    93  	return true
    94  }