Update Client Version to be ethstats friendly (#258)

Update value returned by web3_clientVersion to be ethstats friendly

* Version part starts with a v
* SNAPSHOT builds report 32 bits of the git hash
* OS and architecture are sniffed out and reported
* JVM version and branding are sniffed out and reported

Example values (not all real):
pantheon/v0.9.0-dev-f800a0b1/osx-x86_64/oracle-java-1.8
pantheon/v0.9.0-dev-27960b57/osx-x86_64/zulu-java-11
pantheon/v0.9.0/linux-arm64/openjdk-java-12
Danno Ferrin 6 years ago committed by GitHub
parent 21bc640931
commit 002d9ceef3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      build.gradle
  2. 33
      buildSrc/src/main/groovy/ProjectPropertiesFile.groovy
  3. 8
      config/build.gradle
  4. 8
      consensus/clique/build.gradle
  5. 8
      consensus/common/build.gradle
  6. 8
      consensus/ibft/build.gradle
  7. 8
      consensus/ibftlegacy/build.gradle
  8. 8
      crypto/build.gradle
  9. 8
      ethereum/blockcreation/build.gradle
  10. 8
      ethereum/core/build.gradle
  11. 8
      ethereum/eth/build.gradle
  12. 8
      ethereum/jsonrpc/build.gradle
  13. 8
      ethereum/mock-p2p/build.gradle
  14. 8
      ethereum/p2p/build.gradle
  15. 8
      ethereum/rlp/build.gradle
  16. 8
      ethereum/trie/build.gradle
  17. 11
      pantheon/build.gradle
  18. 20
      pantheon/src/main/java/tech/pegasys/pantheon/PantheonInfo.java
  19. 199
      pantheon/src/main/java/tech/pegasys/pantheon/util/PlatformDetector.java
  20. 31
      pantheon/src/test/java/tech/pegasys/pantheon/PantheonInfoTest.java
  21. 8
      services/kvstore/build.gradle
  22. 8
      testutil/build.gradle
  23. 8
      util/build.gradle

@ -394,6 +394,33 @@ configure(subprojects.findAll {it.name != 'errorprone-checks'}) {
} }
} }
// Takes the version, and if -SNAPSHOT is part of it replaces SNAPSHOT
// with the git commit version.
def calculateVersion() {
String version = rootProject.version
if (version.endsWith("-SNAPSHOT")) {
version = version.replace("-SNAPSHOT", "-dev-" + getCheckedOutGitCommitHash())
}
return version
}
def getCheckedOutGitCommitHash() {
def gitFolder = "$projectDir/.git/"
def takeFromHash = 8
/*
* '.git/HEAD' contains either
* in case of detached head: the currently checked out commit hash
* otherwise: a reference to a file containing the current commit hash
*/
def head = new File(gitFolder + "HEAD").text.split(":") // .git/HEAD
def isCommit = head.length == 1 // e5a7c79edabbf7dd39888442df081b1c9d8e88fd
if(isCommit) return head[0].trim().take(takeFromHash) // e5a7c79edabb
def refHead = new File(gitFolder + head[1].trim()) // .git/refs/heads/master
refHead.text.trim().take takeFromHash
}
apply plugin: 'net.researchgate.release' apply plugin: 'net.researchgate.release'
task releaseIntegrationTest(type: Test){ task releaseIntegrationTest(type: Test){

@ -55,6 +55,10 @@ class ProjectPropertiesFile extends DefaultTask {
properties.add(new Property(name, value, PropertyType.STRING)) properties.add(new Property(name, value, PropertyType.STRING))
} }
void addVersion(String name, String value) {
properties.add(new Property(name, value, PropertyType.VERSION))
}
@Nested @Nested
List<Property> getProperties() { List<Property> getProperties() {
return properties return properties
@ -73,9 +77,11 @@ class ProjectPropertiesFile extends DefaultTask {
String[] methodDeclarations = properties.stream().map({p -> p.methodDeclaration()}).toArray() String[] methodDeclarations = properties.stream().map({p -> p.methodDeclaration()}).toArray()
return """package ${destPackage}; return """package ${destPackage};
import tech.pegasys.pantheon.util.PlatformDetector;
// This file is generated via a gradle task and should not be edited directly. // This file is generated via a gradle task and should not be edited directly.
public class ${filename} { public final class ${filename} {
${String.join("\n ", varDeclarations)} ${String.join("\n", varDeclarations)}
private ${filename}() {} private ${filename}() {}
${String.join("\n", methodDeclarations)} ${String.join("\n", methodDeclarations)}
@ -84,7 +90,8 @@ ${String.join("\n", methodDeclarations)}
} }
private enum PropertyType { private enum PropertyType {
STRING("String") STRING("String"),
VERSION("String");
private final String strVal private final String strVal
PropertyType(String strVal) { PropertyType(String strVal) {
@ -96,7 +103,7 @@ ${String.join("\n", methodDeclarations)}
} }
} }
private static class Property { private class Property {
private final String name private final String name
private final String value private final String value
private final PropertyType type private final PropertyType type
@ -123,13 +130,27 @@ ${String.join("\n", methodDeclarations)}
} }
String variableDeclaration() { String variableDeclaration() {
return " private static final ${type} ${name} = \"${value}\";" def constantName = name.replaceAll("([a-z])([A-Z]+)", '$1_$2').toUpperCase()
def constantValue = value.replaceAll("([a-z])([A-Z]+)", '$1_$2').toUpperCase()
switch (type) {
case PropertyType.STRING:
return " private static final ${type} ${constantName} = \"${value}\";"
case PropertyType.VERSION:
return " private static final ${type} ${constantName} =\n" +
" ${constantValue}\n" +
" + \"/v\"\n" +
" + ${filename}.class.getPackage().getImplementationVersion()\n" +
" + \"/\"\n" +
" + PlatformDetector.getOS()\n" +
" + \"/\"\n" +
" + PlatformDetector.getVM();"
}
} }
String methodDeclaration() { String methodDeclaration() {
return """ return """
public static ${type} ${name}() { public static ${type} ${name}() {
return ${name}; return ${name.replaceAll("([a-z])([A-Z]+)", '$1_$2').toUpperCase()};
}""" }"""
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-config' baseName 'pantheon-config'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ plugins { id 'java' }
jar { jar {
baseName 'pantheon-clique' baseName 'pantheon-clique'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-consensus-common' baseName 'pantheon-consensus-common'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-ibft' baseName 'pantheon-ibft'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -3,8 +3,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-ibftlegacy' baseName 'pantheon-ibftlegacy'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-crypto' baseName 'pantheon-crypto'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -3,8 +3,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-blockcreation' baseName 'pantheon-blockcreation'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-core' baseName 'pantheon-core'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-eth' baseName 'pantheon-eth'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-json-rpc' baseName 'pantheon-json-rpc'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-mock-p2p' baseName 'pantheon-mock-p2p'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-p2p' baseName 'pantheon-p2p'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-ethereum-rlp' baseName 'pantheon-ethereum-rlp'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-trie' baseName 'pantheon-trie'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon' baseName 'pantheon'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }
@ -58,7 +62,8 @@ dependencies {
task writeInfoFile(type: ProjectPropertiesFile) { task writeInfoFile(type: ProjectPropertiesFile) {
destPackage = "tech.pegasys.pantheon" destPackage = "tech.pegasys.pantheon"
addString("version", "$rootProject.name/$rootProject.version") addString("clientIdentity", rootProject.name)
addVersion("version", "clientIdentity")
} }
compileJava.dependsOn(writeInfoFile) compileJava.dependsOn(writeInfoFile)

@ -1,12 +1,26 @@
package tech.pegasys.pantheon; package tech.pegasys.pantheon;
import tech.pegasys.pantheon.util.PlatformDetector;
// This file is generated via a gradle task and should not be edited directly. // This file is generated via a gradle task and should not be edited directly.
public class PantheonInfo { public final class PantheonInfo {
private static final String version = "pantheon/0.9.0-SNAPSHOT"; private static final String CLIENT_IDENTITY = "pantheon";
private static final String VERSION =
CLIENT_IDENTITY
+ "/v"
+ PantheonInfo.class.getPackage().getImplementationVersion()
+ "/"
+ PlatformDetector.getOS()
+ "/"
+ PlatformDetector.getVM();
private PantheonInfo() {} private PantheonInfo() {}
public static String clientIdentity() {
return CLIENT_IDENTITY;
}
public static String version() { public static String version() {
return version; return VERSION;
} }
} }

@ -0,0 +1,199 @@
/*
* Copyright 2018 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon.util;
import java.util.Locale;
/**
* Detects OS and VMs.
*
* <p>Derived from Detector.java https://github.com/trustin/os-maven-plugin/ version 59fd029 on 21
* Apr 2018, Copyright 2014 Trustin Heuiseung Lee.
*/
public class PlatformDetector {
private static String _os;
private static String _osType;
private static String _vm;
public static String getOSType() {
if (_osType == null) {
detect();
}
return _osType;
}
public static String getOS() {
if (_os == null) {
detect();
}
return _os;
}
public static String getVM() {
if (_vm == null) {
detect();
}
return _vm;
}
private static final String UNKNOWN = "unknown";
private static void detect() {
final String detectedOS = normalizeOS(normalize("os.name"));
final String detectedArch = normalizeArch(normalize("os.arch"));
final String detectedVM = normalizeVM(normalize("java.vendor"), normalize("java.vm.name"));
final String detectedJavaVersion = normalizeJavaVersion("java.specification.version");
_os = detectedOS + '-' + detectedArch;
_osType = detectedOS;
_vm = detectedVM + "-java-" + detectedJavaVersion;
}
private static String normalizeOS(final String osName) {
if (osName.startsWith("aix")) {
return "aix";
}
if (osName.startsWith("hpux")) {
return "hpux";
}
if (osName.startsWith("os400")) {
// Avoid the names such as os4000
if (osName.length() <= 5 || !Character.isDigit(osName.charAt(5))) {
return "os400";
}
}
if (osName.startsWith("linux")) {
return "linux";
}
if (osName.startsWith("macosx") || osName.startsWith("osx")) {
return "osx";
}
if (osName.startsWith("freebsd")) {
return "freebsd";
}
if (osName.startsWith("openbsd")) {
return "openbsd";
}
if (osName.startsWith("netbsd")) {
return "netbsd";
}
if (osName.startsWith("solaris") || osName.startsWith("sunos")) {
return "sunos";
}
if (osName.startsWith("windows")) {
return "windows";
}
return UNKNOWN;
}
private static String normalizeArch(final String osArch) {
if (osArch.matches("^(x8664|amd64|ia32e|em64t|x64)$")) {
return "x86_64";
}
if (osArch.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) {
return "x86_32";
}
if (osArch.matches("^(ia64w?|itanium64)$")) {
return "itanium_64";
}
if ("ia64n".equals(osArch)) {
return "itanium_32";
}
if (osArch.matches("^(sparc|sparc32)$")) {
return "sparc_32";
}
if (osArch.matches("^(sparcv9|sparc64)$")) {
return "sparc_64";
}
if (osArch.matches("^(arm|arm32)$")) {
return "arm_32";
}
if ("aarch64".equals(osArch)) {
return "aarch_64";
}
if (osArch.matches("^(mips|mips32)$")) {
return "mips_32";
}
if (osArch.matches("^(mipsel|mips32el)$")) {
return "mipsel_32";
}
if ("mips64".equals(osArch)) {
return "mips_64";
}
if ("mips64el".equals(osArch)) {
return "mipsel_64";
}
if (osArch.matches("^(ppc|ppc32)$")) {
return "ppc_32";
}
if (osArch.matches("^(ppcle|ppc32le)$")) {
return "ppcle_32";
}
if ("ppc64".equals(osArch)) {
return "ppc_64";
}
if ("ppc64le".equals(osArch)) {
return "ppcle_64";
}
if ("s390".equals(osArch)) {
return "s390_32";
}
if ("s390x".equals(osArch)) {
return "s390_64";
}
return UNKNOWN;
}
static String normalizeVM(final String javaVendor, final String javaVmName) {
if (javaVmName.contains("graalvm")) {
return "graalvm";
}
if (javaVendor.contains("oracle")) {
if (javaVmName.contains("openjdk")) {
return "oracle_openjdk";
} else {
return "oracle";
}
}
if (javaVendor.contains("adoptopenjdk")) {
return "adoptopenjdk";
}
if (javaVendor.contains("openj9")) {
return "openj9";
}
if (javaVendor.contains("azul")) {
if (javaVmName.contains("zing")) {
return "zing";
} else {
return "zulu";
}
}
return "-" + javaVendor + "-" + javaVmName;
}
static String normalizeJavaVersion(final String javaVersion) {
// These are already normalized.
return System.getProperty(javaVersion);
}
private static String normalize(final String value) {
if (value == null) {
return "";
}
return System.getProperty(value).toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
}
}

@ -0,0 +1,31 @@
/*
* Copyright 2018 ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/
package tech.pegasys.pantheon;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
public final class PantheonInfoTest {
/**
* Ethstats wants a version string like &lt;foo&gt/v&lt;bar&gt/&lt;baz&gt/&lt;bif&gt. Foo is the
* client identity (pantheon, Geth, Parity, etc). Bar is the version, in semantic version form
* (1.2.3-whatever), baz is OS and chip architecture, and bif is "compiler" - which we use as JVM
* info.
*/
@Test
public void versionStringIsEthstatsFriendly() {
assertThat(PantheonInfo.version()).matches("[^/]+/v(\\d+\\.\\d+\\.\\d+[^/]*|null)/[^/]+/[^/]+");
}
}

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-kvstore' baseName 'pantheon-kvstore'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-util-test' baseName 'pantheon-util-test'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

@ -16,8 +16,12 @@ apply plugin: 'java-library'
jar { jar {
baseName 'pantheon-util' baseName 'pantheon-util'
manifest { manifest {
attributes('Implementation-Title': baseName, attributes(
'Implementation-Version': project.version) 'Specification-Title': baseName,
'Specification-Version': project.version,
'Implementation-Title': baseName,
'Implementation-Version': calculateVersion()
)
} }
} }

Loading…
Cancel
Save