nim_lk/src/nimblepkg/checksums.nim

73 lines
2.7 KiB
Nim

# Copyright (C) Dominik Picheta. All rights reserved.
# BSD License. Look at license.txt for more info.
import os, std/sha1, strformat, algorithm
import common, version, sha1hashes, vcstools, paths, cli
type
ChecksumError* = object of NimbleError
proc checksumError*(name: string, version: Version,
vcsRevision, checksum, expectedChecksum: Sha1Hash):
ref ChecksumError =
result = newNimbleError[ChecksumError](&"""
Downloaded package checksum does not correspond to that in the lock file:
Package: {name}@v.{version}@r.{vcsRevision}
Checksum: {checksum}
Expected checksum: {expectedChecksum}
""")
proc updateSha1Checksum(checksum: var Sha1State, fileName, filePath: string) =
if not filePath.fileExists:
# In some cases a file name returned by `git ls-files` or `hg manifest`
# could be an empty directory name and if so trying to open it will result
# in a crash. This happens for example in the case of a git sub module
# directory from which no files are being installed.
return
checksum.update(fileName)
if symlinkExists(filePath):
# Check whether a file is a symbolic link and if so update the checksum with
# the path to the file that the link points to.
var linkPath: string
try:
linkPath = expandSymlink(filePath)
except OSError:
displayWarning(&"Cannot expand symbolic link \"{filePath}\".\n" &
"Skipping it in the calculation of the checksum.")
return
checksum.update(linkPath)
else:
# Otherwise this is an ordinary file and we are adding its content to the
# checksum.
var file: File
try:
file = filePath.open(fmRead)
except IOError:
## If the file cannot be open for reading do not count its content in the
## checksum.
displayWarning(&"The file \"{filePath}\" cannot be open for reading.\n" &
"Skipping it in the calculation of the checksum.")
return
defer: close(file)
const bufferSize = 8192
var buffer = newString(bufferSize)
while true:
var bytesRead = readChars(file, buffer)
if bytesRead == 0: break
checksum.update(buffer.toOpenArray(0, bytesRead - 1))
proc calculateDirSha1Checksum*(dir: string): Sha1Hash =
## Recursively calculates the sha1 checksum of the contents of the directory
## `dir` and its subdirectories.
##
## Raises a `NimbleError` if:
## - the external command for getting the package file list fails.
## - the directory does not exist.
var packageFiles = getPackageFileList(dir.Path)
packageFiles.sort
var checksum = newSha1State()
for file in packageFiles:
updateSha1Checksum(checksum, file, dir / file)
result = initSha1Hash($SecureHash(checksum.finalize()))