import.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /*
  2. * ECAL
  3. *
  4. * Copyright 2020 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package util
  11. import (
  12. "fmt"
  13. "io/ioutil"
  14. "os"
  15. "path/filepath"
  16. "strings"
  17. )
  18. // ImportLocator implementations
  19. // =============================
  20. /*
  21. MemoryImportLocator holds a given set of code in memory and can provide it as imports.
  22. */
  23. type MemoryImportLocator struct {
  24. Files map[string]string
  25. }
  26. /*
  27. Resolve a given import path and parse the imported file into an AST.
  28. */
  29. func (il *MemoryImportLocator) Resolve(path string) (string, error) {
  30. res, ok := il.Files[path]
  31. if !ok {
  32. return "", fmt.Errorf("Could not find import path: %v", path)
  33. }
  34. return res, nil
  35. }
  36. /*
  37. FileImportLocator tries to locate files on disk relative to a root directory and provide them as imports.
  38. */
  39. type FileImportLocator struct {
  40. Root string // Relative root path
  41. }
  42. /*
  43. Resolve a given import path and parse the imported file into an AST.
  44. */
  45. func (il *FileImportLocator) Resolve(path string) (string, error) {
  46. var res string
  47. importPath := filepath.Clean(filepath.Join(il.Root, path))
  48. ok, err := isSubpath(il.Root, importPath)
  49. if err == nil && !ok {
  50. err = fmt.Errorf("Import path is outside of code root: %v", path)
  51. }
  52. if err == nil {
  53. var b []byte
  54. if b, err = ioutil.ReadFile(importPath); err != nil {
  55. err = fmt.Errorf("Could not import path %v: %v", path, err)
  56. } else {
  57. res = string(b)
  58. }
  59. }
  60. return res, err
  61. }
  62. /*
  63. isSubpath checks if the given sub path is a child path of root.
  64. */
  65. func isSubpath(root, sub string) (bool, error) {
  66. rel, err := filepath.Rel(root, sub)
  67. return err == nil &&
  68. !strings.HasPrefix(rel, fmt.Sprintf("..%v", string(os.PathSeparator))) &&
  69. rel != "..", err
  70. }