bin/svndigest.cc

Code
Comments
Other
Rev Date Author Line
40 13 Jan 06 peter 1 // $Id$
40 13 Jan 06 peter 2
84 13 Mar 06 jari 3 /*
1267 02 Nov 10 peter 4   Copyright (C) 2006, 2007, 2008, 2009 Jari Häkkinen, Peter Johansson
1635 30 Mar 23 peter 5   Copyright (C) 2010, 2011, 2012, 2023 Peter Johansson
84 13 Mar 06 jari 6
687 04 Aug 08 peter 7   This file is part of svndigest, http://dev.thep.lu.se/svndigest
84 13 Mar 06 jari 8
149 12 Aug 06 jari 9   svndigest is free software; you can redistribute it and/or modify it
84 13 Mar 06 jari 10   under the terms of the GNU General Public License as published by
693 11 Sep 08 jari 11   the Free Software Foundation; either version 3 of the License, or
84 13 Mar 06 jari 12   (at your option) any later version.
84 13 Mar 06 jari 13
149 12 Aug 06 jari 14   svndigest is distributed in the hope that it will be useful, but
84 13 Mar 06 jari 15   WITHOUT ANY WARRANTY; without even the implied warranty of
159 14 Aug 06 jari 16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
84 13 Mar 06 jari 17   General Public License for more details.
84 13 Mar 06 jari 18
84 13 Mar 06 jari 19   You should have received a copy of the GNU General Public License
693 11 Sep 08 jari 20   along with svndigest. If not, see <http://www.gnu.org/licenses/>.
84 13 Mar 06 jari 21 */
84 13 Mar 06 jari 22
1619 12 Mar 23 peter 23 #include <config.h>
1619 12 Mar 23 peter 24
1060 02 Jun 10 peter 25 #include "svndigestParameter.h"
91 23 Mar 06 jari 26
1423 16 Dec 11 peter 27 #include "lib/CacheRemover.h"
1119 04 Jul 10 peter 28 #include "lib/Configuration.h"
1119 04 Jul 10 peter 29 #include "lib/css.h"
1197 04 Oct 10 peter 30 #include "lib/Date.h"
1119 04 Jul 10 peter 31 #include "lib/Directory.h"
1119 04 Jul 10 peter 32 #include "lib/first_page.h"
1119 04 Jul 10 peter 33 #include "lib/Graph.h"
1119 04 Jul 10 peter 34 #include "lib/html_utility.h"
1119 04 Jul 10 peter 35 #include "lib/main_utility.h"
1254 31 Oct 10 peter 36 #include "lib/NodeCounter.h"
1119 04 Jul 10 peter 37 #include "lib/rmdirhier.h"
1119 04 Jul 10 peter 38 #include "lib/Stats.h"
1119 04 Jul 10 peter 39 #include "lib/StatsCollection.h"
1119 04 Jul 10 peter 40 #include "lib/SVN.h"
1234 23 Oct 10 peter 41 #include "lib/SvndigestVisitor.h"
1119 04 Jul 10 peter 42 #include "lib/SVNinfo.h"
1119 04 Jul 10 peter 43 #include "lib/SVNlog.h"
1119 04 Jul 10 peter 44 #include "lib/utility.h"
40 13 Jan 06 peter 45
1673 26 Aug 23 peter 46 #include <yat/utility/Exception.h>
1673 26 Aug 23 peter 47 #include <yat/utility/OptionArg.h>
1675 26 Aug 23 peter 48 #include <yat/utility/utility.h>
795 30 Jun 09 peter 49
1280 06 Nov 10 peter 50 #include <algorithm>
315 17 May 07 peter 51 #include <cassert>
896 26 Nov 09 peter 52 #include <cstdlib>
1197 04 Oct 10 peter 53 #include <ctime>
92 23 Mar 06 jari 54 #include <iostream>
129 02 Aug 06 jari 55 #include <fstream>
49 14 Jan 06 jari 56 #include <stdexcept>
49 14 Jan 06 jari 57 #include <string>
49 14 Jan 06 jari 58 #include <sys/stat.h>
49 14 Jan 06 jari 59 #include <unistd.h>
49 14 Jan 06 jari 60
1069 06 Jun 10 peter 61 using namespace theplu;
1069 06 Jun 10 peter 62 using namespace svndigest;
1069 06 Jun 10 peter 63 void copy_option2config(const svndigestParameter&, Configuration&);
1069 06 Jun 10 peter 64
1513 23 Sep 12 peter 65 void create_file_struct(std::string stats_type,
497 14 Oct 07 peter 66                         const theplu::svndigest::Stats& stats);
497 14 Oct 07 peter 67
1234 23 Oct 10 peter 68 void prepare_report(const svndigestParameter& option, const std::string& repo,
1234 23 Oct 10 peter 69                     const Node& tree);
1085 12 Jun 10 peter 70
518 20 Dec 07 peter 71 int main( int argc, char* argv[])
40 13 Jan 06 peter 72 {
229 25 Mar 07 peter 73   // Reading commandline options
1068 06 Jun 10 peter 74   svndigestParameter option;
104 27 Jun 06 peter 75   try {
1068 06 Jun 10 peter 76     option.parse(argc,argv);
1068 06 Jun 10 peter 77     if (option.verbose())
195 07 Sep 06 jari 78       std::cout << "Done parsing parameters" << std::endl;
104 27 Jun 06 peter 79   }
795 30 Jun 09 peter 80   catch (yat::utility::cmd_error& e) {
104 27 Jun 06 peter 81     std::cerr << e.what() << std::endl;
896 26 Nov 09 peter 82     exit(EXIT_FAILURE);
104 27 Jun 06 peter 83   }
1085 12 Jun 10 peter 84   catch (std::runtime_error& e) {
1086 12 Jun 10 peter 85     std::cerr << "svndigest: " << e.what() << std::endl;
1085 12 Jun 10 peter 86     return EXIT_FAILURE;
1085 12 Jun 10 peter 87   }
40 13 Jan 06 peter 88
1067 06 Jun 10 peter 89   try {
1102 15 Jun 10 peter 90     load_config(option.config_file(), option.verbose());
1069 06 Jun 10 peter 91     copy_option2config(option, Configuration::instance());
1070 06 Jun 10 peter 92     if (option.generate_config()) {
1070 06 Jun 10 peter 93       std::cout << Configuration::instance();
1070 06 Jun 10 peter 94       return EXIT_SUCCESS;
1070 06 Jun 10 peter 95     }
1072 06 Jun 10 peter 96
1072 06 Jun 10 peter 97     if (option.verbose())
1072 06 Jun 10 peter 98       std::cout << "Initializing SVN singleton." << std::endl;
1072 06 Jun 10 peter 99     SVN::instance(option.root());
1015 09 Jan 10 peter 100
1085 12 Jun 10 peter 101     // Extract repository location
1085 12 Jun 10 peter 102     std::string repo=SVNinfo(option.root()).repos_root_url();
1085 12 Jun 10 peter 103
1085 12 Jun 10 peter 104     // build directory tree already here ... if WC is not upto date with
1085 12 Jun 10 peter 105     // repo an exception is thrown. This avoids several costly
1085 12 Jun 10 peter 106     // statements below and will not remove a digest tree below if a
1085 12 Jun 10 peter 107     // tree already exists.
1068 06 Jun 10 peter 108     if (option.verbose())
1085 12 Jun 10 peter 109       std::cout << "Building directory tree" << std::endl;
1264 02 Nov 10 peter 110     Directory tree(0,option.root(),"", option.root_basename());
123 29 Jul 06 jari 111
1234 23 Oct 10 peter 112     if (option.report())
1234 23 Oct 10 peter 113       prepare_report(option, repo, tree);
1234 23 Oct 10 peter 114
1085 12 Jun 10 peter 115     if (option.verbose())
1085 12 Jun 10 peter 116       std::cout << "Parsing directory tree" << std::endl;
315 17 May 07 peter 117
1234 23 Oct 10 peter 118     SvndigestVisitor visitor(option.verbose(), option.ignore_cache(),
1535 06 Oct 12 peter 119                              option.report(), option.update());
1234 23 Oct 10 peter 120     tree.traverse(visitor);
1254 31 Oct 10 peter 121     NodeCounter file_count;
1254 31 Oct 10 peter 122     tree.traverse(file_count);
1234 23 Oct 10 peter 123
1085 12 Jun 10 peter 124     if (option.report())
1513 23 Sep 12 peter 125       print_main_page(tree.name(), tree.log(), tree.stats(),
1290 12 Nov 10 peter 126                       tree.svn_info().url(), file_count);
159 14 Aug 06 jari 127
1423 16 Dec 11 peter 128     CacheRemover cache_remover(option.verbose(), ".svndigest-cache");
1423 16 Dec 11 peter 129     tree.traverse(cache_remover);
198 09 Sep 06 peter 130   }
1085 12 Jun 10 peter 131   catch (std::runtime_error& e) {
1085 12 Jun 10 peter 132     std::cerr << "svndigest: " << e.what() << "\n";
1085 12 Jun 10 peter 133     return EXIT_FAILURE;
1085 12 Jun 10 peter 134   }
198 09 Sep 06 peter 135
1068 06 Jun 10 peter 136   if (option.verbose())
195 07 Sep 06 jari 137     std::cout << "Done!" << std::endl;
1085 12 Jun 10 peter 138   return EXIT_SUCCESS;        // normal exit
40 13 Jan 06 peter 139 }
497 14 Oct 07 peter 140
1069 06 Jun 10 peter 141
1069 06 Jun 10 peter 142 void copy_option2config(const svndigestParameter& option, Configuration& config)
1069 06 Jun 10 peter 143 {
1069 06 Jun 10 peter 144   try {
1513 23 Sep 12 peter 145     if (option.format().present())
1069 06 Jun 10 peter 146       Configuration::instance().image_format(option.format().value());
1069 06 Jun 10 peter 147   }
1069 06 Jun 10 peter 148   catch (std::runtime_error& e) {
1069 06 Jun 10 peter 149     std::stringstream ss;
1513 23 Sep 12 peter 150     ss << "invalid argument `"
1513 23 Sep 12 peter 151        << option.format().value() << "' for `--"
1069 06 Jun 10 peter 152        << option.format().long_name() << "'\n"
1069 06 Jun 10 peter 153        << e.what() << "\n"
1513 23 Sep 12 peter 154        << "Try `svndigest --help' for more information.\n";
1069 06 Jun 10 peter 155     throw std::runtime_error(ss.str());
1069 06 Jun 10 peter 156   }
1069 06 Jun 10 peter 157   try {
1513 23 Sep 12 peter 158     if (option.anchor_format().present())
1069 06 Jun 10 peter 159       config.image_anchor_format(option.anchor_format().value());
1069 06 Jun 10 peter 160   }
1069 06 Jun 10 peter 161   catch (std::runtime_error& e) {
1069 06 Jun 10 peter 162     std::stringstream ss;
1513 23 Sep 12 peter 163     ss << "invalid argument `"
1513 23 Sep 12 peter 164        << option.anchor_format().value() << "' for `--"
1069 06 Jun 10 peter 165        << option.anchor_format().long_name() << "'\n"
1069 06 Jun 10 peter 166        << e.what() << "\n"
1513 23 Sep 12 peter 167        << "Try `svndigest --help' for more information.\n";
1069 06 Jun 10 peter 168     throw std::runtime_error(ss.str());
1069 06 Jun 10 peter 169   }
1069 06 Jun 10 peter 170 }
1069 06 Jun 10 peter 171
1069 06 Jun 10 peter 172
1513 23 Sep 12 peter 173 void create_file_struct(std::string stats_type,
1085 12 Jun 10 peter 174                         const theplu::svndigest::Stats& stats)
1085 12 Jun 10 peter 175 {
1085 12 Jun 10 peter 176   using namespace theplu::svndigest;
1675 26 Aug 23 peter 177   yat::utility::mkdir(stats_type);
1085 12 Jun 10 peter 178   touch(stats_type+std::string("index.html"));
1675 26 Aug 23 peter 179   yat::utility::mkdir(stats_type+std::string("all"));
1675 26 Aug 23 peter 180   yat::utility::mkdir(stats_type+std::string("images"));
1085 12 Jun 10 peter 181   touch(stats_type+std::string("all/index.html"));
1085 12 Jun 10 peter 182   touch(stats_type+std::string("images/index.html"));
1085 12 Jun 10 peter 183   for (std::set<std::string>::const_iterator i = stats.authors().begin();
1085 12 Jun 10 peter 184        i!=stats.authors().end(); ++i) {
1675 26 Aug 23 peter 185     yat::utility::mkdir(stats_type+*i);
1085 12 Jun 10 peter 186     touch(stats_type+*i+std::string("/index.html"));
497 14 Oct 07 peter 187   }
1085 12 Jun 10 peter 188 }
1085 12 Jun 10 peter 189
1085 12 Jun 10 peter 190 void remove_target(const std::string& target_path, bool verbose)
1085 12 Jun 10 peter 191 {
1085 12 Jun 10 peter 192   if (verbose)
1257 01 Nov 10 peter 193     std::cout << "Removing old target tree: '" << target_path << "'\n";
1085 12 Jun 10 peter 194   rmdirhier(target_path);
1085 12 Jun 10 peter 195   // exit if remove failed
1085 12 Jun 10 peter 196   if (node_exist(target_path))
1085 12 Jun 10 peter 197     throw std::runtime_error("remove failed");
1085 12 Jun 10 peter 198 }
1085 12 Jun 10 peter 199
1085 12 Jun 10 peter 200
1255 01 Nov 10 peter 201 void set_dates(const svndigest::SVNlog& log)
1085 12 Jun 10 peter 202 {
1280 06 Nov 10 peter 203   // Fill in dates for revisions in log.
1255 01 Nov 10 peter 204   std::vector<time_t> dates(log.latest_commit().revision()+1, 0);
1085 12 Jun 10 peter 205   for (SVNlog::container::const_iterator iter=log.commits().begin();
1085 12 Jun 10 peter 206        iter!=log.commits().end(); ++iter) {
1255 01 Nov 10 peter 207     assert(iter->revision()<static_cast<svn_revnum_t>(dates.size()));
1255 01 Nov 10 peter 208     dates[iter->revision()] = Date(iter->date()).seconds();
1085 12 Jun 10 peter 209   }
1280 06 Nov 10 peter 210   // Fill in dates for revs not seen in log
1280 06 Nov 10 peter 211   time_t prev = dates[log.commits().begin()->revision()];
1280 06 Nov 10 peter 212   for (size_t i=0; i<dates.size(); ++i) {
1280 06 Nov 10 peter 213     if (dates[i]==0)
1280 06 Nov 10 peter 214       dates[i] = prev;
1280 06 Nov 10 peter 215     else
1280 06 Nov 10 peter 216       prev = dates[i];
1280 06 Nov 10 peter 217   }
1255 01 Nov 10 peter 218
1085 12 Jun 10 peter 219   // all plots uses the same dates
1085 12 Jun 10 peter 220   Graph::set_dates(dates);
1085 12 Jun 10 peter 221 }
1085 12 Jun 10 peter 222
1234 23 Oct 10 peter 223 void prepare_report(const svndigestParameter& option, const std::string& repo,
1513 23 Sep 12 peter 224                     const Node& tree)
1085 12 Jun 10 peter 225 {
1675 26 Aug 23 peter 226   std::string target_path =
1675 26 Aug 23 peter 227     concatenate_path(option.targetdir(),
1675 26 Aug 23 peter 228                      yat::utility::basename(option.root()));
1085 12 Jun 10 peter 229   // remove target if needed
1534 06 Oct 12 peter 230   if (node_exist(target_path) && option.force()) {
1085 12 Jun 10 peter 231     remove_target(target_path, option.verbose());
1085 12 Jun 10 peter 232   }
1513 23 Sep 12 peter 233
1280 06 Nov 10 peter 234   if (option.verbose())
1280 06 Nov 10 peter 235     std::cout << "Retrieving log information" << std::endl;
1280 06 Nov 10 peter 236   assert(!tree.log().commits().empty());
1280 06 Nov 10 peter 237   Graph::rev_min(tree.log().commits().begin()->revision());
1280 06 Nov 10 peter 238   Graph::rev_max(tree.log().latest_commit().revision());
1255 01 Nov 10 peter 239   if (!option.revisions()) {
1255 01 Nov 10 peter 240     set_dates(tree.log());
1255 01 Nov 10 peter 241   }
1085 12 Jun 10 peter 242
1675 26 Aug 23 peter 243   yat::utility::chdir(option.targetdir());
1085 12 Jun 10 peter 244
1085 12 Jun 10 peter 245   if (option.verbose())
1085 12 Jun 10 peter 246     std::cout << "Generating output" << std::endl;
1675 26 Aug 23 peter 247   yat::utility::mkdir_p(option.root_basename());
1675 26 Aug 23 peter 248   yat::utility::chdir(option.root_basename());
1085 12 Jun 10 peter 249   print_css("svndigest.css");
1085 12 Jun 10 peter 250 }