/****************************************************************************  
 | 
**  
 | 
** Copyright (C) 2016 The Qt Company Ltd.  
 | 
** Contact: https://www.qt.io/licensing/  
 | 
**  
 | 
** This file is part of the Qt VS Tools.  
 | 
**  
 | 
** $QT_BEGIN_LICENSE:GPL-EXCEPT$  
 | 
** Commercial License Usage  
 | 
** Licensees holding valid commercial Qt licenses may use this file in  
 | 
** accordance with the commercial license agreement provided with the  
 | 
** Software or, alternatively, in accordance with the terms contained in  
 | 
** a written agreement between you and The Qt Company. For licensing terms  
 | 
** and conditions see https://www.qt.io/terms-conditions. For further  
 | 
** information use the contact form at https://www.qt.io/contact-us.  
 | 
**  
 | 
** GNU General Public License Usage  
 | 
** Alternatively, this file may be used under the terms of the GNU  
 | 
** General Public License version 3 as published by the Free Software  
 | 
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT  
 | 
** included in the packaging of this file. Please review the following  
 | 
** information to ensure the GNU General Public License requirements will  
 | 
** be met: https://www.gnu.org/licenses/gpl-3.0.html.  
 | 
**  
 | 
** $QT_END_LICENSE$  
 | 
**  
 | 
****************************************************************************/  
 | 
  
 | 
using System;  
 | 
using System.Collections.Generic;  
 | 
using System.Diagnostics;  
 | 
using System.IO;  
 | 
using System.Linq;  
 | 
using System.Text;  
 | 
using QtVsTools.VisualStudio;  
 | 
  
 | 
namespace QtVsTools.Core  
 | 
{  
 | 
    public abstract class QMake  
 | 
    {  
 | 
        public Dictionary<string, string> Vars { get; protected set; }  
 | 
        public string OutputFile { get; protected set; }  
 | 
        public uint DebugLevel { get; protected set; }  
 | 
        public string TemplatePrefix { get; protected set; }  
 | 
        public bool Recursive { get; protected set; }  
 | 
        public string ProFile { get; protected set; }  
 | 
        public string Query { get; protected set; }  
 | 
        public bool DisableWarnings { get; set; }  
 | 
  
 | 
        protected VersionInformation QtVersion { get; private set; }  
 | 
        protected EnvDTE.DTE Dte { get; private set; }  
 | 
  
 | 
        public QMake(VersionInformation qtVersion, EnvDTE.DTE dte = null)  
 | 
        {  
 | 
            Debug.Assert(qtVersion != null);  
 | 
            QtVersion = qtVersion;  
 | 
            Dte = dte ?? VsServiceProvider.GetService<EnvDTE.DTE>();  
 | 
        }  
 | 
  
 | 
        protected virtual string QMakeExe  
 | 
        {  
 | 
            get  
 | 
            {  
 | 
                var qmakePath = Path.Combine(QtVersion.qtDir, "bin", "qmake.exe");  
 | 
                if (!File.Exists(qmakePath))  
 | 
                    qmakePath = Path.Combine(QtVersion.qtDir, "qmake.exe");  
 | 
                return qmakePath;  
 | 
            }  
 | 
        }  
 | 
  
 | 
        protected virtual string WorkingDirectory  
 | 
        {  
 | 
            get  
 | 
            {  
 | 
                return Path.GetDirectoryName(ProFile);  
 | 
            }  
 | 
        }  
 | 
  
 | 
        string MakeRelative(string absolutePath)  
 | 
        {  
 | 
            var workDir = new Uri(Path.GetDirectoryName(ProFile) + Path.DirectorySeparatorChar);  
 | 
            var path = new Uri(absolutePath);  
 | 
            if (workDir.IsBaseOf(path)) {  
 | 
                return workDir.MakeRelativeUri(path).OriginalString  
 | 
                    .Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);  
 | 
            } else {  
 | 
                return absolutePath;  
 | 
            }  
 | 
        }  
 | 
  
 | 
        protected virtual string QMakeArgs  
 | 
        {  
 | 
            get  
 | 
            {  
 | 
                var args = new StringBuilder();  
 | 
                if (Vars != null) {  
 | 
                    foreach (KeyValuePair<string, string> v in Vars) {  
 | 
                        args.AppendFormat(" {0}={1}", v.Key, v.Value);  
 | 
                    }  
 | 
                }  
 | 
  
 | 
                if (!string.IsNullOrEmpty(OutputFile))  
 | 
                    args.AppendFormat(" -o \"{0}\"", MakeRelative(OutputFile));  
 | 
  
 | 
                for (int i = 0; i < DebugLevel; ++i)  
 | 
                    args.Append(" -d");  
 | 
  
 | 
                if (!string.IsNullOrEmpty(TemplatePrefix))  
 | 
                    args.AppendFormat(" -tp {0}", TemplatePrefix);  
 | 
  
 | 
                if (Recursive)  
 | 
                    args.Append(" -recursive");  
 | 
  
 | 
                if (DisableWarnings)  
 | 
                    args.Append(" -Wnone");  
 | 
  
 | 
                if (!string.IsNullOrEmpty(ProFile))  
 | 
                    args.AppendFormat(" \"{0}\"", MakeRelative(ProFile));  
 | 
  
 | 
                if (!string.IsNullOrEmpty(Query))  
 | 
                    args.AppendFormat(" -query {0}", Query);  
 | 
  
 | 
                return args.ToString();  
 | 
            }  
 | 
        }  
 | 
  
 | 
        protected virtual Process CreateProcess()  
 | 
        {  
 | 
            var qmakeStartInfo = new ProcessStartInfo  
 | 
            {  
 | 
                CreateNoWindow = true,  
 | 
                UseShellExecute = false,  
 | 
                RedirectStandardError = true,  
 | 
                RedirectStandardOutput = true,  
 | 
                FileName = QMakeExe,  
 | 
                Arguments = QMakeArgs,  
 | 
                WorkingDirectory = WorkingDirectory,  
 | 
            };  
 | 
            qmakeStartInfo.EnvironmentVariables["QTDIR"] = QtVersion.qtDir;  
 | 
  
 | 
            var qmakeProc = new Process  
 | 
            {  
 | 
                StartInfo = qmakeStartInfo,  
 | 
            };  
 | 
            qmakeProc.OutputDataReceived += (sender, ev) => OutMsg(ev.Data);  
 | 
            qmakeProc.ErrorDataReceived += (sender, ev) => ErrMsg(ev.Data);  
 | 
  
 | 
            return qmakeProc;  
 | 
        }  
 | 
  
 | 
        protected virtual void OutMsg(string msg)  
 | 
        {  
 | 
            if (Dte != null && !string.IsNullOrEmpty(msg))  
 | 
                Messages.Print(msg);  
 | 
        }  
 | 
  
 | 
        protected virtual void ErrMsg(string msg)  
 | 
        {  
 | 
            if (Dte != null && !string.IsNullOrEmpty(msg))  
 | 
                Messages.Print(msg);  
 | 
        }  
 | 
  
 | 
        protected virtual void InfoMsg(string msg)  
 | 
        {  
 | 
            if (Dte != null && !string.IsNullOrEmpty(msg))  
 | 
                Messages.Print(msg);  
 | 
        }  
 | 
  
 | 
        protected virtual void InfoStart(Process qmakeProc)  
 | 
        {  
 | 
            InfoMsg(string.Format("--- qmake({0}): started {1}",  
 | 
                qmakeProc.Id, qmakeProc.StartInfo.FileName));  
 | 
        }  
 | 
  
 | 
        protected virtual void InfoExit(Process qmakeProc)  
 | 
        {  
 | 
            InfoMsg(string.Format("--- qmake({0}): exit code {1} ({2:0.##} msecs)\r\n",  
 | 
                qmakeProc.Id, qmakeProc.ExitCode,  
 | 
                (qmakeProc.ExitTime - qmakeProc.StartTime).TotalMilliseconds));  
 | 
        }  
 | 
  
 | 
        public virtual int Run(bool setVCVars = false)  
 | 
        {  
 | 
            int exitCode = -1;  
 | 
            using (var qmakeProc = CreateProcess()) {  
 | 
                try {  
 | 
                    if (setVCVars  
 | 
                        && !HelperFunctions.SetVCVars(QtVersion, qmakeProc.StartInfo)) {  
 | 
                        OutMsg("Error setting VC vars");  
 | 
                    }  
 | 
                    if (qmakeProc.Start()) {  
 | 
                        InfoStart(qmakeProc);  
 | 
                        qmakeProc.BeginOutputReadLine();  
 | 
                        qmakeProc.BeginErrorReadLine();  
 | 
                        qmakeProc.WaitForExit();  
 | 
                        exitCode = qmakeProc.ExitCode;  
 | 
                        InfoExit(qmakeProc);  
 | 
                    }  
 | 
                } catch (Exception e) {  
 | 
                    ErrMsg(string.Format("Exception \"{0}\":\r\n{1}",  
 | 
                        e.Message,  
 | 
                        e.StackTrace));  
 | 
                }  
 | 
            }  
 | 
            return exitCode;  
 | 
        }  
 | 
    }  
 | 
  
 | 
    public class QMakeImport : QMake  
 | 
    {  
 | 
        public QMakeImport(  
 | 
            VersionInformation qtVersion,  
 | 
            string proFilePath,  
 | 
            bool recursiveRun = false,  
 | 
            EnvDTE.DTE dte = null)  
 | 
        : base(qtVersion, dte)  
 | 
        {  
 | 
            ProFile = proFilePath;  
 | 
            TemplatePrefix = "vc";  
 | 
            if (recursiveRun)  
 | 
                Recursive = true;  
 | 
            else  
 | 
                OutputFile = Path.ChangeExtension(proFilePath, ".vcxproj");  
 | 
            Vars = new Dictionary<string, string>  
 | 
            {  
 | 
                { "QMAKE_INCDIR_QT", @"$(QTDIR)\include" },  
 | 
                { "QMAKE_LIBDIR", @"$(QTDIR)\lib" },  
 | 
                { "QMAKE_MOC", @"$(QTDIR)\bin\moc.exe" },  
 | 
                { "QMAKE_QMAKE", @"$(QTDIR)\bin\qmake.exe" },  
 | 
            };  
 | 
        }  
 | 
  
 | 
        protected override void InfoStart(Process qmakeProc)  
 | 
        {  
 | 
            base.InfoStart(qmakeProc);  
 | 
            InfoMsg("--- qmake: Working Directory: " + qmakeProc.StartInfo.WorkingDirectory);  
 | 
            InfoMsg("--- qmake: Arguments: " + qmakeProc.StartInfo.Arguments);  
 | 
            if (qmakeProc.StartInfo.EnvironmentVariables.ContainsKey("QMAKESPEC")) {  
 | 
                var qmakeSpec = qmakeProc.StartInfo.EnvironmentVariables["QMAKESPEC"];  
 | 
                if (qmakeSpec != QtVersion.QMakeSpecDirectory) {  
 | 
                    InfoMsg("--- qmake: Environment "  
 | 
                        + "variable QMAKESPEC overwriting Qt version QMAKESPEC.");  
 | 
                    InfoMsg("--- qmake: Qt version "  
 | 
                        + "QMAKESPEC: " + QtVersion.QMakeSpecDirectory);  
 | 
                    InfoMsg("--- qmake: Environment "  
 | 
                        + "variable QMAKESPEC: " + qmakeSpec);  
 | 
                }  
 | 
            }  
 | 
        }  
 | 
    }  
 | 
}  
 |