github.com/bir3/gocompiler@v0.9.2202/extra/mkdir.go (about)

     1  // Copyright 2023 Bergur Ragnarsson
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package extra
     6  
     7  import (
     8  	"fmt"
     9  	"os"
    10  	"path/filepath"
    11  )
    12  
    13  type FileMode = os.FileMode
    14  
    15  func MkdirAllRace(dir string, perm FileMode) error {
    16  	// safe for many processes to run concurrently
    17  	dir = filepath.Clean(dir)
    18  	if !filepath.IsAbs(dir) {
    19  		return fmt.Errorf("not absolute path: %s", dir)
    20  	}
    21  	missing, err := missingFolders(dir, []string{})
    22  	if err != nil {
    23  		return err
    24  	}
    25  	for _, d2 := range missing {
    26  		os.Mkdir(d2, perm) // ignore error as we may race
    27  	}
    28  
    29  	// at the end, we want a folder to exist
    30  	// - no matter who created it:
    31  	info, err := os.Stat(dir)
    32  	if err != nil {
    33  		return fmt.Errorf("failed to create folder %s - %w", dir, err)
    34  	}
    35  	if !info.IsDir() {
    36  		return fmt.Errorf("not a folder %s", dir)
    37  	}
    38  
    39  	return nil
    40  }
    41  
    42  func missingFolders(dir string, missing []string) ([]string, error) {
    43  	for {
    44  		info, err := os.Stat(dir)
    45  		if err == nil {
    46  			if info.IsDir() {
    47  				return missing, nil
    48  			}
    49  			return []string{}, fmt.Errorf("not a folder: %s", dir)
    50  		}
    51  		missing = append([]string{dir}, missing...) // prepend => reverse order
    52  		d2 := filepath.Dir(dir)
    53  		if d2 == dir {
    54  			break
    55  		}
    56  		dir = d2
    57  	}
    58  	return []string{}, fmt.Errorf("program error at folder: %s", dir)
    59  }