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
795 30 Jun 09 peter 46 #include "yat/Exception.h"
1015 09 Jan 10 peter 47 #include "yat/OptionArg.h"
795 30 Jun 09 peter 48
1280 06 Nov 10 peter 49 #include <algorithm>
315 17 May 07 peter 50 #include <cassert>
896 26 Nov 09 peter 51 #include <cstdlib>
1197 04 Oct 10 peter 52 #include <ctime>
92 23 Mar 06 jari 53 #include <iostream>
129 02 Aug 06 jari 54 #include <fstream>
49 14 Jan 06 jari 55 #include <stdexcept>
49 14 Jan 06 jari 56 #include <string>
49 14 Jan 06 jari 57 #include <sys/stat.h>
49 14 Jan 06 jari 58 #include <unistd.h>
49 14 Jan 06 jari 59
1069 06 Jun 10 peter 60 using namespace theplu;
1069 06 Jun 10 peter 61 using namespace svndigest;
1069 06 Jun 10 peter 62 void copy_option2config(const svndigestParameter&, Configuration&);
1069 06 Jun 10 peter 63
1513 23 Sep 12 peter 64 void create_file_struct(std::string stats_type,
497 14 Oct 07 peter 65                         const theplu::svndigest::Stats& stats);
497 14 Oct 07 peter 66
1234 23 Oct 10 peter 67 void prepare_report(const svndigestParameter& option, const std::string& repo,
1234 23 Oct 10 peter 68                     const Node& tree);
1085 12 Jun 10 peter 69
518 20 Dec 07 peter 70 int main( int argc, char* argv[])
40 13 Jan 06 peter 71 {
229 25 Mar 07 peter 72   // Reading commandline options
1068 06 Jun 10 peter 73   svndigestParameter option;
104 27 Jun 06 peter 74   try {
1068 06 Jun 10 peter 75     option.parse(argc,argv);
1068 06 Jun 10 peter 76     if (option.verbose())
195 07 Sep 06 jari 77       std::cout << "Done parsing parameters" << std::endl;
104 27 Jun 06 peter 78   }
795 30 Jun 09 peter 79   catch (yat::utility::cmd_error& e) {
104 27 Jun 06 peter 80     std::cerr << e.what() << std::endl;
896 26 Nov 09 peter 81     exit(EXIT_FAILURE);
104 27 Jun 06 peter 82   }
1085 12 Jun 10 peter 83   catch (std::runtime_error& e) {
1086 12 Jun 10 peter 84     std::cerr << "svndigest: " << e.what() << std::endl;
1085 12 Jun 10 peter 85     return EXIT_FAILURE;
1085 12 Jun 10 peter 86   }
40 13 Jan 06 peter 87
1067 06 Jun 10 peter 88   try {
1102 15 Jun 10 peter 89     load_config(option.config_file(), option.verbose());
1069 06 Jun 10 peter 90     copy_option2config(option, Configuration::instance());
1070 06 Jun 10 peter 91     if (option.generate_config()) {
1070 06 Jun 10 peter 92       std::cout << Configuration::instance();
1070 06 Jun 10 peter 93       return EXIT_SUCCESS;
1070 06 Jun 10 peter 94     }
1072 06 Jun 10 peter 95
1072 06 Jun 10 peter 96     if (option.verbose())
1072 06 Jun 10 peter 97       std::cout << "Initializing SVN singleton." << std::endl;
1072 06 Jun 10 peter 98     SVN::instance(option.root());
1015 09 Jan 10 peter 99
1085 12 Jun 10 peter 100     // Extract repository location
1085 12 Jun 10 peter 101     std::string repo=SVNinfo(option.root()).repos_root_url();
1085 12 Jun 10 peter 102
1085 12 Jun 10 peter 103     // build directory tree already here ... if WC is not upto date with
1085 12 Jun 10 peter 104     // repo an exception is thrown. This avoids several costly
1085 12 Jun 10 peter 105     // statements below and will not remove a digest tree below if a
1085 12 Jun 10 peter 106     // tree already exists.
1068 06 Jun 10 peter 107     if (option.verbose())
1085 12 Jun 10 peter 108       std::cout << "Building directory tree" << std::endl;
1264 02 Nov 10 peter 109     Directory tree(0,option.root(),"", option.root_basename());
123 29 Jul 06 jari 110
1234 23 Oct 10 peter 111     if (option.report())
1234 23 Oct 10 peter 112       prepare_report(option, repo, tree);
1234 23 Oct 10 peter 113
1085 12 Jun 10 peter 114     if (option.verbose())
1085 12 Jun 10 peter 115       std::cout << "Parsing directory tree" << std::endl;
315 17 May 07 peter 116
1234 23 Oct 10 peter 117     SvndigestVisitor visitor(option.verbose(), option.ignore_cache(),
1535 06 Oct 12 peter 118                              option.report(), option.update());
1234 23 Oct 10 peter 119     tree.traverse(visitor);
1254 31 Oct 10 peter 120     NodeCounter file_count;
1254 31 Oct 10 peter 121     tree.traverse(file_count);
1234 23 Oct 10 peter 122
1085 12 Jun 10 peter 123     if (option.report())
1513 23 Sep 12 peter 124       print_main_page(tree.name(), tree.log(), tree.stats(),
1290 12 Nov 10 peter 125                       tree.svn_info().url(), file_count);
159 14 Aug 06 jari 126
1423 16 Dec 11 peter 127     CacheRemover cache_remover(option.verbose(), ".svndigest-cache");
1423 16 Dec 11 peter 128     tree.traverse(cache_remover);
198 09 Sep 06 peter 129   }
1085 12 Jun 10 peter 130   catch (std::runtime_error& e) {
1085 12 Jun 10 peter 131     std::cerr << "svndigest: " << e.what() << "\n";
1085 12 Jun 10 peter 132     return EXIT_FAILURE;
1085 12 Jun 10 peter 133   }
198 09 Sep 06 peter 134
1068 06 Jun 10 peter 135   if (option.verbose())
195 07 Sep 06 jari 136     std::cout << "Done!" << std::endl;
1085 12 Jun 10 peter 137   return EXIT_SUCCESS;        // normal exit
40 13 Jan 06 peter 138 }
497 14 Oct 07 peter 139
1069 06 Jun 10 peter 140
1069 06 Jun 10 peter 141 void copy_option2config(const svndigestParameter& option, Configuration& config)
1069 06 Jun 10 peter 142 {
1069 06 Jun 10 peter 143   try {
1513 23 Sep 12 peter 144     if (option.format().present())
1069 06 Jun 10 peter 145       Configuration::instance().image_format(option.format().value());
1069 06 Jun 10 peter 146   }
1069 06 Jun 10 peter 147   catch (std::runtime_error& e) {
1069 06 Jun 10 peter 148     std::stringstream ss;
1513 23 Sep 12 peter 149     ss << "invalid argument `"
1513 23 Sep 12 peter 150        << option.format().value() << "' for `--"
1069 06 Jun 10 peter 151        << option.format().long_name() << "'\n"
1069 06 Jun 10 peter 152        << e.what() << "\n"
1513 23 Sep 12 peter 153        << "Try `svndigest --help' for more information.\n";
1069 06 Jun 10 peter 154     throw std::runtime_error(ss.str());
1069 06 Jun 10 peter 155   }
1069 06 Jun 10 peter 156   try {
1513 23 Sep 12 peter 157     if (option.anchor_format().present())
1069 06 Jun 10 peter 158       config.image_anchor_format(option.anchor_format().value());
1069 06 Jun 10 peter 159   }
1069 06 Jun 10 peter 160   catch (std::runtime_error& e) {
1069 06 Jun 10 peter 161     std::stringstream ss;
1513 23 Sep 12 peter 162     ss << "invalid argument `"
1513 23 Sep 12 peter 163        << option.anchor_format().value() << "' for `--"
1069 06 Jun 10 peter 164        << option.anchor_format().long_name() << "'\n"
1069 06 Jun 10 peter 165        << e.what() << "\n"
1513 23 Sep 12 peter 166        << "Try `svndigest --help' for more information.\n";
1069 06 Jun 10 peter 167     throw std::runtime_error(ss.str());
1069 06 Jun 10 peter 168   }
1069 06 Jun 10 peter 169 }
1069 06 Jun 10 peter 170
1069 06 Jun 10 peter 171
1513 23 Sep 12 peter 172 void create_file_struct(std::string stats_type,
1085 12 Jun 10 peter 173                         const theplu::svndigest::Stats& stats)
1085 12 Jun 10 peter 174 {
1085 12 Jun 10 peter 175   using namespace theplu::svndigest;
1085 12 Jun 10 peter 176   mkdir(stats_type);
1085 12 Jun 10 peter 177   touch(stats_type+std::string("index.html"));
1085 12 Jun 10 peter 178   mkdir(stats_type+std::string("all"));
1085 12 Jun 10 peter 179   mkdir(stats_type+std::string("images"));
1085 12 Jun 10 peter 180   touch(stats_type+std::string("all/index.html"));
1085 12 Jun 10 peter 181   touch(stats_type+std::string("images/index.html"));
1085 12 Jun 10 peter 182   for (std::set<std::string>::const_iterator i = stats.authors().begin();
1085 12 Jun 10 peter 183        i!=stats.authors().end(); ++i) {
1085 12 Jun 10 peter 184     mkdir(stats_type+*i);
1085 12 Jun 10 peter 185     touch(stats_type+*i+std::string("/index.html"));
497 14 Oct 07 peter 186   }
1085 12 Jun 10 peter 187 }
1085 12 Jun 10 peter 188
1085 12 Jun 10 peter 189 void remove_target(const std::string& target_path, bool verbose)
1085 12 Jun 10 peter 190 {
1085 12 Jun 10 peter 191   if (verbose)
1257 01 Nov 10 peter 192     std::cout << "Removing old target tree: '" << target_path << "'\n";
1085 12 Jun 10 peter 193   rmdirhier(target_path);
1085 12 Jun 10 peter 194   // exit if remove failed
1085 12 Jun 10 peter 195   if (node_exist(target_path))
1085 12 Jun 10 peter 196     throw std::runtime_error("remove failed");
1085 12 Jun 10 peter 197 }
1085 12 Jun 10 peter 198
1085 12 Jun 10 peter 199
1255 01 Nov 10 peter 200 void set_dates(const svndigest::SVNlog& log)
1085 12 Jun 10 peter 201 {
1280 06 Nov 10 peter 202   // Fill in dates for revisions in log.
1255 01 Nov 10 peter 203   std::vector<time_t> dates(log.latest_commit().revision()+1, 0);
1085 12 Jun 10 peter 204   for (SVNlog::container::const_iterator iter=log.commits().begin();
1085 12 Jun 10 peter 205        iter!=log.commits().end(); ++iter) {
1255 01 Nov 10 peter 206     assert(iter->revision()<static_cast<svn_revnum_t>(dates.size()));
1255 01 Nov 10 peter 207     dates[iter->revision()] = Date(iter->date()).seconds();
1085 12 Jun 10 peter 208   }
1280 06 Nov 10 peter 209   // Fill in dates for revs not seen in log
1280 06 Nov 10 peter 210   time_t prev = dates[log.commits().begin()->revision()];
1280 06 Nov 10 peter 211   for (size_t i=0; i<dates.size(); ++i) {
1280 06 Nov 10 peter 212     if (dates[i]==0)
1280 06 Nov 10 peter 213       dates[i] = prev;
1280 06 Nov 10 peter 214     else
1280 06 Nov 10 peter 215       prev = dates[i];
1280 06 Nov 10 peter 216   }
1255 01 Nov 10 peter 217
1085 12 Jun 10 peter 218   // all plots uses the same dates
1085 12 Jun 10 peter 219   Graph::set_dates(dates);
1085 12 Jun 10 peter 220 }
1085 12 Jun 10 peter 221
1234 23 Oct 10 peter 222 void prepare_report(const svndigestParameter& option, const std::string& repo,
1513 23 Sep 12 peter 223                     const Node& tree)
1085 12 Jun 10 peter 224 {
1513 23 Sep 12 peter 225   std::string target_path = concatenate_path(option.targetdir(),
1085 12 Jun 10 peter 226                                              file_name(option.root()));
1085 12 Jun 10 peter 227   // remove target if needed
1534 06 Oct 12 peter 228   if (node_exist(target_path) && option.force()) {
1085 12 Jun 10 peter 229     remove_target(target_path, option.verbose());
1085 12 Jun 10 peter 230   }
1513 23 Sep 12 peter 231
1280 06 Nov 10 peter 232   if (option.verbose())
1280 06 Nov 10 peter 233     std::cout << "Retrieving log information" << std::endl;
1280 06 Nov 10 peter 234   assert(!tree.log().commits().empty());
1280 06 Nov 10 peter 235   Graph::rev_min(tree.log().commits().begin()->revision());
1280 06 Nov 10 peter 236   Graph::rev_max(tree.log().latest_commit().revision());
1255 01 Nov 10 peter 237   if (!option.revisions()) {
1255 01 Nov 10 peter 238     set_dates(tree.log());
1255 01 Nov 10 peter 239   }
1085 12 Jun 10 peter 240
1085 12 Jun 10 peter 241   chdir(option.targetdir());
1085 12 Jun 10 peter 242
1085 12 Jun 10 peter 243   if (option.verbose())
1085 12 Jun 10 peter 244     std::cout << "Generating output" << std::endl;
1534 06 Oct 12 peter 245   mkdir_p(option.root_basename());
1264 02 Nov 10 peter 246   chdir(option.root_basename());
1085 12 Jun 10 peter 247   print_css("svndigest.css");
1085 12 Jun 10 peter 248 }