Autogenerate version.gen - no more outdated versions!
authorManuel Nickschas <sputnick@quassel-irc.org>
Sun, 8 Jun 2008 13:02:47 +0000 (15:02 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Sun, 8 Jun 2008 13:03:00 +0000 (15:03 +0200)
We now generate a file containing the current git revision, or alternatively,
the contents of a version.dist (for tarballs), on every make.
To do that in a crossplatform way, we compile a small binary for that first...

CMakeLists.txt
src/common/CMakeLists.txt
src/common/genversion.cpp [new file with mode: 0644]
src/common/global.cpp
src/common/global.h
src/core/ctcphandler.cpp
src/qtui/aboutdlg.cpp

index a5cf417..6963dfc 100644 (file)
@@ -83,42 +83,6 @@ if(DEFINED STATIC)
   link_directories(${CMAKE_BINARY_DIR}/staticlibs)
 endif(DEFINED STATIC)
 
-# Now see if we can generate a decent version.gen.
-# First, check if we have a git repo and git-describe gives reasonable output...
-# NOTE: This may fail if we have .git but not git binaries installed...
-if(EXISTS ${CMAKE_SOURCE_DIR}/.git)
-  execute_process(COMMAND git-describe --long
-                  WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
-                  RESULT_VARIABLE GIT_RESULT
-                  OUTPUT_VARIABLE GIT_OUTPUT)
-  if(GIT_RESULT OR ${GIT_OUTPUT} MATCHES "fatal")
-    set(GIT_OUTPUT )
-  endif(GIT_RESULT OR ${GIT_OUTPUT} MATCHES "fatal")
-endif(EXISTS ${CMAKE_SOURCE_DIR}/.git)
-
-# Now if we got a valid revision, let's use it...
-# A git-describe string has the form "version-commitcount-gdeadbeef"
-if(GIT_OUTPUT)
-  string(REGEX REPLACE "(.*)-0-g[0-9a-f]+" "\\1" VERSION_STRING ${GIT_OUTPUT})
-  string(REGEX REPLACE "(.*)-([0-9]+)-g([0-9a-f]+)\n" "\\1:git-\\3+\\2" VERSION_STRING ${VERSION_STRING})
-endif(GIT_OUTPUT)
-
-# If got something valid out of it, write it to the file
-if(VERSION_STRING)
-  file(WRITE ${CMAKE_BINARY_DIR}/src/common/version.gen
-       "quasselGeneratedVersion = \"${VERSION_STRING}\";\n")
-elseif(VERSION_STRING)
-  # Maybe we have a version.dist?
-  if(EXISTS ${CMAKE_SOURCE_DIR}/version.dist)
-    file(READ ${CMAKE_SOURCE_DIR}/version.dist VERSION_DIST)
-    file(WRITE ${CMAKE_BINARY_DIR}/src/common/version.gen ${VERSION_DIST})
-  elseif(EXISTS ${CMAKE_SOURCE_DIR}/version.dist)
-    # Ah well, just touch it then
-    file(WRITE ${CMAKE_BINARY_DIR}/src/common/version.gen "\n")
-  endif(EXISTS ${CMAKE_SOURCE_DIR}/version.dist)
-endif(VERSION_STRING)
-
-
 # Here comes the dirty part. Our targets need different Qt4 modules, i.e. different libs
 # and defines. We can't simply include UseQt4 several times, since definitions add up.
 # We workaround this by only setting up QtCore first, and adding additional stuff later.
@@ -126,6 +90,16 @@ set(QT_DONT_USE_QTGUI 1)
 include(${QT_USE_FILE})
 include_directories(${QT_INCLUDES})
 
+# We need to create a version.gen
+# For this, we create our genversion binary and make sure it is run every time.
+add_executable(genversion ${CMAKE_SOURCE_DIR}/src/common/genversion.cpp)
+target_link_libraries(genversion ${QT_LIBRARIES})
+
+add_custom_target(genversion_run ALL ${CMAKE_BINARY_DIR}/genversion
+                  ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR}/src/common/version.gen)
+add_dependencies(genversion_run genversion)
+set_source_files_properties(src/common/global.cpp PROPERTIES OBJECT_DEPENDS genversion_run)
+
 # This macro sets variables for additional Qt modules.
 macro(setup_qt4_variables)
   set(QUASSEL_QT_DEFINITIONS ${QT_DEFINITIONS})
index 2dcabbe..2239e77 100644 (file)
@@ -37,6 +37,7 @@ set(HEADERS
 
 qt4_wrap_cpp(MOC ${HEADERS})
 
-include_directories(${CMAKE_SOURCE_DIR}) # for version.inc and version.gen
+include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}) # for version.inc and version.gen
+add_definitions(-DHAVE_VERSION_GEN) # we ensure that by deps in the main CMakeLists.txt
 
 add_library(mod_common STATIC ${SOURCES} ${MOC})
diff --git a/src/common/genversion.cpp b/src/common/genversion.cpp
new file mode 100644 (file)
index 0000000..e8e75f9
--- /dev/null
@@ -0,0 +1,86 @@
+/***************************************************************************
+ *   Copyright (C) 2005-08 by the Quassel Project                          *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ ***************************************************************************/
+
+/** This is called at compile time and generates a suitable version.gen.
+ *  usage: genversion git_root target_file
+ * 
+ */
+
+#include <QDebug>
+#include <QProcess>
+#include <QString>
+#include <QStringList>
+#include <QRegExp>
+#include <QFile>
+
+int main(int argc, char **argv) {
+  if(argc < 3) {
+    qFatal("Usage: ./genversion <git_root> <target_file>");
+    return 255;
+  }
+  QString gitroot = argv[1];
+  QString target = argv[2];
+  QString version;
+
+  if(QFile::exists(gitroot + "/.git")) {
+    // try to execute git-describe to get a version string
+    QProcess git;
+    git.setWorkingDirectory(gitroot);
+    git.start("git-describe", QStringList("--long"));
+    if(git.waitForFinished(10000)) {
+      QString gitversion = git.readAllStandardOutput();
+      if(!gitversion.isEmpty() && !gitversion.contains("fatal")) {
+        // seems we have a valid version string, now prettify it...
+        // check if the workdir is dirty first
+        QString dirty;
+        QStringList params = QStringList() << "--name-only" << "HEAD";
+        git.start("git-diff-index", params);
+        if(git.waitForFinished(10000)) {
+          if(!git.readAllStandardOutput().isEmpty()) dirty = "*";
+        }
+        // Now we do some replacement magic...
+        QRegExp rxCheckTag("(.*)-0-g[0-9a-f]+\n$");
+        QRegExp rxGittify("(.*)-(\\d+)-g([0-9a-f]+)\n$");
+        gitversion.replace(rxCheckTag, QString("\\1%1").arg(dirty));
+        gitversion.replace(rxGittify, QString("\\1:git-\\3+\\2%1").arg(dirty));
+        if(!gitversion.isEmpty()) version = gitversion;
+      }
+    }
+  }
+  if(version.isEmpty()) {
+    // hmm, Git failed... let's check for version.dist instead
+    QFile dist(gitroot + "/version.dist");
+    if(dist.open(QIODevice::ReadOnly | QIODevice::Text)) {
+      version = dist.readAll();
+      dist.close();
+    }
+  }
+  // ok, create our version.gen now
+  QFile gen(target);
+  if(!gen.open(QIODevice::WriteOnly | QIODevice::Text)) {
+    qFatal(QString("Could not write %1!").arg(target).toAscii());
+    return 255;
+  }
+  gen.write(QString("quasselGeneratedVersion = \"%1\";\n"
+                    "quasselBuildDate = \"%2\";\n"
+                    "quasselBuildTime = \"%3\";\n").arg(version).arg(__DATE__).arg(__TIME__).toAscii());
+  gen.close();
+  return EXIT_SUCCESS;
+}
index a062886..8941d5b 100644 (file)
@@ -110,13 +110,11 @@ void Global::setupVersion() {
     quasselVersion = QString("v%1 (unknown rev)").arg(quasselBaseVersion);
   } else {
     QStringList parts = quasselGeneratedVersion.split(':');
-    if(parts.count() < 2) parts.append("unknown rev");
-    quasselVersion = QString("v%1 (%2)").arg(parts[0], parts[1]);
+    quasselVersion = QString("v%1").arg(parts[0]);
+    if(parts.count() >= 2) quasselVersion.append(QString(" (%1)").arg(parts[1]));
   }
-#  ifdef __DATE__
-    quasselBuildDate = __DATE__;
-#  endif
-
+  quasselBuildDate = __DATE__;
+  quasselBuildTime = __TIME__;
 }
 
 // Static variables
@@ -125,6 +123,7 @@ QString Global::quasselVersion;
 QString Global::quasselBaseVersion;
 QString Global::quasselGeneratedVersion;
 QString Global::quasselBuildDate;
+QString Global::quasselBuildTime;
 uint Global::protocolVersion;
 uint Global::clientNeedsProtocol;
 uint Global::coreNeedsProtocol;
index 65d1110..777be21 100644 (file)
@@ -35,6 +35,7 @@ namespace Global {
   extern QString quasselVersion;
   extern QString quasselBaseVersion;
   extern QString quasselBuildDate;
+  extern QString quasselBuildTime;
   extern uint protocolVersion;
 
   extern uint clientNeedsProtocol;  //< Minimum protocol version the client needs
index b5dcbd7..a864fe6 100644 (file)
@@ -175,7 +175,7 @@ void CtcpHandler::handlePing(CtcpType ctcptype, const QString &prefix, const QSt
 void CtcpHandler::handleVersion(CtcpType ctcptype, const QString &prefix, const QString &target, const QString &param) {
   Q_UNUSED(target)
   if(ctcptype == CtcpQuery) {
-    reply(nickFromMask(prefix), "VERSION", QString("Quassel IRC %1, built: %2 -- http://www.quassel-irc.org")
+    reply(nickFromMask(prefix), "VERSION", QString("Quassel IRC %1 (built on %2) -- http://www.quassel-irc.org")
         .arg(Global::quasselVersion).arg(Global::quasselBuildDate));
     emit displayMsg(Message::Server, BufferInfo::StatusBuffer, "", tr("Received CTCP VERSION request by %1").arg(prefix));
   } else {
index 6dfa3c8..0c55277 100644 (file)
@@ -24,7 +24,8 @@
 AboutDlg::AboutDlg(QWidget *parent) : QDialog(parent) {
   ui.setupUi(this);
 
-  ui.versionLabel->setText(QString("<b>Version %1, built %2</b>").arg(Global::quasselVersion).arg(Global::quasselBuildDate));
+  ui.versionLabel->setText(QString("<b>Version %1</b><br>Built: %2 %3").arg(Global::quasselVersion)
+      .arg(Global::quasselBuildDate).arg(Global::quasselBuildTime));
   ui.aboutTextBrowser->setHtml(about());
   ui.authorTextBrowser->setHtml(authors());
   ui.contributorTextBrowser->setHtml(contributors());