Commit b2f1f2fbe002a18ebefd72a08da559bf42d13ccf

Authored by Jürgen Knödlseder
1 parent ad5d7426

Support application specific system parameter files (#2513)

ChangeLog
1   -2018-06-13
  1 +2018-06-14
2 2  
3 3 * Version 1.6.0 released
4 4 ========================
5 5  
  6 + Support application specific system parameter files (#2513)
6 7 Add methods and operators to handle additional columns in GPha
7 8 Made GApplicationPar::query() method public
8 9 Fix handling of q-mode parameters (#2495)
... ...
1 1 New Features and Important Changes in GammaLib 1.6.0
2 2  
3   -13 June 2018
  3 +14 June 2018
4 4  
5 5  
6 6 1. Introduction
... ... @@ -27,6 +27,7 @@ The following methods have been added:
27 27 - GSkyDir::cos_dist()
28 28 - GApplicationPar::query()
29 29 - GApplicationPar::was_queried()
  30 +- GApplicationPars::syspfiles()
30 31 - operator==(GSkyPixel&, GSkyPixel&)
31 32 - operator!=(GSkyPixel&, GSkyPixel&)
32 33 - GPha::operator(int&, int&)
... ... @@ -84,6 +85,14 @@ Keep existing library path in installation script on Mac OS X (#2420)
84 85  
85 86 4. Application module
86 87 ---------------------
  88 +A GApplicationPars::syspfiles() setter and getter method was added to allow the
  89 +specification of an application specific system parameter file path. If such a
  90 +file path is specified, the loading of the application parameters needs to be
  91 +redone by the client. The GApplicationPars::load() methods now gives priority
  92 +to a parameter file found in the syspfiles folder and updates parameter values
  93 +using the parameter file found in the user's pfiles folder. In that way, any
  94 +changes in the parameter file structure should be handled transparently (#2513).
  95 +
87 96 The GApplicationPar::query() method was made public.
88 97  
89 98 Add GApplicationPar::was_queried() method and do no longer change the mode
... ...
doc/source/admin/release_history/1.6.rst
... ... @@ -30,6 +30,8 @@ Bug fixes
30 30 Improvements
31 31 ------------
32 32  
  33 +* [`2513 <https://cta-redmine.irap.omp.eu/issues/2513>`_] -
  34 + Support application specific system parameter files
33 35 * Add methods and operators to handle additional columns in ``GPha``
34 36 * Made ``GApplicationPar::query()`` method public
35 37 * [`2466 <https://cta-redmine.irap.omp.eu/issues/2466>`_] -
... ...
include/GApplicationPars.hpp
1 1 /***************************************************************************
2 2 * GApplicationPars.hpp - Application parameters *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2010-2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2010-2018 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -83,6 +83,8 @@ public:
83 83 void reserve(const int& num);
84 84 void extend(const GApplicationPars& pars);
85 85 bool contains(const std::string& name) const;
  86 + void syspfiles(const std::string& syspfiles);
  87 + const std::string& syspfiles(void) const;
86 88 void load(const GFilename& filename);
87 89 void load(const GFilename& filename,
88 90 const std::vector<std::string>& args);
... ... @@ -95,11 +97,14 @@ protected:
95 97 void copy_members(const GApplicationPars& pars);
96 98 void free_members(void);
97 99 std::string inpath(const std::string& filename) const;
  100 + std::string pfiles_path(const std::string& filename) const;
  101 + std::string syspfiles_path(const std::string& filename) const;
98 102 std::string outpath(const std::string& filename) const;
99 103 void read(const std::string& filename);
100 104 void write(const std::string& filename) const;
101 105 void parse(void);
102 106 void update(void);
  107 + void synchronise(const std::string& filename);
103 108 int get_index(const std::string& name) const;
104 109 std::string parline(GApplicationPar& par, size_t* start, size_t* stop) const;
105 110  
... ... @@ -110,6 +115,7 @@ protected:
110 115 std::vector<size_t> m_vstart; //!< Column of value start
111 116 std::vector<size_t> m_vstop; //!< Column of value stop
112 117 std::string m_mode; //!< Effective mode
  118 + std::string m_syspfiles; //!< Optional location of syspfiles
113 119 };
114 120  
115 121  
... ... @@ -184,7 +190,7 @@ bool GApplicationPars::is_empty(void) const
184 190 /***********************************************************************//**
185 191 * @brief Reserves space for parameters in container
186 192 *
187   - * @param[in] num Number of parameter
  193 + * @param[in] num Number of parameters.
188 194 *
189 195 * Reserves space for @p num parameters in the container.
190 196 ***************************************************************************/
... ... @@ -195,4 +201,33 @@ void GApplicationPars::reserve(const int&amp; num)
195 201 return;
196 202 }
197 203  
  204 +
  205 +/***********************************************************************//**
  206 + * @brief Set path to system pfiles
  207 + *
  208 + * @param[in] syspfiles Path to system pfiles.
  209 + *
  210 + * Sets the path to system parameter files.
  211 + ***************************************************************************/
  212 +inline
  213 +void GApplicationPars::syspfiles(const std::string& syspfiles)
  214 +{
  215 + m_syspfiles = syspfiles;
  216 + return;
  217 +}
  218 +
  219 +
  220 +/***********************************************************************//**
  221 + * @brief Return path to system pfiles
  222 + *
  223 + * @return Path to system pfiles.
  224 + *
  225 + * Returns path to system parameter files.
  226 + ***************************************************************************/
  227 +inline
  228 +const std::string& GApplicationPars::syspfiles(void) const
  229 +{
  230 + return (m_syspfiles);
  231 +}
  232 +
198 233 #endif /* GAPPLICATIONPARS_HPP */
... ...
pyext/GApplicationPars.i
1 1 /***************************************************************************
2 2 * GApplicationPars.i - Application parameter container *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2010-2017 by Juergen Knoedlseder *
  4 + * copyright (C) 2010-2018 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -48,26 +48,28 @@ public:
48 48 virtual ~GApplicationPars(void);
49 49  
50 50 // Methods
51   - void clear(void);
52   - GApplicationPars* clone(void) const;
53   - std::string classname(void) const;
54   - GApplicationPar& at(const int& index);
55   - int size(void) const;
56   - bool is_empty(void) const;
57   - GApplicationPar& append(const GApplicationPar& par);
58   - void append_standard(void);
59   - GApplicationPar& insert(const int& index, const GApplicationPar& par);
60   - GApplicationPar& insert(const std::string& name,
61   - const GApplicationPar& par);
62   - void remove(const int& index);
63   - void remove(const std::string& name);
64   - void reserve(const int& num);
65   - void extend(const GApplicationPars& pars);
66   - bool contains(const std::string& name) const;
67   - void load(const GFilename& filename);
68   - void load(const GFilename& filename,
69   - const std::vector<std::string>& args);
70   - void save(const GFilename& filename);
  51 + void clear(void);
  52 + GApplicationPars* clone(void) const;
  53 + std::string classname(void) const;
  54 + GApplicationPar& at(const int& index);
  55 + int size(void) const;
  56 + bool is_empty(void) const;
  57 + GApplicationPar& append(const GApplicationPar& par);
  58 + void append_standard(void);
  59 + GApplicationPar& insert(const int& index, const GApplicationPar& par);
  60 + GApplicationPar& insert(const std::string& name,
  61 + const GApplicationPar& par);
  62 + void remove(const int& index);
  63 + void remove(const std::string& name);
  64 + void reserve(const int& num);
  65 + void extend(const GApplicationPars& pars);
  66 + bool contains(const std::string& name) const;
  67 + void syspfiles(const std::string& syspfiles);
  68 + const std::string& syspfiles(void) const;
  69 + void load(const GFilename& filename);
  70 + void load(const GFilename& filename,
  71 + const std::vector<std::string>& args);
  72 + void save(const GFilename& filename);
71 73 };
72 74  
73 75  
... ...
src/app/GApplication.cpp
... ... @@ -91,7 +91,7 @@ GApplication::GApplication(const std::string&amp; name, const std::string&amp; version)
91 91 m_parfile = name+".par";
92 92 m_logfile = name+".log";
93 93  
94   - // Initialise application parameters
  94 + // Load application parameters
95 95 m_pars.load(par_filename());
96 96  
97 97 // Signal that application parameters have been loaded
... ...
src/app/GApplicationPars.cpp
1 1 /***************************************************************************
2 2 * GApplicationPars.cpp - Application parameters *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2010-2016 by Juergen Knoedlseder *
  4 + * copyright (C) 2010-2018 by Juergen Knoedlseder *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -632,23 +632,58 @@ bool GApplicationPars::contains(const std::string&amp; name) const
632 632 * Parameter file not found.
633 633 *
634 634 * Loads all parameters from parameter file.
  635 + *
  636 + * If the syspfiles path is set then load the parameter file from that
  637 + * location and update the parameters using a paramater file that is found
  638 + * in the users "pfiles" directory.
  639 + *
  640 + * Otherwise, search the parameter file in the usual location (see the
  641 + * GApplicationPars::inpath method for more information).
635 642 ***************************************************************************/
636 643 void GApplicationPars::load(const GFilename& filename)
637 644 {
638 645 // Reset parameters
639 646 m_parfile.clear();
640 647  
641   - // Get path to parameter file for input
642   - std::string path = inpath(filename.url());
643   - if (path.length() == 0) {
644   - throw GException::par_file_not_found(G_LOAD1, filename.url());
  648 + // If a syspfiles path was set then get parfile from this path and
  649 + // update the parameters using a copy found in the users "pfiles"
  650 + // directory
  651 + std::string path = syspfiles_path(filename.url());
  652 + if (!path.empty()) {
  653 +
  654 + // Read parfile
  655 + read(path);
  656 +
  657 + // Parse parfile
  658 + parse();
  659 +
  660 + // Synchronize parfile using a copy found in the users "pfiles"
  661 + // directory
  662 + path = pfiles_path(filename.url());
  663 + if (!path.empty()) {
  664 + synchronise(path);
  665 + }
  666 +
645 667 }
646 668  
647   - // Read parfile
648   - read(path);
  669 + // ... otherwise get path to parameter file for input
  670 + else {
649 671  
650   - // Parse parfile
651   - parse();
  672 + // Get parfile file path
  673 + path = inpath(filename.url());
  674 +
  675 + // If file path is empty then throw an exception
  676 + if (path.empty()) {
  677 + throw GException::par_file_not_found(G_LOAD1, filename.url());
  678 + }
  679 +
  680 + // Read parfile
  681 + read(path);
  682 +
  683 + // Parse parfile
  684 + parse();
  685 +
  686 + }
652 687  
653 688 // Return
654 689 return;
... ... @@ -661,8 +696,6 @@ void GApplicationPars::load(const GFilename&amp; filename)
661 696 * @param[in] filename Parameter filename.
662 697 * @param[in] args Command line arguments.
663 698 *
664   - * @exception GException::par_file_not_found
665   - * Parameter file not found.
666 699 * @exception GException::bad_cmdline_argument
667 700 * Invalid command line argument encountered.
668 701 *
... ... @@ -672,20 +705,8 @@ void GApplicationPars::load(const GFilename&amp; filename)
672 705 void GApplicationPars::load(const GFilename& filename,
673 706 const std::vector<std::string>& args)
674 707 {
675   - // Reset parameters
676   - m_parfile.clear();
677   -
678   - // Get path to parameter file for input
679   - std::string path = inpath(filename.url());
680   - if (path.length() == 0) {
681   - throw GException::par_file_not_found(G_LOAD2, filename.url());
682   - }
683   -
684   - // Read parfile
685   - read(path);
686   -
687   - // Parse parfile
688   - parse();
  708 + // Load parameters
  709 + load(filename);
689 710  
690 711 // Overwrite parameter values that are specified in the command line
691 712 for (int i = 1; i < args.size(); ++i) {
... ... @@ -809,6 +830,7 @@ void GApplicationPars::init_members(void)
809 830 m_vstart.clear();
810 831 m_vstop.clear();
811 832 m_mode = "h";
  833 + m_syspfiles.clear();
812 834  
813 835 // Return
814 836 return;
... ... @@ -823,12 +845,13 @@ void GApplicationPars::init_members(void)
823 845 void GApplicationPars::copy_members(const GApplicationPars& pars)
824 846 {
825 847 // Copy attributes
826   - m_parfile = pars.m_parfile;
827   - m_pars = pars.m_pars;
828   - m_line = pars.m_line;
829   - m_vstart = pars.m_vstart;
830   - m_vstop = pars.m_vstop;
831   - m_mode = pars.m_mode;
  848 + m_parfile = pars.m_parfile;
  849 + m_pars = pars.m_pars;
  850 + m_line = pars.m_line;
  851 + m_vstart = pars.m_vstart;
  852 + m_vstop = pars.m_vstop;
  853 + m_mode = pars.m_mode;
  854 + m_syspfiles = pars.m_syspfiles;
832 855  
833 856 // Return
834 857 return;
... ... @@ -937,6 +960,98 @@ std::string GApplicationPars::inpath(const std::string&amp; filename) const
937 960  
938 961  
939 962 /***********************************************************************//**
  963 + * @brief Return path to parfile in $PFILES or $HOME/pfiles folder
  964 + *
  965 + * @param[in] filename Parameter filename to search for.
  966 + * @return Full parameter filename, including absolute access path.
  967 + *
  968 + * Locates parameter file in the directories that are listed in the PFILES
  969 + * environment variable. Directories may be separated by : or by ; in the
  970 + * PFILES environment variable.
  971 + *
  972 + * If the PFILES environment variable is not set the parameter file is
  973 + * searched in the users pfiles directory.
  974 + *
  975 + * If parameter file was not found, or the parameter file is not
  976 + * read-accessible, an empty string is returned.
  977 + ***************************************************************************/
  978 +std::string GApplicationPars::pfiles_path(const std::string& filename) const
  979 +{
  980 + // Allocate result path
  981 + std::string path;
  982 +
  983 + // Search for parameter file in PFILES directories if the PFILES
  984 + // environment variable has been set
  985 + char* ptr = std::getenv("PFILES");
  986 + if (ptr != NULL) {
  987 +
  988 + // Extract directories from PFILES environment variable
  989 + std::string pfiles = ptr;
  990 + std::vector<std::string> dirs = gammalib::split(pfiles, ":;");
  991 +
  992 + // Search for first occurence of parameter file
  993 + for (int i = 0; i < dirs.size(); ++i) {
  994 +
  995 + // Build filename
  996 + std::string fname = dirs[i] + "/" + filename;
  997 +
  998 + // If file is accessible for reading then exit loop
  999 + if (access(fname.c_str(), R_OK) == 0) {
  1000 + path = fname;
  1001 + break;
  1002 + }
  1003 +
  1004 + } // endfor: searched all directories given in PFILES
  1005 +
  1006 + } // endif: PFILES environment variable has been set
  1007 +
  1008 + // ... otherwise, if no PFILES environment variable has been set
  1009 + // then search in users pfiles directory
  1010 + else {
  1011 + uid_t uid = geteuid();
  1012 + struct passwd* pw = getpwuid(uid);
  1013 + if (pw != NULL) {
  1014 + std::string fname = std::string(pw->pw_dir) + "/pfiles/" + filename;
  1015 + if (access(fname.c_str(), R_OK) == 0) {
  1016 + path = fname;
  1017 + }
  1018 + }
  1019 + } // endif: searched in users pfiles directory
  1020 +
  1021 + // Return path
  1022 + return path;
  1023 +}
  1024 +
  1025 +
  1026 +/***********************************************************************//**
  1027 + * @brief Return path to parfile in m_syspfiles folder
  1028 + *
  1029 + * @param[in] filename Parameter filename to search for.
  1030 + * @return Full parameter filename, including absolute access path.
  1031 + *
  1032 + * Locates parameter file in the directory that is specified by the
  1033 + * m_syspfiles string. If the string is empty, the specified file is not
  1034 + * found or read accessible, an empty string is returned.
  1035 + ***************************************************************************/
  1036 +std::string GApplicationPars::syspfiles_path(const std::string& filename) const
  1037 +{
  1038 + // Allocate result path
  1039 + std::string path;
  1040 +
  1041 + // Continue only if m_syspfiles is not empty
  1042 + if (!m_syspfiles.empty()) {
  1043 + std::string fname = m_syspfiles + "/" + filename;
  1044 + if (access(fname.c_str(), R_OK) == 0) {
  1045 + path = fname;
  1046 + }
  1047 + }
  1048 +
  1049 + // Return path
  1050 + return path;
  1051 +}
  1052 +
  1053 +
  1054 +/***********************************************************************//**
940 1055 * @brief Determine filepath for parameter file output
941 1056 *
942 1057 * @param[in] filename Parameter filename.
... ... @@ -1347,6 +1462,54 @@ void GApplicationPars::update(void)
1347 1462  
1348 1463  
1349 1464 /***********************************************************************//**
  1465 + * @brief Synchronise parameter file with the parameter values in a another
  1466 + * parameter file
  1467 + *
  1468 + * @param[in] filename File name of other parameter file.
  1469 + *
  1470 + * Copies over all values from another parameter file that correspond to
  1471 + * parameters with the same name and type, and that are signaled as "learn"
  1472 + * in the other parameter file.
  1473 + ***************************************************************************/
  1474 +void GApplicationPars::synchronise(const std::string& filename)
  1475 +{
  1476 + // Allocate other application parameters
  1477 + GApplicationPars pars;
  1478 +
  1479 + // Read other application parameters
  1480 + pars.read(filename);
  1481 +
  1482 + // Parse other parameters
  1483 + pars.parse();
  1484 +
  1485 + // Loop over all parameters in parameter file
  1486 + for (int i = 0; i < m_pars.size(); ++i) {
  1487 +
  1488 + // If a parameter with the same name and type exists in the other
  1489 + // parameter file
  1490 + int inx = pars.get_index(m_pars[i].name());
  1491 + if (inx != -1) {
  1492 +
  1493 + // If the parameter types match, the mode in the other parameter
  1494 + // file is "learn", and the parameter values differ, then copy
  1495 + // over the value and signal value updating
  1496 + if ((m_pars[i].type() == pars[inx].type()) &&
  1497 + pars[inx].is_learn() &&
  1498 + m_pars[i].m_value != pars[inx].m_value) {
  1499 + m_pars[i].m_value = pars[inx].m_value;
  1500 + m_pars[i].m_update = true;
  1501 + }
  1502 +
  1503 + } // endif: parameter with same name existed
  1504 +
  1505 + } // endfor: looped over all parameters
  1506 +
  1507 + // Return
  1508 + return;
  1509 +}
  1510 +
  1511 +
  1512 +/***********************************************************************//**
1350 1513 * @brief Return parameter index by name
1351 1514 *
1352 1515 * @param[in] name Parameter name.
... ...
src/gammalib-setup.in
... ... @@ -74,19 +74,6 @@ if [ -d $prefix/syspfiles/. ]; then
74 74 syspfiles="$prefix/syspfiles$syspfiles"
75 75 fi
76 76  
77   - # updates any existing PFILES if syspfiles are newer
78   - for filename in $HOME/pfiles/*.par
79   - do
80   - parfile=`basename $filename`
81   - sys_parfile=$prefix/syspfiles/$parfile
82   - if [ -e "$sys_parfile" ]; then
83   - if test "$sys_parfile" -nt "$filename"
84   - then
85   - cp -f "$sys_parfile" "$filename"
86   - fi
87   - fi
88   - done
89   -
90 77 # Set PFILES and PFCLOBBER environment variable
91 78 PFILES="$locpfiles;$syspfiles"
92 79 PFCLOBBER=1
... ...