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

     1  package filesystem
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  
     9  	"github.com/mutagen-io/mutagen/pkg/mutagen"
    10  )
    11  
    12  const (
    13  	// MutagenDataDirectoryName is the name of the global Mutagen data directory
    14  	// inside the user's home directory.
    15  	MutagenDataDirectoryName = ".mutagen"
    16  
    17  	// MutagenDataDirectoryDevelopmentName is the name of the global Mutagen
    18  	// data directory inside the user's home directory for development builds of
    19  	// Mutagen.
    20  	MutagenDataDirectoryDevelopmentName = ".mutagen-dev"
    21  
    22  	// MutagenGlobalConfigurationName is the name of the global Mutagen
    23  	// configuration file inside the user's home directory.
    24  	MutagenGlobalConfigurationName = ".mutagen.yml"
    25  
    26  	// MutagenDaemonDirectoryName is the name of the daemon storage directory
    27  	// within the Mutagen data directory.
    28  	MutagenDaemonDirectoryName = "daemon"
    29  
    30  	// MutagenAgentsDirectoryName is the name of the agent storage directory
    31  	// within the Mutagen data directory.
    32  	MutagenAgentsDirectoryName = "agents"
    33  
    34  	// MutagenSynchronizationSessionsDirectoryName is the name of the
    35  	// synchronization session storage directory within the Mutagen data
    36  	// directory.
    37  	MutagenSynchronizationSessionsDirectoryName = "sessions"
    38  
    39  	// MutagenSynchronizationCachesDirectoryName is the name of the
    40  	// synchronization cache storage directory within the Mutagen data
    41  	// directory.
    42  	MutagenSynchronizationCachesDirectoryName = "caches"
    43  
    44  	// MutagenSynchronizationArchivesDirectoryName is the name of the
    45  	// synchronization archive storage directory within the Mutagen data
    46  	// directory.
    47  	MutagenSynchronizationArchivesDirectoryName = "archives"
    48  
    49  	// MutagenSynchronizationStagingDirectoryName is the name of the
    50  	// synchronization staging storage directory within the Mutagen data
    51  	// directory.
    52  	MutagenSynchronizationStagingDirectoryName = "staging"
    53  
    54  	// MutagenForwardingDirectoryName is the name of the forwarding data
    55  	// directory within the Mutagen data directory.
    56  	MutagenForwardingDirectoryName = "forwarding"
    57  
    58  	// MutagenIODirectoryName is the name of the mutagen.io data directory
    59  	// within the Mutagen data directory. This directory is no longer used. It
    60  	// was originally added to support the tunnel transport, but that no longer
    61  	// exists. This constant is left in-place as a reminder to avoid using this
    62  	// particular name for future functionality (at least without taking care to
    63  	// avoid collision with any existing files).
    64  	MutagenIODirectoryName = "mutagen.io"
    65  
    66  	// MutagenLicensingDirectoryName is the name of the licensing data directory
    67  	// within the Mutagen data directory.
    68  	MutagenLicensingDirectoryName = "licensing"
    69  )
    70  
    71  // Mutagen computes (and optionally creates) subdirectories inside the Mutagen
    72  // data directory.
    73  func Mutagen(create bool, pathComponents ...string) (string, error) {
    74  	// Check if a data directory path has been explicitly specified. If not,
    75  	// compute it using the standard procedure. Also track whether or not we
    76  	// need to mark the directory as hidden on creation.
    77  	mutagenDataDirectoryPath, ok := os.LookupEnv("MUTAGEN_DATA_DIRECTORY")
    78  	var hide bool
    79  	if ok {
    80  		// Validate the provided path.
    81  		if mutagenDataDirectoryPath == "" {
    82  			return "", errors.New("provided data directory path is empty")
    83  		} else if !filepath.IsAbs(mutagenDataDirectoryPath) {
    84  			return "", errors.New("provided data directory path is not absolute")
    85  		}
    86  	} else {
    87  		// Compute the path to the user's home directory.
    88  		homeDirectory, err := os.UserHomeDir()
    89  		if err != nil {
    90  			return "", fmt.Errorf("unable to compute path to home directory: %w", err)
    91  		}
    92  
    93  		// Compute the path to the Mutagen data directory.
    94  		if !mutagen.DevelopmentModeEnabled {
    95  			mutagenDataDirectoryPath = filepath.Join(homeDirectory, MutagenDataDirectoryName)
    96  		} else {
    97  			mutagenDataDirectoryPath = filepath.Join(homeDirectory, MutagenDataDirectoryDevelopmentName)
    98  		}
    99  
   100  		// Flag the directory for hiding.
   101  		hide = true
   102  	}
   103  
   104  	// Compute the target path.
   105  	result := filepath.Join(mutagenDataDirectoryPath, filepath.Join(pathComponents...))
   106  
   107  	// Handle directory creation, if requested.
   108  	//
   109  	// TODO: Should we iterate through each component and ensure the user hasn't
   110  	// changed the directory permissions? MkdirAll won't reset them. But I
   111  	// suppose the user may have changed them for whatever reason (though I
   112  	// can't imagine any).
   113  	if create {
   114  		// Create the directory.
   115  		if err := os.MkdirAll(result, 0700); err != nil {
   116  			return "", fmt.Errorf("unable to create subpath: %w", err)
   117  		}
   118  
   119  		// Mark the directory as hidden, if necessary.
   120  		if hide {
   121  			if err := MarkHidden(mutagenDataDirectoryPath); err != nil {
   122  				return "", fmt.Errorf("unable to hide Mutagen data directory: %w", err)
   123  			}
   124  		}
   125  	}
   126  
   127  	// Success.
   128  	return result, nil
   129  }