diff --git a/src/nimble.nim b/src/nimble.nim index ea626ba..24fefa1 100644 --- a/src/nimble.nim +++ b/src/nimble.nim @@ -32,8 +32,6 @@ else: const nimbleVersion = "0.7.0" - defaultPackageURL = - "https://github.com/nim-lang/packages/raw/master/packages.json" proc writeVersion() = echo("nimble v$# compiled at $# $#" % @@ -55,16 +53,40 @@ proc promptCustom(question, default: string): string = proc update(options: Options) = ## Downloads the package list from the specified URL. ## - ## If the download is successful, the global didUpdatePackages is set to - ## true. Otherwise an exception is raised on error. - let url = - if options.action.typ == actionUpdate and options.action.optionalURL != "": + ## If the download is not successful, an exception is raised. + let parameter = + if options.action.typ == actionUpdate: options.action.optionalURL else: - defaultPackageURL - echo("Downloading package list from " & url) - downloadFile(url, options.getNimbleDir() / "packages.json") - echo("Done.") + "" + + proc downloadList(list: PackageList, options: Options) = + echo("Downloading \"", list.name, "\" package list") + for i in 0 .. newVersion("0.9.6"): @@ -18,6 +22,22 @@ proc initConfig(): Config = result.chcp = true + result.packageLists = initTable[string, PackageList]() + let defaultPkgList = PackageList(name: "Official", urls: @[ + "http://irclogs.nim-lang.org/packages.json", + "http://nim-lang.org/nimble/packages.json", + "https://github.com/nim-lang/packages/raw/master/packages.json" + ]) + result.packageLists["official"] = defaultPkgList + +proc initPackageList(): PackageList = + result.name = "" + result.urls = @[] + +proc addCurrentPkgList(config: var Config, currentPackageList: PackageList) = + if currentPackageList.name.len > 0: + config.packageLists[currentPackageList.name.normalize] = currentPackageList + proc parseConfig*(): Config = result = initConfig() var confFile = getConfigDir() / "nimble" / "nimble.ini" @@ -34,12 +54,23 @@ proc parseConfig*(): Config = echo("Reading from config file at ", confFile) var p: CfgParser open(p, f, confFile) + var currentSection = "" + var currentPackageList = initPackageList() while true: var e = next(p) case e.kind of cfgEof: + addCurrentPkgList(result, currentPackageList) break - of cfgSectionStart: discard + of cfgSectionStart: + addCurrentPkgList(result, currentPackageList) + currentSection = e.section + case currentSection.normalize + of "packagelist": + currentPackageList = initPackageList() + else: + raise newException(NimbleError, "Unable to parse config file:" & + " Unknown section: " & e.key) of cfgKeyValuePair, cfgOption: case e.key.normalize of "nimbledir": @@ -48,6 +79,16 @@ proc parseConfig*(): Config = result.nimbleDir = e.value of "chcp": result.chcp = parseBool(e.value) + of "name": + case currentSection.normalize + of "packagelist": + currentPackageList.name = e.value + else: assert false + of "url": + case currentSection.normalize + of "packagelist": + currentPackageList.urls.add(e.value) + else: assert false else: raise newException(NimbleError, "Unable to parse config file:" & " Unknown key: " & e.key) diff --git a/src/nimblepkg/packageinfo.nim b/src/nimblepkg/packageinfo.nim index ead94a6..c718fe7 100644 --- a/src/nimblepkg/packageinfo.nim +++ b/src/nimblepkg/packageinfo.nim @@ -1,6 +1,6 @@ # Copyright (C) Dominik Picheta. All rights reserved. # BSD License. Look at license.txt for more info. -import parsecfg, json, streams, strutils, parseutils, os +import parsecfg, json, streams, strutils, parseutils, os, sets, tables import version, tools, nimbletypes, options type @@ -127,25 +127,35 @@ proc readMetaData*(path: string): MetaData = let jsonmeta = parseJson(cont) result.url = jsonmeta["url"].str -proc getPackage*(pkg: string, packagesPath: string, resPkg: var Package): bool = - ## Searches ``packagesPath`` file saving into ``resPkg`` the found package. +proc getPackage*(pkg: string, options: Options, + resPkg: var Package): bool = + ## Searches any packages.json files defined in ``options.config.packageLists`` + ## Saves the found package into ``resPkg``. ## ## Pass in ``pkg`` the name of the package you are searching for. As ## convenience the proc returns a boolean specifying if the ``resPkg`` was ## successfully filled with good data. - let packages = parseFile(packagesPath) - for p in packages: - if p["name"].str == pkg: - resPkg = p.fromJson() - return true + for name, list in options.config.packageLists: + echo("Searching in \"", name, "\" package list...") + let packages = parseFile(options.getNimbleDir() / + "packages_" & name.toLower() & ".json") + for p in packages: + if p["name"].str == pkg: + resPkg = p.fromJson() + return true -proc getPackageList*(packagesPath: string): seq[Package] = - ## Returns the list of packages found at the specified path. +proc getPackageList*(options: Options): seq[Package] = + ## Returns the list of packages found in the downloaded packages.json files. result = @[] - let packages = parseFile(packagesPath) - for p in packages: - let pkg: Package = p.fromJson() - result.add(pkg) + var namesAdded = initSet[string]() + for name, list in options.config.packageLists: + let packages = parseFile(options.getNimbleDir() / + "packages_" & name.toLower() & ".json") + for p in packages: + let pkg: Package = p.fromJson() + if pkg.name notin namesAdded: + result.add(pkg) + namesAdded.incl(pkg.name) proc findNimbleFile*(dir: string; error: bool): string = result = "" @@ -250,6 +260,27 @@ proc getDownloadDirName*(pkg: Package, verRange: VersionRange): string = result.add "_" result.add verSimple +proc needsRefresh*(options: Options): bool = + ## Determines whether a ``nimble refresh`` is needed. + ## + ## In the future this will check a stored time stamp to determine how long + ## ago the package list was refreshed. + result = true + for name, list in options.config.packageLists: + if fileExists(options.getNimbleDir() / "packages_" & name & ".json"): + result = false + +proc validatePackagesList*(path: string): bool = + ## Determines whether package list at ``path`` is valid. + try: + let pkgList = parseFile(path) + if pkgList.kind == JArray: + if pkgList.len == 0: + echo("WARNING: ", path, " contains no packages.") + return true + except ValueError, JsonParsingError: + return false + when isMainModule: doAssert getNameVersion("/home/user/.nimble/libs/packagea-0.1") == ("packagea", "0.1") diff --git a/tests/tester.nim b/tests/tester.nim index 7a77c68..d85da8b 100644 --- a/tests/tester.nim +++ b/tests/tester.nim @@ -18,6 +18,38 @@ template cd*(dir: string, body: stmt) = proc processOutput(output: string): seq[string] = output.strip.splitLines().filter((x: string) => (x.len > 0)) +test "can refresh with default urls": + check execCmdEx(path & " refresh").exitCode == QuitSuccess + +test "can refresh with custom urls": + # Backup current config + let configFile = getConfigDir() / "nimble" / "nimble.ini" + let configBakFile = getConfigDir() / "nimble" / "nimble.ini.bak" + if fileExists(configFile): + moveFile(configFile, configBakFile) + writeFile(configFile, """ + [PackageList] + name = "official" + url = "http://google.com" + url = "http://google.com/404" + url = "http://irclogs.nim-lang.org/packages.json" + url = "http://nim-lang.org/nimble/packages.json" + """.unindent) + + let (output, exitCode) = execCmdEx(path & " refresh") + let lines = output.strip.splitLines() + check exitCode == QuitSuccess + check "reading from config file" in lines[0].normalize + check "downloading \"official\" package list" in lines[1].normalize + check "trying http://google.com" in lines[2].normalize + check "packages.json file is invalid" in lines[3].normalize + check "404 not found" in lines[5].normalize + check "done" in lines[^1].normalize + + # Restore config + if fileExists(configBakFile): + moveFile(configBakFile, configFile) + test "can install nimscript package": cd "nimscript": check execCmdEx("../" & path & " install -y").exitCode == QuitSuccess