Changeset 705 for trunk/bin


Ignore:
Timestamp:
Nov 26, 2008, 12:33:26 AM (13 years ago)
Author:
Peter Johansson
Message:

importing classes for commandline parsing from yat. This fixes #349 and #265

Location:
trunk/bin
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/bin/Parameter.cc

    r699 r705  
    2424
    2525#include "ColumnStream.h"
    26 #include "subversion_info.h"
     26#include "OptionArg.h"
     27#include "OptionHelp.h"
     28#include "OptionSwitch.h"
     29#include "OptionVersion.h"
    2730#include "utility.h"
    2831#include <config.h> // this header file is created by configure
    2932
     33#include <cassert>
     34#include <cerrno>
    3035#include <cstddef>
    3136#include <fstream>
     
    4045
    4146  Parameter::Parameter( int argc, char *argv[])
    42     : config_file_(""), copyright_(false), force_(false),
    43       generate_config_(false), ignore_cache_(true), report_(true),
    44       revisions_(false), root_("."), root_node_("."), targetdir_("."),
    45       verbose_(false)
    46   {
    47     for (int i=1; i<argc; ++i) {
    48       std::stringstream ss(argv[i]);
    49       std::string myargv("");
    50       std::string value("");
    51       getline(ss, myargv, '=');
    52       getline(ss, value);
    53 
    54       if (myargv=="--config-file"){
    55         if (value.size()) {
    56           config_file_.value()= value;
     47    : cmd_(
     48     "Mandatory arguments to long options are mandatory for short options too.")
     49  {
     50    init();
     51    try {
     52      cmd_.parse(argc, argv);
     53    }
     54    catch (cmd_error& e) {
     55      std::cerr << e.what() << std::endl;
     56      exit (-1);
     57    }
     58
     59    // set default values
     60    if (!root_->present())
     61      root_->value(".");
     62
     63    if (!target_->present())
     64      target_->value(".");
     65
     66    if (!config_file_->present())
     67      config_file_->value(root_->value()+"/.svndigest/config");
     68
     69    // analyse arguments
     70    analyse();
     71  }
     72
     73
     74  Parameter::~Parameter(void)
     75  {
     76    delete config_file_;
     77    delete copyright_;
     78    delete force_;
     79    delete generate_config_;
     80    delete help_;
     81    delete ignore_cache_;
     82    delete report_;
     83    delete revisions_;
     84    delete root_;
     85    delete target_;
     86    delete verbose_;
     87    delete version_;
     88  }
     89
     90
     91  void Parameter::analyse(void)
     92  {
     93    std::string save_wd = pwd();
     94
     95    // check root but not if -g option given
     96    if (!generate_config()) {
     97      check_existence(root_->value());
     98      check_readable(root_->value());
     99      if (chdir(root_->value().c_str())) {
     100        std::stringstream ss;
     101        ss << "svndigest: cannot read `" << root_->value() << "': "
     102           << strerror(errno);
     103        throw cmd_error(ss.str());
     104      }
     105      root_->value(pwd());
     106      chdir(save_wd.c_str());
     107
     108      // check target (only if we write report)
     109      if (report()) {
     110        check_existence(target_->value());
     111        check_readable(target_->value());
     112        std::string base_root = file_name(root_->value());
     113        std::string path = concatenate_path(target_->value(),base_root);
     114        if (access_rights(target_->value().c_str(), "w")) {
     115          std::stringstream ss;
     116          ss << "svndigest: cannot create directory `" << path
     117             << "': " << strerror(errno);
     118          throw cmd_error(ss.str());
    57119        }
    58         else if (++i<argc){
    59           config_file_.value()= std::string(argv[i]);
     120        if (node_exist(path) && !force()) {
     121          std::stringstream ss;
     122          ss << "svndigest: cannot create directory `" << path << "' "
     123             << strerror(EEXIST);
     124          throw cmd_error(ss.str());
    60125        }
    61         else {
    62           missing_argument(myargv);
     126        if (chdir(target_->value().c_str())) {
     127          std::stringstream ss;
     128          ss << "svndigest: cannot read `" << target_->value() << "': "
     129             << strerror(errno);
     130          throw cmd_error(ss.str());
    63131        }
     132        target_->value(concatenate_path(pwd(), base_root));
     133        chdir(save_wd.c_str());
    64134      }
    65       else if (myargv=="--copyright"){
    66           copyright_.value()=true;
     135    }
     136
     137    // check config file
     138    if (config_file_->present())
     139      check_existence(config_file_->value());
     140    if (node_exist(config_file_->value())) {
     141      check_readable(config_file_->value());
     142      struct stat nodestat;
     143      stat(config_file_->value().c_str(), &nodestat);
     144      if (!S_ISREG(nodestat.st_mode)) {
     145        std::stringstream ss;
     146        ss << "svndigest: `" << root_->value() << "' is not a regular file";
     147        throw cmd_error(ss.str());
    67148      }
    68       else if (myargv=="-f" || myargv=="--force"){
    69           force_.value()=true;
    70       }
    71       else if (myargv=="-g" || myargv=="--generate-config"){
    72           generate_config_.value()=true;
    73       }
    74       else if (myargv=="-h" || myargv=="--help"){
    75         help();
    76         exit(0);      // always exit after printing help
    77       }
    78       else if (myargv=="--ignore-cache"){
    79           ignore_cache_.value()=true;
    80       }
    81       else if (myargv=="-r" || myargv=="--root"){
    82         if (value.size()) {
    83           root_.value()= value;
    84         }
    85         else if (++i<argc){
    86           root_.value()= std::string(argv[i]);
    87         }
    88         else {
    89           missing_argument(myargv);
    90         }
    91       }
    92       else if (myargv=="--report") {
    93           report_.value()=true;
    94       }
    95       else if (myargv=="--no-report") {
    96           report_.value()=false;
    97       }
    98       else if (myargv=="--revisions") {
    99           revisions_.value()=true;
    100       }
    101       else if (myargv=="-t" || myargv=="--target"){
    102         if (value.size()) {
    103           targetdir_.value()= value;
    104         }
    105         else if (++i<argc){
    106           targetdir_.value()= std::string(argv[i]);
    107         }
    108         else {
    109           missing_argument(myargv);
    110         }
    111       }
    112       else if (myargv=="-v" || myargv=="--verbose"){
    113           verbose_.value()=true;
    114       }
    115       else if (myargv=="--version"){
    116         version();
    117         exit(0);
    118       }
    119       else if (myargv=="-vf" || myargv=="-fv"){
    120           verbose_.value()=true;
    121           force_.value()=true;
    122       }
    123       else {
    124         throw std::runtime_error("svndigest: invalid option: " + myargv +
    125                                  "\nTry `svndigest --help' for usage.");
    126       }
    127   }
    128 
    129     analyse();
    130   }
    131 
    132 
    133   void Parameter::analyse(void)
    134   {
    135     using namespace std;
    136 
    137     string workdir(pwd()); // remember current working directory (cwd).
    138 
    139     if (!node_exist(root_.value()))
    140       throw runtime_error(string("svndigest: cannot stat `" + root_.value() +
    141                                  "': no such file or directory"));
    142 
    143     if (access_rights(root_.value(), "r"))
    144       throw runtime_error(string("svndigest: cannot open `" + root_.value() +
    145                                  "' for reading: Permission denied"));
    146 
    147     // Check whether root is directory or file
    148     struct stat nodestat;
    149     stat(root_.value().c_str(), &nodestat);
    150     if (S_ISDIR(nodestat.st_mode)) {
    151       chdir(root_.value().c_str());
    152       root_node_.value() = root_.value() = pwd();
    153     }
    154     else {
    155       std::string fname = file_name(root_.value());
    156       root_.value() = directory_name(root_.value());
    157       chdir(root_.value().c_str());
    158       root_.value() = pwd();
    159       root_node_.value() = root_.value() + "/" + fname;
    160     }
    161 
    162     // need to get back to cwd if relative paths are used.
    163     if (chdir(workdir.c_str()))
    164       runtime_error(string("svndigest: Failed to access cwd: ") + workdir);
    165 
    166     // Checking that targetdir_ exists and retrieve the absolute path
    167     // to targetdir_
    168     if (report()) {
    169       if (chdir(targetdir_.value().c_str()))
    170         throw runtime_error(string("svndigest: Target directory (") +
    171                             targetdir_.value() + ") access failed.");
    172       targetdir_.value() = pwd();
    173       // Checking write permissions for targetdir_
    174       if (access_rights(targetdir_.value(),"w"))
    175         throw runtime_error(string("svndigest: No write permission on target ") +
    176                             "directory (" + targetdir_.value() +").");
    177     }
    178 
    179     // return back to cwd
    180     if (chdir(workdir.c_str()))
    181       throw runtime_error(string("svndigest: Failed to access cwd: ") + workdir);
    182 
    183   }
    184 
     149    }
     150  }
     151
     152
     153  void Parameter::check_existence(std::string path) const
     154  {
     155    if (node_exist(path))
     156      return;
     157    std::stringstream ss;
     158    ss << "svndigest: cannot stat `" << path << "': " << strerror(errno);
     159    throw cmd_error(ss.str());
     160  }
     161
     162 
     163  void Parameter::check_readable(std::string path) const
     164  {
     165    if (!access_rights(path, "r"))
     166      return;
     167    std::stringstream ss;
     168    ss << "svndigest: cannot open `" << path << "': " << strerror(errno);
     169    throw cmd_error(ss.str());
     170  }
     171 
    185172
    186173  std::string Parameter::config_file(void) const
    187174  {
    188     // not default
    189     if (!config_file_.value().empty())
    190       return config_file_.value();
     175    return config_file_->value();
     176  }
     177
     178
     179  bool Parameter::copyright(void) const
     180  {
     181    return copyright_->present();
     182  }
     183
     184
     185  bool Parameter::force(void) const
     186  {
     187    return force_->present();
     188  }
     189
     190
     191  bool Parameter::generate_config(void) const
     192  {
     193    return generate_config_->present();
     194  }
     195
     196
     197  bool Parameter::ignore_cache(void) const
     198  {
     199    return ignore_cache_->present();
     200  }
     201
     202
     203  void Parameter::init(void)
     204  {
     205    // don't use argv[0] because user may rename the binary
     206    cmd_.program_name() = PACKAGE_NAME;
     207    config_file_=new OptionArg<std::string>(cmd_, "config-file",
     208                                "configuration file [<ROOT>/.svndigest/config]");
     209    config_file_->print_arg("=FILE");
     210    std::stringstream ss;
     211    copyright_ = new OptionSwitch(cmd_, "copyright",
     212                                  "update copyright statement");
     213
     214    ss << "if sub-directory named <ROOT> exists in target directory, remove "
     215       << "sub-directory before writing results";
     216    force_ = new OptionSwitch(cmd_, "f,force", ss.str());
     217    ss.str("");
     218
     219    help_ = new OptionHelp(cmd_);
     220    generate_config_ =
     221      new OptionSwitch(cmd_, "g,generate-config",
     222                       "write configuration file to standard output");
     223
     224    ss.str("");
     225    ss << "ignore cache files and analyze everything from repository";
     226    ignore_cache_ = new OptionSwitch(cmd_, "ignore-cache", ss.str());
     227         
     228    report_ = new OptionSwitch(cmd_, "report", "create no HTML report", true);
     229
     230    ss.str("");
     231    ss << "use revision numbers as time scale instead of dates [dates]";
     232    revisions_ = new OptionSwitch(cmd_, "revisions", ss.str());
     233
     234    root_=
     235      new OptionArg<std::string>(cmd_, "r,root",
     236                     "svn controlled directory to perform statistics on [.]");
     237    root_->print_arg("=ROOT");
     238    target_ = new OptionArg<std::string>(cmd_, "t,target",
     239                                         "output directory [.]");
     240    target_->print_arg("=TARGET");
    191241   
    192     // default behaviour
    193     return root()+"/.svndigest/config";
    194   }
    195 
    196 
    197   void Parameter::help(void) const
    198   {
    199     ColumnStream cs(std::cout, 1);
    200     cs.width(0)=79;
    201     cs.margin(0)=0;
    202     ColumnStream cs2(std::cout, 2);
    203     // Widest line should fit exactly
    204     cs2.width(0)=21;
    205     cs2.width(1)=52;
    206     cs2.margin(0)=2;
    207     // Gnits standard suggest three characters gap between option and description
    208     cs2.margin(1)=3;
    209 
    210     std::cout << "Usage: svndigest [OPTION]...\n"
    211               << "\n";
    212 
    213     cs << "Generate statistical report for a subversion repository.\n";
    214 
    215     cs << "\nMandatory arguments to long options are mandatory for "
    216        << "short options too.\n";
    217 
    218     cs2  << "    --config-file=ARG\tconfiguration file "
    219          << "[<ROOT>/.svndigest/config]\n"
    220          << "    --copyright\tupdate copyright statement\n"
    221          << "-f, --force\tif sub-directory named <ROOT> exists in "
    222          << "target directory, remove sub-directory before writing results\n"
    223          << "-g, --generate-config\twrite configuration file "
    224          << "to standard output and exit\n"
    225          << "-h, --help\tdisplay this help and exit\n"
    226          << "    --ignore-cache\tignore cache files and analyze "
    227          << "everything from repository\n"
    228          << "    --no-report\tcreate no HTML report\n"
    229          << "    --revisions\tuse revision numbers as time scale "
    230          << "instead of dates [dates]\n"
    231          << "-r, --root=ROOT\tsvn controlled directory to perform "
    232          << "statistics calculation on [" << root_.default_value() << "]\n"
    233          << "-t, --target=TARGET\toutput directory ["
    234          << targetdir_.default_value() << "]\n"
    235          << "-v, --verbose\texplain what is being done\n"
    236          << "    --version\tprint version information and exit\n";
    237 
    238     std::cout << "\nReport bugs to <" << PACKAGE_BUGREPORT << ">."
    239               << std::endl;
    240   }
    241 
    242 
    243   void Parameter::missing_argument(std::string opt) const
    244   {
    245     if (opt.size()>0 && opt[0]=='-')
    246       opt = opt.substr(1);
    247     if (opt.size()>0 && opt[0]=='-')
    248       opt = opt.substr(1);
    249     std::stringstream ss;
    250     ss << "svndigest: option requires an argument -- " << opt << "\n"
    251        << "Try `svndigest --help' for usage.";
    252     throw std::runtime_error(ss.str());
    253   }
    254 
    255   void Parameter::version(bool verbose) const
    256   {
    257     ColumnStream cs(std::cout, 1);
    258     cs.width(0)=79;
    259     cs << PACKAGE_STRING << version_string() << "\n";
    260     cs << "\nCopyright (C) " << svn_year()
    261        << " Jari H\u00E4kkinen and Peter Johansson.\n"
    262        << "This is free software. You may redistribute copies of it under "
    263        << "the terms of the GNU General Public License "
    264        << "<http://www.gnu.org/licenses/gpl.html>.\n"
    265        << "There is NO WARRANTY; to the extent permitted by law.\n";
    266   }
     242    verbose_ = new OptionSwitch(cmd_, "v,verbose", "explain what is being done");
     243    version_ = new OptionVersion(cmd_);
     244
     245    ss.str("");
     246    ss << "Report bugs to " << PACKAGE_BUGREPORT << ".\n";
     247    help_->post_arguments() = ss.str();
     248    help_->synopsis() =
     249      "Generate statistical report for a subversion repository\n";
     250  }
     251
     252
     253  bool Parameter::report(void) const
     254  {
     255    return report_->value();
     256  }
     257
     258
     259  bool Parameter::revisions(void) const
     260  {
     261    return revisions_->present();
     262  }
     263
     264
     265  std::string Parameter::root(void) const
     266  {
     267    return root_->value();
     268  }
     269
     270 
     271  std::string Parameter::targetdir(void) const
     272  {
     273    return target_->value();
     274  }
     275
     276 
     277  bool Parameter::verbose(void) const
     278  {
     279    return verbose_->present();
     280  }
     281
    267282
    268283}} // of namespace svndigest and namespace theplu
  • trunk/bin/Parameter.h

    r693 r705  
    2424*/
    2525
    26 #include "Option.h"
     26#include "CommandLine.h"
     27#include "OptionArg.h"
    2728
    28 #include <map>
    2929#include <string>
    3030
     
    3232namespace svndigest {
    3333
     34  class OptionHelp;
     35  class OptionSwitch;
     36  class OptionVersion;
     37
    3438  // class for command line options.
    3539  class Parameter {
    3640  public:
    3741    Parameter( int argc, char *argv[]);
     42    virtual ~Parameter(void);
    3843    std::string config_file(void) const;
    39     inline bool copyright(void) const { return copyright_.value(); }
    40     /// @todo
    41     inline bool force(void) const { return force_.value(); }
    42     inline bool generate_config(void) const { return generate_config_.value(); }
    43     inline bool ignore_cache(void) const { return ignore_cache_.value(); }
    44     inline bool report(void) const { return report_.value(); }
    45     inline bool revisions(void) const { return revisions_.value(); }
     44   
     45    bool copyright(void) const;
     46    bool force(void) const;
     47    bool generate_config(void) const ;
     48    bool ignore_cache(void) const;
     49    bool report(void) const;
     50    bool revisions(void) const;
    4651    /// @return absolute path to root directory
    47     inline const std::string& root(void) const { return root_.value(); }
    48     /// @return absolute path to root node
    49     inline const std::string& root_node(void) const {return root_node_.value();}
     52    std::string root(void) const;
    5053    /// @return absolute path to target directory
    51     inline const std::string& targetdir(void) const
    52     { return targetdir_.value(); }
    53     inline bool verbose(void) const { return verbose_.value(); }
     54    std::string targetdir(void) const;
     55    bool verbose(void) const;
    5456
    5557  private:
    5658    void analyse(void);
    57     void help(void) const;
    58     void missing_argument(std::string opt) const;
    59     void version(bool=false) const;
     59    // throw cmd_error if path doesn't exist
     60    void check_existence(std::string path) const;
     61    // throw cmd_error if path is not dir
     62    void check_is_dir(std::string path) const;
     63    // throw cmd_error if path is not readable
     64    void check_readable(std::string path) const;
    6065
    61     Option<std::string> config_file_;
    62     Option<bool> copyright_;
    63     Option<bool> force_;
    64     Option<bool> generate_config_;
    65     Option<bool> ignore_cache_;
    66     Option<bool> report_;
    67     Option<bool> revisions_;
    68     Option<std::string> root_;
    69     Option<std::string> root_node_;
    70     Option<std::string> targetdir_;
    71     Option<bool> verbose_;
     66    void init(void);
     67
     68    CommandLine cmd_;
     69    OptionArg<std::string>* config_file_;
     70    OptionSwitch* copyright_;
     71    OptionSwitch* force_;
     72    OptionSwitch* generate_config_;
     73    OptionHelp* help_;
     74    OptionSwitch* ignore_cache_;
     75    OptionSwitch* report_;
     76    OptionSwitch* revisions_;
     77    OptionArg<std::string>* root_;
     78    OptionArg<std::string>* target_;
     79    OptionSwitch* verbose_;
     80    OptionVersion* version_;
     81
    7282  };
    7383
  • trunk/bin/svndigest.cc

    r693 r705  
    2626#include "css.h"
    2727#include "Directory.h"
     28#include "Exception.h"
    2829#include "first_page.h"
    2930#include "GnuplotFE.h"
     
    5960      std::cout << "Done parsing parameters" << std::endl;
    6061  }
    61   catch (std::runtime_error e) {
     62  catch (cmd_error& e) {
    6263    std::cerr << e.what() << std::endl;
    6364    exit(-1);
Note: See TracChangeset for help on using the changeset viewer.