...

Source file src/gitlab.com/tslocum/desktop/scan.go

Documentation: gitlab.com/tslocum/desktop

     1  package desktop
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"runtime"
     7  	"strings"
     8  	"sync"
     9  )
    10  
    11  const bufferSize = 32 * 1024
    12  
    13  type scan struct {
    14  	e    [][]*Entry
    15  	errs chan error
    16  	in   chan *scanEntry
    17  	sync.Mutex
    18  	sync.WaitGroup
    19  }
    20  
    21  type scanEntry struct {
    22  	i int
    23  	f *os.File
    24  }
    25  
    26  // Scan non-recursively scans provided directories for desktop entry files and
    27  // parses them. A slice of parsed entries is returned for each directory.
    28  func Scan(dirs []string) ([][]*Entry, error) {
    29  	s := &scan{e: make([][]*Entry, len(dirs)), errs: make(chan error), in: make(chan *scanEntry)}
    30  
    31  	for i := 0; i < runtime.GOMAXPROCS(-1); i++ {
    32  		go scanner(s)
    33  	}
    34  
    35  	for i, dir := range dirs {
    36  		i, dir := i, dir
    37  
    38  		s.Add(1)
    39  		go scanDir(i, dir, s)
    40  	}
    41  
    42  	done := make(chan bool, 1)
    43  	go func() {
    44  		s.Wait()
    45  		close(s.in)
    46  
    47  		done <- true
    48  	}()
    49  
    50  	select {
    51  	case err := <-s.errs:
    52  		return nil, err
    53  	case <-done:
    54  		return s.e, nil
    55  	}
    56  }
    57  
    58  func scanner(s *scan) {
    59  	var (
    60  		buf       = make([]byte, bufferSize)
    61  		scanEntry *scanEntry
    62  		entry     *Entry
    63  		err       error
    64  	)
    65  
    66  	for scanEntry = range s.in {
    67  		entry, err = Parse(scanEntry.f, buf)
    68  		scanEntry.f.Close()
    69  		if err != nil {
    70  			s.errs <- err
    71  			s.Done()
    72  			return
    73  		} else if entry == nil {
    74  			s.Done()
    75  			continue
    76  		}
    77  
    78  		s.Lock()
    79  		s.e[scanEntry.i] = append(s.e[scanEntry.i], entry)
    80  		s.Unlock()
    81  
    82  		s.Done()
    83  	}
    84  }
    85  
    86  func scanFunc(i int, s *scan) filepath.WalkFunc {
    87  	return func(path string, f os.FileInfo, err error) error {
    88  		s.Add(1)
    89  
    90  		go func() {
    91  			if os.IsNotExist(err) {
    92  				s.Done()
    93  				return
    94  			} else if err != nil {
    95  				s.errs <- err
    96  				s.Done()
    97  				return
    98  			}
    99  
   100  			if f == nil || f.IsDir() || !strings.HasSuffix(strings.ToLower(path), ".desktop") {
   101  				s.Done()
   102  				return
   103  			}
   104  
   105  			f, err := os.OpenFile(path, os.O_RDONLY, 0644)
   106  			if os.IsNotExist(err) {
   107  				s.Done()
   108  				return
   109  			} else if err != nil {
   110  				s.errs <- err
   111  				s.Done()
   112  				return
   113  			}
   114  
   115  			s.in <- &scanEntry{i: i, f: f}
   116  		}()
   117  
   118  		return nil
   119  	}
   120  }
   121  
   122  func scanDir(i int, dir string, s *scan) {
   123  	defer s.Done()
   124  
   125  	err := filepath.Walk(dir, scanFunc(i, s))
   126  	if os.IsNotExist(err) {
   127  		return
   128  	} else if err != nil {
   129  		s.errs <- err
   130  	}
   131  }
   132  

View as plain text