update packages

This commit is contained in:
2025-02-26 20:16:44 +01:00
parent 59db017445
commit 45d49daef0
291 changed files with 16240 additions and 522600 deletions

View File

@@ -1,4 +1,4 @@
;;; ox-taskjuggler.el --- TaskJuggler Back-End for Org Export Engine
;;; ox-taskjuggler.el --- TaskJuggler Back-End for Org Export Engine -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2007-2021 Free Software Foundation, Inc.
;;
@@ -8,6 +8,7 @@
;; Nicolas Goaziou <n dot goaziou at gmail dot com>
;; Maintainer: Christian Egli
;; Keywords: org, taskjuggler, project planning
;; Homepage: https://github.com/h-oll/ox-taskjuggler
;; Description: Converts an Org mode buffer into a TaskJuggler project plan
;; This file is not part of GNU Emacs.
@@ -145,7 +146,7 @@
;;
;;; Code:
(eval-when-compile (require 'cl))
(eval-when-compile (require 'cl-lib))
(require 'ox)
@@ -177,6 +178,13 @@ for the project."
:group 'org-export-taskjuggler
:type 'string)
(defcustom org-taskjuggler-account-tag "taskjuggler_account"
"Tag marking project's accounts.
This tag is used to find the tree containing all the accounts
for the project."
:group 'org-export-taskjuggler
:type 'string)
(defcustom org-taskjuggler-report-tag "taskjuggler_report"
"Tag marking project's reports.
This tag is used to find the tree containing all the reports for
@@ -311,36 +319,47 @@ exported with the corresponding task.
Note that multiline properties are not supported, so attributes
like note or journalentry have to be on a single line."
:group 'org-export-taskjuggler)
:group 'org-export-taskjuggler
:type '(repeat symbol))
(defcustom org-taskjuggler-valid-project-attributes
'(timingresolution timezone alertlevels currency currencyformat
dailyworkinghours extend includejournalentry now numberformat
outputdir scenario shorttimeformat timeformat trackingscenario
weekstartsmonday weekstartssunday workinghours
yearlyworkingdays)
'( timingresolution timezone alertlevels currency currencyformat
dailyworkinghours extend includejournalentry now numberformat
outputdir scenario shorttimeformat timeformat trackingscenario
weekstartsmonday weekstartssunday workinghours
yearlyworkingdays)
"Valid attributes for Taskjuggler project.
If one of these appears as a property for a headline that is a
project definition, it will be exported with the corresponding
task. Attribute 'timingresolution' should be the first in the
task. Attribute `timingresolution' should be the first in the
list."
:group 'org-export-taskjuggler)
:group 'org-export-taskjuggler
:type '(repeat symbol))
(defcustom org-taskjuggler-valid-resource-attributes
'(limits vacation shift booking efficiency journalentry rate
workinghours flags)
workinghours flags chargeset)
"Valid attributes for Taskjuggler resources.
If one of these appears as a property for a headline, it will be
exported with the corresponding resource."
:group 'org-export-taskjuggler
:type '(repeat symbol))
(defcustom org-taskjuggler-valid-account-attributes
'(aggregate credits flags)
"Valid attributes for Taskjuggler accounts.
If one of these appears as a property for a headline, it will be
exported with the corresponding account."
:group 'org-export-taskjuggler)
(defcustom org-taskjuggler-valid-report-attributes
'(headline columns definitions timeformat hideresource hidetask
loadunit sorttasks formats period)
'(headline columns definitions timeformat hideaccount hideresource hidetask
loadunit sorttasks formats period start end)
"Valid attributes for Taskjuggler reports.
If one of these appears as a property for a headline, it will be
exported with the corresponding report."
:group 'org-export-taskjuggler)
:group 'org-export-taskjuggler
:type '(repeat symbol))
(defcustom org-taskjuggler-process-command
"tj3 --silent --no-color --output-dir %o %f"
@@ -352,7 +371,8 @@ full file name, \"%o\" by the reports directory (see
If you are targeting Taskjuggler 2.4 (see
`org-taskjuggler-target-version') this setting is ignored."
:group 'org-export-taskjuggler)
:group 'org-export-taskjuggler
:type 'string)
(defcustom org-taskjuggler-reports-directory "reports"
"Default directory to generate the Taskjuggler reports in.
@@ -365,7 +385,8 @@ doesn't exist.
If you are targeting Taskjuggler 2.4 (see
`org-taskjuggler-target-version') this setting is ignored."
:group 'org-export-taskjuggler)
:group 'org-export-taskjuggler
:type 'string)
(defcustom org-taskjuggler-keep-project-as-task t
"Non-nil keeps the project headline as an umbrella task for all tasks.
@@ -440,6 +461,19 @@ headlines and their associated ID."
(cons resource id)))
info)))
(defun org-taskjuggler-assign-account-ids (accounts info)
"Assign a unique ID to each account within ACCOUNTS.
ACCOUNTS is a list of headlines. INFO is a plist used as a
communication channel. Return value is an alist between
headlines and their associated ID."
(let (ids)
(org-element-map accounts 'headline
(lambda (account)
(let ((id (org-taskjuggler--build-unique-id account ids)))
(push id ids)
(cons account id)))
info)))
;;; Accessors
@@ -478,7 +512,11 @@ ITEM is a headline. Return value is a string or nil if ITEM
doesn't have any start date defined."
(let ((scheduled (org-element-property :scheduled item)))
(or
(and scheduled (org-timestamp-format scheduled "%Y-%02m-%02d"))
(and scheduled (funcall (eval-and-compile
(if (fboundp 'org-format-timestamp)
#'org-format-timestamp
(with-no-warnings #'org-timestamp-format)))
scheduled "%Y-%02m-%02d"))
(and (memq 'start org-taskjuggler-valid-task-attributes)
(org-element-property :START item)))))
@@ -487,7 +525,10 @@ doesn't have any start date defined."
ITEM is a headline. Return value is a string or nil if ITEM
doesn't have any end date defined."
(let ((deadline (org-element-property :deadline item)))
(and deadline (org-timestamp-format deadline "%Y-%02m-%02d"))))
(or
(and deadline (org-timestamp-format deadline "%Y-%02m-%02d"))
(and (memq 'end org-taskjuggler-valid-task-attributes)
(org-element-property :END item)))))
@@ -626,9 +667,9 @@ doesn't include leading \"depends\"."
;;; Translator Functions
(defun org-taskjuggler-project-plan (contents info)
(defun org-taskjuggler-project-plan (_ info)
"Build TaskJuggler project plan.
CONTENTS is ignored. INFO is a plist holding export options.
INFO is a plist holding export options.
Return complete project plan as a string in TaskJuggler syntax."
(let* ((tree (plist-get info :parse-tree))
(project (or (org-taskjuggler-get-project info)
@@ -640,89 +681,115 @@ Return complete project plan as a string in TaskJuggler syntax."
(org-taskjuggler--build-project project info)
;; 3. Insert global properties.
(org-element-normalize-string org-taskjuggler-default-global-properties)
;; 4. Insert resources. Provide a default one if none is
;; 3.5. Insert accounts. Provide a default one if none is
;; specified.
(let ((main-resources
(let ((main-accounts
;; Collect contents from various trees marked with
;; `org-taskjuggler-resource-tag'. Only gather top level
;; resources.
;; `org-taskjuggler-account-tag'. Only gather top level
;; accounts.
(apply 'append
(org-element-map tree 'headline
(lambda (hl)
(and (member org-taskjuggler-resource-tag
(and (member org-taskjuggler-account-tag
(org-export-get-tags hl info))
(org-element-map (org-element-contents hl) 'headline
'identity info nil 'headline)))
info nil 'headline))))
;; Assign a unique ID to each resource. Store it under
;; Assign a unique ID to each account. Store it under
;; `:taskjuggler-unique-ids' property in INFO.
(setq info
(plist-put info :taskjuggler-unique-ids
(org-taskjuggler-assign-resource-ids
main-resources info)))
(org-taskjuggler-assign-account-ids
main-accounts info)))
(concat
(if main-resources
(if main-accounts
(mapconcat
(lambda (resource) (org-taskjuggler--build-resource resource info))
main-resources "")
(format "resource %s \"%s\" {\n}\n" (user-login-name) user-full-name))
;; 5. Insert tasks.
(let ((main-tasks
;; If `org-taskjuggler-keep-project-as-task' is
;; non-nil, there is only one task. Otherwise, every
;; direct children of PROJECT is a top level task.
(if org-taskjuggler-keep-project-as-task (list project)
(or (org-element-map (org-element-contents project) 'headline
'identity info nil 'headline)
(error "No task specified")))))
;; Assign a unique ID to each task. Add it to
;; `:taskjuggler-unique-ids' property in INFO.
(setq info
(plist-put info :taskjuggler-unique-ids
(append
(org-taskjuggler-assign-task-ids main-tasks info)
(plist-get info :taskjuggler-unique-ids))))
;; If no resource is allocated among tasks, allocate one to
;; the first task.
(unless (org-element-map main-tasks 'headline
(lambda (task) (org-element-property :ALLOCATE task))
info t)
(org-element-put-property
(car main-tasks) :ALLOCATE
(or (org-taskjuggler-get-id (car main-resources) info)
(user-login-name))))
(mapconcat
(lambda (task) (org-taskjuggler--build-task task info))
main-tasks ""))
;; 6. Insert reports. If no report is defined, insert default
;; reports.
(let ((main-reports
(lambda (account) (org-taskjuggler--build-account account info))
main-accounts "")
(format "account %s \"%s\" {\n}\n" (user-login-name) user-full-name))
;; 4. Insert resources. Provide a default one if none is
;; specified.
(let ((main-resources
;; Collect contents from various trees marked with
;; `org-taskjuggler-report-tag'. Only gather top level
;; reports.
;; `org-taskjuggler-resource-tag'. Only gather top level
;; resources.
(apply 'append
(org-element-map tree 'headline
(lambda (hl)
(and (member org-taskjuggler-report-tag
(and (member org-taskjuggler-resource-tag
(org-export-get-tags hl info))
(org-element-map (org-element-contents hl)
'headline 'identity info nil 'headline)))
(org-element-map (org-element-contents hl) 'headline
'identity info nil 'headline)))
info nil 'headline))))
(if main-reports
(mapconcat
(lambda (report) (org-taskjuggler--build-report report info))
main-reports "")
;; insert title in default reports
(let* ((title (org-export-data (plist-get info :title) info))
(report-title (if (string= title "")
(org-taskjuggler-get-name project)
title)))
(mapconcat
'org-element-normalize-string
(mapcar
(lambda (report)
(replace-regexp-in-string "%title" report-title report t t))
org-taskjuggler-default-reports) "")))))))))
;; Assign a unique ID to each resource. Store it under
;; `:taskjuggler-unique-ids' property in INFO.
(setq info
(plist-put info :taskjuggler-unique-ids
(org-taskjuggler-assign-resource-ids
main-resources info)))
(concat
(if main-resources
(mapconcat
(lambda (resource) (org-taskjuggler--build-resource resource info))
main-resources "")
(format "resource %s \"%s\" {\n}\n" (user-login-name) user-full-name))
;; 5. Insert tasks.
(let ((main-tasks
;; If `org-taskjuggler-keep-project-as-task' is
;; non-nil, there is only one task. Otherwise, every
;; direct children of PROJECT is a top level task.
(if org-taskjuggler-keep-project-as-task (list project)
(or (org-element-map (org-element-contents project) 'headline
'identity info nil 'headline)
(error "No task specified")))))
;; Assign a unique ID to each task. Add it to
;; `:taskjuggler-unique-ids' property in INFO.
(setq info
(plist-put info :taskjuggler-unique-ids
(append
(org-taskjuggler-assign-task-ids main-tasks info)
(plist-get info :taskjuggler-unique-ids))))
;; If no resource is allocated among tasks, allocate one to
;; the first task.
(unless (org-element-map main-tasks 'headline
(lambda (task) (org-element-property :ALLOCATE task))
info t)
(org-element-put-property
(car main-tasks) :ALLOCATE
(or (org-taskjuggler-get-id (car main-resources) info)
(user-login-name))))
(mapconcat
(lambda (task) (org-taskjuggler--build-task task info))
main-tasks ""))
;; 6. Insert reports. If no report is defined, insert default
;; reports.
(let ((main-reports
;; Collect contents from various trees marked with
;; `org-taskjuggler-report-tag'. Only gather top level
;; reports.
(apply 'append
(org-element-map tree 'headline
(lambda (hl)
(and (member org-taskjuggler-report-tag
(org-export-get-tags hl info))
(org-element-map (org-element-contents hl)
'headline 'identity info nil 'headline)))
info nil 'headline))))
(if main-reports
(mapconcat
(lambda (report) (org-taskjuggler--build-report report info))
main-reports "")
;; insert title in default reports
(let* ((title (org-export-data (plist-get info :title) info))
(report-title (if (string= title "")
(org-taskjuggler-get-name project)
title)))
(mapconcat
'org-element-normalize-string
(mapcar
(lambda (report)
(replace-regexp-in-string "%title" report-title report t t))
org-taskjuggler-default-reports) "")))))))))))
(defun org-taskjuggler--build-project (project info)
"Return a project declaration.
@@ -785,20 +852,60 @@ neither is defined a unique id will be associated to it."
;; Closing resource.
"}\n"))
(defun org-taskjuggler--build-account (account info)
"Return a account declaration.
ACCOUNT is a headline. INFO is a plist used as a communication
channel.
All valid attributes from ACCOUNT are inserted. If ACCOUNT
defines a property \"account_id\" it will be used as the id for
this account. Otherwise it will use the ID property. If
neither is defined a unique id will be associated to it."
(concat
;; Opening account.
(format "account %s \"%s\" {\n"
(org-taskjuggler--clean-id
(or (org-element-property :ACCOUNT_ID account)
(org-element-property :ID account)
(org-taskjuggler-get-id account info)))
(org-taskjuggler-get-name account))
;; Add attributes.
(org-taskjuggler--indent-string
(org-taskjuggler--build-attributes
account org-taskjuggler-valid-account-attributes))
;; Add inner accounts.
(org-taskjuggler--indent-string
(mapconcat
'identity
(org-element-map (org-element-contents account) 'headline
(lambda (hl) (org-taskjuggler--build-account hl info))
info nil 'headline)
""))
;; Closing account.
"}\n"))
(defun org-taskjuggler--build-report (report info)
"Return a report declaration.
REPORT is a headline. INFO is a plist used as a communication
channel."
(concat
;; Opening report.
(format "%s \"%s\" {\n"
(format "%s %s \"%s\" {\n"
(or (org-element-property :REPORT_KIND report) "taskreport")
(or (org-element-property :REPORT_ID report)
(org-element-property :ID report)
(org-taskjuggler-get-id report info))
(org-taskjuggler-get-name report))
;; Add attributes.
(org-taskjuggler--indent-string
(org-taskjuggler--build-attributes
report org-taskjuggler-valid-report-attributes))
;; Add inner reports.
;; Add core of report, ie the first paragraph after the headline
;; and before the next sub-headline
(format "%s" (if (eq (org-element-type (car (org-element-contents report))) 'section)
(org-element-interpret-data (car (org-element-contents report)))
""))
(org-taskjuggler--indent-string
(mapconcat
'identity