http urls monitor.

file.go 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. // Copyright 2017 Unknwon
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. package ini
  15. import (
  16. "bytes"
  17. "errors"
  18. "fmt"
  19. "io"
  20. "io/ioutil"
  21. "os"
  22. "strings"
  23. "sync"
  24. )
  25. // File represents a combination of a or more INI file(s) in memory.
  26. type File struct {
  27. options LoadOptions
  28. dataSources []dataSource
  29. // Should make things safe, but sometimes doesn't matter.
  30. BlockMode bool
  31. lock sync.RWMutex
  32. // To keep data in order.
  33. sectionList []string
  34. // Actual data is stored here.
  35. sections map[string]*Section
  36. NameMapper
  37. ValueMapper
  38. }
  39. // newFile initializes File object with given data sources.
  40. func newFile(dataSources []dataSource, opts LoadOptions) *File {
  41. return &File{
  42. BlockMode: true,
  43. dataSources: dataSources,
  44. sections: make(map[string]*Section),
  45. sectionList: make([]string, 0, 10),
  46. options: opts,
  47. }
  48. }
  49. // Empty returns an empty file object.
  50. func Empty() *File {
  51. // Ignore error here, we sure our data is good.
  52. f, _ := Load([]byte(""))
  53. return f
  54. }
  55. // NewSection creates a new section.
  56. func (f *File) NewSection(name string) (*Section, error) {
  57. if len(name) == 0 {
  58. return nil, errors.New("error creating new section: empty section name")
  59. } else if f.options.Insensitive && name != DEFAULT_SECTION {
  60. name = strings.ToLower(name)
  61. }
  62. if f.BlockMode {
  63. f.lock.Lock()
  64. defer f.lock.Unlock()
  65. }
  66. if inSlice(name, f.sectionList) {
  67. return f.sections[name], nil
  68. }
  69. f.sectionList = append(f.sectionList, name)
  70. f.sections[name] = newSection(f, name)
  71. return f.sections[name], nil
  72. }
  73. // NewRawSection creates a new section with an unparseable body.
  74. func (f *File) NewRawSection(name, body string) (*Section, error) {
  75. section, err := f.NewSection(name)
  76. if err != nil {
  77. return nil, err
  78. }
  79. section.isRawSection = true
  80. section.rawBody = body
  81. return section, nil
  82. }
  83. // NewSections creates a list of sections.
  84. func (f *File) NewSections(names ...string) (err error) {
  85. for _, name := range names {
  86. if _, err = f.NewSection(name); err != nil {
  87. return err
  88. }
  89. }
  90. return nil
  91. }
  92. // GetSection returns section by given name.
  93. func (f *File) GetSection(name string) (*Section, error) {
  94. if len(name) == 0 {
  95. name = DEFAULT_SECTION
  96. }
  97. if f.options.Insensitive {
  98. name = strings.ToLower(name)
  99. }
  100. if f.BlockMode {
  101. f.lock.RLock()
  102. defer f.lock.RUnlock()
  103. }
  104. sec := f.sections[name]
  105. if sec == nil {
  106. return nil, fmt.Errorf("section '%s' does not exist", name)
  107. }
  108. return sec, nil
  109. }
  110. // Section assumes named section exists and returns a zero-value when not.
  111. func (f *File) Section(name string) *Section {
  112. sec, err := f.GetSection(name)
  113. if err != nil {
  114. // Note: It's OK here because the only possible error is empty section name,
  115. // but if it's empty, this piece of code won't be executed.
  116. sec, _ = f.NewSection(name)
  117. return sec
  118. }
  119. return sec
  120. }
  121. // Section returns list of Section.
  122. func (f *File) Sections() []*Section {
  123. if f.BlockMode {
  124. f.lock.RLock()
  125. defer f.lock.RUnlock()
  126. }
  127. sections := make([]*Section, len(f.sectionList))
  128. for i, name := range f.sectionList {
  129. sections[i] = f.sections[name]
  130. }
  131. return sections
  132. }
  133. // ChildSections returns a list of child sections of given section name.
  134. func (f *File) ChildSections(name string) []*Section {
  135. return f.Section(name).ChildSections()
  136. }
  137. // SectionStrings returns list of section names.
  138. func (f *File) SectionStrings() []string {
  139. list := make([]string, len(f.sectionList))
  140. copy(list, f.sectionList)
  141. return list
  142. }
  143. // DeleteSection deletes a section.
  144. func (f *File) DeleteSection(name string) {
  145. if f.BlockMode {
  146. f.lock.Lock()
  147. defer f.lock.Unlock()
  148. }
  149. if len(name) == 0 {
  150. name = DEFAULT_SECTION
  151. }
  152. for i, s := range f.sectionList {
  153. if s == name {
  154. f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...)
  155. delete(f.sections, name)
  156. return
  157. }
  158. }
  159. }
  160. func (f *File) reload(s dataSource) error {
  161. r, err := s.ReadCloser()
  162. if err != nil {
  163. return err
  164. }
  165. defer r.Close()
  166. return f.parse(r)
  167. }
  168. // Reload reloads and parses all data sources.
  169. func (f *File) Reload() (err error) {
  170. for _, s := range f.dataSources {
  171. if err = f.reload(s); err != nil {
  172. // In loose mode, we create an empty default section for nonexistent files.
  173. if os.IsNotExist(err) && f.options.Loose {
  174. f.parse(bytes.NewBuffer(nil))
  175. continue
  176. }
  177. return err
  178. }
  179. }
  180. return nil
  181. }
  182. // Append appends one or more data sources and reloads automatically.
  183. func (f *File) Append(source interface{}, others ...interface{}) error {
  184. ds, err := parseDataSource(source)
  185. if err != nil {
  186. return err
  187. }
  188. f.dataSources = append(f.dataSources, ds)
  189. for _, s := range others {
  190. ds, err = parseDataSource(s)
  191. if err != nil {
  192. return err
  193. }
  194. f.dataSources = append(f.dataSources, ds)
  195. }
  196. return f.Reload()
  197. }
  198. func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
  199. equalSign := "="
  200. if PrettyFormat || PrettyEqual {
  201. equalSign = " = "
  202. }
  203. // Use buffer to make sure target is safe until finish encoding.
  204. buf := bytes.NewBuffer(nil)
  205. for i, sname := range f.sectionList {
  206. sec := f.Section(sname)
  207. if len(sec.Comment) > 0 {
  208. // Support multiline comments
  209. lines := strings.Split(sec.Comment, LineBreak)
  210. for i := range lines {
  211. if lines[i][0] != '#' && lines[i][0] != ';' {
  212. lines[i] = "; " + lines[i]
  213. } else {
  214. lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:])
  215. }
  216. if _, err := buf.WriteString(lines[i] + LineBreak); err != nil {
  217. return nil, err
  218. }
  219. }
  220. }
  221. if i > 0 || DefaultHeader {
  222. if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil {
  223. return nil, err
  224. }
  225. } else {
  226. // Write nothing if default section is empty
  227. if len(sec.keyList) == 0 {
  228. continue
  229. }
  230. }
  231. if sec.isRawSection {
  232. if _, err := buf.WriteString(sec.rawBody); err != nil {
  233. return nil, err
  234. }
  235. if PrettySection {
  236. // Put a line between sections
  237. if _, err := buf.WriteString(LineBreak); err != nil {
  238. return nil, err
  239. }
  240. }
  241. continue
  242. }
  243. // Count and generate alignment length and buffer spaces using the
  244. // longest key. Keys may be modifed if they contain certain characters so
  245. // we need to take that into account in our calculation.
  246. alignLength := 0
  247. if PrettyFormat {
  248. for _, kname := range sec.keyList {
  249. keyLength := len(kname)
  250. // First case will surround key by ` and second by """
  251. if strings.ContainsAny(kname, "\"=:") {
  252. keyLength += 2
  253. } else if strings.Contains(kname, "`") {
  254. keyLength += 6
  255. }
  256. if keyLength > alignLength {
  257. alignLength = keyLength
  258. }
  259. }
  260. }
  261. alignSpaces := bytes.Repeat([]byte(" "), alignLength)
  262. KEY_LIST:
  263. for _, kname := range sec.keyList {
  264. key := sec.Key(kname)
  265. if len(key.Comment) > 0 {
  266. if len(indent) > 0 && sname != DEFAULT_SECTION {
  267. buf.WriteString(indent)
  268. }
  269. // Support multiline comments
  270. lines := strings.Split(key.Comment, LineBreak)
  271. for i := range lines {
  272. if lines[i][0] != '#' && lines[i][0] != ';' {
  273. lines[i] = "; " + lines[i]
  274. } else {
  275. lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:])
  276. }
  277. if _, err := buf.WriteString(lines[i] + LineBreak); err != nil {
  278. return nil, err
  279. }
  280. }
  281. }
  282. if len(indent) > 0 && sname != DEFAULT_SECTION {
  283. buf.WriteString(indent)
  284. }
  285. switch {
  286. case key.isAutoIncrement:
  287. kname = "-"
  288. case strings.ContainsAny(kname, "\"=:"):
  289. kname = "`" + kname + "`"
  290. case strings.Contains(kname, "`"):
  291. kname = `"""` + kname + `"""`
  292. }
  293. for _, val := range key.ValueWithShadows() {
  294. if _, err := buf.WriteString(kname); err != nil {
  295. return nil, err
  296. }
  297. if key.isBooleanType {
  298. if kname != sec.keyList[len(sec.keyList)-1] {
  299. buf.WriteString(LineBreak)
  300. }
  301. continue KEY_LIST
  302. }
  303. // Write out alignment spaces before "=" sign
  304. if PrettyFormat {
  305. buf.Write(alignSpaces[:alignLength-len(kname)])
  306. }
  307. // In case key value contains "\n", "`", "\"", "#" or ";"
  308. if strings.ContainsAny(val, "\n`") {
  309. val = `"""` + val + `"""`
  310. } else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") {
  311. val = "`" + val + "`"
  312. }
  313. if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil {
  314. return nil, err
  315. }
  316. }
  317. for _, val := range key.nestedValues {
  318. if _, err := buf.WriteString(indent + " " + val + LineBreak); err != nil {
  319. return nil, err
  320. }
  321. }
  322. }
  323. if PrettySection {
  324. // Put a line between sections
  325. if _, err := buf.WriteString(LineBreak); err != nil {
  326. return nil, err
  327. }
  328. }
  329. }
  330. return buf, nil
  331. }
  332. // WriteToIndent writes content into io.Writer with given indention.
  333. // If PrettyFormat has been set to be true,
  334. // it will align "=" sign with spaces under each section.
  335. func (f *File) WriteToIndent(w io.Writer, indent string) (int64, error) {
  336. buf, err := f.writeToBuffer(indent)
  337. if err != nil {
  338. return 0, err
  339. }
  340. return buf.WriteTo(w)
  341. }
  342. // WriteTo writes file content into io.Writer.
  343. func (f *File) WriteTo(w io.Writer) (int64, error) {
  344. return f.WriteToIndent(w, "")
  345. }
  346. // SaveToIndent writes content to file system with given value indention.
  347. func (f *File) SaveToIndent(filename, indent string) error {
  348. // Note: Because we are truncating with os.Create,
  349. // so it's safer to save to a temporary file location and rename afte done.
  350. buf, err := f.writeToBuffer(indent)
  351. if err != nil {
  352. return err
  353. }
  354. return ioutil.WriteFile(filename, buf.Bytes(), 0666)
  355. }
  356. // SaveTo writes content to file system.
  357. func (f *File) SaveTo(filename string) error {
  358. return f.SaveToIndent(filename, "")
  359. }