packagesjson.nim 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import std / [json, os, sets, strutils]
  2. type
  3. Package* = ref object
  4. # Required fields in a package.
  5. name*: string
  6. url*: string # Download location.
  7. license*: string
  8. downloadMethod*: string
  9. description*: string
  10. tags*: seq[string] # \
  11. # From here on, optional fields set to the empty string if not available.
  12. version*: string
  13. dvcsTag*: string
  14. web*: string # Info url for humans.
  15. proc optionalField(obj: JsonNode, name: string, default = ""): string =
  16. if hasKey(obj, name) and obj[name].kind == JString:
  17. result = obj[name].str
  18. else:
  19. result = default
  20. proc requiredField(obj: JsonNode, name: string): string =
  21. result = optionalField(obj, name, "")
  22. proc fromJson*(obj: JSonNode): Package =
  23. result = Package()
  24. result.name = obj.requiredField("name")
  25. if result.name.len == 0: return nil
  26. result.version = obj.optionalField("version")
  27. result.url = obj.requiredField("url")
  28. if result.url.len == 0: return nil
  29. result.downloadMethod = obj.requiredField("method")
  30. if result.downloadMethod.len == 0: return nil
  31. result.dvcsTag = obj.optionalField("dvcs-tag")
  32. result.license = obj.optionalField("license")
  33. result.tags = @[]
  34. for t in obj["tags"]:
  35. result.tags.add(t.str)
  36. result.description = obj.requiredField("description")
  37. result.web = obj.optionalField("web")
  38. const PackagesDir* = "packages"
  39. proc getPackages*(workspaceDir: string): seq[Package] =
  40. result = @[]
  41. var uniqueNames = initHashSet[string]()
  42. var jsonFiles = 0
  43. for kind, path in walkDir(workspaceDir / PackagesDir):
  44. if kind == pcFile and path.endsWith(".json"):
  45. inc jsonFiles
  46. let packages = json.parseFile(path)
  47. for p in packages:
  48. let pkg = p.fromJson()
  49. if pkg != nil and not uniqueNames.containsOrIncl(pkg.name):
  50. result.add(pkg)
  51. proc `$`*(pkg: Package): string =
  52. result = pkg.name & ":\n"
  53. result &= " url: " & pkg.url & " (" & pkg.downloadMethod & ")\n"
  54. result &= " tags: " & pkg.tags.join(", ") & "\n"
  55. result &= " description: " & pkg.description & "\n"
  56. result &= " license: " & pkg.license & "\n"
  57. if pkg.web.len > 0:
  58. result &= " website: " & pkg.web & "\n"
  59. proc search*(pkgList: seq[Package]; terms: seq[string]) =
  60. var found = false
  61. template onFound =
  62. echo pkg
  63. found = true
  64. break forPackage
  65. for pkg in pkgList:
  66. if terms.len > 0:
  67. block forPackage:
  68. for term in terms:
  69. let word = term.toLower
  70. # Search by name.
  71. if word in pkg.name.toLower:
  72. onFound()
  73. # Search by tag.
  74. for tag in pkg.tags:
  75. if word in tag.toLower:
  76. onFound()
  77. else:
  78. echo(pkg)
  79. if not found and terms.len > 0:
  80. echo("No package found.")
  81. type PkgCandidates* = array[3, seq[Package]]
  82. proc determineCandidates*(pkgList: seq[Package];
  83. terms: seq[string]): PkgCandidates =
  84. result[0] = @[]
  85. result[1] = @[]
  86. result[2] = @[]
  87. for pkg in pkgList:
  88. block termLoop:
  89. for term in terms:
  90. let word = term.toLower
  91. if word == pkg.name.toLower:
  92. result[0].add pkg
  93. break termLoop
  94. elif word in pkg.name.toLower:
  95. result[1].add pkg
  96. break termLoop
  97. else:
  98. for tag in pkg.tags:
  99. if word in tag.toLower:
  100. result[2].add pkg
  101. break termLoop