github.com/atrn/dcc@v0.0.0-20220806184050-4470d2553272/find.go (about)

     1  // dcc - dependency-driven C/C++ compiler front end
     2  //
     3  // Copyright © A.Newman 2015.
     4  //
     5  // This source code is released under version 2 of the  GNU Public License.
     6  // See the file LICENSE for details.
     7  //
     8  
     9  package main
    10  
    11  import (
    12  	"log"
    13  	"os"
    14  	"path/filepath"
    15  )
    16  
    17  // FindFile returns a path for a filename and a flag indicating if the
    18  // file was actually found.
    19  //
    20  func FindFile(filename string) (string, bool) {
    21  	ofilename := filename
    22  	if DebugFind {
    23  		log.Printf("DEBUG FIND: FindFile %q", ofilename)
    24  	}
    25  	path, _, exists, err := FindFileFromCwd(filename)
    26  	if err == nil && exists {
    27  		if DebugFind {
    28  			log.Printf("DEBUG FIND: FindFile %q -> %q", filename, path)
    29  		}
    30  		return path, true
    31  	}
    32  	if err != nil {
    33  		log.Print(err)
    34  	}
    35  	if DebugFind {
    36  		log.Printf("DEBUG FIND: FindFile %q -> %q", filename, filename)
    37  	}
    38  	return filename, false
    39  }
    40  
    41  // FindFileFromCwd finds a file starting from the current directory and searching towards the root.
    42  //
    43  func FindFileFromCwd(filename string) (string, os.FileInfo, bool, error) {
    44  	if DebugFind {
    45  		log.Printf("DEBUG FIND: FindFileFromCwd %q", filename)
    46  	}
    47  	return FindFileFromDirectory(filename, MustGetwd())
    48  }
    49  
    50  // FindFileFromDirectory finds a file starting from the specified directory, search towards the root.
    51  //
    52  func FindFileFromDirectory(filename, dir string) (string, os.FileInfo, bool, error) {
    53  	if DebugFind {
    54  		log.Printf("DEBUG FIND: FindFileFromDirectory %q %q", filename, dir)
    55  	}
    56  	if !filepath.IsAbs(dir) {
    57  		path, err := filepath.Abs(dir)
    58  		if err != nil {
    59  			return "", nil, false, err
    60  		}
    61  		dir = path
    62  	}
    63  	paths := []string{dir}
    64  	for !platform.IsRoot(dir) {
    65  		dir = filepath.Dir(dir)
    66  		paths = append(paths, dir)
    67  	}
    68  	paths = append(paths, dir)
    69  	return FindFileOnPath(paths, filename)
    70  }
    71  
    72  // FindFileOnPath finds a file along a search path.
    73  //
    74  func FindFileOnPath(paths []string, filename string) (string, os.FileInfo, bool, error) {
    75  	if DebugFind {
    76  		log.Printf("DEBUG FIND: FindFileOnPath %q %q", paths, filename)
    77  	}
    78  	for _, dir := range paths {
    79  		if path, info, found, err := FindFileInDirectory(filename, dir); err != nil {
    80  			return "", nil, false, err
    81  		} else if found {
    82  			return path, info, true, nil
    83  		}
    84  	}
    85  	if DebugFind {
    86  		log.Printf("DEBUG FIND: %q not found", filename)
    87  	}
    88  	return "", nil, false, nil
    89  }
    90  
    91  func FindFileInDirectory(filename string, dirname string) (string, os.FileInfo, bool, error) {
    92  	try := func(dirname, filename string) (string, os.FileInfo, bool, error) {
    93  		path := filepath.Join(dirname, filename)
    94  		if DebugFind {
    95  			log.Printf("DEBUG FIND: FindFileInDirectory trying %q", path)
    96  		}
    97  		if info, err := Stat(path); err == nil {
    98  			if DebugFind {
    99  				log.Printf("DEBUG FIND: FindFileInDirectory returning %q", path)
   100  			}
   101  			return path, info, true, nil
   102  		} else if !os.IsNotExist(err) {
   103  			if DebugFind {
   104  				log.Printf("DEBUG FIND: FindFileInDirectory %q: %s", path, err.Error())
   105  			}
   106  			return path, nil, true, err
   107  		}
   108  		return "", nil, false, nil
   109  	}
   110  
   111  	tryAll := func() (string, os.FileInfo, bool, error) {
   112  		if path, info, found, err := try(dirname, OsAndArchSpecificFilename(filename)); err != nil || found {
   113  			return path, info, found, err
   114  		}
   115  		if path, info, found, err := try(dirname, OsSpecificFilename(filename)); err != nil || found {
   116  			return path, info, found, err
   117  		}
   118  		if path, info, found, err := try(dirname, ArchSpecificFilename(filename)); err != nil || found {
   119  			return path, info, found, err
   120  		}
   121  		return try(dirname, filename)
   122  	}
   123  
   124  	if path, info, found, err := tryAll(); err != nil || found {
   125  		return path, info, found, err
   126  	}
   127  
   128  	dirname = filepath.Join(dirname, DccDir)
   129  
   130  	if path, info, found, err := tryAll(); err != nil || found {
   131  		return path, info, found, err
   132  	}
   133  
   134  	return "", nil, false, nil
   135  }
   136  
   137  // FindLibrary finds a library file on a search path, either static or dynamic.
   138  //
   139  func FindLibrary(paths []string, name string) (string, os.FileInfo, bool, error) {
   140  	if path, info, found, err := FindFileOnPath(paths, platform.DynamicLibrary(name)); found || err != nil {
   141  		return path, info, found, err
   142  	}
   143  	if path, info, found, err := FindFileOnPath(paths, platform.StaticLibrary(name)); found || err != nil {
   144  		return path, info, found, err
   145  	}
   146  	return "", nil, false, nil
   147  }