Dynamically adding reports

Chris Dennis cgdennis at btinternet.com
Sun Jun 14 17:53:10 EDT 2009

Derek Atkins wrote:
> Quoting Phil Longstaff <plongstaff at rogers.com>:
>> I played around last night with how reports are loaded in the system. 
>>  I basically replaced:
>> (use-module (gnucash report report-A))
>> (use-module (gnucash report report-B))
>> which appears in standard-reports.scm, with
>> (define (get-report-list) (list
>>    'report-A
>>    'report-B
>> ))
>> (for-each (lambda (x) (resolve-module (append '(gnucash report) x))) 
>> (get-report-list))
>> which does nothing new, but does allow me to replace (get-report-list) 
>> with a function which returns the names of all .scm files.  This will 
>> then allow a user/developer to just drop a new report file into the 
>> reports directory, restart gnucash, and it will be picked up.  Or, 
>> (get-report-list) could read the list of report file names from a 
>> standard-report-names.txt file, which would allow the user/developer 
>> to drop a report file into the reports directory, add the file name to 
>> the standard-report-names.txt, then restart.  My preference is for the 
>> former (fewer steps), but a little more difficult.
>> The reports directory currently holds all of the report files (both 
>> standard and business) as well as some support files.  I think what I 
>> will do is create a 'standard-reports' subdirectory to the reports 
>> directory, and put the standard reports (or symlinks) there.  
>> get-report-list will then have a single directory from which to get 
>> all of the file names.
>> Comments?
> How do you determine the runtime location of this directory?
> So long as it can be determined at runtime (and not a compile-time
> constant) I think this is a perfectly reasonable idea.

Is the following any help?  It's a function I came up with to allow 
eguile-based reports to find their corresponding template file, but in 
fact it's not that specific -- it will look for any file in ~/.gnucash 
or <any-dir-in-the-search-path>/gnucash/report.  It could easily be 
adapted or made more general-purpose.

  (define (find-template fname)
    ;; Find the eguile template file 'fname', and return its full path.
    ;; First look in the user's .gnucash directory.
    ;; Then look in Gnucash's standard report directory.
    ;; This is complicated because of the need to cater for
    ;; various operating systems; so it takes a fairly heuristic,
    ;; 'best guess' approach.
    ;; If no file is found, returns just 'fname' for use in error
    ;; messages.
    ;; Note: this has been tested on Linux and Windows Vista so far...
    (let* ((userdir (sub-vicinity (user-vicinity) ".gnucash"))
           (sysdir  (sub-vicinity (sub-vicinity (user-vicinity)
                                              "gnucash") "report"))
           (home (or (home-vicinity)
                     (getenv "USERPROFILE")
      ; make sure there's a trailing delimiter
      (set! home (sub-vicinity (user-vicinity) home))
      (let ((home-template (in-vicinity
                (in-vicinity home userdir) fname)))
        (if (access? home-template R_OK)
          (or (%search-load-path (in-vicinity sysdir fname))


Chris Dennis                                  cgdennis at btinternet.com
Fordingbridge, Hampshire, UK

More information about the gnucash-devel mailing list