github.com/richardwilkes/toolbox@v1.121.0/xio/fs/roots.go (about)

     1  // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the Mozilla Public
     4  // License, version 2.0. If a copy of the MPL was not distributed with
     5  // this file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  //
     7  // This Source Code Form is "Incompatible With Secondary Licenses", as
     8  // defined by the Mozilla Public License, version 2.0.
     9  
    10  package fs
    11  
    12  import (
    13  	"path/filepath"
    14  	"strings"
    15  
    16  	"github.com/richardwilkes/toolbox/errs"
    17  )
    18  
    19  // UniquePaths returns a list of unique paths from the given paths, pruning out paths that are a subset of another.
    20  func UniquePaths(paths ...string) ([]string, error) {
    21  	set := make(map[string]bool, len(paths))
    22  	for _, path := range paths {
    23  		actual, err := filepath.Abs(path)
    24  		if err != nil {
    25  			return nil, errs.NewWithCause(path, err)
    26  		}
    27  		if actual, err = filepath.EvalSymlinks(actual); err != nil {
    28  			return nil, errs.NewWithCause(path, err)
    29  		}
    30  		if _, exists := set[actual]; !exists {
    31  			add := true
    32  			for one := range set {
    33  				var p1, p2 string
    34  				if p1, err = filepath.Rel(one, actual); err != nil {
    35  					return nil, errs.NewWithCause(path, err)
    36  				}
    37  				if p2, err = filepath.Rel(actual, one); err != nil {
    38  					return nil, errs.NewWithCause(path, err)
    39  				}
    40  				prefixed := strings.HasPrefix(p1, "..")
    41  				if prefixed != strings.HasPrefix(p2, "..") {
    42  					if prefixed {
    43  						delete(set, one)
    44  					} else {
    45  						add = false
    46  						break
    47  					}
    48  				}
    49  			}
    50  			if add {
    51  				set[actual] = true
    52  			}
    53  		}
    54  	}
    55  	result := make([]string, 0, len(set))
    56  	for p := range set {
    57  		result = append(result, p)
    58  	}
    59  	return result, nil
    60  }