blob: 485554d874adba9917a967d7aea5e31bdf75c921 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This file exposes two constexpr values |kVCSID| and |kShortVCSID|.
// These are translations of the build system's |VCSID| macro into pure C++
// constants.
//
// The bellow |kVCSID| and |kShortVCSID| definitions are in an anonymous
// namesace inside a header file because |VCSID| is set as a preprocessor macro
// by the build system for a particular package. So, the |VCSID| seen by a
// libbrillo source file will be different to that seen by a source file
// in the biod package, at compile time.
//
// To avoid ODR violations (and odd behavior) these constants should not be
// used in any header files that could be potentially shared across
// packages. This is because redefinitions of identical inline [header]
// functions is allowed, but an inline function that uses this constant will
// have a different definitions across packages. In practice, the
// compiler/linker silently chooses one of the definitions, which may not be
// the one you expected.
#ifndef LIBBRILLO_BRILLO_VCSID_H_
#define LIBBRILLO_BRILLO_VCSID_H_
#include <cctype>
#include <openssl/sha.h>
#include <string_view>
#include <optional>
#include <base/logging.h>
namespace brillo {
namespace vcsid_internal {
// Checks if |str| could be a SHA1 hash encoded as a hexadecimal string.
constexpr bool IsSHA1HexString(const std::string_view& str) {
if (str.length() != (2 * SHA_DIGEST_LENGTH))
return false;
return str.find_first_not_of("0123456789ABCDEFabcdef") ==
std::string_view::npos;
}
// Checks if |vcsid| matches our expected VCSID pattern.
constexpr bool IsValidVCSID(const std::string_view& vcsid) {
const std::size_t delim = vcsid.find_last_of('-');
// Check that there is a '-' delimiter.
if (delim == std::string_view::npos)
return false;
return IsSHA1HexString(vcsid.substr(delim + 1));
}
// Parameter |vcsid| is assumed to be IsValidVCSID(vcsid).
constexpr std::string_view ShortenVCSID(const std::string_view& vcsid) {
// If IsValidVCSID(vcsid), vcsid is is guaranteed to contain a '-' and
// the trailing part is larger than 10 characters.
return vcsid.substr(0, vcsid.find_last_of('-') + 1 + 10);
}
} // namespace vcsid_internal
namespace { // NOLINT(build/namespaces)
// |kVCSID| is the full VCSID reported from the package build system as a
// string. This requires "CROS_WORKON_USE_VCSID=1" to be set in the pkg ebuild.
// Return nullopt if VCSID was not set (CROS_WORKON_USE_VCSID not enabled).
//
// The string is of the format <GENTOO_PVR>-<VCS_REV_ID>, where
// GENTOO_PVR could be 9999 or <sw_ver>-<pkg_rev>.
//
// Examples:
// * "9999-67ec4c03828a50c2b8cacba45c0cf5f9b4f2ff34"
// * "0.0.1-r2004-67ec4c03828a50c2b8cacba45c0cf5f9b4f2ff34"
constexpr std::optional<std::string_view> kVCSID =
#ifdef VCSID
std::string_view(VCSID);
#else
std::nullopt;
#endif
// |kShortVCSID| is |kVCSID|, but with a shorter git hash.
// This is useful when logging the VCSID, since the full git SHA1 would
// be automatically shortened to an unusable small length by the feedback report
// log sanitizer. We pre-shorten the hash to a usable 10 characters so that
// the sanitizer ignores it.
// Return nullopt if |kVCSID| is nullopt.
//
// Example usage:
// #include <base/logging.h>
// LOG(INFO) << "Version ID: " << brillo::kShortVCSID.value_or("VCSID UNSET");
static_assert(!kVCSID || vcsid_internal::IsValidVCSID(*kVCSID),
"VCSID doesn't match the expected format.");
constexpr std::optional<std::string_view> kShortVCSID =
kVCSID
? std::optional<std::string_view>(vcsid_internal::ShortenVCSID(*kVCSID))
: std::optional<std::string_view>(std::nullopt);
} // namespace
} // namespace brillo
#endif // LIBBRILLO_BRILLO_VCSID_H_