add meta file classes
authorKonrad Rosenbaum <konrad@silmor.de>
Sun, 11 Aug 2013 13:14:34 +0000 (15:14 +0200)
committerKonrad Rosenbaum <konrad@silmor.de>
Sun, 11 Aug 2013 13:14:34 +0000 (15:14 +0200)
.gitignore
aurora/common/metafile.cpp [new file with mode: 0644]
aurora/common/metafile.h [new file with mode: 0644]
aurora/dloader/dloader.pro
aurora/instgen/instgen.pro
aurora/instgen/main.cpp

index 23e564d..0a07b4b 100644 (file)
@@ -1,5 +1,9 @@
 *.bak
 *~
 lib/
+bin/
 .ctmp
 Makefile*
+core
+core.*
+.kdev*
diff --git a/aurora/common/metafile.cpp b/aurora/common/metafile.cpp
new file mode 100644 (file)
index 0000000..94f09c0
--- /dev/null
@@ -0,0 +1,257 @@
+// Copyright (C) 2012 by Konrad Rosenbaum <konrad@silmor.de>
+// protected under the GNU LGPL version 3 or at your option any newer.
+// See COPYING.LGPL file that comes with this distribution.
+//
+
+#include "metafile.h"
+#include "../gnupg/include/host2net.h"
+#include <QFile>
+#include <QFileInfo>
+#include <QProcess>
+#include <QDir>
+
+#include <QtXml>
+
+static const QString slocalOS =
+#ifdef Q_OS_LINUX
+        "linux"
+#elif defined(Q_OS_WIN)
+        "windows"
+#else
+#warning "Unknown OS, please extend me"
+        "unknown"
+#endif
+;
+
+static const QString slocalCPU =
+#ifdef Q_PROCESSOR_X86_32
+        "x86"
+#elif defined(Q_PROCESSOR_X86_64)
+        "x86-64"
+#else
+#warning "Unknown CPU, please extend me"
+        "unknown"
+#endif
+;
+
+static inline bool matchLocalOS(const QString &os)
+{
+        if(os==slocalOS || os=="all")return true;
+#ifdef AURORA_INSTGEN_BUILD
+        if(os=="any")return true;
+#endif
+        return false;
+}
+
+static inline bool matchLocalCPU(const QString &cpu)
+{
+        if(cpu==slocalCPU || cpu=="all")return true;
+#ifdef AURORA_INSTGEN_BUILD
+        if(cpu=="any")return true;
+#endif
+        return false;
+}
+
+static inline bool matchLocal(const QString &os,const QString &cpu)
+{
+        return matchLocalOS(os)&&matchLocalCPU(cpu);
+}
+
+#ifdef AURORA_INSTGEN_BUILD
+static inline QString createArchiveName(const QString&name,const QString&os, const QString&cpu)
+{
+        //shortcut
+        if(!name.contains('*'))return name;
+        //create the replacement for *: os-cpu; any is replaced with the actual os/cpu
+        QString ast;
+        if(os=="any")ast=slocalOS;
+        else ast=os;
+        ast+="-";
+        if(cpu=="any")ast+=slocalCPU;
+        else ast+=cpu;
+        return QString(name).replace('*',ast);
+}
+
+static inline QString resolveDir(QString dir,const QString&base=".")
+{
+        if(dir.isEmpty())dir=".";
+        //stage 1: resolve pipe
+        if(dir.startsWith("|")){
+                QProcess prc;
+                prc.start(dir.mid(1),QIODevice::ReadOnly);
+                if(!prc.waitForFinished()){
+                        qDebug()<<"Error: Failed to resolve directory externally.";
+                        qDebug()<<"   Command:"<<dir;
+                        qDebug()<<"    Result:"<<prc.exitCode()<<prc.readAllStandardError().trimmed();
+                        return QString();
+                }
+                dir=QString::fromLocal8Bit(prc.readAllStandardOutput()).trimmed();
+        }
+        //stage 2: if absolute - use it, otherwise combine
+        if(!QFileInfo(dir).isAbsolute() && !base.isEmpty())dir=base+"/"+dir;
+        //stage 3: normalize
+        const bool slash=dir.startsWith('/');
+        QStringList dl;
+        for(const QString&dc:dir.replace('\\','/').split("/",QString::SkipEmptyParts)){
+                if(dc==".")continue;
+                if(dc==".."){
+                        if(dl.size()==0)dl<<dc;
+                        else if(dl[dl.size()-1]=="..")dl<<dc;
+                        else dl.takeLast();
+                }else dl<<dc;
+        }
+        if(slash)dir="/";else dir="";
+        for(const QString&dc:dl){
+                if(dir.size()>0 && dir!="/")dir+="/";
+                dir+=dc;
+        }
+        if(dir.size()==0)dir=".";
+        //done
+        return dir;
+}
+#endif
+
+QString MetaFile::localPlatform()
+{
+        return slocalOS+"-"+slocalCPU;
+}
+
+Archive::Archive(const QDomElement& ael)
+#ifdef AURORA_INSTGEN_BUILD
+        :misSource(false)
+#endif
+{
+        mName=ael.attribute("name");
+        msha1=ael.attribute("sha1sum");
+        mos=ael.attribute("os");
+        mcpu=ael.attribute("cpu");
+}
+
+MetaFile::MetaFile(const QString& fname)
+{
+        QFile fd(fname);
+        if(!fd.open(QIODevice::ReadOnly)){
+                qDebug()<<"Unable to open Meta File";
+                return;
+        }
+        QDomDocument doc;
+        if(!doc.setContent(&fd)){
+                qDebug()<<"Meta File is not XML";
+                return;
+        }
+        QDomElement root=doc.documentElement();
+        mValid=root.tagName()=="AuroraInfo";
+        QDomElement el=doc.elementsByTagName("CurrentVersion").at(0).toElement();
+        mBuilt=QDateTime::fromString(el.attribute("buildDate"),Qt::ISODate);
+        mInstalled=QDateTime::fromString(el.attribute("installDate"),Qt::ISODate);
+        mVersionH=el.attribute("version");
+        mVersionM=el.attribute("mrv");
+        el=doc.elementsByTagName("Settings").at(0).toElement();
+        mBaseUrl=el.attribute("baseurl");
+        mIndexFile=el.attribute("indexfile");
+        mPollInterval=el.attribute("pollinterval","-1").toInt();
+        //go through archive sources
+        QDomNodeList nl;
+#ifdef AURORA_INSTGEN_BUILD
+        nl=doc.elementsByTagName("ArchiveSource");
+        for(int i=0;i<nl.size();i++){
+                el=nl.at(i).toElement();
+                if(el.isNull())continue;
+                if(!el.hasAttribute("name")){
+                        qDebug()<<"Warning: ArchiveSource at line"<<el.lineNumber()<<"column"<<el.columnNumber()<<"has no name, skipping it.";
+                        continue;
+                }
+                const QString aname=el.attribute("name");
+                const QString buildbase=resolveDir(el.attribute("buildbase","."));
+                const QString zipbase=el.attribute("zipbase",".");
+                qDebug()<<"Found Archive Source"<<aname<<"; buildbase:"<<buildbase<<"; zipbase:"<<zipbase;
+                //go through platforms, look for match
+                QDomNodeList nlp=el.elementsByTagName("Platform");
+                for(int j=0;j<nlp.size();j++){
+                        QDomElement elp=nlp.at(j).toElement();
+                        if(elp.isNull())continue;
+                        const QString os=elp.attribute("os","any");
+                        const QString cpu=elp.attribute("cpu","any");
+                        if(!matchLocal(os,cpu)){
+                                qDebug()<<"Skipping OS"<<os<<"CPU"<<cpu;
+                                continue;
+                        }
+                        qDebug()<<"Recording OS"<<os<<"CPU"<<cpu;
+                        const QString pbuildbase=resolveDir(el.attribute("buildbase","."),buildbase);
+                        const QString pzipbase=resolveDir(el.attribute("zipbase","."),zipbase);
+                        //generate Archive object
+                        mArchives.append(Archive(elp,pbuildbase,pzipbase,aname));
+                }
+        }
+#endif
+        //go through finished archives
+        nl=doc.elementsByTagName("Archive");
+        for(int i=0;i<nl.size();i++){
+                el=nl.at(i).toElement();
+                if(el.isNull())continue;
+                if(!el.hasAttribute("name")){
+                        qDebug()<<"Warning: Archive at line"<<el.lineNumber()<<"column"<<el.columnNumber()<<"has no name, skipping it.";
+                        continue;
+                }
+                mArchives.append(Archive(el));
+        }
+}
+
+#ifdef AURORA_INSTGEN_BUILD
+
+bool ArchiveFile::fileMatches(QString filename) const
+{
+        return mpat.exactMatch(filename) && !mexclude.exactMatch(filename);
+}
+
+static inline QStringList listdir(const QString&dirn)
+{
+        QDir d(dirn);
+        QStringList ret;
+        for(const QFileInfo&fi:d.entryInfoList(QDir::Dirs|QDir::Files|QDir::NoDotAndDotDot|QDir::Readable)){
+                if(fi.isFile())
+                        ret.append(dirn+"/"+fi.fileName());
+                else
+                        ret.append(listdir(dirn+"/"+fi.fileName()));
+        }
+        return ret;
+}
+
+QStringList ArchiveFile::getFiles() const
+{
+        //split pattern
+        QStringList ret;
+        for(const QString&c:listdir(mSource)){
+                if(mpat.exactMatch(c) && !mexclude.exactMatch(c))
+                        ret.append(c);
+        }
+        return ret;
+}
+
+Archive::Archive(const QDomElement& pfel, const QString& bb, const QString& zb,const QString&nm)
+        :mBuildBase(bb),mZipBase(zb),misSource(true)
+{
+        mos=pfel.attribute("os","any");
+        mcpu=pfel.attribute("cpu","any");
+        if(nm.contains("*"))mName=createArchiveName(nm,mos,mcpu);
+        else mName=nm;
+        //files...
+        QDomNodeList nl=pfel.elementsByTagName("Files");
+        for(int i=0;i<nl.size();i++){
+                QDomElement el=nl.at(i).toElement();
+                if(el.isNull())continue;
+                //bases
+                const QString buildbase=resolveDir(el.attribute("buildbase","."),mBuildBase);
+                const QString zipbase=resolveDir(el.attribute("zipbase","."),mZipBase);
+                const QString exclude=el.attribute("exclude");
+                //files
+                for(QString fp:el.text().split("\n")){
+                        fp=fp.trimmed();
+                        if(fp.isEmpty())continue;
+                        mFiles.append(ArchiveFile(buildbase,zipbase,fp,exclude));
+                }
+        }
+}
+
+//end of library build
+#endif
diff --git a/aurora/common/metafile.h b/aurora/common/metafile.h
new file mode 100644 (file)
index 0000000..b2ee84c
--- /dev/null
@@ -0,0 +1,123 @@
+// Copyright (C) 2013 by Konrad Rosenbaum <konrad@silmor.de>
+// protected under the GNU LGPL version 3 or at your option any newer.
+// See COPYING.LGPL file that comes with this distribution.
+//
+
+#ifndef AURORA_META_H
+#define AURORA_META_H
+
+#include <QStringList>
+#include <QDateTime>
+#include <QRegExp>
+
+class QDomElement;
+namespace AuroraUpdater {
+
+#define AURORA_INSTGEN_BUILD
+#ifdef AURORA_INSTGEN_BUILD
+
+#ifdef Q_OS_WIN
+#define CS Qt::CaseInsensitive
+#else
+#define CS Qt::CaseSensitive
+#endif
+class ArchiveFile {
+        QString mSource,mDest;
+        QRegExp mpat,mexclude;
+        
+        friend class Archive;
+        ArchiveFile(QString src,QString dst,QString pat,QString excl)
+         :mSource(src.replace('\\','/')),
+          mDest(dst.replace('\\','/')),
+          mpat(pat,CS,QRegExp::WildcardUnix),
+          mexclude(excl,CS,QRegExp::WildcardUnix)
+         {}
+public:
+        ArchiveFile(){}
+        ArchiveFile(const ArchiveFile&)=default;
+        
+        QString sourcePath()const{return mSource;}
+        QString destinationPath()const{return mDest;}
+        QRegExp pattern()const{return mpat;}
+        QRegExp excludePattern()const{return mexclude;}
+        
+        bool fileMatches(QString filename)const;
+        QStringList getFiles()const;
+};
+#undef CS
+#endif
+
+///Description of a single Archive File
+class Archive {
+        QString mName,msha1,mos,mcpu;
+        
+        friend class MetaFile;
+        ///instantiate from <Archive>
+        Archive(const QDomElement&);
+#ifdef AURORA_INSTGEN_BUILD
+        ///instantiate from <Platform> and <Files>
+        Archive(const QDomElement&,const QString&,const QString&,const QString&);
+        QString mBuildBase,mZipBase;
+        bool misSource=false;
+        QList<ArchiveFile>mFiles;
+#endif
+public:
+        Archive(){}
+        Archive(const Archive&)=default;
+        
+        QString name()const{return mName;}
+        
+        QString sha1sum()const{return msha1;}
+        
+        QString operatingSystem()const{return mos;}
+        QString cpu()const{return mcpu;}
+
+#ifdef AURORA_INSTGEN_BUILD
+        QString buildBaseDir()const{return mBuildBase;}
+        QString zipBaseDir()const{return mZipBase;}
+        bool isSource()const{return misSource;}
+        QList<ArchiveFile>filePatterns()const{return mFiles;}
+#endif
+        
+};
+
+///Encapsulates meta files: XML descriptions of how to generate and/or download packages.
+class MetaFile
+{
+        QDateTime mBuilt,mInstalled;
+        QString mVersionH,mVersionM,mBaseUrl,mIndexFile;
+        int mPollInterval=-1;
+        QList<Archive>mArchives;
+        bool mValid=false;
+public:
+        ///create empty meta file object, not recommended
+        MetaFile(){}
+        ///copies a meta file object
+        MetaFile(const MetaFile&)=default;
+        ///expects a file name and tries to read this file as an XML meta file
+        MetaFile(const QString&);
+        
+        QDateTime buildTime()const{return mBuilt;}
+        QDateTime installTime()const{return mInstalled;}
+        
+        QString version()const{return mVersionH;}
+        QString machineVersion()const{return mVersionM;}
+        
+        QString baseUrl()const{return mBaseUrl;}
+        QString indexFile()const{return mIndexFile;}
+        
+        int pollInterval()const{return mPollInterval;}
+        
+        QList<Archive> archives()const{return mArchives;}
+        
+        bool isValid()const{return mValid;}
+        
+        static QString localPlatform();
+};
+
+//end of namespace
+};
+
+using namespace AuroraUpdater;
+
+#endif
index eb4acf6..8efa243 100644 (file)
@@ -14,12 +14,14 @@ VERSION = 0.2.0
 SOURCES += \
         aurora.cpp \
         subtask.cpp \
-        gpgwrap.cpp
+        gpgwrap.cpp \
+        ../common/metafile.cpp
 
 HEADERS += \
         aurora.h \
         subtask.h \
-        gpgwrap.h
+        gpgwrap.h \
+        ../common/metafile.h
 
 INCLUDEPATH += src gpg/include
 DEPENDPATH += $$INCLUDEPATH
index bea4a7f..5758f88 100644 (file)
@@ -3,7 +3,8 @@ TEMPLATE = app
 TARGET = instgen
 DESTDIR = $$PWD/../../bin
 QT -= gui
-CONFIG += release hide_symbols separate_debug_info
+QT += xml
+CONFIG += release hide_symbols separate_debug_info console
 
 include ($$PWD/../../zip.pri)
 
@@ -11,11 +12,26 @@ OBJECTS_DIR = .ctmp
 MOC_DIR = .ctmp
 RCC_DIR = .ctmp
 
+DEFINES += AURORA_INSTGEN_BUILD=1
+
+INCLUDEPATH += $$PWD/../common
 DEPENDPATH += $$INCLUDEPATH
 
-SOURCES += main.cpp
+SOURCES += main.cpp \
+        ../common/metafile.cpp
+
+HEADERS += \
+        ../common/metafile.h
 
 
 gcc {
   QMAKE_CXXFLAGS += -std=gnu++11
 }
+
+linux {
+  QMAKE_CFLAGS += -fPIE
+  QMAKE_CXXFLAGS += -fPIE
+  QMAKE_LFLAGS += -pie
+  #make sure we find our libs
+  QMAKE_LFLAGS += -Wl,-rpath,\'\$$ORIGIN/../lib\'
+}
index 6bb1737..b13337f 100644 (file)
@@ -4,11 +4,37 @@
 //
 
 #include <QCoreApplication>
+#include <QStringList>
+#include <QDebug>
+#include <QDir>
+
+#include "metafile.h"
 
 int main(int ac,char**av)
 {
         QCoreApplication app(ac,av);
+        //get parameters
+        if(app.arguments().size()!=2){
+                qDebug()<<"Usage: instgen metafile.aurora";
+                return 1;
+        }
+        
+        //get file
+        const QString mfname=app.arguments().at(1);
+        QFileInfo inf(mfname);
+        if(!inf.exists()){
+                qDebug()<<"File"<<mfname<<"does not exist.";
+                return 1;
+        }
+        QDir::setCurrent(inf.absolutePath());
+        MetaFile mf(inf.fileName());
+        if(!mf.isValid()){
+                qDebug()<<"File"<<mfname<<"is not a valid Aurora Meta File.";
+                return 1;
+        }
+        qDebug()<<"Building"<<mfname<<"for platform spec"<<MetaFile::localPlatform();
         
+        //actually build
         
         return 0;
 }
\ No newline at end of file