├── config.nims ├── .gitattributes ├── validate_json.js ├── .github └── workflows │ └── test.yml ├── pretty_json.nim ├── README.md └── package_scanner.nim /config.nims: -------------------------------------------------------------------------------- 1 | --define:ssl 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /packages.json merge=union 2 | -------------------------------------------------------------------------------- /validate_json.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | JSON.parse(fs.readFileSync('packages.json', 'utf8')); 3 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | push: 4 | 5 | jobs: 6 | default: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: iffy/install-nim@v3.2.2 11 | with: 12 | version: stable 13 | - run: nim c -d:ssl -r -d:release package_scanner.nim 14 | env: 15 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 16 | - run: node ./validate_json.js 17 | -------------------------------------------------------------------------------- /pretty_json.nim: -------------------------------------------------------------------------------- 1 | 2 | import strutils, json, os 3 | 4 | proc cleanupWhitespace(s: string): string = 5 | ## Removes trailing whitespace and normalizes line endings to LF. 6 | result = newStringOfCap(s.len) 7 | var i = 0 8 | while i < s.len: 9 | if s[i] == ' ': 10 | var j = i+1 11 | while s[j] == ' ': inc j 12 | if s[j] == '\c': 13 | inc j 14 | if s[j] == '\L': inc j 15 | result.add '\L' 16 | i = j 17 | elif s[j] == '\L': 18 | result.add '\L' 19 | i = j+1 20 | else: 21 | result.add ' ' 22 | inc i 23 | elif s[i] == '\c': 24 | inc i 25 | if s[i] == '\L': inc i 26 | result.add '\L' 27 | elif s[i] == '\L': 28 | result.add '\L' 29 | inc i 30 | else: 31 | result.add s[i] 32 | inc i 33 | if result[^1] != '\L': 34 | result.add '\L' 35 | 36 | proc editJson() = 37 | var contents = parseFile("packages.json") 38 | doAssert contents.kind == JArray 39 | writeFile("packages.json", contents.pretty.cleanupWhitespace) 40 | 41 | editJson() 42 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nim packages [![Build Status](https://travis-ci.org/nim-lang/packages.svg?branch=master)](https://travis-ci.org/nim-lang/packages) 2 | 3 | This is a central listing of all packages for 4 | [Nimble](https://github.com/nim-lang/nimble), a package manager for the 5 | [Nim programming language](http://nim-lang.org). 6 | 7 | An overview of all packages is available at https://nimble.directory. 8 | 9 | NOTE: The packages listed here are not peer-reviewed or otherwise screened. We try to keep the list up-to-date but we cannot guarantee quality or maturity of the packages. 10 | 11 | ## Adding your own package 12 | To add your own package, fork this repository, edit 13 | [packages.json](packages.json) and make a pull request. 14 | 15 | [Packages.json](packages.json) is a simple array of objects. Each package 16 | object should have the following fields (unless the field is marked as 17 | optional): 18 | 19 | * name - The name of the package, this should match the name in the package's 20 | nimble file. 21 | * url - The url from which to retrieve the package. 22 | * method - The method that should be used to retrieve this package. Currently 23 | "git" and "hg" is supported. 24 | * tags - A list of tags describing this package. 25 | * description - A description of this package. 26 | * license - The license of the source code in the package. 27 | * web - An optional URL for humans to read additional information about 28 | the package. 29 | * doc - An optional URL for humans to read the package HTML documentation 30 | 31 | ### Requirements 32 | 33 | While we really appreciate your contribution, please follow the requirements: other developers will rely on your package. Non-compliant packages might be removed with no warning. 34 | 35 | * The URL should work, a .nimble file should be present and the package should be installable 36 | * The package should build correctly with the latest Nim release 37 | * The package should not contain files without a license or in breach of 3rd parties licensing 38 | * Non-mature packages should be flagged as such, especially if they perform security-critical tasks (e.g. encryption) 39 | * If a vulnerability is found, make a patch release against the latest stable release (or more) that fixes the issue without introducing any other change. 40 | * Tiny libraries should be avoided where possible 41 | * Avoid having many dependencies. Use "when defined(...)" to enable optional features. 42 | * If abandoning a package, please tag it as "abandoned" 43 | * The package name should be unique and specific. Avoid overly generic names e.g. "math", "http" 44 | * Provide a contact email address. 45 | * Optionally try to support older Nim releases (6 months to 1 year) 46 | * Optionally GPG-sign your releases 47 | * Optionally follow [SemVer 2](http://semver.org) 48 | 49 | Your packages may be removed if the url stops working. It goes without saying 50 | that your pull request will not be accepted unless you fill out all of the 51 | above required fields correctly, the package that ``url`` points to must also 52 | contain a .nimble file, or else it will be rejected. 53 | 54 | The requirements might change in future. 55 | 56 | ## Releasing a new package version 57 | 58 | The version number in the directory is derived from git tags (not the `version` field in the `.nimble` script). To release a new version of a package, follow the [instructions from the Nimble readme](https://github.com/nim-lang/nimble#releasing-a-new-version): 59 | 60 | > * Increment the version in your ``.nimble`` file. 61 | > * Commit your changes. 62 | > * Tag your release, by for example running ``git tag v0.2.0``. 63 | > * Push your tags and commits. 64 | 65 | ## Renaming packages 66 | 67 | To rename a package you will need to add a new entry for your package. Simply 68 | perform the following steps: 69 | 70 | * Duplicate your package's current entry. 71 | * Remove every field in one of the entries apart from the `name` field. 72 | * Add an `alias` field to that entry. 73 | * Change the name in the other package entry. 74 | 75 | For example: 76 | 77 | ``` 78 | ... 79 | { 80 | "name": "myoldname", 81 | "alias": "mynewname" 82 | }, 83 | { 84 | "name": "mynewname", 85 | "url": "...", 86 | "method": "git", 87 | ... 88 | }, 89 | ... 90 | ``` 91 | 92 | -------------------------------------------------------------------------------- /package_scanner.nim: -------------------------------------------------------------------------------- 1 | # A very simple Nim package scanner. 2 | # 3 | # Scans the package list from this repository. 4 | # 5 | # Check the packages for: 6 | # * Missing name 7 | # * Missing/unknown method 8 | # * Missing/unreachable repository 9 | # * Missing tags 10 | # * Empty tags 11 | # * Missing description 12 | # * Missing/unknown license 13 | # * Insecure git:// url on GitHub 14 | # 15 | # Usage: nim r [-d:dontFetchRepos] package_scanner.nim 16 | # 17 | # Copyright 2015 Federico Ceratto 18 | # Released under GPLv3 License, see /usr/share/common-licenses/GPL-3 19 | 20 | import std/[httpclient, net, json, os, sets, strutils] 21 | 22 | const licenses = [ 23 | "allegro 4 giftware", 24 | "apache license 2.0", 25 | "apache", 26 | "apache2", 27 | "apache 2.0", 28 | "apache-2.0", 29 | "apache-2.0 license", 30 | "apache version 2.0", 31 | "mit or apache 2.0", 32 | "apache license 2.0 or mit", 33 | "mit or apache license 2.0", 34 | "(mit or apache license 2.0) and simplified bsd", 35 | "lxxsdt-mit", 36 | "lgplv2.1", 37 | "0bsd", 38 | "bsd", 39 | "bsd2", 40 | "bsd-2", 41 | "bsd3", 42 | "bsd-3", 43 | "bsd 3-clause", 44 | "bsd-3-clause", 45 | "boost", 46 | "boost-1.0", 47 | "bsl", 48 | "bsl-1.0", 49 | "2-clause bsd", 50 | "cc0", 51 | "cc0-1.0", 52 | "gpl", 53 | "gpl2", 54 | "gpl-2.0-only", 55 | "gpl3", 56 | "gplv2", 57 | "gplv3", 58 | "gplv3+", 59 | "gpl-2.0", 60 | "agpl-3.0", 61 | "gpl-3.0", 62 | "gpl-3.0-or-later", 63 | "gpl-3.0-only", 64 | "lgplv3 or gplv2", 65 | "apache 2.0 or gplv2", 66 | "lgpl-2.1-or-later", 67 | "lgpl with static linking exception", 68 | "gnu lesser general public license v2.1", 69 | "openldap", 70 | "lgpl", 71 | "lgplv2", 72 | "lgplv3", 73 | "lgpl-2.1", 74 | "lgpl-3.0", 75 | "agplv3", 76 | "mit", 77 | "mit/isc", 78 | "ms-pl", 79 | "mpl", 80 | "mplv2", 81 | "mpl-2.0", 82 | "mpl 2.0", 83 | "epl-2.0", 84 | "eupl-1.2", 85 | "wtfpl", 86 | "libpng", 87 | "fontconfig", 88 | "zlib", 89 | "isc", 90 | "ppl", 91 | "hydra", 92 | "openssl and ssleay", 93 | "unlicense", 94 | "public domain", 95 | "proprietary", 96 | ] 97 | 98 | proc canFetchNimbleRepository(name: string, urlJson: JsonNode): bool = 99 | # TODO: Make this check the actual repo url and check if there is a 100 | # nimble file in it 101 | result = true 102 | var url: string 103 | var client = newHttpClient(timeout = 100_000) 104 | 105 | if not urlJson.isNil: 106 | url = urlJson.str 107 | if url.startsWith("https://github.com"): 108 | if existsEnv("GITHUB_TOKEN"): 109 | client.headers = newHttpHeaders({"authorization": "Bearer " & getEnv("GITHUB_TOKEN")}) 110 | try: 111 | discard client.getContent(url) 112 | except TimeoutError: 113 | echo "W: ", name, ": Timeout error fetching repo ", url, " ", getCurrentExceptionMsg() 114 | except HttpRequestError: 115 | echo "W: ", name, ": HTTP error fetching repo ", url, " ", getCurrentExceptionMsg() 116 | except AssertionDefect: 117 | echo "W: ", name, ": httpclient error fetching repo ", url, " ", getCurrentExceptionMsg() 118 | except: 119 | echo "W: Unkown error fetching repo ", url, " ", getCurrentExceptionMsg() 120 | finally: 121 | client.close() 122 | 123 | proc verifyAlias(pkg: JsonNode, result: var int) = 124 | if not pkg.hasKey("name"): 125 | echo "E: Missing alias' package name" 126 | inc result 127 | # TODO: Verify that 'alias' points to a known package. 128 | 129 | proc check(): int = 130 | var name: string 131 | var names = initHashSet[string]() 132 | 133 | for pkg in parseJson(readFile(getCurrentDir() / "packages.json")): 134 | name = if pkg.hasKey("name"): pkg["name"].str else: "" 135 | if pkg.hasKey("alias"): 136 | verifyAlias(pkg, result) 137 | else: 138 | if name.len == 0: 139 | echo "E: missing package name" 140 | inc result 141 | elif not pkg.hasKey("method"): 142 | echo "E: ", name, " has no method" 143 | inc result 144 | elif pkg["method"].str notin ["git", "hg"]: 145 | echo "E: ", name, " has an unknown method: ", pkg["method"].str 146 | inc result 147 | elif not pkg.hasKey("url"): 148 | echo "E: ", name, " has no URL" 149 | inc result 150 | elif not pkg.hasKey("tags"): 151 | echo "E: ", name, " has no tags" 152 | inc result 153 | elif not pkg.hasKey("description"): 154 | echo "E: ", name, " has no description" 155 | inc result 156 | elif pkg.hasKey("description") and pkg["description"].str == "": 157 | echo "E: ", name, " has empty description" 158 | inc result 159 | elif not pkg.hasKey("license"): 160 | echo "E: ", name, " has no license" 161 | inc result 162 | elif pkg["url"].str.normalize.startsWith("git://github.com/"): 163 | echo "E: ", name, " has an insecure git:// URL instead of https://" 164 | inc result 165 | elif pkg["license"].str.toLowerAscii notin licenses: 166 | echo "E: ", name, " has an unexpected license: ", pkg["license"] 167 | inc result 168 | elif pkg.hasKey("web"): 169 | when not defined(dontFetchRepos): 170 | if not canFetchNimbleRepository(name, pkg["web"]): 171 | echo "W: Failed to fetch source code repo for ", name 172 | elif pkg.hasKey("tags"): 173 | var emptyTags = 0 174 | for tag in pkg["tags"]: 175 | if tag.getStr.len == 0: 176 | inc emptyTags 177 | 178 | if emptyTags > 0: 179 | echo "E: ", name, " has ", emptyTags, " empty tags" 180 | inc result 181 | 182 | if name.normalize notin names: 183 | names.incl name.normalize 184 | else: 185 | echo("E: ", name, ": a package by that name already exists.") 186 | inc result 187 | 188 | echo "\nProblematic packages count: ", result 189 | 190 | 191 | when isMainModule: 192 | quit(check()) 193 | --------------------------------------------------------------------------------