Browse Source

Migrate carbonzipper to viper as config parsing library

This will make config parsing consistent with carbonapi.
Vladimir Smirnov 4 months ago
parent
commit
ca0cdfd061
100 changed files with 16485 additions and 53 deletions
  1. 3
    0
      CHANGES.md
  2. 81
    1
      Gopkg.lock
  3. 0
    4
      Gopkg.toml
  4. 1
    0
      example.conf
  5. 49
    20
      main.go
  6. 5
    0
      vendor/github.com/fsnotify/fsnotify/.editorconfig
  7. 6
    0
      vendor/github.com/fsnotify/fsnotify/.gitignore
  8. 30
    0
      vendor/github.com/fsnotify/fsnotify/.travis.yml
  9. 52
    0
      vendor/github.com/fsnotify/fsnotify/AUTHORS
  10. 317
    0
      vendor/github.com/fsnotify/fsnotify/CHANGELOG.md
  11. 77
    0
      vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
  12. 28
    0
      vendor/github.com/fsnotify/fsnotify/LICENSE
  13. 79
    0
      vendor/github.com/fsnotify/fsnotify/README.md
  14. 37
    0
      vendor/github.com/fsnotify/fsnotify/fen.go
  15. 66
    0
      vendor/github.com/fsnotify/fsnotify/fsnotify.go
  16. 337
    0
      vendor/github.com/fsnotify/fsnotify/inotify.go
  17. 187
    0
      vendor/github.com/fsnotify/fsnotify/inotify_poller.go
  18. 521
    0
      vendor/github.com/fsnotify/fsnotify/kqueue.go
  19. 11
    0
      vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go
  20. 12
    0
      vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go
  21. 561
    0
      vendor/github.com/fsnotify/fsnotify/windows.go
  22. 9
    0
      vendor/github.com/hashicorp/hcl/.gitignore
  23. 13
    0
      vendor/github.com/hashicorp/hcl/.travis.yml
  24. 354
    0
      vendor/github.com/hashicorp/hcl/LICENSE
  25. 18
    0
      vendor/github.com/hashicorp/hcl/Makefile
  26. 125
    0
      vendor/github.com/hashicorp/hcl/README.md
  27. 19
    0
      vendor/github.com/hashicorp/hcl/appveyor.yml
  28. 729
    0
      vendor/github.com/hashicorp/hcl/decoder.go
  29. 11
    0
      vendor/github.com/hashicorp/hcl/hcl.go
  30. 219
    0
      vendor/github.com/hashicorp/hcl/hcl/ast/ast.go
  31. 52
    0
      vendor/github.com/hashicorp/hcl/hcl/ast/walk.go
  32. 17
    0
      vendor/github.com/hashicorp/hcl/hcl/parser/error.go
  33. 526
    0
      vendor/github.com/hashicorp/hcl/hcl/parser/parser.go
  34. 779
    0
      vendor/github.com/hashicorp/hcl/hcl/printer/nodes.go
  35. 66
    0
      vendor/github.com/hashicorp/hcl/hcl/printer/printer.go
  36. 652
    0
      vendor/github.com/hashicorp/hcl/hcl/scanner/scanner.go
  37. 241
    0
      vendor/github.com/hashicorp/hcl/hcl/strconv/quote.go
  38. 46
    0
      vendor/github.com/hashicorp/hcl/hcl/token/position.go
  39. 219
    0
      vendor/github.com/hashicorp/hcl/hcl/token/token.go
  40. 117
    0
      vendor/github.com/hashicorp/hcl/json/parser/flatten.go
  41. 313
    0
      vendor/github.com/hashicorp/hcl/json/parser/parser.go
  42. 451
    0
      vendor/github.com/hashicorp/hcl/json/scanner/scanner.go
  43. 46
    0
      vendor/github.com/hashicorp/hcl/json/token/position.go
  44. 118
    0
      vendor/github.com/hashicorp/hcl/json/token/token.go
  45. 38
    0
      vendor/github.com/hashicorp/hcl/lex.go
  46. 39
    0
      vendor/github.com/hashicorp/hcl/parse.go
  47. 6
    0
      vendor/github.com/magiconair/properties/.gitignore
  48. 9
    0
      vendor/github.com/magiconair/properties/.travis.yml
  49. 123
    0
      vendor/github.com/magiconair/properties/CHANGELOG.md
  50. 25
    0
      vendor/github.com/magiconair/properties/LICENSE
  51. 128
    0
      vendor/github.com/magiconair/properties/README.md
  52. 289
    0
      vendor/github.com/magiconair/properties/decode.go
  53. 156
    0
      vendor/github.com/magiconair/properties/doc.go
  54. 34
    0
      vendor/github.com/magiconair/properties/integrate.go
  55. 407
    0
      vendor/github.com/magiconair/properties/lex.go
  56. 241
    0
      vendor/github.com/magiconair/properties/load.go
  57. 95
    0
      vendor/github.com/magiconair/properties/parser.go
  58. 822
    0
      vendor/github.com/magiconair/properties/properties.go
  59. 31
    0
      vendor/github.com/magiconair/properties/rangecheck.go
  60. 8
    0
      vendor/github.com/mitchellh/mapstructure/.travis.yml
  61. 21
    0
      vendor/github.com/mitchellh/mapstructure/LICENSE
  62. 46
    0
      vendor/github.com/mitchellh/mapstructure/README.md
  63. 171
    0
      vendor/github.com/mitchellh/mapstructure/decode_hooks.go
  64. 50
    0
      vendor/github.com/mitchellh/mapstructure/error.go
  65. 1043
    0
      vendor/github.com/mitchellh/mapstructure/mapstructure.go
  66. 2
    0
      vendor/github.com/pelletier/go-toml/.gitignore
  67. 22
    0
      vendor/github.com/pelletier/go-toml/.travis.yml
  68. 21
    0
      vendor/github.com/pelletier/go-toml/LICENSE
  69. 131
    0
      vendor/github.com/pelletier/go-toml/README.md
  70. 164
    0
      vendor/github.com/pelletier/go-toml/benchmark.json
  71. 32
    0
      vendor/github.com/pelletier/go-toml/benchmark.sh
  72. 244
    0
      vendor/github.com/pelletier/go-toml/benchmark.toml
  73. 121
    0
      vendor/github.com/pelletier/go-toml/benchmark.yml
  74. 23
    0
      vendor/github.com/pelletier/go-toml/doc.go
  75. 29
    0
      vendor/github.com/pelletier/go-toml/example-crlf.toml
  76. 29
    0
      vendor/github.com/pelletier/go-toml/example.toml
  77. 31
    0
      vendor/github.com/pelletier/go-toml/fuzz.go
  78. 15
    0
      vendor/github.com/pelletier/go-toml/fuzz.sh
  79. 85
    0
      vendor/github.com/pelletier/go-toml/keysparsing.go
  80. 750
    0
      vendor/github.com/pelletier/go-toml/lexer.go
  81. 600
    0
      vendor/github.com/pelletier/go-toml/marshal.go
  82. 38
    0
      vendor/github.com/pelletier/go-toml/marshal_test.toml
  83. 430
    0
      vendor/github.com/pelletier/go-toml/parser.go
  84. 29
    0
      vendor/github.com/pelletier/go-toml/position.go
  85. 91
    0
      vendor/github.com/pelletier/go-toml/test.sh
  86. 144
    0
      vendor/github.com/pelletier/go-toml/token.go
  87. 309
    0
      vendor/github.com/pelletier/go-toml/toml.go
  88. 142
    0
      vendor/github.com/pelletier/go-toml/tomltree_create.go
  89. 289
    0
      vendor/github.com/pelletier/go-toml/tomltree_write.go
  90. 21
    0
      vendor/github.com/spf13/afero/.travis.yml
  91. 1
    28
      vendor/github.com/spf13/afero/LICENSE.txt
  92. 452
    0
      vendor/github.com/spf13/afero/README.md
  93. 108
    0
      vendor/github.com/spf13/afero/afero.go
  94. 15
    0
      vendor/github.com/spf13/afero/appveyor.yml
  95. 145
    0
      vendor/github.com/spf13/afero/basepath.go
  96. 290
    0
      vendor/github.com/spf13/afero/cacheOnReadFs.go
  97. 22
    0
      vendor/github.com/spf13/afero/const_bsds.go
  98. 25
    0
      vendor/github.com/spf13/afero/const_win_unix.go
  99. 253
    0
      vendor/github.com/spf13/afero/copyOnWriteFs.go
  100. 0
    0
      vendor/github.com/spf13/afero/httpFs.go

+ 3
- 0
CHANGES.md View File

@@ -14,6 +14,9 @@ Changes
14 14
 
15 15
 Changes
16 16
 -------
17
+**1.0.0-beta.1** **It's not recommended to switch to this release in production, until it's marked as stable**
18
+   - Migrate config parsing to viper. This should give consistent expreience with carbonapi
19
+
17 20
 **1.0.0-alpha.4** **It's not recommended to switch to this release until it's marked as stable**
18 21
    - [Code] Convert timestamps to int64
19 22
 

+ 81
- 1
Gopkg.lock View File

@@ -59,6 +59,12 @@
59 59
   revision = "1b76add642e42c6ffba7211ad7b3939ce654526e"
60 60
 
61 61
 [[projects]]
62
+  name = "github.com/fsnotify/fsnotify"
63
+  packages = ["."]
64
+  revision = "c2828203cd70a50dcccfb2761f8b1f8ceef9a8e9"
65
+  version = "v1.4.7"
66
+
67
+[[projects]]
62 68
   name = "github.com/go-graphite/protocol"
63 69
   packages = [
64 70
     "carbonapi_v2_pb",
@@ -94,6 +100,23 @@
94 100
 
95 101
 [[projects]]
96 102
   branch = "master"
103
+  name = "github.com/hashicorp/hcl"
104
+  packages = [
105
+    ".",
106
+    "hcl/ast",
107
+    "hcl/parser",
108
+    "hcl/printer",
109
+    "hcl/scanner",
110
+    "hcl/strconv",
111
+    "hcl/token",
112
+    "json/parser",
113
+    "json/scanner",
114
+    "json/token"
115
+  ]
116
+  revision = "f40e974e75af4e271d97ce0fc917af5898ae7bda"
117
+
118
+[[projects]]
119
+  branch = "master"
97 120
   name = "github.com/lestrrat/go-file-rotatelogs"
98 121
   packages = ["."]
99 122
   revision = "d3151e2a480fdcd05fb97102f5310a47d96274c4"
@@ -117,6 +140,24 @@
117 140
   revision = "3b568a1c89582d7059d81f13aa9e3f97aa9af97e"
118 141
 
119 142
 [[projects]]
143
+  name = "github.com/magiconair/properties"
144
+  packages = ["."]
145
+  revision = "c3beff4c2358b44d0493c7dda585e7db7ff28ae6"
146
+  version = "v1.7.6"
147
+
148
+[[projects]]
149
+  branch = "master"
150
+  name = "github.com/mitchellh/mapstructure"
151
+  packages = ["."]
152
+  revision = "00c29f56e2386353d58c599509e8dc3801b0d716"
153
+
154
+[[projects]]
155
+  name = "github.com/pelletier/go-toml"
156
+  packages = ["."]
157
+  revision = "acdc4509485b587f5e675510c4f2c63e90ff68a8"
158
+  version = "v1.1.0"
159
+
160
+[[projects]]
120 161
   branch = "master"
121 162
   name = "github.com/peterbourgon/g2g"
122 163
   packages = ["."]
@@ -135,6 +176,39 @@
135 176
   version = "v1.2.0"
136 177
 
137 178
 [[projects]]
179
+  name = "github.com/spf13/afero"
180
+  packages = [
181
+    ".",
182
+    "mem"
183
+  ]
184
+  revision = "bb8f1927f2a9d3ab41c9340aa034f6b803f4359c"
185
+  version = "v1.0.2"
186
+
187
+[[projects]]
188
+  name = "github.com/spf13/cast"
189
+  packages = ["."]
190
+  revision = "8965335b8c7107321228e3e3702cab9832751bac"
191
+  version = "v1.2.0"
192
+
193
+[[projects]]
194
+  branch = "master"
195
+  name = "github.com/spf13/jwalterweatherman"
196
+  packages = ["."]
197
+  revision = "7c0cea34c8ece3fbeb2b27ab9b59511d360fb394"
198
+
199
+[[projects]]
200
+  name = "github.com/spf13/pflag"
201
+  packages = ["."]
202
+  revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
203
+  version = "v1.0.0"
204
+
205
+[[projects]]
206
+  name = "github.com/spf13/viper"
207
+  packages = ["."]
208
+  revision = "b5e8006cbee93ec955a89ab31e0e3ce3204f3736"
209
+  version = "v1.0.2"
210
+
211
+[[projects]]
138 212
   name = "go.uber.org/atomic"
139 213
   packages = ["."]
140 214
   revision = "8474b86a5a6f79c443ce4b2992817ff32cf208b8"
@@ -174,6 +248,12 @@
174 248
   revision = "6078986fec03a1dcc236c34816c71b0e05018fda"
175 249
 
176 250
 [[projects]]
251
+  branch = "master"
252
+  name = "golang.org/x/sys"
253
+  packages = ["unix"]
254
+  revision = "13d03a9a82fba647c21a0ef8fba44a795d0f0835"
255
+
256
+[[projects]]
177 257
   name = "golang.org/x/text"
178 258
   packages = [
179 259
     "collate",
@@ -240,6 +320,6 @@
240 320
 [solve-meta]
241 321
   analyzer-name = "dep"
242 322
   analyzer-version = 1
243
-  inputs-digest = "e4c3cf39399fd5d435ef8a7133349c13c243b92965179d0ef785d98a8e5de868"
323
+  inputs-digest = "23b89ce08f2fa2ad418421df2f3a2a2ea4d0ec1dd64a6c60e68430691e11b9ea"
244 324
   solver-name = "gps-cdcl"
245 325
   solver-version = 1

+ 0
- 4
Gopkg.toml View File

@@ -89,10 +89,6 @@
89 89
   name = "google.golang.org/grpc"
90 90
   version = "1.10.0"
91 91
 
92
-[[constraint]]
93
-  name = "gopkg.in/yaml.v2"
94
-  version = "2.1.1"
95
-
96 92
 [prune]
97 93
   go-tests = true
98 94
   unused-packages = true

+ 1
- 0
example.conf View File

@@ -51,6 +51,7 @@ backends:
51 51
 
52 52
 # New backend format. Will be used ONLY if 'backends' section is empty
53 53
 backendsv2:
54
+  backends:
54 55
     -
55 56
         groupName: "some-broadcast"
56 57
         protocol: "protobuf" # supported: carbonapi_v3_grpc, carbonapi_v3_pb (new fancy protocos), carbonapi_v2_pb (old one)

+ 49
- 20
main.go View File

@@ -1,6 +1,7 @@
1 1
 package main
2 2
 
3 3
 import (
4
+	"bytes"
4 5
 	"encoding/json"
5 6
 	"expvar"
6 7
 	"flag"
@@ -21,6 +22,7 @@ import (
21 22
 	"github.com/facebookgo/pidfile"
22 23
 	"github.com/go-graphite/carbonzipper/intervalset"
23 24
 	"github.com/go-graphite/carbonzipper/mstats"
25
+	"github.com/spf13/viper"
24 26
 	// "github.com/go-graphite/carbonzipper/pathcache"
25 27
 	cu "github.com/go-graphite/carbonzipper/util/apictx"
26 28
 	util "github.com/go-graphite/carbonzipper/util/zipperctx"
@@ -29,8 +31,6 @@ import (
29 31
 	"github.com/go-graphite/carbonzipper/zipper/types"
30 32
 	protov2 "github.com/go-graphite/protocol/carbonapi_v2_pb"
31 33
 	protov3 "github.com/go-graphite/protocol/carbonapi_v3_pb"
32
-	"gopkg.in/yaml.v2"
33
-
34 34
 	"github.com/lomik/zapwriter"
35 35
 
36 36
 	pickle "github.com/lomik/og-rek"
@@ -59,27 +59,27 @@ type GraphiteConfig struct {
59 59
 
60 60
 // config contains necessary information for global
61 61
 var config = struct {
62
-	Backends   []string         `yaml:"backends"`
63
-	Backendsv2 types.BackendsV2 `yaml:"backendsv2"`
64
-	MaxProcs   int              `yaml:"maxProcs"`
65
-	Graphite   GraphiteConfig   `yaml:"graphite"`
66
-	GRPCListen string           `yaml:"grpcListen"`
67
-	Listen     string           `yaml:"listen"`
68
-	Buckets    int              `yaml:"buckets"`
62
+	Backends   []string         `mapstructure:"backends"`
63
+	Backendsv2 types.BackendsV2 `mapstructure:"backendsv2"`
64
+	MaxProcs   int              `mapstructure:"maxProcs"`
65
+	Graphite   GraphiteConfig   `mapstructure:"graphite"`
66
+	GRPCListen string           `mapstructure:"grpcListen"`
67
+	Listen     string           `mapstructure:"listen"`
68
+	Buckets    int              `mapstructure:"buckets"`
69 69
 
70
-	Timeouts          types.Timeouts `yaml:"timeouts"`
71
-	KeepAliveInterval time.Duration  `yaml:"keepAliveInterval"`
70
+	Timeouts          types.Timeouts `mapstructure:"timeouts"`
71
+	KeepAliveInterval time.Duration  `mapstructure:"keepAliveInterval"`
72 72
 
73
-	CarbonSearch   types.CarbonSearch   `yaml:"carbonsearch"`
74
-	CarbonSearchV2 types.CarbonSearchV2 `yaml:"carbonsearchv2"`
73
+	CarbonSearch   types.CarbonSearch   `mapstructure:"carbonsearch"`
74
+	CarbonSearchV2 types.CarbonSearchV2 `mapstructure:"carbonsearchv2"`
75 75
 
76
-	MaxIdleConnsPerHost int `yaml:"maxIdleConnsPerHost"`
77
-	MaxGlobs            int `yaml:"maxGlobs"`
76
+	MaxIdleConnsPerHost int `mapstructure:"maxIdleConnsPerHost"`
77
+	MaxGlobs            int `mapstructure:"maxGlobs"`
78 78
 
79
-	ConcurrencyLimitPerServer  int                `yaml:"concurrencyLimit"`
80
-	ExpireDelaySec             int32              `yaml:"expireDelaySec"`
81
-	Logger                     []zapwriter.Config `yaml:"logger"`
82
-	GraphiteWeb09Compatibility bool               `yaml:"graphite09compat"`
79
+	ConcurrencyLimitPerServer  int                `mapstructure:"concurrencyLimit"`
80
+	ExpireDelaySec             int32              `mapstructure:"expireDelaySec"`
81
+	Logger                     []zapwriter.Config `mapstructure:"logger"`
82
+	GraphiteWeb09Compatibility bool               `mapstructure:"graphite09compat"`
83 83
 
84 84
 	zipper *zipper.Zipper
85 85
 }{
@@ -574,6 +574,10 @@ func main() {
574 574
 
575 575
 	configFile := flag.String("config", "", "config file (yaml)")
576 576
 	pidFile := flag.String("pid", "", "pidfile (default: empty, don't create pidfile)")
577
+	envPrefix := flag.String("envprefix", "CARBONZIPPER_", "Preifx for environment variables override")
578
+	if *envPrefix == "" {
579
+		logger.Fatal("empty prefix is not suppoerted due to possible collisions with OS environment variables")
580
+	}
577 581
 
578 582
 	flag.Parse()
579 583
 
@@ -591,7 +595,32 @@ func main() {
591 595
 		)
592 596
 	}
593 597
 
594
-	err = yaml.Unmarshal(cfg, &config)
598
+	if strings.HasSuffix(*configFile, ".toml") {
599
+		logger.Info("will parse config as toml",
600
+			zap.String("config_file", *configFile),
601
+		)
602
+		viper.SetConfigType("TOML")
603
+	} else {
604
+		logger.Info("will parse config as yaml",
605
+			zap.String("config_file", *configFile),
606
+		)
607
+		viper.SetConfigType("YAML")
608
+	}
609
+	err = viper.ReadConfig(bytes.NewBuffer(cfg))
610
+	if err != nil {
611
+		logger.Fatal("failed to parse config",
612
+			zap.String("config_path", *configFile),
613
+			zap.Error(err),
614
+		)
615
+	}
616
+
617
+	if *envPrefix != "" {
618
+		viper.SetEnvPrefix(*envPrefix)
619
+	}
620
+	viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
621
+	viper.AutomaticEnv()
622
+
623
+	err = viper.Unmarshal(&config)
595 624
 	if err != nil {
596 625
 		logger.Fatal("failed to parse config",
597 626
 			zap.String("config_path", *configFile),

+ 5
- 0
vendor/github.com/fsnotify/fsnotify/.editorconfig View File

@@ -0,0 +1,5 @@
1
+root = true
2
+
3
+[*]
4
+indent_style = tab
5
+indent_size = 4

+ 6
- 0
vendor/github.com/fsnotify/fsnotify/.gitignore View File

@@ -0,0 +1,6 @@
1
+# Setup a Global .gitignore for OS and editor generated files:
2
+# https://help.github.com/articles/ignoring-files
3
+# git config --global core.excludesfile ~/.gitignore_global
4
+
5
+.vagrant
6
+*.sublime-project

+ 30
- 0
vendor/github.com/fsnotify/fsnotify/.travis.yml View File

@@ -0,0 +1,30 @@
1
+sudo: false
2
+language: go
3
+
4
+go:
5
+  - 1.8.x
6
+  - 1.9.x
7
+  - tip
8
+
9
+matrix:
10
+  allow_failures:
11
+    - go: tip
12
+  fast_finish: true
13
+
14
+before_script:
15
+  - go get -u github.com/golang/lint/golint
16
+
17
+script:
18
+  - go test -v --race ./...
19
+
20
+after_script:
21
+  - test -z "$(gofmt -s -l -w . | tee /dev/stderr)"
22
+  - test -z "$(golint ./...     | tee /dev/stderr)"
23
+  - go vet ./...
24
+
25
+os:
26
+  - linux
27
+  - osx
28
+
29
+notifications:
30
+  email: false

+ 52
- 0
vendor/github.com/fsnotify/fsnotify/AUTHORS View File

@@ -0,0 +1,52 @@
1
+# Names should be added to this file as
2
+#	Name or Organization <email address>
3
+# The email address is not required for organizations.
4
+
5
+# You can update this list using the following command:
6
+#
7
+#   $ git shortlog -se | awk '{print $2 " " $3 " " $4}'
8
+
9
+# Please keep the list sorted.
10
+
11
+Aaron L <aaron@bettercoder.net>
12
+Adrien Bustany <adrien@bustany.org>
13
+Amit Krishnan <amit.krishnan@oracle.com>
14
+Anmol Sethi <me@anmol.io>
15
+Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
16
+Bruno Bigras <bigras.bruno@gmail.com>
17
+Caleb Spare <cespare@gmail.com>
18
+Case Nelson <case@teammating.com>
19
+Chris Howey <chris@howey.me> <howeyc@gmail.com>
20
+Christoffer Buchholz <christoffer.buchholz@gmail.com>
21
+Daniel Wagner-Hall <dawagner@gmail.com>
22
+Dave Cheney <dave@cheney.net>
23
+Evan Phoenix <evan@fallingsnow.net>
24
+Francisco Souza <f@souza.cc>
25
+Hari haran <hariharan.uno@gmail.com>
26
+John C Barstow
27
+Kelvin Fo <vmirage@gmail.com>
28
+Ken-ichirou MATSUZAWA <chamas@h4.dion.ne.jp>
29
+Matt Layher <mdlayher@gmail.com>
30
+Nathan Youngman <git@nathany.com>
31
+Nickolai Zeldovich <nickolai@csail.mit.edu>
32
+Patrick <patrick@dropbox.com>
33
+Paul Hammond <paul@paulhammond.org>
34
+Pawel Knap <pawelknap88@gmail.com>
35
+Pieter Droogendijk <pieter@binky.org.uk>
36
+Pursuit92 <JoshChase@techpursuit.net>
37
+Riku Voipio <riku.voipio@linaro.org>
38
+Rob Figueiredo <robfig@gmail.com>
39
+Rodrigo Chiossi <rodrigochiossi@gmail.com>
40
+Slawek Ligus <root@ooz.ie>
41
+Soge Zhang <zhssoge@gmail.com>
42
+Tiffany Jernigan <tiffany.jernigan@intel.com>
43
+Tilak Sharma <tilaks@google.com>
44
+Tom Payne <twpayne@gmail.com>
45
+Travis Cline <travis.cline@gmail.com>
46
+Tudor Golubenco <tudor.g@gmail.com>
47
+Vahe Khachikyan <vahe@live.ca>
48
+Yukang <moorekang@gmail.com>
49
+bronze1man <bronze1man@gmail.com>
50
+debrando <denis.brandolini@gmail.com>
51
+henrikedwards <henrik.edwards@gmail.com>
52
+铁哥 <guotie.9@gmail.com>

+ 317
- 0
vendor/github.com/fsnotify/fsnotify/CHANGELOG.md View File

@@ -0,0 +1,317 @@
1
+# Changelog
2
+
3
+## v1.4.7 / 2018-01-09
4
+
5
+* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine)
6
+* Tests: Fix missing verb on format string (thanks @rchiossi)
7
+* Linux: Fix deadlock in Remove (thanks @aarondl)
8
+* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne)
9
+* Docs: Moved FAQ into the README (thanks @vahe)
10
+* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich)
11
+* Docs: replace references to OS X with macOS
12
+
13
+## v1.4.2 / 2016-10-10
14
+
15
+* Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack)
16
+
17
+## v1.4.1 / 2016-10-04
18
+
19
+* Fix flaky inotify stress test on Linux [#177](https://github.com/fsnotify/fsnotify/pull/177) (thanks @pattyshack)
20
+
21
+## v1.4.0 / 2016-10-01
22
+
23
+* add a String() method to Event.Op [#165](https://github.com/fsnotify/fsnotify/pull/165) (thanks @oozie)
24
+
25
+## v1.3.1 / 2016-06-28
26
+
27
+* Windows: fix for double backslash when watching the root of a drive [#151](https://github.com/fsnotify/fsnotify/issues/151) (thanks @brunoqc)
28
+
29
+## v1.3.0 / 2016-04-19
30
+
31
+* Support linux/arm64 by [patching](https://go-review.googlesource.com/#/c/21971/) x/sys/unix and switching to to it from syscall (thanks @suihkulokki) [#135](https://github.com/fsnotify/fsnotify/pull/135)
32
+
33
+## v1.2.10 / 2016-03-02
34
+
35
+* Fix golint errors in windows.go [#121](https://github.com/fsnotify/fsnotify/pull/121) (thanks @tiffanyfj)
36
+
37
+## v1.2.9 / 2016-01-13
38
+
39
+kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsnotify/pull/111) (thanks @bep)
40
+
41
+## v1.2.8 / 2015-12-17
42
+
43
+* kqueue: fix race condition in Close [#105](https://github.com/fsnotify/fsnotify/pull/105) (thanks @djui for reporting the issue and @ppknap for writing a failing test)
44
+* inotify: fix race in test
45
+* enable race detection for continuous integration (Linux, Mac, Windows)
46
+
47
+## v1.2.5 / 2015-10-17
48
+
49
+* inotify: use epoll_create1 for arm64 support (requires Linux 2.6.27 or later) [#100](https://github.com/fsnotify/fsnotify/pull/100) (thanks @suihkulokki)
50
+* inotify: fix path leaks [#73](https://github.com/fsnotify/fsnotify/pull/73) (thanks @chamaken)
51
+* kqueue: watch for rename events on subdirectories [#83](https://github.com/fsnotify/fsnotify/pull/83) (thanks @guotie)
52
+* kqueue: avoid infinite loops from symlinks cycles [#101](https://github.com/fsnotify/fsnotify/pull/101) (thanks @illicitonion)
53
+
54
+## v1.2.1 / 2015-10-14
55
+
56
+* kqueue: don't watch named pipes [#98](https://github.com/fsnotify/fsnotify/pull/98) (thanks @evanphx)
57
+
58
+## v1.2.0 / 2015-02-08
59
+
60
+* inotify: use epoll to wake up readEvents [#66](https://github.com/fsnotify/fsnotify/pull/66) (thanks @PieterD)
61
+* inotify: closing watcher should now always shut down goroutine [#63](https://github.com/fsnotify/fsnotify/pull/63) (thanks @PieterD)
62
+* kqueue: close kqueue after removing watches, fixes [#59](https://github.com/fsnotify/fsnotify/issues/59)
63
+
64
+## v1.1.1 / 2015-02-05
65
+
66
+* inotify: Retry read on EINTR [#61](https://github.com/fsnotify/fsnotify/issues/61) (thanks @PieterD)
67
+
68
+## v1.1.0 / 2014-12-12
69
+
70
+* kqueue: rework internals [#43](https://github.com/fsnotify/fsnotify/pull/43)
71
+    * add low-level functions
72
+    * only need to store flags on directories
73
+    * less mutexes [#13](https://github.com/fsnotify/fsnotify/issues/13)
74
+    * done can be an unbuffered channel
75
+    * remove calls to os.NewSyscallError
76
+* More efficient string concatenation for Event.String() [#52](https://github.com/fsnotify/fsnotify/pull/52) (thanks @mdlayher)
77
+* kqueue: fix regression in  rework causing subdirectories to be watched [#48](https://github.com/fsnotify/fsnotify/issues/48)
78
+* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
79
+
80
+## v1.0.4 / 2014-09-07
81
+
82
+* kqueue: add dragonfly to the build tags.
83
+* Rename source code files, rearrange code so exported APIs are at the top.
84
+* Add done channel to example code. [#37](https://github.com/fsnotify/fsnotify/pull/37) (thanks @chenyukang)
85
+
86
+## v1.0.3 / 2014-08-19
87
+
88
+* [Fix] Windows MOVED_TO now translates to Create like on BSD and Linux. [#36](https://github.com/fsnotify/fsnotify/issues/36)
89
+
90
+## v1.0.2 / 2014-08-17
91
+
92
+* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
93
+* [Fix] Make ./path and path equivalent. (thanks @zhsso)
94
+
95
+## v1.0.0 / 2014-08-15
96
+
97
+* [API] Remove AddWatch on Windows, use Add.
98
+* Improve documentation for exported identifiers. [#30](https://github.com/fsnotify/fsnotify/issues/30)
99
+* Minor updates based on feedback from golint.
100
+
101
+## dev / 2014-07-09
102
+
103
+* Moved to [github.com/fsnotify/fsnotify](https://github.com/fsnotify/fsnotify).
104
+* Use os.NewSyscallError instead of returning errno (thanks @hariharan-uno)
105
+
106
+## dev / 2014-07-04
107
+
108
+* kqueue: fix incorrect mutex used in Close()
109
+* Update example to demonstrate usage of Op.
110
+
111
+## dev / 2014-06-28
112
+
113
+* [API] Don't set the Write Op for attribute notifications [#4](https://github.com/fsnotify/fsnotify/issues/4)
114
+* Fix for String() method on Event (thanks Alex Brainman)
115
+* Don't build on Plan 9 or Solaris (thanks @4ad)
116
+
117
+## dev / 2014-06-21
118
+
119
+* Events channel of type Event rather than *Event.
120
+* [internal] use syscall constants directly for inotify and kqueue.
121
+* [internal] kqueue: rename events to kevents and fileEvent to event.
122
+
123
+## dev / 2014-06-19
124
+
125
+* Go 1.3+ required on Windows (uses syscall.ERROR_MORE_DATA internally).
126
+* [internal] remove cookie from Event struct (unused).
127
+* [internal] Event struct has the same definition across every OS.
128
+* [internal] remove internal watch and removeWatch methods.
129
+
130
+## dev / 2014-06-12
131
+
132
+* [API] Renamed Watch() to Add() and RemoveWatch() to Remove().
133
+* [API] Pluralized channel names: Events and Errors.
134
+* [API] Renamed FileEvent struct to Event.
135
+* [API] Op constants replace methods like IsCreate().
136
+
137
+## dev / 2014-06-12
138
+
139
+* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
140
+
141
+## dev / 2014-05-23
142
+
143
+* [API] Remove current implementation of WatchFlags.
144
+    * current implementation doesn't take advantage of OS for efficiency
145
+    * provides little benefit over filtering events as they are received, but has  extra bookkeeping and mutexes
146
+    * no tests for the current implementation
147
+    * not fully implemented on Windows [#93](https://github.com/howeyc/fsnotify/issues/93#issuecomment-39285195)
148
+
149
+## v0.9.3 / 2014-12-31
150
+
151
+* kqueue: cleanup internal watch before sending remove event [#51](https://github.com/fsnotify/fsnotify/issues/51)
152
+
153
+## v0.9.2 / 2014-08-17
154
+
155
+* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso)
156
+
157
+## v0.9.1 / 2014-06-12
158
+
159
+* Fix data race on kevent buffer (thanks @tilaks) [#98](https://github.com/howeyc/fsnotify/pull/98)
160
+
161
+## v0.9.0 / 2014-01-17
162
+
163
+* IsAttrib() for events that only concern a file's metadata [#79][] (thanks @abustany)
164
+* [Fix] kqueue: fix deadlock [#77][] (thanks @cespare)
165
+* [NOTICE] Development has moved to `code.google.com/p/go.exp/fsnotify` in preparation for inclusion in the Go standard library.
166
+
167
+## v0.8.12 / 2013-11-13
168
+
169
+* [API] Remove FD_SET and friends from Linux adapter
170
+
171
+## v0.8.11 / 2013-11-02
172
+
173
+* [Doc] Add Changelog [#72][] (thanks @nathany)
174
+* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond)
175
+
176
+## v0.8.10 / 2013-10-19
177
+
178
+* [Fix] kqueue: remove file watches when parent directory is removed [#71][] (reported by @mdwhatcott)
179
+* [Fix] kqueue: race between Close and readEvents [#70][] (reported by @bernerdschaefer)
180
+* [Doc] specify OS-specific limits in README (thanks @debrando)
181
+
182
+## v0.8.9 / 2013-09-08
183
+
184
+* [Doc] Contributing (thanks @nathany)
185
+* [Doc] update package path in example code [#63][] (thanks @paulhammond)
186
+* [Doc] GoCI badge in README (Linux only) [#60][]
187
+* [Doc] Cross-platform testing with Vagrant  [#59][] (thanks @nathany)
188
+
189
+## v0.8.8 / 2013-06-17
190
+
191
+* [Fix] Windows: handle `ERROR_MORE_DATA` on Windows [#49][] (thanks @jbowtie)
192
+
193
+## v0.8.7 / 2013-06-03
194
+
195
+* [API] Make syscall flags internal
196
+* [Fix] inotify: ignore event changes
197
+* [Fix] race in symlink test [#45][] (reported by @srid)
198
+* [Fix] tests on Windows
199
+* lower case error messages
200
+
201
+## v0.8.6 / 2013-05-23
202
+
203
+* kqueue: Use EVT_ONLY flag on Darwin
204
+* [Doc] Update README with full example
205
+
206
+## v0.8.5 / 2013-05-09
207
+
208
+* [Fix] inotify: allow monitoring of "broken" symlinks (thanks @tsg)
209
+
210
+## v0.8.4 / 2013-04-07
211
+
212
+* [Fix] kqueue: watch all file events [#40][] (thanks @ChrisBuchholz)
213
+
214
+## v0.8.3 / 2013-03-13
215
+
216
+* [Fix] inoitfy/kqueue memory leak [#36][] (reported by @nbkolchin)
217
+* [Fix] kqueue: use fsnFlags for watching a directory [#33][] (reported by @nbkolchin)
218
+
219
+## v0.8.2 / 2013-02-07
220
+
221
+* [Doc] add Authors
222
+* [Fix] fix data races for map access [#29][] (thanks @fsouza)
223
+
224
+## v0.8.1 / 2013-01-09
225
+
226
+* [Fix] Windows path separators
227
+* [Doc] BSD License
228
+
229
+## v0.8.0 / 2012-11-09
230
+
231
+* kqueue: directory watching improvements (thanks @vmirage)
232
+* inotify: add `IN_MOVED_TO` [#25][] (requested by @cpisto)
233
+* [Fix] kqueue: deleting watched directory [#24][] (reported by @jakerr)
234
+
235
+## v0.7.4 / 2012-10-09
236
+
237
+* [Fix] inotify: fixes from https://codereview.appspot.com/5418045/ (ugorji)
238
+* [Fix] kqueue: preserve watch flags when watching for delete [#21][] (reported by @robfig)
239
+* [Fix] kqueue: watch the directory even if it isn't a new watch (thanks @robfig)
240
+* [Fix] kqueue: modify after recreation of file
241
+
242
+## v0.7.3 / 2012-09-27
243
+
244
+* [Fix] kqueue: watch with an existing folder inside the watched folder (thanks @vmirage)
245
+* [Fix] kqueue: no longer get duplicate CREATE events
246
+
247
+## v0.7.2 / 2012-09-01
248
+
249
+* kqueue: events for created directories
250
+
251
+## v0.7.1 / 2012-07-14
252
+
253
+* [Fix] for renaming files
254
+
255
+## v0.7.0 / 2012-07-02
256
+
257
+* [Feature] FSNotify flags
258
+* [Fix] inotify: Added file name back to event path
259
+
260
+## v0.6.0 / 2012-06-06
261
+
262
+* kqueue: watch files after directory created (thanks @tmc)
263
+
264
+## v0.5.1 / 2012-05-22
265
+
266
+* [Fix] inotify: remove all watches before Close()
267
+
268
+## v0.5.0 / 2012-05-03
269
+
270
+* [API] kqueue: return errors during watch instead of sending over channel
271
+* kqueue: match symlink behavior on Linux
272
+* inotify: add `DELETE_SELF` (requested by @taralx)
273
+* [Fix] kqueue: handle EINTR (reported by @robfig)
274
+* [Doc] Godoc example [#1][] (thanks @davecheney)
275
+
276
+## v0.4.0 / 2012-03-30
277
+
278
+* Go 1 released: build with go tool
279
+* [Feature] Windows support using winfsnotify
280
+* Windows does not have attribute change notifications
281
+* Roll attribute notifications into IsModify
282
+
283
+## v0.3.0 / 2012-02-19
284
+
285
+* kqueue: add files when watch directory
286
+
287
+## v0.2.0 / 2011-12-30
288
+
289
+* update to latest Go weekly code
290
+
291
+## v0.1.0 / 2011-10-19
292
+
293
+* kqueue: add watch on file creation to match inotify
294
+* kqueue: create file event
295
+* inotify: ignore `IN_IGNORED` events
296
+* event String()
297
+* linux: common FileEvent functions
298
+* initial commit
299
+
300
+[#79]: https://github.com/howeyc/fsnotify/pull/79
301
+[#77]: https://github.com/howeyc/fsnotify/pull/77
302
+[#72]: https://github.com/howeyc/fsnotify/issues/72
303
+[#71]: https://github.com/howeyc/fsnotify/issues/71
304
+[#70]: https://github.com/howeyc/fsnotify/issues/70
305
+[#63]: https://github.com/howeyc/fsnotify/issues/63
306
+[#62]: https://github.com/howeyc/fsnotify/issues/62
307
+[#60]: https://github.com/howeyc/fsnotify/issues/60
308
+[#59]: https://github.com/howeyc/fsnotify/issues/59
309
+[#49]: https://github.com/howeyc/fsnotify/issues/49
310
+[#45]: https://github.com/howeyc/fsnotify/issues/45
311
+[#40]: https://github.com/howeyc/fsnotify/issues/40
312
+[#36]: https://github.com/howeyc/fsnotify/issues/36
313
+[#33]: https://github.com/howeyc/fsnotify/issues/33
314
+[#29]: https://github.com/howeyc/fsnotify/issues/29
315
+[#25]: https://github.com/howeyc/fsnotify/issues/25
316
+[#24]: https://github.com/howeyc/fsnotify/issues/24
317
+[#21]: https://github.com/howeyc/fsnotify/issues/21

+ 77
- 0
vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md
File diff suppressed because it is too large
View File


+ 28
- 0
vendor/github.com/fsnotify/fsnotify/LICENSE View File

@@ -0,0 +1,28 @@
1
+Copyright (c) 2012 The Go Authors. All rights reserved.
2
+Copyright (c) 2012 fsnotify Authors. All rights reserved.
3
+
4
+Redistribution and use in source and binary forms, with or without
5
+modification, are permitted provided that the following conditions are
6
+met:
7
+
8
+   * Redistributions of source code must retain the above copyright
9
+notice, this list of conditions and the following disclaimer.
10
+   * Redistributions in binary form must reproduce the above
11
+copyright notice, this list of conditions and the following disclaimer
12
+in the documentation and/or other materials provided with the
13
+distribution.
14
+   * Neither the name of Google Inc. nor the names of its
15
+contributors may be used to endorse or promote products derived from
16
+this software without specific prior written permission.
17
+
18
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 79
- 0
vendor/github.com/fsnotify/fsnotify/README.md View File

@@ -0,0 +1,79 @@
1
+# File system notifications for Go
2
+
3
+[![GoDoc](https://godoc.org/github.com/fsnotify/fsnotify?status.svg)](https://godoc.org/github.com/fsnotify/fsnotify) [![Go Report Card](https://goreportcard.com/badge/github.com/fsnotify/fsnotify)](https://goreportcard.com/report/github.com/fsnotify/fsnotify)
4
+
5
+fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather than `syscall` from the standard library. Ensure you have the latest version installed by running:
6
+
7
+```console
8
+go get -u golang.org/x/sys/...
9
+```
10
+
11
+Cross platform: Windows, Linux, BSD and macOS.
12
+
13
+|Adapter   |OS        |Status    |
14
+|----------|----------|----------|
15
+|inotify   |Linux 2.6.27 or later, Android\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)|
16
+|kqueue    |BSD, macOS, iOS\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)|
17
+|ReadDirectoryChangesW|Windows|Supported [![Build status](https://ci.appveyor.com/api/projects/status/ivwjubaih4r0udeh/branch/master?svg=true)](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)|
18
+|FSEvents  |macOS         |[Planned](https://github.com/fsnotify/fsnotify/issues/11)|
19
+|FEN       |Solaris 11    |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)|
20
+|fanotify  |Linux 2.6.37+ | |
21
+|USN Journals |Windows    |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)|
22
+|Polling   |*All*         |[Maybe](https://github.com/fsnotify/fsnotify/issues/9)|
23
+
24
+\* Android and iOS are untested.
25
+
26
+Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information.
27
+
28
+## API stability
29
+
30
+fsnotify is a fork of [howeyc/fsnotify](https://godoc.org/github.com/howeyc/fsnotify) with a new API as of v1.0. The API is based on [this design document](http://goo.gl/MrYxyA). 
31
+
32
+All [releases](https://github.com/fsnotify/fsnotify/releases) are tagged based on [Semantic Versioning](http://semver.org/). Further API changes are [planned](https://github.com/fsnotify/fsnotify/milestones), and will be tagged with a new major revision number.
33
+
34
+Go 1.6 supports dependencies located in the `vendor/` folder. Unless you are creating a library, it is recommended that you copy fsnotify into `vendor/github.com/fsnotify/fsnotify` within your project, and likewise for `golang.org/x/sys`.
35
+
36
+## Contributing
37
+
38
+Please refer to [CONTRIBUTING][] before opening an issue or pull request.
39
+
40
+## Example
41
+
42
+See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go).
43
+
44
+## FAQ
45
+
46
+**When a file is moved to another directory is it still being watched?**
47
+
48
+No (it shouldn't be, unless you are watching where it was moved to).
49
+
50
+**When I watch a directory, are all subdirectories watched as well?**
51
+
52
+No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]).
53
+
54
+**Do I have to watch the Error and Event channels in a separate goroutine?**
55
+
56
+As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7])
57
+
58
+**Why am I receiving multiple events for the same file on OS X?**
59
+
60
+Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]).
61
+
62
+**How many files can be watched at once?**
63
+
64
+There are OS-specific limits as to how many watches can be created:
65
+* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error.
66
+* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error.
67
+
68
+[#62]: https://github.com/howeyc/fsnotify/issues/62
69
+[#18]: https://github.com/fsnotify/fsnotify/issues/18
70
+[#11]: https://github.com/fsnotify/fsnotify/issues/11
71
+[#7]: https://github.com/howeyc/fsnotify/issues/7
72
+
73
+[contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md
74
+
75
+## Related Projects
76
+
77
+* [notify](https://github.com/rjeczalik/notify)
78
+* [fsevents](https://github.com/fsnotify/fsevents)
79
+

+ 37
- 0
vendor/github.com/fsnotify/fsnotify/fen.go View File

@@ -0,0 +1,37 @@
1
+// Copyright 2010 The Go Authors. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+// +build solaris
6
+
7
+package fsnotify
8
+
9
+import (
10
+	"errors"
11
+)
12
+
13
+// Watcher watches a set of files, delivering events to a channel.
14
+type Watcher struct {
15
+	Events chan Event
16
+	Errors chan error
17
+}
18
+
19
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
20
+func NewWatcher() (*Watcher, error) {
21
+	return nil, errors.New("FEN based watcher not yet supported for fsnotify\n")
22
+}
23
+
24
+// Close removes all watches and closes the events channel.
25
+func (w *Watcher) Close() error {
26
+	return nil
27
+}
28
+
29
+// Add starts watching the named file or directory (non-recursively).
30
+func (w *Watcher) Add(name string) error {
31
+	return nil
32
+}
33
+
34
+// Remove stops watching the the named file or directory (non-recursively).
35
+func (w *Watcher) Remove(name string) error {
36
+	return nil
37
+}

+ 66
- 0
vendor/github.com/fsnotify/fsnotify/fsnotify.go View File

@@ -0,0 +1,66 @@
1
+// Copyright 2012 The Go Authors. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+// +build !plan9
6
+
7
+// Package fsnotify provides a platform-independent interface for file system notifications.
8
+package fsnotify
9
+
10
+import (
11
+	"bytes"
12
+	"errors"
13
+	"fmt"
14
+)
15
+
16
+// Event represents a single file system notification.
17
+type Event struct {
18
+	Name string // Relative path to the file or directory.
19
+	Op   Op     // File operation that triggered the event.
20
+}
21
+
22
+// Op describes a set of file operations.
23
+type Op uint32
24
+
25
+// These are the generalized file operations that can trigger a notification.
26
+const (
27
+	Create Op = 1 << iota
28
+	Write
29
+	Remove
30
+	Rename
31
+	Chmod
32
+)
33
+
34
+func (op Op) String() string {
35
+	// Use a buffer for efficient string concatenation
36
+	var buffer bytes.Buffer
37
+
38
+	if op&Create == Create {
39
+		buffer.WriteString("|CREATE")
40
+	}
41
+	if op&Remove == Remove {
42
+		buffer.WriteString("|REMOVE")
43
+	}
44
+	if op&Write == Write {
45
+		buffer.WriteString("|WRITE")
46
+	}
47
+	if op&Rename == Rename {
48
+		buffer.WriteString("|RENAME")
49
+	}
50
+	if op&Chmod == Chmod {
51
+		buffer.WriteString("|CHMOD")
52
+	}
53
+	if buffer.Len() == 0 {
54
+		return ""
55
+	}
56
+	return buffer.String()[1:] // Strip leading pipe
57
+}
58
+
59
+// String returns a string representation of the event in the form
60
+// "file: REMOVE|WRITE|..."
61
+func (e Event) String() string {
62
+	return fmt.Sprintf("%q: %s", e.Name, e.Op.String())
63
+}
64
+
65
+// Common errors that can be reported by a watcher
66
+var ErrEventOverflow = errors.New("fsnotify queue overflow")

+ 337
- 0
vendor/github.com/fsnotify/fsnotify/inotify.go View File

@@ -0,0 +1,337 @@
1
+// Copyright 2010 The Go Authors. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+// +build linux
6
+
7
+package fsnotify
8
+
9
+import (
10
+	"errors"
11
+	"fmt"
12
+	"io"
13
+	"os"
14
+	"path/filepath"
15
+	"strings"
16
+	"sync"
17
+	"unsafe"
18
+
19
+	"golang.org/x/sys/unix"
20
+)
21
+
22
+// Watcher watches a set of files, delivering events to a channel.
23
+type Watcher struct {
24
+	Events   chan Event
25
+	Errors   chan error
26
+	mu       sync.Mutex // Map access
27
+	fd       int
28
+	poller   *fdPoller
29
+	watches  map[string]*watch // Map of inotify watches (key: path)
30
+	paths    map[int]string    // Map of watched paths (key: watch descriptor)
31
+	done     chan struct{}     // Channel for sending a "quit message" to the reader goroutine
32
+	doneResp chan struct{}     // Channel to respond to Close
33
+}
34
+
35
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
36
+func NewWatcher() (*Watcher, error) {
37
+	// Create inotify fd
38
+	fd, errno := unix.InotifyInit1(unix.IN_CLOEXEC)
39
+	if fd == -1 {
40
+		return nil, errno
41
+	}
42
+	// Create epoll
43
+	poller, err := newFdPoller(fd)
44
+	if err != nil {
45
+		unix.Close(fd)
46
+		return nil, err
47
+	}
48
+	w := &Watcher{
49
+		fd:       fd,
50
+		poller:   poller,
51
+		watches:  make(map[string]*watch),
52
+		paths:    make(map[int]string),
53
+		Events:   make(chan Event),
54
+		Errors:   make(chan error),
55
+		done:     make(chan struct{}),
56
+		doneResp: make(chan struct{}),
57
+	}
58
+
59
+	go w.readEvents()
60
+	return w, nil
61
+}
62
+
63
+func (w *Watcher) isClosed() bool {
64
+	select {
65
+	case <-w.done:
66
+		return true
67
+	default:
68
+		return false
69
+	}
70
+}
71
+
72
+// Close removes all watches and closes the events channel.
73
+func (w *Watcher) Close() error {
74
+	if w.isClosed() {
75
+		return nil
76
+	}
77
+
78
+	// Send 'close' signal to goroutine, and set the Watcher to closed.
79
+	close(w.done)
80
+
81
+	// Wake up goroutine
82
+	w.poller.wake()
83
+
84
+	// Wait for goroutine to close
85
+	<-w.doneResp
86
+
87
+	return nil
88
+}
89
+
90
+// Add starts watching the named file or directory (non-recursively).
91
+func (w *Watcher) Add(name string) error {
92
+	name = filepath.Clean(name)
93
+	if w.isClosed() {
94
+		return errors.New("inotify instance already closed")
95
+	}
96
+
97
+	const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
98
+		unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
99
+		unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
100
+
101
+	var flags uint32 = agnosticEvents
102
+
103
+	w.mu.Lock()
104
+	defer w.mu.Unlock()
105
+	watchEntry := w.watches[name]
106
+	if watchEntry != nil {
107
+		flags |= watchEntry.flags | unix.IN_MASK_ADD
108
+	}
109
+	wd, errno := unix.InotifyAddWatch(w.fd, name, flags)
110
+	if wd == -1 {
111
+		return errno
112
+	}
113
+
114
+	if watchEntry == nil {
115
+		w.watches[name] = &watch{wd: uint32(wd), flags: flags}
116
+		w.paths[wd] = name
117
+	} else {
118
+		watchEntry.wd = uint32(wd)
119
+		watchEntry.flags = flags
120
+	}
121
+
122
+	return nil
123
+}
124
+
125
+// Remove stops watching the named file or directory (non-recursively).
126
+func (w *Watcher) Remove(name string) error {
127
+	name = filepath.Clean(name)
128
+
129
+	// Fetch the watch.
130
+	w.mu.Lock()
131
+	defer w.mu.Unlock()
132
+	watch, ok := w.watches[name]
133
+
134
+	// Remove it from inotify.
135
+	if !ok {
136
+		return fmt.Errorf("can't remove non-existent inotify watch for: %s", name)
137
+	}
138
+
139
+	// We successfully removed the watch if InotifyRmWatch doesn't return an
140
+	// error, we need to clean up our internal state to ensure it matches
141
+	// inotify's kernel state.
142
+	delete(w.paths, int(watch.wd))
143
+	delete(w.watches, name)
144
+
145
+	// inotify_rm_watch will return EINVAL if the file has been deleted;
146
+	// the inotify will already have been removed.
147
+	// watches and pathes are deleted in ignoreLinux() implicitly and asynchronously
148
+	// by calling inotify_rm_watch() below. e.g. readEvents() goroutine receives IN_IGNORE
149
+	// so that EINVAL means that the wd is being rm_watch()ed or its file removed
150
+	// by another thread and we have not received IN_IGNORE event.
151
+	success, errno := unix.InotifyRmWatch(w.fd, watch.wd)
152
+	if success == -1 {
153
+		// TODO: Perhaps it's not helpful to return an error here in every case.
154
+		// the only two possible errors are:
155
+		// EBADF, which happens when w.fd is not a valid file descriptor of any kind.
156
+		// EINVAL, which is when fd is not an inotify descriptor or wd is not a valid watch descriptor.
157
+		// Watch descriptors are invalidated when they are removed explicitly or implicitly;
158
+		// explicitly by inotify_rm_watch, implicitly when the file they are watching is deleted.
159
+		return errno
160
+	}
161
+
162
+	return nil
163
+}
164
+
165
+type watch struct {
166
+	wd    uint32 // Watch descriptor (as returned by the inotify_add_watch() syscall)
167
+	flags uint32 // inotify flags of this watch (see inotify(7) for the list of valid flags)
168
+}
169
+
170
+// readEvents reads from the inotify file descriptor, converts the
171
+// received events into Event objects and sends them via the Events channel
172
+func (w *Watcher) readEvents() {
173
+	var (
174
+		buf   [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events
175
+		n     int                                  // Number of bytes read with read()
176
+		errno error                                // Syscall errno
177
+		ok    bool                                 // For poller.wait
178
+	)
179
+
180
+	defer close(w.doneResp)
181
+	defer close(w.Errors)
182
+	defer close(w.Events)
183
+	defer unix.Close(w.fd)
184
+	defer w.poller.close()
185
+
186
+	for {
187
+		// See if we have been closed.
188
+		if w.isClosed() {
189
+			return
190
+		}
191
+
192
+		ok, errno = w.poller.wait()
193
+		if errno != nil {
194
+			select {
195
+			case w.Errors <- errno:
196
+			case <-w.done:
197
+				return
198
+			}
199
+			continue
200
+		}
201
+
202
+		if !ok {
203
+			continue
204
+		}
205
+
206
+		n, errno = unix.Read(w.fd, buf[:])
207
+		// If a signal interrupted execution, see if we've been asked to close, and try again.
208
+		// http://man7.org/linux/man-pages/man7/signal.7.html :
209
+		// "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable"
210
+		if errno == unix.EINTR {
211
+			continue
212
+		}
213
+
214
+		// unix.Read might have been woken up by Close. If so, we're done.
215
+		if w.isClosed() {
216
+			return
217
+		}
218
+
219
+		if n < unix.SizeofInotifyEvent {
220
+			var err error
221
+			if n == 0 {
222
+				// If EOF is received. This should really never happen.
223
+				err = io.EOF
224
+			} else if n < 0 {
225
+				// If an error occurred while reading.
226
+				err = errno
227
+			} else {
228
+				// Read was too short.
229
+				err = errors.New("notify: short read in readEvents()")
230
+			}
231
+			select {
232
+			case w.Errors <- err:
233
+			case <-w.done:
234
+				return
235
+			}
236
+			continue
237
+		}
238
+
239
+		var offset uint32
240
+		// We don't know how many events we just read into the buffer
241
+		// While the offset points to at least one whole event...
242
+		for offset <= uint32(n-unix.SizeofInotifyEvent) {
243
+			// Point "raw" to the event in the buffer
244
+			raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset]))
245
+
246
+			mask := uint32(raw.Mask)
247
+			nameLen := uint32(raw.Len)
248
+
249
+			if mask&unix.IN_Q_OVERFLOW != 0 {
250
+				select {
251
+				case w.Errors <- ErrEventOverflow:
252
+				case <-w.done:
253
+					return
254
+				}
255
+			}
256
+
257
+			// If the event happened to the watched directory or the watched file, the kernel
258
+			// doesn't append the filename to the event, but we would like to always fill the
259
+			// the "Name" field with a valid filename. We retrieve the path of the watch from
260
+			// the "paths" map.
261
+			w.mu.Lock()
262
+			name, ok := w.paths[int(raw.Wd)]
263
+			// IN_DELETE_SELF occurs when the file/directory being watched is removed.
264
+			// This is a sign to clean up the maps, otherwise we are no longer in sync
265
+			// with the inotify kernel state which has already deleted the watch
266
+			// automatically.
267
+			if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF {
268
+				delete(w.paths, int(raw.Wd))
269
+				delete(w.watches, name)
270
+			}
271
+			w.mu.Unlock()
272
+
273
+			if nameLen > 0 {
274
+				// Point "bytes" at the first byte of the filename
275
+				bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent]))
276
+				// The filename is padded with NULL bytes. TrimRight() gets rid of those.
277
+				name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000")
278
+			}
279
+
280
+			event := newEvent(name, mask)
281
+
282
+			// Send the events that are not ignored on the events channel
283
+			if !event.ignoreLinux(mask) {
284
+				select {
285
+				case w.Events <- event:
286
+				case <-w.done:
287
+					return
288
+				}
289
+			}
290
+
291
+			// Move to the next event in the buffer
292
+			offset += unix.SizeofInotifyEvent + nameLen
293
+		}
294
+	}
295
+}
296
+
297
+// Certain types of events can be "ignored" and not sent over the Events
298
+// channel. Such as events marked ignore by the kernel, or MODIFY events
299
+// against files that do not exist.
300
+func (e *Event) ignoreLinux(mask uint32) bool {
301
+	// Ignore anything the inotify API says to ignore
302
+	if mask&unix.IN_IGNORED == unix.IN_IGNORED {
303
+		return true
304
+	}
305
+
306
+	// If the event is not a DELETE or RENAME, the file must exist.
307
+	// Otherwise the event is ignored.
308
+	// *Note*: this was put in place because it was seen that a MODIFY
309
+	// event was sent after the DELETE. This ignores that MODIFY and
310
+	// assumes a DELETE will come or has come if the file doesn't exist.
311
+	if !(e.Op&Remove == Remove || e.Op&Rename == Rename) {
312
+		_, statErr := os.Lstat(e.Name)
313
+		return os.IsNotExist(statErr)
314
+	}
315
+	return false
316
+}
317
+
318
+// newEvent returns an platform-independent Event based on an inotify mask.
319
+func newEvent(name string, mask uint32) Event {
320
+	e := Event{Name: name}
321
+	if mask&unix.IN_CREATE == unix.IN_CREATE || mask&unix.IN_MOVED_TO == unix.IN_MOVED_TO {
322
+		e.Op |= Create
323
+	}
324
+	if mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF || mask&unix.IN_DELETE == unix.IN_DELETE {
325
+		e.Op |= Remove
326
+	}
327
+	if mask&unix.IN_MODIFY == unix.IN_MODIFY {
328
+		e.Op |= Write
329
+	}
330
+	if mask&unix.IN_MOVE_SELF == unix.IN_MOVE_SELF || mask&unix.IN_MOVED_FROM == unix.IN_MOVED_FROM {
331
+		e.Op |= Rename
332
+	}
333
+	if mask&unix.IN_ATTRIB == unix.IN_ATTRIB {
334
+		e.Op |= Chmod
335
+	}
336
+	return e
337
+}

+ 187
- 0
vendor/github.com/fsnotify/fsnotify/inotify_poller.go View File

@@ -0,0 +1,187 @@
1
+// Copyright 2015 The Go Authors. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+// +build linux
6
+
7
+package fsnotify
8
+
9
+import (
10
+	"errors"
11
+
12
+	"golang.org/x/sys/unix"
13
+)
14
+
15
+type fdPoller struct {
16
+	fd   int    // File descriptor (as returned by the inotify_init() syscall)
17
+	epfd int    // Epoll file descriptor
18
+	pipe [2]int // Pipe for waking up
19
+}
20
+
21
+func emptyPoller(fd int) *fdPoller {
22
+	poller := new(fdPoller)
23
+	poller.fd = fd
24
+	poller.epfd = -1
25
+	poller.pipe[0] = -1
26
+	poller.pipe[1] = -1
27
+	return poller
28
+}
29
+
30
+// Create a new inotify poller.
31
+// This creates an inotify handler, and an epoll handler.
32
+func newFdPoller(fd int) (*fdPoller, error) {
33
+	var errno error
34
+	poller := emptyPoller(fd)
35
+	defer func() {
36
+		if errno != nil {
37
+			poller.close()
38
+		}
39
+	}()
40
+	poller.fd = fd
41
+
42
+	// Create epoll fd
43
+	poller.epfd, errno = unix.EpollCreate1(0)
44
+	if poller.epfd == -1 {
45
+		return nil, errno
46
+	}
47
+	// Create pipe; pipe[0] is the read end, pipe[1] the write end.
48
+	errno = unix.Pipe2(poller.pipe[:], unix.O_NONBLOCK)
49
+	if errno != nil {
50
+		return nil, errno
51
+	}
52
+
53
+	// Register inotify fd with epoll
54
+	event := unix.EpollEvent{
55
+		Fd:     int32(poller.fd),
56
+		Events: unix.EPOLLIN,
57
+	}
58
+	errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.fd, &event)
59
+	if errno != nil {
60
+		return nil, errno
61
+	}
62
+
63
+	// Register pipe fd with epoll
64
+	event = unix.EpollEvent{
65
+		Fd:     int32(poller.pipe[0]),
66
+		Events: unix.EPOLLIN,
67
+	}
68
+	errno = unix.EpollCtl(poller.epfd, unix.EPOLL_CTL_ADD, poller.pipe[0], &event)
69
+	if errno != nil {
70
+		return nil, errno
71
+	}
72
+
73
+	return poller, nil
74
+}
75
+
76
+// Wait using epoll.
77
+// Returns true if something is ready to be read,
78
+// false if there is not.
79
+func (poller *fdPoller) wait() (bool, error) {
80
+	// 3 possible events per fd, and 2 fds, makes a maximum of 6 events.
81
+	// I don't know whether epoll_wait returns the number of events returned,
82
+	// or the total number of events ready.
83
+	// I decided to catch both by making the buffer one larger than the maximum.
84
+	events := make([]unix.EpollEvent, 7)
85
+	for {
86
+		n, errno := unix.EpollWait(poller.epfd, events, -1)
87
+		if n == -1 {
88
+			if errno == unix.EINTR {
89
+				continue
90
+			}
91
+			return false, errno
92
+		}
93
+		if n == 0 {
94
+			// If there are no events, try again.
95
+			continue
96
+		}
97
+		if n > 6 {
98
+			// This should never happen. More events were returned than should be possible.
99
+			return false, errors.New("epoll_wait returned more events than I know what to do with")
100
+		}
101
+		ready := events[:n]
102
+		epollhup := false
103
+		epollerr := false
104
+		epollin := false
105
+		for _, event := range ready {
106
+			if event.Fd == int32(poller.fd) {
107
+				if event.Events&unix.EPOLLHUP != 0 {
108
+					// This should not happen, but if it does, treat it as a wakeup.
109
+					epollhup = true
110
+				}
111
+				if event.Events&unix.EPOLLERR != 0 {
112
+					// If an error is waiting on the file descriptor, we should pretend
113
+					// something is ready to read, and let unix.Read pick up the error.
114
+					epollerr = true
115
+				}
116
+				if event.Events&unix.EPOLLIN != 0 {
117
+					// There is data to read.
118
+					epollin = true
119
+				}
120
+			}
121
+			if event.Fd == int32(poller.pipe[0]) {
122
+				if event.Events&unix.EPOLLHUP != 0 {
123
+					// Write pipe descriptor was closed, by us. This means we're closing down the
124
+					// watcher, and we should wake up.
125
+				}
126
+				if event.Events&unix.EPOLLERR != 0 {
127
+					// If an error is waiting on the pipe file descriptor.
128
+					// This is an absolute mystery, and should never ever happen.
129
+					return false, errors.New("Error on the pipe descriptor.")
130
+				}
131
+				if event.Events&unix.EPOLLIN != 0 {
132
+					// This is a regular wakeup, so we have to clear the buffer.
133
+					err := poller.clearWake()
134
+					if err != nil {
135
+						return false, err
136
+					}
137
+				}
138
+			}
139
+		}
140
+
141
+		if epollhup || epollerr || epollin {
142
+			return true, nil
143
+		}
144
+		return false, nil
145
+	}
146
+}
147
+
148
+// Close the write end of the poller.
149
+func (poller *fdPoller) wake() error {
150
+	buf := make([]byte, 1)
151
+	n, errno := unix.Write(poller.pipe[1], buf)
152
+	if n == -1 {
153
+		if errno == unix.EAGAIN {
154
+			// Buffer is full, poller will wake.
155
+			return nil
156
+		}
157
+		return errno
158
+	}
159
+	return nil
160
+}
161
+
162
+func (poller *fdPoller) clearWake() error {
163
+	// You have to be woken up a LOT in order to get to 100!
164
+	buf := make([]byte, 100)
165
+	n, errno := unix.Read(poller.pipe[0], buf)
166
+	if n == -1 {
167
+		if errno == unix.EAGAIN {
168
+			// Buffer is empty, someone else cleared our wake.
169
+			return nil
170
+		}
171
+		return errno
172
+	}
173
+	return nil
174
+}
175
+
176
+// Close all poller file descriptors, but not the one passed to it.
177
+func (poller *fdPoller) close() {
178
+	if poller.pipe[1] != -1 {
179
+		unix.Close(poller.pipe[1])
180
+	}
181
+	if poller.pipe[0] != -1 {
182
+		unix.Close(poller.pipe[0])
183
+	}
184
+	if poller.epfd != -1 {
185
+		unix.Close(poller.epfd)
186
+	}
187
+}

+ 521
- 0
vendor/github.com/fsnotify/fsnotify/kqueue.go View File

@@ -0,0 +1,521 @@
1
+// Copyright 2010 The Go Authors. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+// +build freebsd openbsd netbsd dragonfly darwin
6
+
7
+package fsnotify
8
+
9
+import (
10
+	"errors"
11
+	"fmt"
12
+	"io/ioutil"
13
+	"os"
14
+	"path/filepath"
15
+	"sync"
16
+	"time"
17
+
18
+	"golang.org/x/sys/unix"
19
+)
20
+
21
+// Watcher watches a set of files, delivering events to a channel.
22
+type Watcher struct {
23
+	Events chan Event
24
+	Errors chan error
25
+	done   chan struct{} // Channel for sending a "quit message" to the reader goroutine
26
+
27
+	kq int // File descriptor (as returned by the kqueue() syscall).
28
+
29
+	mu              sync.Mutex        // Protects access to watcher data
30
+	watches         map[string]int    // Map of watched file descriptors (key: path).
31
+	externalWatches map[string]bool   // Map of watches added by user of the library.
32
+	dirFlags        map[string]uint32 // Map of watched directories to fflags used in kqueue.
33
+	paths           map[int]pathInfo  // Map file descriptors to path names for processing kqueue events.
34
+	fileExists      map[string]bool   // Keep track of if we know this file exists (to stop duplicate create events).
35
+	isClosed        bool              // Set to true when Close() is first called
36
+}
37
+
38
+type pathInfo struct {
39
+	name  string
40
+	isDir bool
41
+}
42
+
43
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
44
+func NewWatcher() (*Watcher, error) {
45
+	kq, err := kqueue()
46
+	if err != nil {
47
+		return nil, err
48
+	}
49
+
50
+	w := &Watcher{
51
+		kq:              kq,
52
+		watches:         make(map[string]int),
53
+		dirFlags:        make(map[string]uint32),
54
+		paths:           make(map[int]pathInfo),
55
+		fileExists:      make(map[string]bool),
56
+		externalWatches: make(map[string]bool),
57
+		Events:          make(chan Event),
58
+		Errors:          make(chan error),
59
+		done:            make(chan struct{}),
60
+	}
61
+
62
+	go w.readEvents()
63
+	return w, nil
64
+}
65
+
66
+// Close removes all watches and closes the events channel.
67
+func (w *Watcher) Close() error {
68
+	w.mu.Lock()
69
+	if w.isClosed {
70
+		w.mu.Unlock()
71
+		return nil
72
+	}
73
+	w.isClosed = true
74
+
75
+	// copy paths to remove while locked
76
+	var pathsToRemove = make([]string, 0, len(w.watches))
77
+	for name := range w.watches {
78
+		pathsToRemove = append(pathsToRemove, name)
79
+	}
80
+	w.mu.Unlock()
81
+	// unlock before calling Remove, which also locks
82
+
83
+	for _, name := range pathsToRemove {
84
+		w.Remove(name)
85
+	}
86
+
87
+	// send a "quit" message to the reader goroutine
88
+	close(w.done)
89
+
90
+	return nil
91
+}
92
+
93
+// Add starts watching the named file or directory (non-recursively).
94
+func (w *Watcher) Add(name string) error {
95
+	w.mu.Lock()
96
+	w.externalWatches[name] = true
97
+	w.mu.Unlock()
98
+	_, err := w.addWatch(name, noteAllEvents)
99
+	return err
100
+}
101
+
102
+// Remove stops watching the the named file or directory (non-recursively).
103
+func (w *Watcher) Remove(name string) error {
104
+	name = filepath.Clean(name)
105
+	w.mu.Lock()
106
+	watchfd, ok := w.watches[name]
107
+	w.mu.Unlock()
108
+	if !ok {
109
+		return fmt.Errorf("can't remove non-existent kevent watch for: %s", name)
110
+	}
111
+
112
+	const registerRemove = unix.EV_DELETE
113
+	if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil {
114
+		return err
115
+	}
116
+
117
+	unix.Close(watchfd)
118
+
119
+	w.mu.Lock()
120
+	isDir := w.paths[watchfd].isDir
121
+	delete(w.watches, name)
122
+	delete(w.paths, watchfd)
123
+	delete(w.dirFlags, name)
124
+	w.mu.Unlock()
125
+
126
+	// Find all watched paths that are in this directory that are not external.
127
+	if isDir {
128
+		var pathsToRemove []string
129
+		w.mu.Lock()
130
+		for _, path := range w.paths {
131
+			wdir, _ := filepath.Split(path.name)
132
+			if filepath.Clean(wdir) == name {
133
+				if !w.externalWatches[path.name] {
134
+					pathsToRemove = append(pathsToRemove, path.name)
135
+				}
136
+			}
137
+		}
138
+		w.mu.Unlock()
139
+		for _, name := range pathsToRemove {
140
+			// Since these are internal, not much sense in propagating error
141
+			// to the user, as that will just confuse them with an error about
142
+			// a path they did not explicitly watch themselves.
143
+			w.Remove(name)
144
+		}
145
+	}
146
+
147
+	return nil
148
+}
149
+
150
+// Watch all events (except NOTE_EXTEND, NOTE_LINK, NOTE_REVOKE)
151
+const noteAllEvents = unix.NOTE_DELETE | unix.NOTE_WRITE | unix.NOTE_ATTRIB | unix.NOTE_RENAME
152
+
153
+// keventWaitTime to block on each read from kevent
154
+var keventWaitTime = durationToTimespec(100 * time.Millisecond)
155
+
156
+// addWatch adds name to the watched file set.
157
+// The flags are interpreted as described in kevent(2).
158
+// Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks.
159
+func (w *Watcher) addWatch(name string, flags uint32) (string, error) {
160
+	var isDir bool
161
+	// Make ./name and name equivalent
162
+	name = filepath.Clean(name)
163
+
164
+	w.mu.Lock()
165
+	if w.isClosed {
166
+		w.mu.Unlock()
167
+		return "", errors.New("kevent instance already closed")
168
+	}
169
+	watchfd, alreadyWatching := w.watches[name]
170
+	// We already have a watch, but we can still override flags.
171
+	if alreadyWatching {
172
+		isDir = w.paths[watchfd].isDir
173
+	}
174
+	w.mu.Unlock()
175
+
176
+	if !alreadyWatching {
177
+		fi, err := os.Lstat(name)
178
+		if err != nil {
179
+			return "", err
180
+		}
181
+
182
+		// Don't watch sockets.
183
+		if fi.Mode()&os.ModeSocket == os.ModeSocket {
184
+			return "", nil
185
+		}
186
+
187
+		// Don't watch named pipes.
188
+		if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe {
189
+			return "", nil
190
+		}
191
+
192
+		// Follow Symlinks
193
+		// Unfortunately, Linux can add bogus symlinks to watch list without
194
+		// issue, and Windows can't do symlinks period (AFAIK). To  maintain
195
+		// consistency, we will act like everything is fine. There will simply
196
+		// be no file events for broken symlinks.
197
+		// Hence the returns of nil on errors.
198
+		if fi.Mode()&os.ModeSymlink == os.ModeSymlink {
199
+			name, err = filepath.EvalSymlinks(name)
200
+			if err != nil {
201
+				return "", nil
202
+			}
203
+
204
+			w.mu.Lock()
205
+			_, alreadyWatching = w.watches[name]
206
+			w.mu.Unlock()
207
+
208
+			if alreadyWatching {
209
+				return name, nil
210
+			}
211
+
212
+			fi, err = os.Lstat(name)
213
+			if err != nil {
214
+				return "", nil
215
+			}
216
+		}
217
+
218
+		watchfd, err = unix.Open(name, openMode, 0700)
219
+		if watchfd == -1 {
220
+			return "", err
221
+		}
222
+
223
+		isDir = fi.IsDir()
224
+	}
225
+
226
+	const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE
227
+	if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil {
228
+		unix.Close(watchfd)
229
+		return "", err
230
+	}
231
+
232
+	if !alreadyWatching {
233
+		w.mu.Lock()
234
+		w.watches[name] = watchfd
235
+		w.paths[watchfd] = pathInfo{name: name, isDir: isDir}
236
+		w.mu.Unlock()
237
+	}
238
+
239
+	if isDir {
240
+		// Watch the directory if it has not been watched before,
241
+		// or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles)
242
+		w.mu.Lock()
243
+
244
+		watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE &&
245
+			(!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE)
246
+		// Store flags so this watch can be updated later
247
+		w.dirFlags[name] = flags
248
+		w.mu.Unlock()
249
+
250
+		if watchDir {
251
+			if err := w.watchDirectoryFiles(name); err != nil {
252
+				return "", err
253
+			}
254
+		}
255
+	}
256
+	return name, nil
257
+}
258
+
259
+// readEvents reads from kqueue and converts the received kevents into
260
+// Event values that it sends down the Events channel.
261
+func (w *Watcher) readEvents() {
262
+	eventBuffer := make([]unix.Kevent_t, 10)
263
+
264
+loop:
265
+	for {
266
+		// See if there is a message on the "done" channel
267
+		select {
268
+		case <-w.done:
269
+			break loop
270
+		default:
271
+		}
272
+
273
+		// Get new events
274
+		kevents, err := read(w.kq, eventBuffer, &keventWaitTime)
275
+		// EINTR is okay, the syscall was interrupted before timeout expired.
276
+		if err != nil && err != unix.EINTR {
277
+			select {
278
+			case w.Errors <- err:
279
+			case <-w.done:
280
+				break loop
281
+			}
282
+			continue
283
+		}
284
+
285
+		// Flush the events we received to the Events channel
286
+		for len(kevents) > 0 {
287
+			kevent := &kevents[0]
288
+			watchfd := int(kevent.Ident)
289
+			mask := uint32(kevent.Fflags)
290
+			w.mu.Lock()
291
+			path := w.paths[watchfd]
292
+			w.mu.Unlock()
293
+			event := newEvent(path.name, mask)
294
+
295
+			if path.isDir && !(event.Op&Remove == Remove) {
296
+				// Double check to make sure the directory exists. This can happen when
297
+				// we do a rm -fr on a recursively watched folders and we receive a
298
+				// modification event first but the folder has been deleted and later
299
+				// receive the delete event
300
+				if _, err := os.Lstat(event.Name); os.IsNotExist(err) {
301
+					// mark is as delete event
302
+					event.Op |= Remove
303
+				}
304
+			}
305
+
306
+			if event.Op&Rename == Rename || event.Op&Remove == Remove {
307
+				w.Remove(event.Name)
308
+				w.mu.Lock()
309
+				delete(w.fileExists, event.Name)
310
+				w.mu.Unlock()
311
+			}
312
+
313
+			if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) {
314
+				w.sendDirectoryChangeEvents(event.Name)
315
+			} else {
316
+				// Send the event on the Events channel.
317
+				select {
318
+				case w.Events <- event:
319
+				case <-w.done:
320
+					break loop
321
+				}
322
+			}
323
+
324
+			if event.Op&Remove == Remove {
325
+				// Look for a file that may have overwritten this.
326
+				// For example, mv f1 f2 will delete f2, then create f2.
327
+				if path.isDir {
328
+					fileDir := filepath.Clean(event.Name)
329
+					w.mu.Lock()
330
+					_, found := w.watches[fileDir]
331
+					w.mu.Unlock()
332
+					if found {
333
+						// make sure the directory exists before we watch for changes. When we
334
+						// do a recursive watch and perform rm -fr, the parent directory might
335
+						// have gone missing, ignore the missing directory and let the
336
+						// upcoming delete event remove the watch from the parent directory.
337
+						if _, err := os.Lstat(fileDir); err == nil {
338
+							w.sendDirectoryChangeEvents(fileDir)
339
+						}
340
+					}
341
+				} else {
342
+					filePath := filepath.Clean(event.Name)
343
+					if fileInfo, err := os.Lstat(filePath); err == nil {
344
+						w.sendFileCreatedEventIfNew(filePath, fileInfo)
345
+					}
346
+				}
347
+			}
348
+
349
+			// Move to next event
350
+			kevents = kevents[1:]
351
+		}
352
+	}
353
+
354
+	// cleanup
355
+	err := unix.Close(w.kq)
356
+	if err != nil {
357
+		// only way the previous loop breaks is if w.done was closed so we need to async send to w.Errors.
358
+		select {
359
+		case w.Errors <- err:
360
+		default:
361
+		}
362
+	}
363
+	close(w.Events)
364
+	close(w.Errors)
365
+}
366
+
367
+// newEvent returns an platform-independent Event based on kqueue Fflags.
368
+func newEvent(name string, mask uint32) Event {
369
+	e := Event{Name: name}
370
+	if mask&unix.NOTE_DELETE == unix.NOTE_DELETE {
371
+		e.Op |= Remove
372
+	}
373
+	if mask&unix.NOTE_WRITE == unix.NOTE_WRITE {
374
+		e.Op |= Write
375
+	}
376
+	if mask&unix.NOTE_RENAME == unix.NOTE_RENAME {
377
+		e.Op |= Rename
378
+	}
379
+	if mask&unix.NOTE_ATTRIB == unix.NOTE_ATTRIB {
380
+		e.Op |= Chmod
381
+	}
382
+	return e
383
+}
384
+
385
+func newCreateEvent(name string) Event {
386
+	return Event{Name: name, Op: Create}
387
+}
388
+
389
+// watchDirectoryFiles to mimic inotify when adding a watch on a directory
390
+func (w *Watcher) watchDirectoryFiles(dirPath string) error {
391
+	// Get all files
392
+	files, err := ioutil.ReadDir(dirPath)
393
+	if err != nil {
394
+		return err
395
+	}
396
+
397
+	for _, fileInfo := range files {
398
+		filePath := filepath.Join(dirPath, fileInfo.Name())
399
+		filePath, err = w.internalWatch(filePath, fileInfo)
400
+		if err != nil {
401
+			return err
402
+		}
403
+
404
+		w.mu.Lock()
405
+		w.fileExists[filePath] = true
406
+		w.mu.Unlock()
407
+	}
408
+
409
+	return nil
410
+}
411
+
412
+// sendDirectoryEvents searches the directory for newly created files
413
+// and sends them over the event channel. This functionality is to have
414
+// the BSD version of fsnotify match Linux inotify which provides a
415
+// create event for files created in a watched directory.
416
+func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
417
+	// Get all files
418
+	files, err := ioutil.ReadDir(dirPath)
419
+	if err != nil {
420
+		select {
421
+		case w.Errors <- err:
422
+		case <-w.done:
423
+			return
424
+		}
425
+	}
426
+
427
+	// Search for new files
428
+	for _, fileInfo := range files {
429
+		filePath := filepath.Join(dirPath, fileInfo.Name())
430
+		err := w.sendFileCreatedEventIfNew(filePath, fileInfo)
431
+
432
+		if err != nil {
433
+			return
434
+		}
435
+	}
436
+}
437
+
438
+// sendFileCreatedEvent sends a create event if the file isn't already being tracked.
439
+func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInfo) (err error) {
440
+	w.mu.Lock()
441
+	_, doesExist := w.fileExists[filePath]
442
+	w.mu.Unlock()
443
+	if !doesExist {
444
+		// Send create event
445
+		select {
446
+		case w.Events <- newCreateEvent(filePath):
447
+		case <-w.done:
448
+			return
449
+		}
450
+	}
451
+
452
+	// like watchDirectoryFiles (but without doing another ReadDir)
453
+	filePath, err = w.internalWatch(filePath, fileInfo)
454
+	if err != nil {
455
+		return err
456
+	}
457
+
458
+	w.mu.Lock()
459
+	w.fileExists[filePath] = true
460
+	w.mu.Unlock()
461
+
462
+	return nil
463
+}
464
+
465
+func (w *Watcher) internalWatch(name string, fileInfo os.FileInfo) (string, error) {
466
+	if fileInfo.IsDir() {
467
+		// mimic Linux providing delete events for subdirectories
468
+		// but preserve the flags used if currently watching subdirectory
469
+		w.mu.Lock()
470
+		flags := w.dirFlags[name]
471
+		w.mu.Unlock()
472
+
473
+		flags |= unix.NOTE_DELETE | unix.NOTE_RENAME
474
+		return w.addWatch(name, flags)
475
+	}
476
+
477
+	// watch file to mimic Linux inotify
478
+	return w.addWatch(name, noteAllEvents)
479
+}
480
+
481
+// kqueue creates a new kernel event queue and returns a descriptor.
482
+func kqueue() (kq int, err error) {
483
+	kq, err = unix.Kqueue()
484
+	if kq == -1 {
485
+		return kq, err
486
+	}
487
+	return kq, nil
488
+}
489
+
490
+// register events with the queue
491
+func register(kq int, fds []int, flags int, fflags uint32) error {
492
+	changes := make([]unix.Kevent_t, len(fds))
493
+
494
+	for i, fd := range fds {
495
+		// SetKevent converts int to the platform-specific types:
496
+		unix.SetKevent(&changes[i], fd, unix.EVFILT_VNODE, flags)
497
+		changes[i].Fflags = fflags
498
+	}
499
+
500
+	// register the events
501
+	success, err := unix.Kevent(kq, changes, nil, nil)
502
+	if success == -1 {
503
+		return err
504
+	}
505
+	return nil
506
+}
507
+
508
+// read retrieves pending events, or waits until an event occurs.
509
+// A timeout of nil blocks indefinitely, while 0 polls the queue.
510
+func read(kq int, events []unix.Kevent_t, timeout *unix.Timespec) ([]unix.Kevent_t, error) {
511
+	n, err := unix.Kevent(kq, nil, events, timeout)
512
+	if err != nil {
513
+		return nil, err
514
+	}
515
+	return events[0:n], nil
516
+}
517
+
518
+// durationToTimespec prepares a timeout value
519
+func durationToTimespec(d time.Duration) unix.Timespec {
520
+	return unix.NsecToTimespec(d.Nanoseconds())
521
+}

+ 11
- 0
vendor/github.com/fsnotify/fsnotify/open_mode_bsd.go View File

@@ -0,0 +1,11 @@
1
+// Copyright 2013 The Go Authors. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+// +build freebsd openbsd netbsd dragonfly
6
+
7
+package fsnotify
8
+
9
+import "golang.org/x/sys/unix"
10
+
11
+const openMode = unix.O_NONBLOCK | unix.O_RDONLY

+ 12
- 0
vendor/github.com/fsnotify/fsnotify/open_mode_darwin.go View File

@@ -0,0 +1,12 @@
1
+// Copyright 2013 The Go Authors. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+// +build darwin
6
+
7
+package fsnotify
8
+
9
+import "golang.org/x/sys/unix"
10
+
11
+// note: this constant is not defined on BSD
12
+const openMode = unix.O_EVTONLY

+ 561
- 0
vendor/github.com/fsnotify/fsnotify/windows.go View File

@@ -0,0 +1,561 @@
1
+// Copyright 2011 The Go Authors. All rights reserved.
2
+// Use of this source code is governed by a BSD-style
3
+// license that can be found in the LICENSE file.
4
+
5
+// +build windows
6
+
7
+package fsnotify
8
+
9
+import (
10
+	"errors"
11
+	"fmt"
12
+	"os"
13
+	"path/filepath"
14
+	"runtime"
15
+	"sync"
16
+	"syscall"
17
+	"unsafe"
18
+)
19
+
20
+// Watcher watches a set of files, delivering events to a channel.
21
+type Watcher struct {
22
+	Events   chan Event
23
+	Errors   chan error
24
+	isClosed bool           // Set to true when Close() is first called
25
+	mu       sync.Mutex     // Map access
26
+	port     syscall.Handle // Handle to completion port
27
+	watches  watchMap       // Map of watches (key: i-number)
28
+	input    chan *input    // Inputs to the reader are sent on this channel
29
+	quit     chan chan<- error
30
+}
31
+
32
+// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events.
33
+func NewWatcher() (*Watcher, error) {
34
+	port, e := syscall.CreateIoCompletionPort(syscall.InvalidHandle, 0, 0, 0)
35
+	if e != nil {
36
+		return nil, os.NewSyscallError("CreateIoCompletionPort", e)
37
+	}
38
+	w := &Watcher{
39
+		port:    port,
40
+		watches: make(watchMap),
41
+		input:   make(chan *input, 1),
42
+		Events:  make(chan Event, 50),
43
+		Errors:  make(chan error),
44
+		quit:    make(chan chan<- error, 1),
45
+	}
46
+	go w.readEvents()
47
+	return w, nil
48
+}
49
+
50
+// Close removes all watches and closes the events channel.
51
+func (w *Watcher) Close() error {
52
+	if w.isClosed {
53
+		return nil
54
+	}
55
+	w.isClosed = true
56
+
57
+	// Send "quit" message to the reader goroutine
58
+	ch := make(chan error)
59
+	w.quit <- ch
60
+	if err := w.wakeupReader(); err != nil {
61
+		return err
62
+	}
63
+	return <-ch
64
+}
65
+
66
+// Add starts watching the named file or directory (non-recursively).
67
+func (w *Watcher) Add(name string) error {
68
+	if w.isClosed {
69
+		return errors.New("watcher already closed")
70
+	}
71
+	in := &input{
72
+		op:    opAddWatch,
73
+		path:  filepath.Clean(name),
74
+		flags: sysFSALLEVENTS,
75
+		reply: make(chan error),
76
+	}
77
+	w.input <- in
78
+	if err := w.wakeupReader(); err != nil {
79
+		return err
80
+	}
81
+	return <-in.reply
82
+}
83
+
84
+// Remove stops watching the the named file or directory (non-recursively).
85
+func (w *Watcher) Remove(name string) error {
86
+	in := &input{
87
+		op:    opRemoveWatch,
88
+		path:  filepath.Clean(name),
89
+		reply: make(chan error),
90
+	}
91
+	w.input <- in
92
+	if err := w.wakeupReader(); err != nil {
93
+		return err
94
+	}
95
+	return <-in.reply
96
+}
97
+
98
+const (
99
+	// Options for AddWatch
100
+	sysFSONESHOT = 0x80000000
101
+	sysFSONLYDIR = 0x1000000
102
+
103
+	// Events
104
+	sysFSACCESS     = 0x1
105
+	sysFSALLEVENTS  = 0xfff
106
+	sysFSATTRIB     = 0x4
107
+	sysFSCLOSE      = 0x18
108
+	sysFSCREATE     = 0x100
109
+	sysFSDELETE     = 0x200
110
+	sysFSDELETESELF = 0x400
111
+	sysFSMODIFY     = 0x2
112
+	sysFSMOVE       = 0xc0
113
+	sysFSMOVEDFROM  = 0x40
114
+	sysFSMOVEDTO    = 0x80
115
+	sysFSMOVESELF   = 0x800
116
+
117
+	// Special events
118
+	sysFSIGNORED   = 0x8000
119
+	sysFSQOVERFLOW = 0x4000
120
+)
121
+
122
+func newEvent(name string, mask uint32) Event {
123
+	e := Event{Name: name}
124
+	if mask&sysFSCREATE == sysFSCREATE || mask&sysFSMOVEDTO == sysFSMOVEDTO {
125
+		e.Op |= Create
126
+	}
127
+	if mask&sysFSDELETE == sysFSDELETE || mask&sysFSDELETESELF == sysFSDELETESELF {
128
+		e.Op |= Remove
129
+	}
130
+	if mask&sysFSMODIFY == sysFSMODIFY {
131
+		e.Op |= Write
132
+	}
133
+	if mask&sysFSMOVE == sysFSMOVE || mask&sysFSMOVESELF == sysFSMOVESELF || mask&sysFSMOVEDFROM == sysFSMOVEDFROM {
134
+		e.Op |= Rename
135
+	}
136
+	if mask&sysFSATTRIB == sysFSATTRIB {
137
+		e.Op |= Chmod
138
+	}
139
+	return e
140
+}
141
+
142
+const (
143
+	opAddWatch = iota
144
+	opRemoveWatch
145
+)
146
+
147
+const (
148
+	provisional uint64 = 1 << (32 + iota)
149
+)
150
+
151
+type input struct {
152
+	op    int
153
+	path  string
154
+	flags uint32
155
+	reply chan error
156
+}
157
+
158
+type inode struct {
159
+	handle syscall.Handle
160
+	volume uint32
161
+	index  uint64
162
+}
163
+
164
+type watch struct {
165
+	ov     syscall.Overlapped
166
+	ino    *inode            // i-number
167
+	path   string            // Directory path
168
+	mask   uint64            // Directory itself is being watched with these notify flags
169
+	names  map[string]uint64 // Map of names being watched and their notify flags
170
+	rename string            // Remembers the old name while renaming a file
171
+	buf    [4096]byte
172
+}
173
+
174
+type indexMap map[uint64]*watch
175
+type watchMap map[uint32]indexMap
176
+
177
+func (w *Watcher) wakeupReader() error {
178
+	e := syscall.PostQueuedCompletionStatus(w.port, 0, 0, nil)
179
+	if e != nil {
180
+		return os.NewSyscallError("PostQueuedCompletionStatus", e)
181
+	}
182
+	return nil
183
+}
184
+
185
+func getDir(pathname string) (dir string, err error) {
186
+	attr, e := syscall.GetFileAttributes(syscall.StringToUTF16Ptr(pathname))
187
+	if e != nil {
188
+		return "", os.NewSyscallError("GetFileAttributes", e)
189
+	}
190
+	if attr&syscall.FILE_ATTRIBUTE_DIRECTORY != 0 {
191
+		dir = pathname
192
+	} else {
193
+		dir, _ = filepath.Split(pathname)
194
+		dir = filepath.Clean(dir)
195
+	}
196
+	return
197
+}
198
+
199
+func getIno(path string) (ino *inode, err error) {
200
+	h, e := syscall.CreateFile(syscall.StringToUTF16Ptr(path),
201
+		syscall.FILE_LIST_DIRECTORY,
202
+		syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE|syscall.FILE_SHARE_DELETE,
203
+		nil, syscall.OPEN_EXISTING,
204
+		syscall.FILE_FLAG_BACKUP_SEMANTICS|syscall.FILE_FLAG_OVERLAPPED, 0)
205
+	if e != nil {
206
+		return nil, os.NewSyscallError("CreateFile", e)
207
+	}
208
+	var fi syscall.ByHandleFileInformation
209
+	if e = syscall.GetFileInformationByHandle(h, &fi); e != nil {
210
+		syscall.CloseHandle(h)
211
+		return nil, os.NewSyscallError("GetFileInformationByHandle", e)
212
+	}
213
+	ino = &inode{
214
+		handle: h,
215
+		volume: fi.VolumeSerialNumber,
216
+		index:  uint64(fi.FileIndexHigh)<<32 | uint64(fi.FileIndexLow),
217
+	}
218
+	return ino, nil
219
+}
220
+
221
+// Must run within the I/O thread.
222
+func (m watchMap) get(ino *inode) *watch {
223
+	if i := m[ino.volume]; i != nil {
224
+		return i[ino.index]
225
+	}
226
+	return nil
227
+}
228
+
229
+// Must run within the I/O thread.
230
+func (m watchMap) set(ino *inode, watch *watch) {
231
+	i := m[ino.volume]
232
+	if i == nil {
233
+		i = make(indexMap)
234
+		m[ino.volume] = i
235
+	}
236
+	i[ino.index] = watch
237
+}
238
+
239
+// Must run within the I/O thread.
240
+func (w *Watcher) addWatch(pathname string, flags uint64) error {
241
+	dir, err := getDir(pathname)
242
+	if err != nil {
243
+		return err
244
+	}
245
+	if flags&sysFSONLYDIR != 0 && pathname != dir {
246
+		return nil
247
+	}
248
+	ino, err := getIno(dir)
249
+	if err != nil {
250
+		return err
251
+	}
252
+	w.mu.Lock()
253
+	watchEntry := w.watches.get(ino)
254
+	w.mu.Unlock()
255
+	if watchEntry == nil {
256
+		if _, e := syscall.CreateIoCompletionPort(ino.handle, w.port, 0, 0); e != nil {
257
+			syscall.CloseHandle(ino.handle)
258
+			return os.NewSyscallError("CreateIoCompletionPort", e)
259
+		}
260
+		watchEntry = &watch{
261
+			ino:   ino,
262
+			path:  dir,
263
+			names: make(map[string]uint64),
264
+		}
265
+		w.mu.Lock()
266
+		w.watches.set(ino, watchEntry)
267
+		w.mu.Unlock()
268
+		flags |= provisional
269
+	} else {
270
+		syscall.CloseHandle(ino.handle)
271
+	}
272
+	if pathname == dir {
273
+		watchEntry.mask |= flags
274
+	} else {
275
+		watchEntry.names[filepath.Base(pathname)] |= flags
276
+	}
277
+	if err = w.startRead(watchEntry); err != nil {
278
+		return err
279
+	}
280
+	if pathname == dir {
281
+		watchEntry.mask &= ^provisional
282
+	} else {
283
+		watchEntry.names[filepath.Base(pathname)] &= ^provisional
284
+	}
285
+	return nil
286
+}
287
+
288
+// Must run within the I/O thread.
289
+func (w *Watcher) remWatch(pathname string) error {
290
+	dir, err := getDir(pathname)
291
+	if err != nil {
292
+		return err
293
+	}
294
+	ino, err := getIno(dir)
295
+	if err != nil {
296
+		return err
297
+	}
298
+	w.mu.Lock()
299
+	watch := w.watches.get(ino)
300
+	w.mu.Unlock()
301
+	if watch == nil {
302
+		return fmt.Errorf("can't remove non-existent watch for: %s", pathname)
303
+	}
304
+	if pathname == dir {
305
+		w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
306
+		watch.mask = 0
307
+	} else {
308
+		name := filepath.Base(pathname)
309
+		w.sendEvent(filepath.Join(watch.path, name), watch.names[name]&sysFSIGNORED)
310
+		delete(watch.names, name)
311
+	}
312
+	return w.startRead(watch)
313
+}
314
+
315
+// Must run within the I/O thread.
316
+func (w *Watcher) deleteWatch(watch *watch) {
317
+	for name, mask := range watch.names {
318
+		if mask&provisional == 0 {
319
+			w.sendEvent(filepath.Join(watch.path, name), mask&sysFSIGNORED)
320
+		}
321
+		delete(watch.names, name)
322
+	}
323
+	if watch.mask != 0 {
324
+		if watch.mask&provisional == 0 {
325
+			w.sendEvent(watch.path, watch.mask&sysFSIGNORED)
326
+		}
327
+		watch.mask = 0
328
+	}
329
+}
330
+
331
+// Must run within the I/O thread.
332
+func (w *Watcher) startRead(watch *watch) error {
333
+	if e := syscall.CancelIo(watch.ino.handle); e != nil {
334
+		w.Errors <- os.NewSyscallError("CancelIo", e)
335
+		w.deleteWatch(watch)
336
+	}
337
+	mask := toWindowsFlags(watch.mask)
338
+	for _, m := range watch.names {
339
+		mask |= toWindowsFlags(m)
340
+	}
341
+	if mask == 0 {
342
+		if e := syscall.CloseHandle(watch.ino.handle); e != nil {
343
+			w.Errors <- os.NewSyscallError("CloseHandle", e)
344
+		}
345
+		w.mu.Lock()
346
+		delete(w.watches[watch.ino.volume], watch.ino.index)
347
+		w.mu.Unlock()
348
+		return nil
349
+	}
350
+	e := syscall.ReadDirectoryChanges(watch.ino.handle, &watch.buf[0],
351
+		uint32(unsafe.Sizeof(watch.buf)), false, mask, nil, &watch.ov, 0)
352
+	if e != nil {
353
+		err := os.NewSyscallError("ReadDirectoryChanges", e)
354
+		if e == syscall.ERROR_ACCESS_DENIED && watch.mask&provisional == 0 {
355
+			// Watched directory was probably removed
356
+			if w.sendEvent(watch.path, watch.mask&sysFSDELETESELF) {
357
+				if watch.mask&sysFSONESHOT != 0 {
358
+					watch.mask = 0
359
+				}
360
+			}
361
+			err = nil
362
+		}
363
+		w.deleteWatch(watch)
364
+		w.startRead(watch)
365
+		return err
366
+	}
367
+	return nil
368
+}
369
+
370
+// readEvents reads from the I/O completion port, converts the
371
+// received events into Event objects and sends them via the Events channel.
372
+// Entry point to the I/O thread.
373
+func (w *Watcher) readEvents() {
374
+	var (
375
+		n, key uint32
376
+		ov     *syscall.Overlapped
377
+	)
378
+	runtime.LockOSThread()
379
+
380
+	for {
381
+		e := syscall.GetQueuedCompletionStatus(w.port, &n, &key, &ov, syscall.INFINITE)
382
+		watch := (*watch)(unsafe.Pointer(ov))
383
+
384
+		if watch == nil {
385
+			select {
386
+			case ch := <-w.quit:
387
+				w.mu.Lock()
388
+				var indexes []indexMap
389
+				for _, index := range w.watches {
390
+					indexes = append(indexes, index)
391
+				}
392
+				w.mu.Unlock()
393
+				for _, index := range indexes {
394
+					for _, watch := range index {
395
+						w.deleteWatch(watch)
396
+						w.startRead(watch)
397
+					}
398
+				}
399
+				var err error
400
+				if e := syscall.CloseHandle(w.port); e != nil {
401
+					err = os.NewSyscallError("CloseHandle", e)
402
+				}
403
+				close(w.Events)
404
+				close(w.Errors)
405
+				ch <- err
406
+				return
407
+			case in := <-w.input:
408
+				switch in.op {
409
+				case opAddWatch:
410
+					in.reply <- w.addWatch(in.path, uint64(in.flags))
411
+				case opRemoveWatch:
412
+					in.reply <- w.remWatch(in.path)
413
+				}
414
+			default:
415
+			}
416
+			continue
417
+		}
418
+
419
+		switch e {
420
+		case syscall.ERROR_MORE_DATA:
421
+			if watch == nil {
422
+				w.Errors <- errors.New("ERROR_MORE_DATA has unexpectedly null lpOverlapped buffer")
423
+			} else {
424
+				// The i/o succeeded but the buffer is full.
425
+				// In theory we should be building up a full packet.
426
+				// In practice we can get away with just carrying on.
427
+				n = uint32(unsafe.Sizeof(watch.buf))
428
+			}
429
+		case syscall.ERROR_ACCESS_DENIED:
430
+			// Watched directory was probably removed
431
+			w.sendEvent(watch.path, watch.mask&sysFSDELETESELF)
432
+			w.deleteWatch(watch)
433
+			w.startRead(watch)
434
+			continue
435
+		case syscall.ERROR_OPERATION_ABORTED:
436
+			// CancelIo was called on this handle
437
+			continue
438
+		default:
439
+			w.Errors <- os.NewSyscallError("GetQueuedCompletionPort", e)
440
+			continue
441
+		case nil:
442
+		}
443
+
444
+		var offset uint32
445
+		for {
446
+			if n == 0 {
447
+				w.Events <- newEvent("", sysFSQOVERFLOW)
448
+				w.Errors <- errors.New("short read in readEvents()")
449
+				break
450
+			}
451
+
452
+			// Point "raw" to the event in the buffer
453
+			raw := (*syscall.FileNotifyInformation)(unsafe.Pointer(&watch.buf[offset]))
454
+			buf := (*[syscall.MAX_PATH]uint16)(unsafe.Pointer(&raw.FileName))
455
+			name := syscall.UTF16ToString(buf[:raw.FileNameLength/2])
456
+			fullname := filepath.Join(watch.path, name)
457
+
458
+			var mask uint64
459
+			switch raw.Action {
460
+			case syscall.FILE_ACTION_REMOVED:
461
+				mask = sysFSDELETESELF
462
+			case syscall.FILE_ACTION_MODIFIED:
463
+				mask = sysFSMODIFY
464
+			case syscall.FILE_ACTION_RENAMED_OLD_NAME:
465
+				watch.rename = name
466
+			case syscall.FILE_ACTION_RENAMED_NEW_NAME:
467
+				if watch.names[watch.rename] != 0 {
468
+					watch.names[name] |= watch.names[watch.rename]
469
+					delete(watch.names, watch.rename)
470
+					mask = sysFSMOVESELF
471
+				}
472
+			}
473
+
474
+			sendNameEvent := func() {
475
+				if w.sendEvent(fullname, watch.names[name]&mask) {
476
+					if watch.names[name]&sysFSONESHOT != 0 {
477
+						delete(watch.names, name)
478
+					}
479
+				}
480
+			}
481
+			if raw.Action != syscall.FILE_ACTION_RENAMED_NEW_NAME {
482
+				sendNameEvent()
483
+			}
484
+			if raw.Action == syscall.FILE_ACTION_REMOVED {
485
+				w.sendEvent(fullname, watch.names[name]&sysFSIGNORED)
486
+				delete(watch.names, name)
487
+			}
488
+			if w.sendEvent(fullname, watch.mask&toFSnotifyFlags(raw.Action)) {
489
+				if watch.mask&sysFSONESHOT != 0 {
490
+					watch.mask = 0
491
+				}
492
+			}
493
+			if raw.Action == syscall.FILE_ACTION_RENAMED_NEW_NAME {
494
+				fullname = filepath.Join(watch.path, watch.rename)
495
+				sendNameEvent()
496
+			}
497
+
498
+			// Move to the next event in the buffer
499
+			if raw.NextEntryOffset == 0 {
500
+				break
501
+			}
502
+			offset += raw.NextEntryOffset
503
+
504
+			// Error!
505
+			if offset >= n {
506
+				w.Errors <- errors.New("Windows system assumed buffer larger than it is, events have likely been missed.")
507
+				break
508
+			}
509
+		}
510
+
511
+		if err := w.startRead(watch); err != nil {
512
+			w.Errors <- err
513
+		}
514
+	}
515
+}
516
+
517
+func (w *Watcher) sendEvent(name string, mask uint64) bool {
518
+	if mask == 0 {
519
+		return false
520
+	}
521
+	event := newEvent(name, uint32(mask))
522
+	select {
523
+	case ch := <-w.quit:
524
+		w.quit <- ch
525
+	case w.Events <- event:
526
+	}
527
+	return true
528
+}
529
+
530
+func toWindowsFlags(mask uint64) uint32 {
531
+	var m uint32
532
+	if mask&sysFSACCESS != 0 {
533
+		m |= syscall.FILE_NOTIFY_CHANGE_LAST_ACCESS
534
+	}
535
+	if mask&sysFSMODIFY != 0 {
536
+		m |= syscall.FILE_NOTIFY_CHANGE_LAST_WRITE
537
+	}
538
+	if mask&sysFSATTRIB != 0 {
539
+		m |= syscall.FILE_NOTIFY_CHANGE_ATTRIBUTES
540
+	}
541
+	if mask&(sysFSMOVE|sysFSCREATE|sysFSDELETE) != 0 {
542
+		m |= syscall.FILE_NOTIFY_CHANGE_FILE_NAME | syscall.FILE_NOTIFY_CHANGE_DIR_NAME
543
+	}
544
+	return m
545
+}
546
+
547
+func toFSnotifyFlags(action uint32) uint64 {
548
+	switch action {
549
+	case syscall.FILE_ACTION_ADDED:
550
+		return sysFSCREATE
551
+	case syscall.FILE_ACTION_REMOVED:
552
+		return sysFSDELETE
553
+	case syscall.FILE_ACTION_MODIFIED:
554
+		return sysFSMODIFY
555
+	case syscall.FILE_ACTION_RENAMED_OLD_NAME:
556
+		return sysFSMOVEDFROM
557
+	case syscall.FILE_ACTION_RENAMED_NEW_NAME:
558
+		return sysFSMOVEDTO
559
+	}
560
+	return 0
561
+}

+ 9
- 0
vendor/github.com/hashicorp/hcl/.gitignore View File

@@ -0,0 +1,9 @@
1
+y.output
2
+
3
+# ignore intellij files
4
+.idea
5
+*.iml
6
+*.ipr
7
+*.iws
8
+
9
+*.test

+ 13
- 0
vendor/github.com/hashicorp/hcl/.travis.yml View File

@@ -0,0 +1,13 @@
1
+sudo: false
2
+
3
+language: go
4
+
5
+go:
6
+  - 1.x
7
+  - tip
8
+
9
+branches:
10
+  only:
11
+    - master
12
+
13
+script: make test

+ 354
- 0
vendor/github.com/hashicorp/hcl/LICENSE View File

@@ -0,0 +1,354 @@
1
+Mozilla Public License, version 2.0
2
+
3
+1. Definitions
4
+
5
+1.1. “Contributor”
6
+
7
+     means each individual or legal entity that creates, contributes to the
8
+     creation of, or owns Covered Software.
9
+
10