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 }