Switch to new git version number recognition

This commit is contained in:
Sebastian Messmer 2016-03-02 13:53:37 +01:00
parent bff40532a3
commit 5753e4f71c
51 changed files with 392 additions and 3068 deletions

View File

@ -33,6 +33,7 @@ install:
script:
- cmake .. -DBUILD_TESTING=on -DCMAKE_BUILD_TYPE=Debug
- make -j$NUMCORES
- ./test/gitversion/gitversion-test
- ./test/cpp-utils/cpp-utils-test
# TODO Also run on osx once fixed
- if [ "${TRAVIS_OS_NAME}" == "linux" ]; then ./run_with_fuse.sh ./test/fspp/fspp-test ; fi

View File

@ -1,486 +0,0 @@
# This file helps to compute a version number in source trees obtained from
# git-archive tarball (such as those provided by githubs download-from-tag
# feature). Distribution tarballs (built by setup.py sdist) and build
# directories (produced by setup.py build) will contain a much shorter file
# that just contains the computed version number.
# This file is released into the public domain. Generated by
# versioneer-0.15+dev (https://github.com/warner/python-versioneer)
"""Git implementation of _version.py."""
import errno
import os
import re
import subprocess
import sys
def get_keywords():
"""Get the keywords needed to look up the version information."""
# these strings will be replaced by git during git-archive.
# setup.py/versioneer.py will grep for the variable names, so they must
# each be defined on a line of their own. _version.py will just call
# get_keywords().
git_refnames = "$Format:%d$"
git_full = "$Format:%H$"
keywords = {"refnames": git_refnames, "full": git_full}
return keywords
class VersioneerConfig:
"""Container for Versioneer configuration parameters."""
def get_config():
"""Create, populate and return the VersioneerConfig() object."""
# these strings are filled in when 'setup.py versioneer' creates
# _version.py
cfg = VersioneerConfig()
cfg.VCS = "git"
cfg.style = "pep440"
cfg.tag_prefix = ""
cfg.parentdir_prefix = ""
cfg.versionfile_source = "_version_source.py"
cfg.verbose = False
return cfg
class NotThisMethod(Exception):
"""Exception raised if a method is not valid for the current scenario."""
LONG_VERSION_PY = {}
HANDLERS = {}
def register_vcs_handler(vcs, method): # decorator
"""Decorator to mark a method as the handler for a particular VCS."""
def decorate(f):
"""Store f in HANDLERS[vcs][method]."""
if vcs not in HANDLERS:
HANDLERS[vcs] = {}
HANDLERS[vcs][method] = f
return f
return decorate
def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False):
"""Call the given command(s)."""
assert isinstance(commands, list)
p = None
for c in commands:
try:
dispcmd = str([c] + args)
# remember shell=False, so use git.cmd on windows, not just git
p = subprocess.Popen([c] + args, cwd=cwd, stdout=subprocess.PIPE,
stderr=(subprocess.PIPE if hide_stderr
else None))
break
except EnvironmentError:
e = sys.exc_info()[1]
if e.errno == errno.ENOENT:
continue
if verbose:
print("unable to run %s" % dispcmd)
print(e)
return None
else:
if verbose:
print("unable to find command, tried %s" % (commands,))
return None
stdout = p.communicate()[0].strip()
if sys.version_info[0] >= 3:
stdout = stdout.decode()
if p.returncode != 0:
if verbose:
print("unable to run %s (error)" % dispcmd)
return None
return stdout
def versions_from_parentdir(parentdir_prefix, root, verbose):
"""Try to determine the version from the parent directory name.
Source tarballs conventionally unpack into a directory that includes
both the project name and a version string.
"""
dirname = os.path.basename(root)
if not dirname.startswith(parentdir_prefix):
if verbose:
print("guessing rootdir is '%s', but '%s' doesn't start with "
"prefix '%s'" % (root, dirname, parentdir_prefix))
raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
return {"version": dirname[len(parentdir_prefix):],
"full-revisionid": None,
"dirty": False, "error": None}
@register_vcs_handler("git", "get_keywords")
def git_get_keywords(versionfile_abs):
"""Extract version information from the given file."""
# the code embedded in _version.py can just fetch the value of these
# keywords. When used from setup.py, we don't want to import _version.py,
# so we do it with a regexp instead. This function is not used from
# _version.py.
keywords = {}
try:
f = open(versionfile_abs, "r")
for line in f.readlines():
if line.strip().startswith("git_refnames ="):
mo = re.search(r'=\s*"(.*)"', line)
if mo:
keywords["refnames"] = mo.group(1)
if line.strip().startswith("git_full ="):
mo = re.search(r'=\s*"(.*)"', line)
if mo:
keywords["full"] = mo.group(1)
f.close()
except EnvironmentError:
pass
return keywords
@register_vcs_handler("git", "keywords")
def git_versions_from_keywords(keywords, tag_prefix, verbose):
"""Get version information from git keywords."""
if not keywords:
raise NotThisMethod("no keywords at all, weird")
refnames = keywords["refnames"].strip()
if refnames.startswith("$Format"):
if verbose:
print("keywords are unexpanded, not using")
raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
refs = set([r.strip() for r in refnames.strip("()").split(",")])
# starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
# just "foo-1.0". If we see a "tag: " prefix, prefer those.
TAG = "tag: "
tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
if not tags:
# Either we're using git < 1.8.3, or there really are no tags. We use
# a heuristic: assume all version tags have a digit. The old git %d
# expansion behaves like git log --decorate=short and strips out the
# refs/heads/ and refs/tags/ prefixes that would let us distinguish
# between branches and tags. By ignoring refnames without digits, we
# filter out many common branch names like "release" and
# "stabilization", as well as "HEAD" and "master".
tags = set([r for r in refs if re.search(r'\d', r)])
if verbose:
print("discarding '%s', no digits" % ",".join(refs-tags))
if verbose:
print("likely tags: %s" % ",".join(sorted(tags)))
for ref in sorted(tags):
# sorting will prefer e.g. "2.0" over "2.0rc1"
if ref.startswith(tag_prefix):
r = ref[len(tag_prefix):]
if verbose:
print("picking %s" % r)
return {"version": r,
"full-revisionid": keywords["full"].strip(),
"dirty": False, "error": None
}
# no suitable tags, so version is "0+unknown", but full hex is still there
if verbose:
print("no suitable tags, using unknown + full revision id")
return {"version": "0+unknown",
"full-revisionid": keywords["full"].strip(),
"dirty": False, "error": "no suitable tags"}
@register_vcs_handler("git", "pieces_from_vcs")
def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
"""Get version from 'git describe' in the root of the source tree.
This only gets called if the git-archive 'subst' keywords were *not*
expanded, and _version.py hasn't already been rewritten with a short
version string, meaning we're inside a checked out source tree.
"""
if not os.path.exists(os.path.join(root, ".git")):
if verbose:
print("no .git in %s" % root)
raise NotThisMethod("no .git directory")
GITS = ["git"]
if sys.platform == "win32":
GITS = ["git.cmd", "git.exe"]
# if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
# if there isn't one, this yields HEX[-dirty] (no NUM)
describe_out = run_command(GITS, ["describe", "--tags", "--dirty",
"--always", "--long",
"--match", "%s*" % tag_prefix],
cwd=root)
# --long was added in git-1.5.5
if describe_out is None:
raise NotThisMethod("'git describe' failed")
describe_out = describe_out.strip()
full_out = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
if full_out is None:
raise NotThisMethod("'git rev-parse' failed")
full_out = full_out.strip()
pieces = {}
pieces["long"] = full_out
pieces["short"] = full_out[:7] # maybe improved later
pieces["error"] = None
# parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
# TAG might have hyphens.
git_describe = describe_out
# look for -dirty suffix
dirty = git_describe.endswith("-dirty")
pieces["dirty"] = dirty
if dirty:
git_describe = git_describe[:git_describe.rindex("-dirty")]
# now we have TAG-NUM-gHEX or HEX
if "-" in git_describe:
# TAG-NUM-gHEX
mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
if not mo:
# unparseable. Maybe git-describe is misbehaving?
pieces["error"] = ("unable to parse git-describe output: '%s'"
% describe_out)
return pieces
# tag
full_tag = mo.group(1)
if not full_tag.startswith(tag_prefix):
if verbose:
fmt = "tag '%s' doesn't start with prefix '%s'"
print(fmt % (full_tag, tag_prefix))
pieces["error"] = ("tag '%s' doesn't start with prefix '%s'"
% (full_tag, tag_prefix))
return pieces
pieces["closest-tag"] = full_tag[len(tag_prefix):]
# distance: number of commits since tag
pieces["distance"] = int(mo.group(2))
# commit: short hex revision ID
pieces["short"] = mo.group(3)
else:
# HEX: no tags
pieces["closest-tag"] = None
count_out = run_command(GITS, ["rev-list", "HEAD", "--count"],
cwd=root)
pieces["distance"] = int(count_out) # total number of commits
return pieces
def plus_or_dot(pieces):
"""Return a + if we don't already have one, else return a ."""
if "+" in pieces.get("closest-tag", ""):
return "."
return "+"
def render_pep440(pieces):
"""Build up version string, with post-release "local version identifier".
Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
Exceptions:
1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
if pieces["distance"] or pieces["dirty"]:
rendered += plus_or_dot(pieces)
rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
if pieces["dirty"]:
rendered += ".dirty"
else:
# exception #1
rendered = "0+untagged.%d.g%s" % (pieces["distance"],
pieces["short"])
if pieces["dirty"]:
rendered += ".dirty"
return rendered
def render_pep440_pre(pieces):
"""TAG[.post.devDISTANCE] -- No -dirty.
Exceptions:
1: no tags. 0.post.devDISTANCE
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
if pieces["distance"]:
rendered += ".post.dev%d" % pieces["distance"]
else:
# exception #1
rendered = "0.post.dev%d" % pieces["distance"]
return rendered
def render_pep440_post(pieces):
"""TAG[.postDISTANCE[.dev0]+gHEX] .
The ".dev0" means dirty. Note that .dev0 sorts backwards
(a dirty tree will appear "older" than the corresponding clean one),
but you shouldn't be releasing software with -dirty anyways.
Exceptions:
1: no tags. 0.postDISTANCE[.dev0]
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
if pieces["distance"] or pieces["dirty"]:
rendered += ".post%d" % pieces["distance"]
if pieces["dirty"]:
rendered += ".dev0"
rendered += plus_or_dot(pieces)
rendered += "g%s" % pieces["short"]
else:
# exception #1
rendered = "0.post%d" % pieces["distance"]
if pieces["dirty"]:
rendered += ".dev0"
rendered += "+g%s" % pieces["short"]
return rendered
def render_pep440_old(pieces):
"""TAG[.postDISTANCE[.dev0]] .
The ".dev0" means dirty.
Eexceptions:
1: no tags. 0.postDISTANCE[.dev0]
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
if pieces["distance"] or pieces["dirty"]:
rendered += ".post%d" % pieces["distance"]
if pieces["dirty"]:
rendered += ".dev0"
else:
# exception #1
rendered = "0.post%d" % pieces["distance"]
if pieces["dirty"]:
rendered += ".dev0"
return rendered
def render_git_describe(pieces):
"""TAG[-DISTANCE-gHEX][-dirty].
Like 'git describe --tags --dirty --always'.
Exceptions:
1: no tags. HEX[-dirty] (note: no 'g' prefix)
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
if pieces["distance"]:
rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
else:
# exception #1
rendered = pieces["short"]
if pieces["dirty"]:
rendered += "-dirty"
return rendered
def render_git_describe_long(pieces):
"""TAG-DISTANCE-gHEX[-dirty].
Like 'git describe --tags --dirty --always -long'.
The distance/hash is unconditional.
Exceptions:
1: no tags. HEX[-dirty] (note: no 'g' prefix)
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
else:
# exception #1
rendered = pieces["short"]
if pieces["dirty"]:
rendered += "-dirty"
return rendered
def render(pieces, style):
"""Render the given version pieces into the requested style."""
if pieces["error"]:
return {"version": "unknown",
"full-revisionid": pieces.get("long"),
"dirty": None,
"error": pieces["error"]}
if not style or style == "default":
style = "pep440" # the default
if style == "pep440":
rendered = render_pep440(pieces)
elif style == "pep440-pre":
rendered = render_pep440_pre(pieces)
elif style == "pep440-post":
rendered = render_pep440_post(pieces)
elif style == "pep440-old":
rendered = render_pep440_old(pieces)
elif style == "git-describe":
rendered = render_git_describe(pieces)
elif style == "git-describe-long":
rendered = render_git_describe_long(pieces)
else:
raise ValueError("unknown style '%s'" % style)
return {"version": rendered, "full-revisionid": pieces["long"],
"dirty": pieces["dirty"], "error": None}
def get_versions():
"""Get version information or return default if unable to do so."""
# I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
# __file__, we can work backwards from there to the root. Some
# py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
# case we can only use expanded keywords.
cfg = get_config()
verbose = cfg.verbose
try:
return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
verbose)
except NotThisMethod:
pass
try:
root = os.path.realpath(__file__)
# versionfile_source is the relative path from the top of the source
# tree (where the .git directory might live) to this file. Invert
# this to find the root from __file__.
for i in cfg.versionfile_source.split('/'):
root = os.path.dirname(root)
except NameError:
return {"version": "0+unknown", "full-revisionid": None,
"dirty": None,
"error": "unable to find root of source tree"}
try:
pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
return render(pieces, cfg.style)
except NotThisMethod:
pass
try:
if cfg.parentdir_prefix:
return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
except NotThisMethod:
pass
return {"version": "0+unknown", "full-revisionid": None,
"dirty": None,
"error": "unable to compute version"}

View File

@ -1,19 +0,0 @@
#!/usr/bin/env python
from setuptools import setup
import versioneer
setup(name='git-version',
version=versioneer.get_version(),
cmdclass=versioneer.get_cmdclass(),
description='Make git version information (e.g. git tag name, git commit id, ...) available to your C++ or python source files. A simple use case scenario is to output this version information when the application is called with "--version".',
author='Sebastian Messmer',
author_email='messmer@cryfs.org',
license='GPLv3',
packages=['gitversion'],
entry_points = {
'console_scripts': [
"git-version = __main__:main"
]
},
)

View File

@ -1,5 +1,6 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
add_subdirectory(gitversion)
add_subdirectory(cpp-utils)
add_subdirectory(fspp)
add_subdirectory(parallelaccessstore)

View File

@ -12,10 +12,9 @@ set(SOURCES
)
add_library(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} PUBLIC cryfs cpp-utils)
target_link_libraries(${PROJECT_NAME} PUBLIC cryfs cpp-utils gitversion)
target_enable_style_warnings(${PROJECT_NAME})
target_activate_cpp14(${PROJECT_NAME})
target_git_version_init(${PROJECT_NAME})
add_executable(${PROJECT_NAME}_bin main.cpp)
set_target_properties(${PROJECT_NAME}_bin PROPERTIES OUTPUT_NAME cryfs)

View File

@ -17,8 +17,8 @@
#include "program_options/Parser.h"
#include <boost/filesystem.hpp>
#include <gitversion/version.h>
#include <cryfs/filesystem/CryDir.h>
#include <gitversion/gitversion.h>
#include "VersionChecker.h"
#include "VersionCompare.h"
@ -78,11 +78,11 @@ namespace cryfs {
}
void Cli::_showVersion() {
cout << "CryFS Version " << version::VERSION_STRING << endl;
if (version::IS_DEV_VERSION) {
cout << "WARNING! This is a development version based on git commit " << version::GIT_COMMIT_ID <<
cout << "CryFS Version " << gitversion::VersionString() << endl;
if (gitversion::IsDevVersion()) {
cout << "WARNING! This is a development version based on git commit " << gitversion::GitCommitId() <<
". Please do not use in production!" << endl;
} else if (!version::IS_STABLE_VERSION) {
} else if (!gitversion::IsStableVersion()) {
cout << "WARNING! This is an experimental version. Please backup your data frequently!" << endl;
} else {
//TODO This is even shown for stable version numbers like 0.8 - remove once we reach 1.0
@ -104,10 +104,10 @@ namespace cryfs {
optional<string> newestVersion = versionChecker.newestVersion();
if (newestVersion == none) {
cout << "Could not check for updates." << endl;
} else if (VersionCompare::isOlderThan(version::VERSION_STRING, *newestVersion)) {
} else if (VersionCompare::isOlderThan(gitversion::VersionString(), *newestVersion)) {
cout << "CryFS " << *newestVersion << " is released. Please update." << endl;
}
optional<string> securityWarning = versionChecker.securityWarningFor(version::VERSION_STRING);
optional<string> securityWarning = versionChecker.securityWarningFor(gitversion::VersionString());
if (securityWarning != none) {
cout << *securityWarning << endl;
}

View File

@ -44,11 +44,10 @@ set(LIB_SOURCES
add_library(${PROJECT_NAME} STATIC ${LIB_SOURCES})
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME cryfs)
target_link_libraries(${PROJECT_NAME} PRIVATE cpp-utils blockstore blobstore fspp) # TODO Check that dependent projects don't get this linked in
target_link_libraries(${PROJECT_NAME} PRIVATE cpp-utils blockstore blobstore fspp gitversion) # TODO Check that dependent projects don't get this linked in
target_add_boost(${PROJECT_NAME} program_options chrono) # TODO Check that dependent projects don't get boost added (use PRIVATE here)
target_enable_style_warnings(${PROJECT_NAME})
target_activate_cpp14(${PROJECT_NAME})
target_git_version_init(${PROJECT_NAME})
#install(TARGETS ${PROJECT_NAME}
# DESTINATION lib

View File

@ -1,6 +1,6 @@
#include "CryConfigCreator.h"
#include "CryCipher.h"
#include <gitversion/version.h>
#include <gitversion/gitversion.h>
using cpputils::Console;
using cpputils::unique_ref;
@ -20,7 +20,7 @@ namespace cryfs {
CryConfig CryConfigCreator::create(const optional<string> &cipherFromCommandLine) {
CryConfig config;
config.SetCipher(_generateCipher(cipherFromCommandLine));
config.SetVersion(version::VERSION_STRING);
config.SetVersion(gitversion::VersionString());
config.SetBlocksizeBytes(_generateBlocksizeBytes());
config.SetRootBlob(_generateRootBlobKey());
config.SetEncryptionKey(_generateEncKey(config.Cipher()));

View File

@ -4,7 +4,7 @@
#include <cpp-utils/random/Random.h>
#include <cpp-utils/logging/logging.h>
#include <boost/algorithm/string/predicate.hpp>
#include <gitversion/version.h>
#include <gitversion/gitversion.h>
namespace bf = boost::filesystem;
using cpputils::unique_ref;
@ -45,7 +45,7 @@ optional<CryConfigFile> CryConfigLoader::_loadConfig(const bf::path &filename) {
}
void CryConfigLoader::_checkVersion(const CryConfig &config) {
const string allowedVersionPrefix = string() + version::VERSION_COMPONENTS[0] + "." + version::VERSION_COMPONENTS[1] + ".";
const string allowedVersionPrefix = string() + gitversion::MajorVersion() + "." + gitversion::MinorVersion() + ".";
if (!boost::starts_with(config.Version(), allowedVersionPrefix)) {
throw std::runtime_error(string() + "This filesystem was created with CryFS " + config.Version() + " and is incompatible. Please create a new one with your version of CryFS and migrate your data.");
}

View File

@ -0,0 +1,11 @@
project (gitversion)
include(gitversion.cmake)
get_git_version(GIT_VERSION)
add_library(${PROJECT_NAME} STATIC gitversion.cpp versionstring.cpp parser.cpp)
target_link_libraries(${PROJECT_NAME})
target_compile_definitions(${PROJECT_NAME} PRIVATE GIT_VERSION_STRING="${GIT_VERSION}")
target_add_boost(${PROJECT_NAME})
target_enable_style_warnings(${PROJECT_NAME})
target_activate_cpp14(${PROJECT_NAME})

Binary file not shown.

View File

@ -0,0 +1,14 @@
set(DIR_OF_GITVERSION_TOOL "${CMAKE_CURRENT_LIST_DIR}" CACHE INTERNAL "DIR_OF_GITVERSION_TOOL")
function (get_git_version OUTPUT_VARIABLE)
EXECUTE_PROCESS(COMMAND ${DIR_OF_GITVERSION_TOOL}/getversion.py
OUTPUT_VARIABLE VERSION
ERROR_VARIABLE error
RESULT_VARIABLE result)
STRING(STRIP "${VERSION}" STRIPPED_VERSION)
SET(${OUTPUT_VARIABLE} "${STRIPPED_VERSION}" CACHE INTERNAL "${OUTPUT_VARIABLE}")
MESSAGE(STATUS "Building version ${${OUTPUT_VARIABLE}}")
IF(NOT ${result} EQUAL 0)
MESSAGE(FATAL_ERROR "Error running versioneer. Return code is: ${result}, error message is: ${error}")
ENDIF()
endfunction(get_git_version)

View File

@ -0,0 +1,32 @@
#include "gitversion.h"
#include "parser.h"
using std::string;
namespace gitversion {
const VersionInfo &parse() {
static VersionInfo versionInfo = Parser::parse(VersionString());
return versionInfo;
}
bool IsDevVersion() {
return parse().isDevVersion;
}
bool IsStableVersion() {
return parse().isStableVersion;
}
string GitCommitId() {
return parse().gitCommitId;
}
string MajorVersion() {
return parse().majorVersion;
}
string MinorVersion() {
return parse().minorVersion;
}
}

View File

@ -0,0 +1,15 @@
#pragma once
#ifndef GITVERSION_GITVERSION_H
#define GITVERSION_GITVERSION_H
#include "versionstring.h"
namespace gitversion {
bool IsDevVersion();
bool IsStableVersion();
std::string MajorVersion();
std::string MinorVersion();
std::string GitCommitId();
}
#endif

79
src/gitversion/parser.cpp Normal file
View File

@ -0,0 +1,79 @@
#include "parser.h"
#include <regex>
using std::string;
using std::pair;
using std::tuple;
using std::tie;
using std::regex;
using std::smatch;
using std::regex_match;
using boost::optional;
using boost::none;
namespace gitversion {
VersionInfo Parser::parse(const string &versionString) {
VersionInfo result;
string versionNumber;
optional<string> versionInfo;
tie(versionNumber, versionInfo) = _splitAtPlusSign(versionString);
tie(result.majorVersion, result.minorVersion, result.versionTag) = _extractMajorMinorTag(versionNumber);
result.isDevVersion = (versionInfo != none);
result.isStableVersion = !result.isDevVersion && (result.versionTag == "" || result.versionTag == "stable");
if (versionInfo != none) {
result.gitCommitId = _extractGitCommitId(*versionInfo);
} else {
result.gitCommitId = "";
}
return result;
}
pair<string, optional<string>> Parser::_splitAtPlusSign(const string &versionString) {
regex splitRegex("^([^+]+)(\\+([^+]+))?$");
smatch match;
regex_match(versionString, match, splitRegex);
if(match[0] != versionString) {
throw std::logic_error("First match group should be whole string");
}
if(match.size() != 4) {
throw std::logic_error("Wrong number of match groups");
}
if (match[2].matched) {
return std::make_pair(match[1], optional<string>(match[3]));
} else {
return std::make_pair(match[1], none);
}
};
tuple<string, string, string> Parser::_extractMajorMinorTag(const string &versionNumber) {
regex splitRegex("^([0-9]+)\\.([0-9]+)\\.[0-9\\.]*(-(.*))?$");
smatch match;
regex_match(versionNumber, match, splitRegex);
if(match[0] != versionNumber) {
throw std::logic_error("First match group should be whole string");
}
if(match.size() != 5) {
throw std::logic_error("Wrong number of match groups");
}
if(match[3].matched) {
return std::make_tuple(match[1], match[2], match[4]);
} else {
return std::make_tuple(match[1], match[2], "");
}
};
string Parser::_extractGitCommitId(const string &versionInfo) {
regex extractRegex("^[0-9]+\\.g([0-9a-f]+)(\\..*)?$");
smatch match;
regex_match(versionInfo, match, extractRegex);
if(match[0] != versionInfo) {
throw std::logic_error("First match group should be whole string");
}
if(match.size() != 3) {
throw std::logic_error("Wrong number of match groups");
}
return match[1];
}
}

30
src/gitversion/parser.h Normal file
View File

@ -0,0 +1,30 @@
#pragma once
#ifndef GITVERSION_PARSER_H
#define GITVERSION_PARSER_H
#include <boost/optional.hpp>
#include <string>
#include <utility>
namespace gitversion {
struct VersionInfo {
bool isDevVersion;
bool isStableVersion;
std::string versionTag;
std::string gitCommitId;
std::string majorVersion;
std::string minorVersion;
};
class Parser final {
public:
static VersionInfo parse(const std::string &versionString);
private:
static std::pair<std::string, boost::optional<std::string>> _splitAtPlusSign(const std::string &versionString);
static std::tuple<std::string, std::string, std::string> _extractMajorMinorTag(const std::string &versionNumber);
static std::string _extractGitCommitId(const std::string &versionInfo);
};
}
#endif

13
src/gitversion/setup.py Normal file
View File

@ -0,0 +1,13 @@
#!/usr/bin/env python
from setuptools import setup
import versioneer
setup(name='git-version',
version=versioneer.get_version(),
cmdclass=versioneer.get_cmdclass(),
description='Make git version information (e.g. git tag name, git commit id, ...) available to C++ source files.',
author='Sebastian Messmer',
author_email='messmer@cryfs.org',
license='GPLv3'
)

View File

@ -1048,8 +1048,8 @@ def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
expanded, and _version.py hasn't already been rewritten with a short
version string, meaning we're inside a checked out source tree.
"""
# -- (MESSMER) CHANGED FOLLOWING LINE TO LOOK FOR ../.git instead of .git --
if not os.path.exists(os.path.join(root, "../.git")):
# -- (MESSMER) CHANGED FOLLOWING LINE TO LOOK FOR ../../.git instead of .git --
if not os.path.exists(os.path.join(root, "../../.git")):
if verbose:
print("no .git in %s" % root)
raise NotThisMethod("no .git directory")

Binary file not shown.

View File

@ -0,0 +1,11 @@
#include "versionstring.h"
using std::string;
namespace gitversion {
const string &VersionString() {
static const string VERSION_STRING = GIT_VERSION_STRING; // GIT_VERSION_STRING is set by our CMake file as a macro
return VERSION_STRING;
}
}

View File

@ -0,0 +1,11 @@
#pragma once
#ifndef GITVERSION_VERSIONSTRING_H
#define GITVERSION_VERSIONSTRING_H
#include <string>
namespace gitversion {
const std::string &VersionString();
}
#endif

View File

@ -1,6 +1,7 @@
if (BUILD_TESTING)
include_directories(../src)
add_subdirectory(gitversion)
add_subdirectory(cpp-utils)
add_subdirectory(fspp)
add_subdirectory(parallelaccessstore)

View File

@ -0,0 +1,12 @@
project (gitversion-test)
set(SOURCES
ParserTest.cpp
)
add_executable(${PROJECT_NAME} ${SOURCES})
target_link_libraries(${PROJECT_NAME} googletest gitversion)
add_test(${PROJECT_NAME} ${PROJECT_NAME})
target_enable_style_warnings(${PROJECT_NAME})
target_activate_cpp14(${PROJECT_NAME})

View File

@ -0,0 +1,146 @@
#include <gtest/gtest.h>
#include <gitversion/parser.h>
using namespace gitversion;
TEST(ParserTest, TestReleaseVersion_1) {
VersionInfo info = Parser::parse("0.9.2");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_FALSE( info.isDevVersion);
EXPECT_TRUE( info.isStableVersion);
EXPECT_EQ("", info.gitCommitId);
EXPECT_EQ("", info.versionTag);
}
TEST(ParserTest, TestReleaseVersion_2) {
VersionInfo info = Parser::parse("1.02.3");
EXPECT_EQ("1", info.majorVersion);
EXPECT_EQ("02", info.minorVersion);
EXPECT_FALSE( info.isDevVersion);
EXPECT_TRUE( info.isStableVersion);
EXPECT_EQ("", info.gitCommitId);
EXPECT_EQ("", info.versionTag);
}
TEST(ParserTest, TestReleaseVersion_3) {
VersionInfo info = Parser::parse("01.020.3");
EXPECT_EQ("01", info.majorVersion);
EXPECT_EQ("020", info.minorVersion);
EXPECT_FALSE( info.isDevVersion);
EXPECT_TRUE( info.isStableVersion);
EXPECT_EQ("", info.gitCommitId);
EXPECT_EQ("", info.versionTag);
}
TEST(ParserTest, TestDevVersion) {
VersionInfo info = Parser::parse("0.9.0+2.g0123abcdef");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_TRUE( info.isDevVersion);
EXPECT_FALSE( info.isStableVersion);
EXPECT_EQ("0123abcdef", info.gitCommitId);
EXPECT_EQ("", info.versionTag);
}
TEST(ParserTest, TestDirtyDevVersion) {
VersionInfo info = Parser::parse("0.9.0+20.g0123abcdef.dirty");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_TRUE( info.isDevVersion);
EXPECT_FALSE( info.isStableVersion);
EXPECT_EQ("0123abcdef", info.gitCommitId);
EXPECT_EQ("", info.versionTag);
}
TEST(ParserTest, TestReleaseVersion_StableTag) {
VersionInfo info = Parser::parse("0.9.2-stable");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_FALSE( info.isDevVersion);
EXPECT_TRUE( info.isStableVersion);
EXPECT_EQ("", info.gitCommitId);
EXPECT_EQ("stable", info.versionTag);
}
TEST(ParserTest, TestDevVersion_StableTag) {
VersionInfo info = Parser::parse("0.9.0-stable+2.g0123abcdef");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_TRUE( info.isDevVersion);
EXPECT_FALSE( info.isStableVersion);
EXPECT_EQ("0123abcdef", info.gitCommitId);
EXPECT_EQ("stable", info.versionTag);
}
TEST(ParserTest, TestDirtyDevVersion_StableTag) {
VersionInfo info = Parser::parse("0.9.0-stable+20.g0123abcdef.dirty");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_TRUE( info.isDevVersion);
EXPECT_FALSE( info.isStableVersion);
EXPECT_EQ("0123abcdef", info.gitCommitId);
EXPECT_EQ("stable", info.versionTag);
}
TEST(ParserTest, TestReleaseVersion_AlphaTag) {
VersionInfo info = Parser::parse("0.9.2-alpha");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_FALSE( info.isDevVersion);
EXPECT_FALSE( info.isStableVersion);
EXPECT_EQ("", info.gitCommitId);
EXPECT_EQ("alpha", info.versionTag);
}
TEST(ParserTest, TestDevVersion_AlphaTag) {
VersionInfo info = Parser::parse("0.9.0-alpha+2.g0123abcdef");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_TRUE( info.isDevVersion);
EXPECT_FALSE( info.isStableVersion);
EXPECT_EQ("0123abcdef", info.gitCommitId);
EXPECT_EQ("alpha", info.versionTag);
}
TEST(ParserTest, TestDirtyDevVersion_AlphaTag) {
VersionInfo info = Parser::parse("0.9.0-alpha+20.g0123abcdef.dirty");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_TRUE( info.isDevVersion);
EXPECT_FALSE( info.isStableVersion);
EXPECT_EQ("0123abcdef", info.gitCommitId);
EXPECT_EQ("alpha", info.versionTag);
}
TEST(ParserTest, TestReleaseVersion_RCTag) {
VersionInfo info = Parser::parse("0.9.2-rc1");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_FALSE( info.isDevVersion);
EXPECT_FALSE( info.isStableVersion);
EXPECT_EQ("", info.gitCommitId);
EXPECT_EQ("rc1", info.versionTag);
}
TEST(ParserTest, TestDevVersion_RCTag) {
VersionInfo info = Parser::parse("0.9.0-rc1+2.g0123abcdef");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_TRUE( info.isDevVersion);
EXPECT_FALSE( info.isStableVersion);
EXPECT_EQ("0123abcdef", info.gitCommitId);
EXPECT_EQ("rc1", info.versionTag);
}
TEST(ParserTest, TestDirtyDevVersion_RCTag) {
VersionInfo info = Parser::parse("0.9.0-rc1+20.g0123abcdef.dirty");
EXPECT_EQ("0", info.majorVersion);
EXPECT_EQ("9", info.minorVersion);
EXPECT_TRUE( info.isDevVersion);
EXPECT_FALSE( info.isStableVersion);
EXPECT_EQ("0123abcdef", info.gitCommitId);
EXPECT_EQ("rc1", info.versionTag);
}
//TODO Dirty non-dev version

View File

@ -1,4 +1,3 @@
add_subdirectory(googletest)
add_subdirectory(scrypt)
add_subdirectory(spdlog)
add_subdirectory(gitversion)

View File

@ -1 +0,0 @@
include(gitversion-1.9/cmake.cmake)

View File

@ -1,61 +0,0 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
.idea
MANIFEST
Version.py

View File

@ -1,675 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against