summaryrefslogtreecommitdiff
path: root/Source/cmFilePathChecksum.cxx
blob: bb3f610d125adec66a6f6f2c9cba5b86ce0ffaa6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
#include "cmFilePathChecksum.h"

#include <vector>

#include "cmBase32.h"
#include "cmCryptoHash.h"
#include "cmMakefile.h"
#include "cmSystemTools.h"

cmFilePathChecksum::cmFilePathChecksum() = default;

cmFilePathChecksum::cmFilePathChecksum(std::string const& currentSrcDir,
                                       std::string const& currentBinDir,
                                       std::string const& projectSrcDir,
                                       std::string const& projectBinDir)
{
  setupParentDirs(currentSrcDir, currentBinDir, projectSrcDir, projectBinDir);
}

cmFilePathChecksum::cmFilePathChecksum(cmMakefile* makefile)
{
  setupParentDirs(makefile->GetCurrentSourceDirectory(),
                  makefile->GetCurrentBinaryDirectory(),
                  makefile->GetHomeDirectory(),
                  makefile->GetHomeOutputDirectory());
}

void cmFilePathChecksum::setupParentDirs(std::string const& currentSrcDir,
                                         std::string const& currentBinDir,
                                         std::string const& projectSrcDir,
                                         std::string const& projectBinDir)
{
  this->parentDirs[0].first = cmSystemTools::GetRealPath(currentSrcDir);
  this->parentDirs[1].first = cmSystemTools::GetRealPath(currentBinDir);
  this->parentDirs[2].first = cmSystemTools::GetRealPath(projectSrcDir);
  this->parentDirs[3].first = cmSystemTools::GetRealPath(projectBinDir);

  this->parentDirs[0].second = "CurrentSource";
  this->parentDirs[1].second = "CurrentBinary";
  this->parentDirs[2].second = "ProjectSource";
  this->parentDirs[3].second = "ProjectBinary";
}

std::string cmFilePathChecksum::get(std::string const& filePath) const
{
  std::string relPath;
  std::string relSeed;
  {
    std::string const fileReal = cmSystemTools::GetRealPath(filePath);
    std::string parentDir;
    // Find closest project parent directory
    for (auto const& pDir : this->parentDirs) {
      if (!pDir.first.empty() &&
          cmsys::SystemTools::IsSubDirectory(fileReal, pDir.first)) {
        parentDir = pDir.first;
        relSeed = pDir.second;
        break;
      }
    }
    // Use file system root as fallback parent directory
    if (parentDir.empty()) {
      relSeed = "FileSystemRoot";
      cmsys::SystemTools::SplitPathRootComponent(fileReal, &parentDir);
    }
    // Calculate relative path from project parent directory
    relPath = cmsys::SystemTools::RelativePath(
      parentDir, cmsys::SystemTools::GetParentDirectory(fileReal));
  }

  // Calculate the file ( seed + relative path ) binary checksum
  std::vector<unsigned char> hashBytes =
    cmCryptoHash(cmCryptoHash::AlgoSHA256).ByteHashString(relSeed + relPath);

  // Convert binary checksum to string
  return cmBase32Encoder().encodeString(hashBytes.data(), hashBytes.size(),
                                        false);
}

std::string cmFilePathChecksum::getPart(std::string const& filePath,
                                        size_t length) const
{
  return get(filePath).substr(0, length);
}