xaizek / uncov (License: AGPLv3+) (since 2018-12-07)
Uncov(er) is a tool that collects and processes code coverage reports.
<root> / web / diff.ecpp (7aea51c2cc2ef9f8122135c49d48f8f618a9250d) (6,784B) (mode 100644) [raw]
<!--

Copyright (C) 2017 xaizek <xaizek@posteo.net>

This file is part of uncov.

uncov is free software: you can redistribute it and/or modify
it under the terms of version 3 of the GNU Affero General Public License as
published by the Free Software Foundation.

uncov 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 Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with uncov.  If not, see <http://www.gnu.org/licenses/>.

-->

<%pre>
    #include <cstdlib>

    #include <boost/optional.hpp>

    #include <tnt/httperror.h>

    #include "utils/Text.hpp"
    #include "utils/strings.hpp"
    #include "BuildHistory.hpp"
    #include "ColorCane.hpp"
    #include "FilePrinter.hpp"
    #include "Repository.hpp"
    #include "Settings.hpp"
    #include "colors.hpp"
    #include "listings.hpp"

    extern Repository *globalRepo;
    extern BuildHistory *globalBH;
    extern Settings *globalSettings;

    static int toNum(const std::string &s) {
        char *end;
        return std::strtol(s.c_str(), &end, 10);
    }
</%pre>

<%cpp>
    const std::string buildIdStr = request.getArg("buildId");
    const int buildId = [&request, &buildIdStr]() {
        try {
            return std::stoi(buildIdStr);
        } catch (const std::exception &) {
            return 0;
        }
    }();
    const std::string filePath = request.getArg("filePath");
</%cpp>

<%application>
    // srchilite::SourceHighlight doesn't seem to be thread safe (in particular
    // it has grammar parsing with global state) and needs to be globally
    // locked
    FilePrinter printer(*globalSettings);
</%application>

<html>

<head>
    <title>Diff of <$ filePath $> in build #<$ buildIdStr $> | uncov</title>
    <%include>web/header.ecpp</%include>
</head>

<body>
%   if (boost::optional<Build> build = globalBH->getBuild(buildId)) {
%   if (boost::optional<Build> prevBuild =
%       globalBH->getBuild(globalBH->getPreviousBuildId(buildId))) {
%   if (boost::optional<File &> file = build->getFile(filePath)) {
%   boost::optional<File &> prevFile = prevBuild->getFile(filePath);

%   std::vector<std::string> fileInfo = describeFile(globalBH, *build, *file,
%                                                    DoSpacing{});
%   std::vector<std::string> buildInfo = describeBuild(globalBH, *build,
%                                                      !DoExtraAlign{},
%                                                      DoSpacing{});

    <div class="sidenav">
    <a href="/builds">All builds</a>
    <a class="branch" href="/branches/<$ buildInfo[5] $>">Current branch</a>
    <a href="/builds/<$ buildIdStr $>">Current build</a>
    <br/>
    <a class="action" href="/changes/<$ buildIdStr $>">Changed files</a>
    </div>

    <div class="rightbar">
    <div class="bargroup">
        <span class="barelem">Build <$$ buildInfo[0] $></span>
        <span class="barelem"><$$ buildInfo[1] $></br>
                              <small><$$ buildInfo[2] $></small></span>
        <span class="barelem"><$$ buildInfo[3] $></br>
                              <small><$$ buildInfo[4] $></small></span>
        <span class="barelem">
            <div class="tooltip">
                <span class="tooltipobj">
                    <a class="branch" href="/branches/<$ buildInfo[5] $>">
                        <$$ buildInfo[5] $>
                    </a>
                </span>
                <span class="tooltiptext">
                    <$$ buildInfo[6] $>
                </span>
            </div>
        </span>
    </div>

    <div class="bargroup">
        <span class="barelem">File</span>
        <span class="barelem"><$$ fileInfo[1] $></br>
                              <small><$$ fileInfo[2] $></small></span>
        <span class="barelem"><$$ fileInfo[3] $></br>
                              <small><$$ fileInfo[4] $></small></span>
    </div>

    <%include>web/footer.ecpp</%include>
    </div>

    <h3 class="title">
    Changes of a file between two builds
    </h3>

    <h4>
    Path: <a class="path" href="/builds/<$ buildIdStr $>">&lt;root&gt;</a>
%   std::string pathPrefix;
%   for (const std::string &entry : split(fileInfo[0], '/')) {
%       pathPrefix += '/' + entry;
%       const std::string slash = pathPrefix == "/" + fileInfo[0] ? "" : "/";
        / <a class="path"
             href="/builds/<$ buildIdStr  $><$ pathPrefix + slash $>"><$ entry $></a>
%   }
    </h4>

%   const std::vector<int> &oldCov = prevFile ? prevFile->getCoverage()
%                                             : std::vector<int>{};
%   const std::vector<int> &newCov = file ? file->getCoverage()
%                                         : std::vector<int>{};

%   Text oldVersion(prevFile
%                 ? globalRepo->readFile(prevBuild->getRef(), filePath)
%                 : std::string());
%   Text newVersion(file ? globalRepo->readFile(build->getRef(), filePath)
%                        : std::string());

%   FileComparator comparator(oldVersion.asLines(), oldCov,
%                             newVersion.asLines(), newCov,
%                             CompareStrategy::State, *globalSettings);

<pre>
%   ColorCane cc = printer.printDiff(filePath,
%                                    oldVersion.asStream(), oldCov,
%                                    newVersion.asStream(), newCov,
%                                    comparator);
%   std::string oldId = std::to_string(prevBuild->getId());
%   std::string newId = std::to_string(build->getId());
%   for (const ColorCanePiece &piece : cc) {
%       if (piece.hi == ColorGroup::OldLineNo ||
%           piece.hi == ColorGroup::NewLineNo) {
%           const std::string & id = (piece.hi == ColorGroup::OldLineNo)
%                                  ? oldId : newId;
%           if (int n = toNum(piece.text)) {
%               reply.out() << "<a href='" << "/builds/" << id << '/'
%                           << fileInfo[0] << "#l" << std::to_string(n) << "'>"
%                           << piece
%                           << "</a>";
%           } else {
%               reply.out() << "<span class='blank'>" << piece << "</span>";
%           }
%       } else {
%           reply.out() << piece;
%       }
%   }
</pre>

%   } else {
%   log_warn("Can't find requested file " + filePath + " in build #"
%          + buildIdStr);
    <h1>No such file</h1>
%   }
%   } else {
%   log_warn("Can't build preceding build #" + buildIdStr);
    <h1>No previous build</h1>
%   }
%   } else {
%   log_warn("Can't find requested build #" + buildIdStr);
    <h1>No such build</h1>
%   }

</body>

</html>
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/uncov

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/uncov

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master