github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/cmd/ipfswatch/main.go (about)

     1  package main
     2  
     3  import (
     4  	"flag"
     5  	"log"
     6  	"os"
     7  	"os/signal"
     8  	"path/filepath"
     9  
    10  	process "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
    11  	homedir "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/mitchellh/go-homedir"
    12  	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
    13  	fsnotify "github.com/ipfs/go-ipfs/Godeps/_workspace/src/gopkg.in/fsnotify.v1"
    14  	commands "github.com/ipfs/go-ipfs/commands"
    15  	core "github.com/ipfs/go-ipfs/core"
    16  	corehttp "github.com/ipfs/go-ipfs/core/corehttp"
    17  	coreunix "github.com/ipfs/go-ipfs/core/coreunix"
    18  	config "github.com/ipfs/go-ipfs/repo/config"
    19  	fsrepo "github.com/ipfs/go-ipfs/repo/fsrepo"
    20  )
    21  
    22  var http = flag.Bool("http", false, "expose IPFS HTTP API")
    23  var repoPath = flag.String("repo", os.Getenv("IPFS_PATH"), "IPFS_PATH to use")
    24  var watchPath = flag.String("path", ".", "the path to watch")
    25  
    26  func main() {
    27  	flag.Parse()
    28  
    29  	// precedence
    30  	// 1. --repo flag
    31  	// 2. IPFS_PATH environment variable
    32  	// 3. default repo path
    33  	var ipfsPath string
    34  	if *repoPath != "" {
    35  		ipfsPath = *repoPath
    36  	} else {
    37  		var err error
    38  		ipfsPath, err = fsrepo.BestKnownPath()
    39  		if err != nil {
    40  			log.Fatal(err)
    41  		}
    42  	}
    43  
    44  	if err := run(ipfsPath, *watchPath); err != nil {
    45  		log.Fatal(err)
    46  	}
    47  }
    48  
    49  func run(ipfsPath, watchPath string) error {
    50  
    51  	proc := process.WithParent(process.Background())
    52  	log.Printf("running IPFSWatch on '%s' using repo at '%s'...", watchPath, ipfsPath)
    53  
    54  	ipfsPath, err := homedir.Expand(ipfsPath)
    55  	if err != nil {
    56  		return err
    57  	}
    58  	watcher, err := fsnotify.NewWatcher()
    59  	if err != nil {
    60  		return err
    61  	}
    62  	defer watcher.Close()
    63  
    64  	if err := addTree(watcher, watchPath); err != nil {
    65  		return err
    66  	}
    67  
    68  	r, err := fsrepo.Open(ipfsPath)
    69  	if err != nil {
    70  		// TODO handle case: daemon running
    71  		// TODO handle case: repo doesn't exist or isn't initialized
    72  		return err
    73  	}
    74  
    75  	node, err := core.NewNode(context.Background(), &core.BuildCfg{
    76  		Online: true,
    77  		Repo:   r,
    78  	})
    79  	if err != nil {
    80  		return err
    81  	}
    82  	defer node.Close()
    83  
    84  	if *http {
    85  		addr := "/ip4/127.0.0.1/tcp/5001"
    86  		var opts = []corehttp.ServeOption{
    87  			corehttp.GatewayOption(true),
    88  			corehttp.WebUIOption,
    89  			corehttp.CommandsOption(cmdCtx(node, ipfsPath)),
    90  		}
    91  		proc.Go(func(p process.Process) {
    92  			if err := corehttp.ListenAndServe(node, addr, opts...); err != nil {
    93  				return
    94  			}
    95  		})
    96  	}
    97  
    98  	interrupts := make(chan os.Signal)
    99  	signal.Notify(interrupts, os.Interrupt, os.Kill)
   100  
   101  	for {
   102  		select {
   103  		case <-interrupts:
   104  			return nil
   105  		case e := <-watcher.Events:
   106  			log.Printf("received event: %s", e)
   107  			isDir, err := IsDirectory(e.Name)
   108  			if err != nil {
   109  				continue
   110  			}
   111  			switch e.Op {
   112  			case fsnotify.Remove:
   113  				if isDir {
   114  					if err := watcher.Remove(e.Name); err != nil {
   115  						return err
   116  					}
   117  				}
   118  			default:
   119  				// all events except for Remove result in an IPFS.Add, but only
   120  				// directory creation triggers a new watch
   121  				switch e.Op {
   122  				case fsnotify.Create:
   123  					if isDir {
   124  						addTree(watcher, e.Name)
   125  					}
   126  				}
   127  				proc.Go(func(p process.Process) {
   128  					file, err := os.Open(e.Name)
   129  					if err != nil {
   130  						log.Println(err)
   131  					}
   132  					defer file.Close()
   133  					k, err := coreunix.Add(node, file)
   134  					if err != nil {
   135  						log.Println(err)
   136  					}
   137  					log.Printf("added %s... key: %s", e.Name, k)
   138  				})
   139  			}
   140  		case err := <-watcher.Errors:
   141  			log.Println(err)
   142  		}
   143  	}
   144  	return nil
   145  }
   146  
   147  func addTree(w *fsnotify.Watcher, root string) error {
   148  	err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
   149  		isDir, err := IsDirectory(path)
   150  		if err != nil {
   151  			log.Println(err)
   152  			return nil
   153  		}
   154  		switch {
   155  		case isDir && IsHidden(path):
   156  			log.Println(path)
   157  			return filepath.SkipDir
   158  		case isDir:
   159  			log.Println(path)
   160  			if err := w.Add(path); err != nil {
   161  				return err
   162  			}
   163  		default:
   164  			return nil
   165  		}
   166  		return nil
   167  	})
   168  	if err != nil {
   169  		return err
   170  	}
   171  	return nil
   172  }
   173  
   174  func IsDirectory(path string) (bool, error) {
   175  	fileInfo, err := os.Stat(path)
   176  	return fileInfo.IsDir(), err
   177  }
   178  
   179  func IsHidden(path string) bool {
   180  	path = filepath.Base(path)
   181  	if path == "." || path == "" {
   182  		return false
   183  	}
   184  	if rune(path[0]) == rune('.') {
   185  		return true
   186  	}
   187  	return false
   188  }
   189  
   190  func cmdCtx(node *core.IpfsNode, repoPath string) commands.Context {
   191  	return commands.Context{
   192  		Online:     true,
   193  		ConfigRoot: repoPath,
   194  		LoadConfig: func(path string) (*config.Config, error) {
   195  			return node.Repo.Config()
   196  		},
   197  		ConstructNode: func() (*core.IpfsNode, error) {
   198  			return node, nil
   199  		},
   200  	}
   201  }