strutil.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. // Copyright (c) 2014 The sortutil 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. // Package strutil collects utils supplemental to the standard strings package.
  5. package strutil
  6. import (
  7. "bytes"
  8. "encoding/base32"
  9. "encoding/base64"
  10. "fmt"
  11. "io"
  12. "os"
  13. "path/filepath"
  14. "reflect"
  15. "runtime"
  16. "sort"
  17. "strconv"
  18. "strings"
  19. "sync"
  20. )
  21. // Base32ExtDecode decodes base32 extended (RFC 4648) text to binary data.
  22. func Base32ExtDecode(text []byte) (data []byte, err error) {
  23. n := base32.HexEncoding.DecodedLen(len(text))
  24. data = make([]byte, n)
  25. decoder := base32.NewDecoder(base32.HexEncoding, bytes.NewBuffer(text))
  26. if n, err = decoder.Read(data); err != nil {
  27. n = 0
  28. }
  29. data = data[:n]
  30. return
  31. }
  32. // Base32ExtEncode encodes binary data to base32 extended (RFC 4648) encoded text.
  33. func Base32ExtEncode(data []byte) (text []byte) {
  34. n := base32.HexEncoding.EncodedLen(len(data))
  35. buf := bytes.NewBuffer(make([]byte, 0, n))
  36. encoder := base32.NewEncoder(base32.HexEncoding, buf)
  37. encoder.Write(data)
  38. encoder.Close()
  39. if buf.Len() != n {
  40. panic("internal error")
  41. }
  42. return buf.Bytes()
  43. }
  44. // Base64Decode decodes base64 text to binary data.
  45. func Base64Decode(text []byte) (data []byte, err error) {
  46. n := base64.StdEncoding.DecodedLen(len(text))
  47. data = make([]byte, n)
  48. decoder := base64.NewDecoder(base64.StdEncoding, bytes.NewBuffer(text))
  49. if n, err = decoder.Read(data); err != nil {
  50. n = 0
  51. }
  52. data = data[:n]
  53. return
  54. }
  55. // Base64Encode encodes binary data to base64 encoded text.
  56. func Base64Encode(data []byte) (text []byte) {
  57. n := base64.StdEncoding.EncodedLen(len(data))
  58. buf := bytes.NewBuffer(make([]byte, 0, n))
  59. encoder := base64.NewEncoder(base64.StdEncoding, buf)
  60. encoder.Write(data)
  61. encoder.Close()
  62. if buf.Len() != n {
  63. panic("internal error")
  64. }
  65. return buf.Bytes()
  66. }
  67. // Formatter is an io.Writer extended by a fmt.Printf like function Format
  68. type Formatter interface {
  69. io.Writer
  70. Format(format string, args ...interface{}) (n int, errno error)
  71. }
  72. type indentFormatter struct {
  73. io.Writer
  74. indent []byte
  75. indentLevel int
  76. state int
  77. }
  78. const (
  79. st0 = iota
  80. stBOL
  81. stPERC
  82. stBOLPERC
  83. )
  84. // IndentFormatter returns a new Formatter which interprets %i and %u in the
  85. // Format() format string as indent and undent commands. The commands can
  86. // nest. The Formatter writes to io.Writer 'w' and inserts one 'indent'
  87. // string per current indent level value.
  88. // Behaviour of commands reaching negative indent levels is undefined.
  89. // IndentFormatter(os.Stdout, "\t").Format("abc%d%%e%i\nx\ny\n%uz\n", 3)
  90. // output:
  91. // abc3%e
  92. // x
  93. // y
  94. // z
  95. // The Go quoted string literal form of the above is:
  96. // "abc%%e\n\tx\n\tx\nz\n"
  97. // The commands can be scattered between separate invocations of Format(),
  98. // i.e. the formatter keeps track of the indent level and knows if it is
  99. // positioned on start of a line and should emit indentation(s).
  100. // The same output as above can be produced by e.g.:
  101. // f := IndentFormatter(os.Stdout, " ")
  102. // f.Format("abc%d%%e%i\nx\n", 3)
  103. // f.Format("y\n%uz\n")
  104. func IndentFormatter(w io.Writer, indent string) Formatter {
  105. return &indentFormatter{w, []byte(indent), 0, stBOL}
  106. }
  107. func (f *indentFormatter) format(flat bool, format string, args ...interface{}) (n int, errno error) {
  108. buf := []byte{}
  109. for i := 0; i < len(format); i++ {
  110. c := format[i]
  111. switch f.state {
  112. case st0:
  113. switch c {
  114. case '\n':
  115. cc := c
  116. if flat && f.indentLevel != 0 {
  117. cc = ' '
  118. }
  119. buf = append(buf, cc)
  120. f.state = stBOL
  121. case '%':
  122. f.state = stPERC
  123. default:
  124. buf = append(buf, c)
  125. }
  126. case stBOL:
  127. switch c {
  128. case '\n':
  129. cc := c
  130. if flat && f.indentLevel != 0 {
  131. cc = ' '
  132. }
  133. buf = append(buf, cc)
  134. case '%':
  135. f.state = stBOLPERC
  136. default:
  137. if !flat {
  138. for i := 0; i < f.indentLevel; i++ {
  139. buf = append(buf, f.indent...)
  140. }
  141. }
  142. buf = append(buf, c)
  143. f.state = st0
  144. }
  145. case stBOLPERC:
  146. switch c {
  147. case 'i':
  148. f.indentLevel++
  149. f.state = stBOL
  150. case 'u':
  151. f.indentLevel--
  152. f.state = stBOL
  153. default:
  154. if !flat {
  155. for i := 0; i < f.indentLevel; i++ {
  156. buf = append(buf, f.indent...)
  157. }
  158. }
  159. buf = append(buf, '%', c)
  160. f.state = st0
  161. }
  162. case stPERC:
  163. switch c {
  164. case 'i':
  165. f.indentLevel++
  166. f.state = st0
  167. case 'u':
  168. f.indentLevel--
  169. f.state = st0
  170. default:
  171. buf = append(buf, '%', c)
  172. f.state = st0
  173. }
  174. default:
  175. panic("unexpected state")
  176. }
  177. }
  178. switch f.state {
  179. case stPERC, stBOLPERC:
  180. buf = append(buf, '%')
  181. }
  182. return f.Write([]byte(fmt.Sprintf(string(buf), args...)))
  183. }
  184. func (f *indentFormatter) Format(format string, args ...interface{}) (n int, errno error) {
  185. return f.format(false, format, args...)
  186. }
  187. type flatFormatter indentFormatter
  188. // FlatFormatter returns a newly created Formatter with the same functionality as the one returned
  189. // by IndentFormatter except it allows a newline in the 'format' string argument of Format
  190. // to pass through iff indent level is currently zero.
  191. //
  192. // If indent level is non-zero then such new lines are changed to a space character.
  193. // There is no indent string, the %i and %u format verbs are used solely to determine the indent level.
  194. //
  195. // The FlatFormatter is intended for flattening of normally nested structure textual representation to
  196. // a one top level structure per line form.
  197. // FlatFormatter(os.Stdout, " ").Format("abc%d%%e%i\nx\ny\n%uz\n", 3)
  198. // output in the form of a Go quoted string literal:
  199. // "abc3%%e x y z\n"
  200. func FlatFormatter(w io.Writer) Formatter {
  201. return (*flatFormatter)(IndentFormatter(w, "").(*indentFormatter))
  202. }
  203. func (f *flatFormatter) Format(format string, args ...interface{}) (n int, errno error) {
  204. return (*indentFormatter)(f).format(true, format, args...)
  205. }
  206. // Pool handles aligning of strings having equal values to the same string instance.
  207. // Intended use is to conserve some memory e.g. where a large number of identically valued strings
  208. // with non identical backing arrays may exists in several semantically distinct instances of some structs.
  209. // Pool is *not* concurrent access safe. It doesn't handle common prefix/suffix aligning,
  210. // e.g. having s1 == "abc" and s2 == "bc", s2 is not automatically aligned as s1[1:].
  211. type Pool struct {
  212. pool map[string]string
  213. }
  214. // NewPool returns a newly created Pool.
  215. func NewPool() *Pool {
  216. return &Pool{map[string]string{}}
  217. }
  218. // Align returns a string with the same value as its argument. It guarantees that
  219. // all aligned strings share a single instance in memory.
  220. func (p *Pool) Align(s string) string {
  221. if a, ok := p.pool[s]; ok {
  222. return a
  223. }
  224. s = StrPack(s)
  225. p.pool[s] = s
  226. return s
  227. }
  228. // Count returns the number of items in the pool.
  229. func (p *Pool) Count() int {
  230. return len(p.pool)
  231. }
  232. // GoPool is a concurrent access safe version of Pool.
  233. type GoPool struct {
  234. pool map[string]string
  235. rwm *sync.RWMutex
  236. }
  237. // NewGoPool returns a newly created GoPool.
  238. func NewGoPool() (p *GoPool) {
  239. return &GoPool{map[string]string{}, &sync.RWMutex{}}
  240. }
  241. // Align returns a string with the same value as its argument. It guarantees that
  242. // all aligned strings share a single instance in memory.
  243. func (p *GoPool) Align(s string) (y string) {
  244. if s != "" {
  245. p.rwm.RLock() // R++
  246. if a, ok := p.pool[s]; ok { // found
  247. p.rwm.RUnlock() // R--
  248. return a
  249. }
  250. p.rwm.RUnlock() // R--
  251. // not found but with a race condition, retry within a write lock
  252. p.rwm.Lock() // W++
  253. defer p.rwm.Unlock() // W--
  254. if a, ok := p.pool[s]; ok { // done in a race
  255. return a
  256. }
  257. // we won
  258. s = StrPack(s)
  259. p.pool[s] = s
  260. return s
  261. }
  262. return
  263. }
  264. // Count returns the number of items in the pool.
  265. func (p *GoPool) Count() int {
  266. return len(p.pool)
  267. }
  268. // Dict is a string <-> id bijection. Dict is *not* concurrent access safe for assigning new ids
  269. // to strings not yet contained in the bijection.
  270. // Id for an empty string is guaranteed to be 0,
  271. // thus Id for any non empty string is guaranteed to be non zero.
  272. type Dict struct {
  273. si map[string]int
  274. is []string
  275. }
  276. // NewDict returns a newly created Dict.
  277. func NewDict() (d *Dict) {
  278. d = &Dict{map[string]int{}, []string{}}
  279. d.Id("")
  280. return
  281. }
  282. // Count returns the number of items in the dict.
  283. func (d *Dict) Count() int {
  284. return len(d.is)
  285. }
  286. // Id maps string s to its numeric identificator.
  287. func (d *Dict) Id(s string) (y int) {
  288. if y, ok := d.si[s]; ok {
  289. return y
  290. }
  291. s = StrPack(s)
  292. y = len(d.is)
  293. d.si[s] = y
  294. d.is = append(d.is, s)
  295. return
  296. }
  297. // S maps an id to its string value and ok == true. Id values not contained in the bijection
  298. // return "", false.
  299. func (d *Dict) S(id int) (s string, ok bool) {
  300. if id >= len(d.is) {
  301. return "", false
  302. }
  303. return d.is[id], true
  304. }
  305. // GoDict is a concurrent access safe version of Dict.
  306. type GoDict struct {
  307. si map[string]int
  308. is []string
  309. rwm *sync.RWMutex
  310. }
  311. // NewGoDict returns a newly created GoDict.
  312. func NewGoDict() (d *GoDict) {
  313. d = &GoDict{map[string]int{}, []string{}, &sync.RWMutex{}}
  314. d.Id("")
  315. return
  316. }
  317. // Count returns the number of items in the dict.
  318. func (d *GoDict) Count() int {
  319. return len(d.is)
  320. }
  321. // Id maps string s to its numeric identificator. The implementation honors getting
  322. // an existing id at the cost of assigning a new one.
  323. func (d *GoDict) Id(s string) (y int) {
  324. d.rwm.RLock() // R++
  325. if y, ok := d.si[s]; ok { // found
  326. d.rwm.RUnlock() // R--
  327. return y
  328. }
  329. d.rwm.RUnlock() // R--
  330. // not found but with a race condition
  331. d.rwm.Lock() // W++ recheck with write lock
  332. defer d.rwm.Unlock() // W--
  333. if y, ok := d.si[s]; ok { // some other goroutine won already
  334. return y
  335. }
  336. // a race free not found state => insert the string
  337. s = StrPack(s)
  338. y = len(d.is)
  339. d.si[s] = y
  340. d.is = append(d.is, s)
  341. return
  342. }
  343. // S maps an id to its string value and ok == true. Id values not contained in the bijection
  344. // return "", false.
  345. func (d *GoDict) S(id int) (s string, ok bool) {
  346. d.rwm.RLock() // R++
  347. defer d.rwm.RUnlock() // R--
  348. if id >= len(d.is) {
  349. return "", false
  350. }
  351. return d.is[id], true
  352. }
  353. // StrPack returns a new instance of s which is tightly packed in memory.
  354. // It is intended for avoiding the situation where having a live reference
  355. // to a string slice over an unreferenced biger underlying string keeps the biger one
  356. // in memory anyway - it can't be GCed.
  357. func StrPack(s string) string {
  358. return string([]byte(s))
  359. }
  360. // JoinFields returns strings in flds joined by sep. Flds may contain arbitrary
  361. // bytes, including the sep as they are safely escaped. JoinFields panics if
  362. // sep is the backslash character or if len(sep) != 1.
  363. func JoinFields(flds []string, sep string) string {
  364. if len(sep) != 1 || sep == "\\" {
  365. panic("invalid separator")
  366. }
  367. a := make([]string, len(flds))
  368. for i, v := range flds {
  369. v = strings.Replace(v, "\\", "\\0", -1)
  370. a[i] = strings.Replace(v, sep, "\\1", -1)
  371. }
  372. return strings.Join(a, sep)
  373. }
  374. // SplitFields splits s, which must be produced by JoinFields using the same
  375. // sep, into flds. SplitFields panics if sep is the backslash character or if
  376. // len(sep) != 1.
  377. func SplitFields(s, sep string) (flds []string) {
  378. if len(sep) != 1 || sep == "\\" {
  379. panic("invalid separator")
  380. }
  381. a := strings.Split(s, sep)
  382. r := make([]string, len(a))
  383. for i, v := range a {
  384. v = strings.Replace(v, "\\1", sep, -1)
  385. r[i] = strings.Replace(v, "\\0", "\\", -1)
  386. }
  387. return r
  388. }
  389. // PrettyPrintHooks allow to customize the result of PrettyPrint for types
  390. // listed in the map value.
  391. type PrettyPrintHooks map[reflect.Type]func(f Formatter, v interface{}, prefix, suffix string)
  392. // PrettyString returns the output of PrettyPrint as a string.
  393. func PrettyString(v interface{}, prefix, suffix string, hooks PrettyPrintHooks) string {
  394. var b bytes.Buffer
  395. PrettyPrint(&b, v, prefix, suffix, hooks)
  396. return b.String()
  397. }
  398. // PrettyPrint pretty prints v to w. Zero values and unexported struct fields
  399. // are omitted.
  400. func PrettyPrint(w io.Writer, v interface{}, prefix, suffix string, hooks PrettyPrintHooks) {
  401. if v == nil {
  402. return
  403. }
  404. f := IndentFormatter(w, "· ")
  405. defer func() {
  406. if e := recover(); e != nil {
  407. f.Format("\npanic: %v", e)
  408. }
  409. }()
  410. prettyPrint(nil, f, prefix, suffix, v, hooks)
  411. }
  412. func prettyPrint(protect map[interface{}]struct{}, sf Formatter, prefix, suffix string, v interface{}, hooks PrettyPrintHooks) {
  413. if v == nil {
  414. return
  415. }
  416. rt := reflect.TypeOf(v)
  417. if handler := hooks[rt]; handler != nil {
  418. handler(sf, v, prefix, suffix)
  419. return
  420. }
  421. rv := reflect.ValueOf(v)
  422. switch rt.Kind() {
  423. case reflect.Slice:
  424. if rv.Len() == 0 {
  425. return
  426. }
  427. sf.Format("%s[]%T{ // len %d%i\n", prefix, rv.Index(0).Interface(), rv.Len())
  428. for i := 0; i < rv.Len(); i++ {
  429. prettyPrint(protect, sf, fmt.Sprintf("%d: ", i), ",\n", rv.Index(i).Interface(), hooks)
  430. }
  431. suffix = strings.Replace(suffix, "%", "%%", -1)
  432. sf.Format("%u}" + suffix)
  433. case reflect.Array:
  434. if reflect.Zero(rt).Interface() == rv.Interface() {
  435. return
  436. }
  437. sf.Format("%s[%d]%T{%i\n", prefix, rv.Len(), rv.Index(0).Interface())
  438. for i := 0; i < rv.Len(); i++ {
  439. prettyPrint(protect, sf, fmt.Sprintf("%d: ", i), ",\n", rv.Index(i).Interface(), hooks)
  440. }
  441. suffix = strings.Replace(suffix, "%", "%%", -1)
  442. sf.Format("%u}" + suffix)
  443. case reflect.Struct:
  444. if rt.NumField() == 0 {
  445. return
  446. }
  447. if reflect.DeepEqual(reflect.Zero(rt).Interface(), rv.Interface()) {
  448. return
  449. }
  450. sf.Format("%s%T{%i\n", prefix, v)
  451. for i := 0; i < rt.NumField(); i++ {
  452. f := rv.Field(i)
  453. if !f.CanInterface() {
  454. continue
  455. }
  456. prettyPrint(protect, sf, fmt.Sprintf("%s: ", rt.Field(i).Name), ",\n", f.Interface(), hooks)
  457. }
  458. suffix = strings.Replace(suffix, "%", "%%", -1)
  459. sf.Format("%u}" + suffix)
  460. case reflect.Ptr:
  461. if rv.IsNil() {
  462. return
  463. }
  464. rvi := rv.Interface()
  465. if _, ok := protect[rvi]; ok {
  466. suffix = strings.Replace(suffix, "%", "%%", -1)
  467. sf.Format("%s&%T{ /* recursive/repetitive pointee not shown */ }"+suffix, prefix, rv.Elem().Interface())
  468. return
  469. }
  470. if protect == nil {
  471. protect = map[interface{}]struct{}{}
  472. }
  473. protect[rvi] = struct{}{}
  474. prettyPrint(protect, sf, prefix+"&", suffix, rv.Elem().Interface(), hooks)
  475. case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int8:
  476. if v := rv.Int(); v != 0 {
  477. suffix = strings.Replace(suffix, "%", "%%", -1)
  478. sf.Format("%s%v"+suffix, prefix, v)
  479. }
  480. case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint8:
  481. if v := rv.Uint(); v != 0 {
  482. suffix = strings.Replace(suffix, "%", "%%", -1)
  483. sf.Format("%s%v"+suffix, prefix, v)
  484. }
  485. case reflect.Float32, reflect.Float64:
  486. if v := rv.Float(); v != 0 {
  487. suffix = strings.Replace(suffix, "%", "%%", -1)
  488. sf.Format("%s%v"+suffix, prefix, v)
  489. }
  490. case reflect.Complex64, reflect.Complex128:
  491. if v := rv.Complex(); v != 0 {
  492. suffix = strings.Replace(suffix, "%", "%%", -1)
  493. sf.Format("%s%v"+suffix, prefix, v)
  494. }
  495. case reflect.Uintptr:
  496. if v := rv.Uint(); v != 0 {
  497. suffix = strings.Replace(suffix, "%", "%%", -1)
  498. sf.Format("%s%v"+suffix, prefix, v)
  499. }
  500. case reflect.UnsafePointer:
  501. s := fmt.Sprintf("%p", rv.Interface())
  502. if s == "0x0" {
  503. return
  504. }
  505. suffix = strings.Replace(suffix, "%", "%%", -1)
  506. sf.Format("%s%s"+suffix, prefix, s)
  507. case reflect.Bool:
  508. if v := rv.Bool(); v {
  509. suffix = strings.Replace(suffix, "%", "%%", -1)
  510. sf.Format("%s%v"+suffix, prefix, rv.Bool())
  511. }
  512. case reflect.String:
  513. s := rv.Interface().(string)
  514. if s == "" {
  515. return
  516. }
  517. suffix = strings.Replace(suffix, "%", "%%", -1)
  518. sf.Format("%s%q"+suffix, prefix, s)
  519. case reflect.Chan:
  520. if reflect.Zero(rt).Interface() == rv.Interface() {
  521. return
  522. }
  523. c := rv.Cap()
  524. s := ""
  525. if c != 0 {
  526. s = fmt.Sprintf("// capacity: %d", c)
  527. }
  528. suffix = strings.Replace(suffix, "%", "%%", -1)
  529. sf.Format("%s%s %s%s"+suffix, prefix, rt.ChanDir(), rt.Elem().Name(), s)
  530. case reflect.Func:
  531. if rv.IsNil() {
  532. return
  533. }
  534. var in, out []string
  535. for i := 0; i < rt.NumIn(); i++ {
  536. x := reflect.Zero(rt.In(i))
  537. in = append(in, fmt.Sprintf("%T", x.Interface()))
  538. }
  539. if rt.IsVariadic() {
  540. i := len(in) - 1
  541. in[i] = "..." + in[i][2:]
  542. }
  543. for i := 0; i < rt.NumOut(); i++ {
  544. out = append(out, rt.Out(i).Name())
  545. }
  546. s := "(" + strings.Join(in, ", ") + ")"
  547. t := strings.Join(out, ", ")
  548. if len(out) > 1 {
  549. t = "(" + t + ")"
  550. }
  551. if t != "" {
  552. t = " " + t
  553. }
  554. suffix = strings.Replace(suffix, "%", "%%", -1)
  555. sf.Format("%sfunc%s%s { ... }"+suffix, prefix, s, t)
  556. case reflect.Map:
  557. keys := rv.MapKeys()
  558. if len(keys) == 0 {
  559. return
  560. }
  561. var buf bytes.Buffer
  562. nf := IndentFormatter(&buf, "· ")
  563. var skeys []string
  564. for i, k := range keys {
  565. prettyPrint(protect, nf, "", "", k.Interface(), hooks)
  566. skeys = append(skeys, fmt.Sprintf("%s%10d", buf.Bytes(), i))
  567. buf.Reset()
  568. }
  569. sort.Strings(skeys)
  570. sf.Format("%s%T{%i\n", prefix, v)
  571. for _, k := range skeys {
  572. si := strings.TrimSpace(k[len(k)-10:])
  573. k = k[:len(k)-10]
  574. n, _ := strconv.ParseUint(si, 10, 64)
  575. mv := rv.MapIndex(keys[n])
  576. prettyPrint(protect, sf, fmt.Sprintf("%s: ", k), ",\n", mv.Interface(), hooks)
  577. }
  578. suffix = strings.Replace(suffix, "%", "%%", -1)
  579. sf.Format("%u}" + suffix)
  580. }
  581. }
  582. // Gopath returns the value of the $GOPATH environment variable or its default
  583. // value if not set.
  584. func Gopath() string {
  585. if r := os.Getenv("GOPATH"); r != "" {
  586. return r
  587. }
  588. // go1.8: https://github.com/golang/go/blob/74628a8b9f102bddd5078ee426efe0fd57033115/doc/code.html#L122
  589. switch runtime.GOOS {
  590. case "plan9":
  591. return os.Getenv("home")
  592. case "windows":
  593. return filepath.Join(os.Getenv("USERPROFILE"), "go")
  594. default:
  595. return filepath.Join(os.Getenv("HOME"), "go")
  596. }
  597. }
  598. // ImportPath returns the import path of the caller or an error, if any.
  599. func ImportPath() (string, error) {
  600. _, file, _, ok := runtime.Caller(1)
  601. if !ok {
  602. return "", fmt.Errorf("runtime.Caller failed")
  603. }
  604. gopath := Gopath()
  605. for _, v := range filepath.SplitList(gopath) {
  606. gp := filepath.Join(v, "src")
  607. path, err := filepath.Rel(gp, file)
  608. if err != nil {
  609. continue
  610. }
  611. return filepath.Dir(path), nil
  612. }
  613. return "", fmt.Errorf("cannot determine import path using GOPATH=%s", gopath)
  614. }