123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- #
- #
- # The Nim Compiler
- # (c) Copyright 2012 Andreas Rumpf
- #
- # See the file "copying.txt", included in this
- # distribution, for details about the copyright.
- #
- ## Implements some helper procs for Nimble (Nim's package manager) support.
- import parseutils, strutils, os, options, msgs, sequtils, lineinfos, pathutils,
- tables
- when defined(nimPreviewSlimSystem):
- import std/[syncio, assertions]
- import ../dist/checksums/src/checksums/sha1
- proc addPath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) =
- if not conf.searchPaths.contains(path):
- conf.searchPaths.insert(path, 0)
- type
- Version* = distinct string
- PackageInfo = Table[string, tuple[version, checksum: string]]
- proc `$`*(ver: Version): string {.borrow.}
- proc newVersion*(ver: string): Version =
- doAssert(ver.len == 0 or ver[0] in {'#', '\0'} + Digits,
- "Wrong version: " & ver)
- return Version(ver)
- proc isSpecial(ver: Version): bool =
- return ($ver).len > 0 and ($ver)[0] == '#'
- proc isValidVersion(v: string): bool =
- if v.len > 0:
- if v[0] in {'#'} + Digits:
- result = true
- else:
- result = false
- else:
- result = false
- proc `<`*(ver: Version, ver2: Version): bool =
- ## This is synced from Nimble's version module.
- result = false
- # Handling for special versions such as "#head" or "#branch".
- if ver.isSpecial or ver2.isSpecial:
- if ver2.isSpecial and ($ver2).normalize == "#head":
- return ($ver).normalize != "#head"
- if not ver2.isSpecial:
- # `#aa111 < 1.1`
- return ($ver).normalize != "#head"
- # Handling for normal versions such as "0.1.0" or "1.0".
- var sVer = string(ver).split('.')
- var sVer2 = string(ver2).split('.')
- for i in 0..<max(sVer.len, sVer2.len):
- var sVerI = 0
- if i < sVer.len:
- discard parseInt(sVer[i], sVerI)
- var sVerI2 = 0
- if i < sVer2.len:
- discard parseInt(sVer2[i], sVerI2)
- if sVerI < sVerI2:
- return true
- elif sVerI == sVerI2:
- discard
- else:
- return false
- proc getPathVersionChecksum*(p: string): tuple[name, version, checksum: string] =
- ## Splits path ``p`` in the format
- ## ``/home/user/.nimble/pkgs/package-0.1-febadeaea2345e777f0f6f8433f7f0a52edd5d1b`` into
- ## ``("/home/user/.nimble/pkgs/package", "0.1", "febadeaea2345e777f0f6f8433f7f0a52edd5d1b")``
- const checksumSeparator = '-'
- const versionSeparator = '-'
- const specialVersionSepartator = "-#"
- const separatorNotFound = -1
- var checksumSeparatorIndex = p.rfind(checksumSeparator)
- if checksumSeparatorIndex != separatorNotFound:
- result.checksum = p.substr(checksumSeparatorIndex + 1)
- if not result.checksum.isValidSha1Hash():
- result.checksum = ""
- checksumSeparatorIndex = p.len()
- else:
- checksumSeparatorIndex = p.len()
- var versionSeparatorIndex = p.rfind(
- specialVersionSepartator, 0, checksumSeparatorIndex - 1)
- if versionSeparatorIndex != separatorNotFound:
- result.version = p.substr(
- versionSeparatorIndex + 1, checksumSeparatorIndex - 1)
- else:
- versionSeparatorIndex = p.rfind(
- versionSeparator, 0, checksumSeparatorIndex - 1)
- if versionSeparatorIndex != separatorNotFound:
- result.version = p.substr(
- versionSeparatorIndex + 1, checksumSeparatorIndex - 1)
- else:
- versionSeparatorIndex = checksumSeparatorIndex
- result.name = p[0..<versionSeparatorIndex]
- proc addPackage*(conf: ConfigRef; packages: var PackageInfo, p: string;
- info: TLineInfo) =
- let (name, ver, checksum) = getPathVersionChecksum(p)
- if isValidVersion(ver):
- let version = newVersion(ver)
- if packages.getOrDefault(name).version.newVersion < version or
- (not packages.hasKey(name)):
- if checksum.isValidSha1Hash():
- packages[name] = ($version, checksum)
- else:
- packages[name] = ($version, "")
- else:
- localError(conf, info, "invalid package name: " & p)
- iterator chosen(packages: PackageInfo): string =
- for key, val in pairs(packages):
- var res = key
- if val.version.len != 0:
- res &= '-'
- res &= val.version
- if val.checksum.len != 0:
- res &= '-'
- res &= val.checksum
- yield res
- proc addNimblePath(conf: ConfigRef; p: string, info: TLineInfo) =
- var path = p
- let nimbleLinks = toSeq(walkPattern(p / "*.nimble-link"))
- if nimbleLinks.len > 0:
- # If the user has more than one .nimble-link file then... we just ignore it.
- # Spec for these files is available in Nimble's readme:
- # https://github.com/nim-lang/nimble#nimble-link
- let nimbleLinkLines = readFile(nimbleLinks[0]).splitLines()
- path = nimbleLinkLines[1]
- if not path.isAbsolute():
- path = p / path
- if not contains(conf.searchPaths, AbsoluteDir path):
- message(conf, info, hintPath, path)
- conf.lazyPaths.insert(AbsoluteDir path, 0)
- proc addPathRec(conf: ConfigRef; dir: string, info: TLineInfo) =
- var packages: PackageInfo = initTable[string, tuple[version, checksum: string]]()
- var pos = dir.len-1
- if dir[pos] in {DirSep, AltSep}: inc(pos)
- for k,p in os.walkDir(dir):
- if k == pcDir and p[pos] != '.':
- addPackage(conf, packages, p, info)
- for p in packages.chosen:
- addNimblePath(conf, p, info)
- proc nimblePath*(conf: ConfigRef; path: AbsoluteDir, info: TLineInfo) =
- addPathRec(conf, path.string, info)
- addNimblePath(conf, path.string, info)
- let i = conf.nimblePaths.find(path)
- if i != -1:
- conf.nimblePaths.delete(i)
- conf.nimblePaths.insert(path, 0)
|