Skip to content

Commit bd4f085

Browse files
authored
[Common] Add possibility to verify commit hash from metadata (#13343)
1 parent 6f4e9ac commit bd4f085

File tree

3 files changed

+157
-0
lines changed

3 files changed

+157
-0
lines changed

Common/Core/MetadataHelper.cxx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <Framework/InitContext.h>
2222
#include <Framework/Logger.h>
2323

24+
#include <TSystem.h>
25+
2426
#include <array>
2527
#include <string>
2628

@@ -140,3 +142,31 @@ std::string MetadataHelper::makeMetadataLabel() const
140142
}
141143
return label;
142144
}
145+
146+
std::string MetadataHelper::getO2Version() const
147+
{
148+
if (!mIsInitialized) {
149+
LOG(warning) << "Metadata not initialized";
150+
return "undefined";
151+
}
152+
return get("O2Version");
153+
}
154+
155+
bool MetadataHelper::isCommitInSoftwareTag(const std::string& commitHash, const std::string& ccdbUrl) const
156+
{
157+
const std::string softwareTag = getO2Version();
158+
std::string command = "curl -i -L ";
159+
command += ccdbUrl;
160+
command += "O2Version/CommitHash/";
161+
command += commitHash;
162+
command += "/-1/";
163+
command += "O2Version=" + softwareTag;
164+
command += " 2>&1 | grep --text O2Version:";
165+
// LOG(info) << "Command to check if commit " << commitHash << " is in software tag " << softwareTag << ": " << command;
166+
TString res = gSystem->GetFromPipe(command.c_str());
167+
if (res.Contains(Form("O2Version: %s", softwareTag.c_str()))) {
168+
LOG(debug) << "Commit " << commitHash << " is contained in software tag " << softwareTag;
169+
return true;
170+
}
171+
return false;
172+
}

Common/Core/MetadataHelper.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,21 @@ struct MetadataHelper {
5151
/// @return true if the data has been initialized, false otherwise
5252
bool isInitialized() const;
5353

54+
/// @brief Function to get the O2 version from the metadata in the monalisa format
55+
/// @return the O2 version from the metadata
56+
std::string getO2Version() const;
57+
5458
/// @brief Function to get the metadata value for a given key
5559
/// @param key the key of the metadata
5660
/// @return the value of the metadata. Throws an exception if the key is not found
5761
std::string get(const std::string& key) const;
5862

63+
/// @brief Function to set a metadata key to a given value
64+
/// @param key the key of the metadata
65+
/// @param value the value to set
66+
/// Note: this function does not check if the key is valid
67+
void set(const std::string& key, const std::string& value) { mMetadata[key] = value; }
68+
5969
/// @brief Function to check if a key is defined in the metadata
6070
/// @param key the key to check
6171
/// @return true if the key is defined, false otherwise. Throws an exception if the key is not found
@@ -64,6 +74,11 @@ struct MetadataHelper {
6474
/// @brief Function to create a label with the metadata information, useful e.g. for histogram naming
6575
std::string makeMetadataLabel() const;
6676

77+
/// Function to check if a commit is included in the software tag
78+
/// @param commitHash the commit hash to check
79+
/// @return true if the commit is included in the software tag, false otherwise
80+
bool isCommitInSoftwareTag(const std::string& commitHash, const std::string& ccdbUrl = "http://ccdb-test.cern.ch:8080/") const;
81+
6782
private:
6883
std::map<std::string, std::string> mMetadata; /// < The metadata map
6984
bool mIsInitialized = false; /// < Flag to check if the metadata has been initialized

Common/Core/macros/testMetadataHelper.C

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "Common/Core/MetadataHelper.h"
1717

18+
#include <CCDB/CcdbApi.h>
1819
#include <Framework/ConfigContext.h>
1920
#include <Framework/ConfigParamRegistry.h>
2021
#include <Framework/ConfigParamStore.h>
@@ -24,7 +25,9 @@
2425
#include <TFile.h>
2526
#include <TMap.h>
2627
#include <TObjString.h>
28+
#include <TSystem.h>
2729

30+
#include <map>
2831
#include <memory>
2932
#include <string>
3033
#include <utility>
@@ -57,8 +60,100 @@ auto readMetadata(std::unique_ptr<TFile>& currentFile) -> std::vector<o2::framew
5760
return results;
5861
}
5962

63+
// Create a file with all the versions of the O2 software with alienv q
64+
void createO2VersionFile()
65+
{
66+
// Can do this only if on lxplus
67+
std::string host = gSystem->HostName() ? gSystem->HostName() : "";
68+
if (host.find("lxplus") == std::string::npos) {
69+
LOG(warn) << "Not on lxplus (" << host << "); skipping creation of /tmp/o2version.txt";
70+
return;
71+
}
72+
// If file exists, do nothing
73+
std::ifstream infile("/tmp/o2version.txt");
74+
if (infile.is_open()) {
75+
return;
76+
}
77+
gSystem->Exec("alienv q | grep VO_ALICE@O2:: > /tmp/o2version.txt");
78+
}
79+
80+
std::map<std::string, bool> buildMapForCommitHash(const std::string& hash)
81+
{
82+
// Change directory to /tmp
83+
std::map<std::string, bool> results;
84+
std::ifstream infileO2Versions("/tmp/o2version.txt");
85+
std::string lineOfO2Version;
86+
const std::string fileContainingCommit = "/tmp/branches_" + hash + ".txt";
87+
std::ifstream infileO2VersionsWithHash(fileContainingCommit);
88+
if (!infileO2VersionsWithHash.is_open()) {
89+
gSystem->cd("/tmp/");
90+
gSystem->Exec("git clone git@github.com:AliceO2Group/AliceO2.git");
91+
gSystem->cd("AliceO2");
92+
std::string cmd = Form("git branch -r --contains %s > %s 2>&1", hash.c_str(), fileContainingCommit.c_str());
93+
LOG(info) << "Executing command " << cmd;
94+
gSystem->Exec(cmd.c_str());
95+
}
96+
std::string lineOfO2VersionsWithHash;
97+
while (std::getline(infileO2Versions, lineOfO2Version)) {
98+
// Extract the tag
99+
int stripSize = 4;
100+
std::string tag = lineOfO2Version.substr(lineOfO2Version.find("O2::") + stripSize);
101+
// Strip a trailing "-1" (some alienv entries append this)
102+
stripSize = 2;
103+
if (tag.size() >= stripSize && tag.compare(tag.size() - stripSize, stripSize, "-1") == 0) {
104+
tag.resize(tag.size() - stripSize);
105+
}
106+
LOG(debug) << "Checking tag '" << lineOfO2Version << "' tag (" << tag << ")";
107+
bool found = false;
108+
infileO2VersionsWithHash.open(fileContainingCommit);
109+
while (std::getline(infileO2VersionsWithHash, lineOfO2VersionsWithHash)) {
110+
// LOG(info) << "Comparing " << lineOfO2Version << " with " << lineOfO2VersionsWithHash;
111+
if (lineOfO2VersionsWithHash.find(tag) != std::string::npos) {
112+
LOG(info) << "Tag " << tag << " contains hash " << hash;
113+
found = true;
114+
break;
115+
}
116+
}
117+
infileO2VersionsWithHash.close();
118+
results[tag] = found;
119+
}
120+
return results;
121+
}
122+
123+
void populateCCDBWithCommitAvailability(std::map<string, bool> hasHashMap,
124+
const std::string commitHash const std::string ccdbUrl = "http://ccdb-test.cern.ch:8080/")
125+
{
126+
// First, init the CCDB manager to test if the ccdb is already populated
127+
o2::ccdb::CcdbApi api;
128+
api.init(ccdbUrl);
129+
if (!api.isHostReachable()) {
130+
LOG(fatal) << "CCDB host " << ccdbUrl << " is not reacheable, cannot go forward";
131+
}
132+
for (const auto& entry : hasHashMap) {
133+
if (!entry.second) { // Version of the code does not have the hash
134+
continue;
135+
}
136+
LOG(info) << "Populating CCDB with information that commit hash " << commitHash << " is contained in software tag " << entry.first;
137+
std::map<std::string, std::string> metadata;
138+
metadata["O2Version"] = entry.first;
139+
const std::string ccdbPath = "O2Version/CommitHash/" + commitHash;
140+
auto headers = api.retrieveHeaders(ccdbPath, metadata, -1);
141+
if (headers.size() != 0) {
142+
LOG(info) << "Entry in CCDB already present for commit hash " << commitHash << ", skipping creation";
143+
continue;
144+
}
145+
LOG(info) << "No entry in CCDB for commit hash " << commitHash << ", creating it";
146+
std::string s = "available";
147+
api.storeAsTFileAny<std::string>(&s, ccdbPath, metadata);
148+
}
149+
}
150+
60151
void testMetadataHelper(std::string aod = "/tmp/AO2D.root")
61152
{
153+
createO2VersionFile();
154+
const std::string commitHash = "63bc2e3893851ef0f849bb4c98c65eae1ba21e47";
155+
const std::map<std::string, bool> hasHashMap = buildMapForCommitHash(commitHash);
156+
populateCCDBWithCommitAvailability(hasHashMap, commitHash);
62157

63158
TFile* file = TFile::Open(aod.c_str());
64159
if (!file || file->IsZombie()) {
@@ -79,6 +174,23 @@ void testMetadataHelper(std::string aod = "/tmp/AO2D.root")
79174
aodCfg.options().get<std::string>("aod-metadata-DataType");
80175
o2::common::core::MetadataHelper metadataInfo;
81176
metadataInfo.initMetadata(aodCfg);
177+
metadataInfo.set("O2Version", "epn-20250715"); // Override the O2 version to a known one
82178
metadataInfo.print();
83179
LOG(info) << "Metadata label: " << metadataInfo.makeMetadataLabel();
180+
181+
// Check if the hash is in the software tag
182+
const std::string v = metadataInfo.getO2Version();
183+
if (hasHashMap.find(v) == hasHashMap.end()) {
184+
LOG(fatal) << "Software tag " << v << " not found in available O2 versions";
185+
}
186+
if (hasHashMap.at(v)) {
187+
LOG(info) << "Hash " << commitHash << " is contained in software tag " << v;
188+
} else {
189+
LOG(warn) << "Hash " << commitHash << " is NOT contained in software tag " << v;
190+
}
191+
if (metadataInfo.isCommitInSoftwareTag(commitHash)) {
192+
LOG(info) << "MetadataHelper confirms that hash " << commitHash << " is contained in software tag " << v;
193+
} else {
194+
LOG(warn) << "MetadataHelper confirms that hash " << commitHash << " is NOT contained in software tag " << v;
195+
}
84196
}

0 commit comments

Comments
 (0)