taskjuggler 3.1.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (410) hide show
  1. data/CHANGELOG +44 -0
  2. data/bin/tj3webd +4 -0
  3. data/data/css/tjreport.css +14 -5
  4. data/data/tjp.vim +22 -7
  5. data/examples/Fedora-20/reports.tji +2 -4
  6. data/examples/Scrum/Product Burndown.csv +26 -0
  7. data/examples/Scrum/Sprint 1 Burndown.csv +26 -0
  8. data/examples/Scrum/Sprint 2 Burndown.csv +26 -0
  9. data/examples/Scrum/Sprint 3 Burndown.csv +26 -0
  10. data/examples/Scrum/scrum.tjp +141 -0
  11. data/examples/Tutorial/tutorial.tjp +13 -7
  12. data/lib/taskjuggler/Attributes.rb +2 -3
  13. data/lib/taskjuggler/HTMLDocument.rb +25 -18
  14. data/lib/taskjuggler/Journal.rb +85 -65
  15. data/lib/taskjuggler/KeywordDocumentation.rb +25 -13
  16. data/lib/taskjuggler/LeaveList.rb +1 -1
  17. data/lib/taskjuggler/Limits.rb +3 -5
  18. data/lib/taskjuggler/MessageHandler.rb +173 -19
  19. data/lib/taskjuggler/Painter.rb +75 -0
  20. data/lib/taskjuggler/Painter/BasicShapes.rb +76 -0
  21. data/lib/taskjuggler/Painter/Color.rb +273 -0
  22. data/lib/taskjuggler/Painter/Element.rb +56 -0
  23. data/lib/taskjuggler/Painter/FontData.rb +221 -0
  24. data/lib/taskjuggler/Painter/FontMetrics.rb +125 -0
  25. data/lib/taskjuggler/Painter/FontMetricsData.rb +151 -0
  26. data/lib/taskjuggler/Painter/Group.rb +77 -0
  27. data/lib/taskjuggler/Painter/Points.rb +47 -0
  28. data/lib/taskjuggler/Painter/Primitives.rb +100 -0
  29. data/lib/taskjuggler/Painter/SVGSupport.rb +36 -0
  30. data/lib/taskjuggler/Painter/Text.rb +36 -0
  31. data/lib/taskjuggler/Project.rb +46 -29
  32. data/lib/taskjuggler/ProjectFileParser.rb +24 -22
  33. data/lib/taskjuggler/ProjectFileScanner.rb +2 -2
  34. data/lib/taskjuggler/PropertyTreeNode.rb +26 -34
  35. data/lib/taskjuggler/Query.rb +8 -5
  36. data/lib/taskjuggler/RealFormat.rb +3 -0
  37. data/lib/taskjuggler/Resource.rb +3 -5
  38. data/lib/taskjuggler/ResourceScenario.rb +19 -7
  39. data/lib/taskjuggler/RichText.rb +4 -6
  40. data/lib/taskjuggler/RichText/FunctionExample.rb +1 -1
  41. data/lib/taskjuggler/RichText/FunctionHandler.rb +5 -6
  42. data/lib/taskjuggler/RichText/Parser.rb +4 -6
  43. data/lib/taskjuggler/RichText/RTFNavigator.rb +1 -1
  44. data/lib/taskjuggler/RichText/RTFQuery.rb +2 -3
  45. data/lib/taskjuggler/RichText/RTFReport.rb +1 -1
  46. data/lib/taskjuggler/RichText/RTFReportLink.rb +1 -2
  47. data/lib/taskjuggler/RichText/RTFWithQuerySupport.rb +1 -1
  48. data/lib/taskjuggler/RichText/Scanner.rb +6 -6
  49. data/lib/taskjuggler/RichText/Snip.rb +1 -2
  50. data/lib/taskjuggler/RuntimeConfig.rb +9 -6
  51. data/lib/taskjuggler/ScenarioData.rb +4 -3
  52. data/lib/taskjuggler/Scoreboard.rb +6 -0
  53. data/lib/taskjuggler/SheetHandlerBase.rb +25 -8
  54. data/lib/taskjuggler/SimpleQueryExpander.rb +14 -5
  55. data/lib/taskjuggler/SyntaxReference.rb +1 -2
  56. data/lib/taskjuggler/TableColumnSorter.rb +84 -0
  57. data/lib/taskjuggler/Task.rb +3 -5
  58. data/lib/taskjuggler/TaskJuggler.rb +36 -29
  59. data/lib/taskjuggler/TaskScenario.rb +154 -66
  60. data/lib/taskjuggler/TextParser.rb +24 -17
  61. data/lib/taskjuggler/TextParser/Scanner.rb +16 -11
  62. data/lib/taskjuggler/TextParser/SourceFileInfo.rb +20 -15
  63. data/lib/taskjuggler/TimeSheets.rb +6 -12
  64. data/lib/taskjuggler/Tj3AppBase.rb +35 -16
  65. data/lib/taskjuggler/Tj3Config.rb +1 -1
  66. data/lib/taskjuggler/TjpSyntaxRules.rb +239 -49
  67. data/lib/taskjuggler/XMLElement.rb +9 -2
  68. data/lib/taskjuggler/apps/Tj3.rb +43 -37
  69. data/lib/taskjuggler/apps/Tj3Client.rb +62 -112
  70. data/lib/taskjuggler/apps/Tj3Daemon.rb +66 -29
  71. data/lib/taskjuggler/apps/Tj3Man.rb +5 -5
  72. data/lib/taskjuggler/apps/Tj3SsReceiver.rb +10 -13
  73. data/lib/taskjuggler/apps/Tj3SsSender.rb +13 -16
  74. data/lib/taskjuggler/apps/Tj3TsReceiver.rb +10 -13
  75. data/lib/taskjuggler/apps/Tj3TsSender.rb +12 -15
  76. data/lib/taskjuggler/apps/Tj3TsSummary.rb +12 -15
  77. data/lib/taskjuggler/apps/Tj3WebD.rb +99 -0
  78. data/lib/taskjuggler/daemon/Daemon.rb +50 -10
  79. data/lib/taskjuggler/daemon/DaemonConnector.rb +127 -0
  80. data/lib/taskjuggler/daemon/ProcessIntercom.rb +36 -21
  81. data/lib/taskjuggler/daemon/ProjectBroker.rb +122 -112
  82. data/lib/taskjuggler/daemon/ProjectServer.rb +78 -46
  83. data/lib/taskjuggler/daemon/ReportServer.rb +52 -28
  84. data/lib/taskjuggler/daemon/ReportServlet.rb +92 -21
  85. data/lib/taskjuggler/daemon/WebServer.rb +75 -22
  86. data/lib/taskjuggler/daemon/WelcomePage.rb +1 -0
  87. data/lib/taskjuggler/reports/AccountListRE.rb +3 -3
  88. data/lib/taskjuggler/reports/CSVFile.rb +9 -2
  89. data/lib/taskjuggler/reports/ChartPlotter.rb +453 -0
  90. data/lib/taskjuggler/reports/Navigator.rb +1 -0
  91. data/lib/taskjuggler/reports/NikuReport.rb +4 -4
  92. data/lib/taskjuggler/reports/Report.rb +6 -18
  93. data/lib/taskjuggler/reports/ReportBase.rb +9 -9
  94. data/lib/taskjuggler/reports/ReportContext.rb +2 -2
  95. data/lib/taskjuggler/reports/StatusSheetReport.rb +6 -6
  96. data/lib/taskjuggler/reports/TableReport.rb +24 -15
  97. data/lib/taskjuggler/reports/TimeSheetReport.rb +5 -5
  98. data/lib/taskjuggler/reports/TraceReport.rb +251 -0
  99. data/lib/tj3webd.rb +17 -0
  100. data/manual/Day_To_Day_Juggling +10 -3
  101. data/manual/Installation +38 -19
  102. data/manual/Software +25 -19
  103. data/manual/Tutorial +119 -110
  104. data/manual/html/Day_To_Day_Juggling.html +7 -5
  105. data/manual/html/Getting_Started.html +4 -4
  106. data/manual/html/How_To_Contribute.html +4 -4
  107. data/manual/html/Installation.html +19 -11
  108. data/manual/html/Intro.html +4 -4
  109. data/manual/html/Reporting_Bugs.html +4 -4
  110. data/manual/html/Rich_Text_Attributes.html +4 -4
  111. data/manual/html/Software.html +15 -11
  112. data/manual/html/TaskJuggler_2x_Migration.html +4 -4
  113. data/manual/html/TaskJuggler_Internals.html +4 -4
  114. data/manual/html/The_TaskJuggler_Syntax.html +4 -4
  115. data/manual/html/Tutorial.html +41 -32
  116. data/manual/html/account.html +4 -4
  117. data/manual/html/account.task.html +4 -4
  118. data/manual/html/accountprefix.html +4 -4
  119. data/manual/html/accountreport.html +27 -9
  120. data/manual/html/accountroot.html +5 -5
  121. data/manual/html/active.html +4 -4
  122. data/manual/html/adopt.task.html +4 -4
  123. data/manual/html/aggregate.html +4 -4
  124. data/manual/html/alert.html +4 -4
  125. data/manual/html/alertlevels.html +4 -4
  126. data/manual/html/allocate.html +5 -5
  127. data/manual/html/alphabet.html +4 -4
  128. data/manual/html/alternative.html +4 -4
  129. data/manual/html/author.html +4 -4
  130. data/manual/html/balance.html +5 -5
  131. data/manual/html/booking.resource.html +4 -4
  132. data/manual/html/booking.task.html +4 -4
  133. data/manual/html/caption.html +5 -5
  134. data/manual/html/cellcolor.column.html +43 -8
  135. data/manual/html/celltext.column.html +4 -4
  136. data/manual/html/center.html +5 -5
  137. data/manual/html/charge.html +4 -4
  138. data/manual/html/chargeset.html +4 -4
  139. data/manual/html/columnid.html +27 -15
  140. data/manual/html/columns.html +5 -5
  141. data/manual/html/complete.html +4 -4
  142. data/manual/html/copyright.html +4 -4
  143. data/manual/html/credits.html +4 -4
  144. data/manual/html/css/tjreport.css +14 -5
  145. data/manual/html/currency.html +4 -4
  146. data/manual/html/currencyformat.html +5 -5
  147. data/manual/html/dailymax.html +5 -5
  148. data/manual/html/dailymin.html +5 -5
  149. data/manual/html/dailyworkinghours.html +4 -4
  150. data/manual/html/date.extend.html +4 -4
  151. data/manual/html/date.html +5 -5
  152. data/manual/html/definitions.html +4 -4
  153. data/manual/html/depends.html +4 -4
  154. data/manual/html/details.html +4 -4
  155. data/manual/html/disabled.html +4 -4
  156. data/manual/html/duration.html +4 -4
  157. data/manual/html/efficiency.html +4 -4
  158. data/manual/html/effort.html +4 -4
  159. data/manual/html/email.html +4 -4
  160. data/manual/html/enabled.html +4 -4
  161. data/manual/html/end.column.html +4 -4
  162. data/manual/html/end.html +4 -4
  163. data/manual/html/end.limit.html +4 -4
  164. data/manual/html/end.report.html +5 -5
  165. data/manual/html/end.timesheet.html +4 -4
  166. data/manual/html/endcredit.html +4 -4
  167. data/manual/html/epilog.html +5 -5
  168. data/manual/html/export.html +4 -4
  169. data/manual/html/extend.html +4 -4
  170. data/manual/html/fail.html +43 -8
  171. data/manual/html/fdl.html +4 -4
  172. data/manual/html/flags.account.html +4 -4
  173. data/manual/html/flags.html +4 -4
  174. data/manual/html/flags.journalentry.html +4 -4
  175. data/manual/html/flags.report.html +5 -5
  176. data/manual/html/flags.resource.html +4 -4
  177. data/manual/html/flags.statussheet.html +4 -4
  178. data/manual/html/flags.task.html +4 -4
  179. data/manual/html/flags.timesheet.html +4 -4
  180. data/manual/html/fontcolor.column.html +43 -8
  181. data/manual/html/footer.html +5 -5
  182. data/manual/html/formats.html +5 -5
  183. data/manual/html/functions.html +4 -4
  184. data/manual/html/gapduration.html +4 -4
  185. data/manual/html/gaplength.html +4 -4
  186. data/manual/html/halign.center.html +4 -4
  187. data/manual/html/halign.column.html +43 -8
  188. data/manual/html/halign.left.html +4 -4
  189. data/manual/html/halign.right.html +4 -4
  190. data/manual/html/hasalert.html +4 -4
  191. data/manual/html/header.html +5 -5
  192. data/manual/html/headline.html +7 -7
  193. data/manual/html/height.html +72 -0
  194. data/manual/html/hideaccount.html +46 -11
  195. data/manual/html/hidejournalentry.html +5 -5
  196. data/manual/html/hidereport.html +43 -8
  197. data/manual/html/hideresource.html +44 -9
  198. data/manual/html/hidetask.html +44 -9
  199. data/manual/html/icalreport.html +4 -4
  200. data/manual/html/include.macro.html +4 -4
  201. data/manual/html/include.project.html +4 -4
  202. data/manual/html/include.properties.html +4 -4
  203. data/manual/html/index.html +2 -1
  204. data/manual/html/inherit.extend.html +4 -4
  205. data/manual/html/interval1.html +4 -4
  206. data/manual/html/interval2.html +4 -4
  207. data/manual/html/interval3.html +4 -4
  208. data/manual/html/interval4.html +4 -4
  209. data/manual/html/isactive.html +4 -4
  210. data/manual/html/ischildof.html +4 -4
  211. data/manual/html/isdependencyof.html +4 -4
  212. data/manual/html/isdutyof.html +4 -4
  213. data/manual/html/isfeatureof.html +4 -4
  214. data/manual/html/isleaf.html +4 -4
  215. data/manual/html/ismilestone.html +4 -4
  216. data/manual/html/isongoing.html +4 -4
  217. data/manual/html/isresource.html +4 -4
  218. data/manual/html/isresponsibilityof.html +4 -4
  219. data/manual/html/istask.html +4 -4
  220. data/manual/html/journalattributes.html +11 -7
  221. data/manual/html/journalentry.html +4 -4
  222. data/manual/html/journalmode.html +5 -5
  223. data/manual/html/leaveallowance.html +5 -5
  224. data/manual/html/leaves.html +5 -6
  225. data/manual/html/left.html +5 -5
  226. data/manual/html/length.html +4 -4
  227. data/manual/html/limits.allocate.html +4 -4
  228. data/manual/html/limits.html +4 -4
  229. data/manual/html/limits.resource.html +4 -4
  230. data/manual/html/limits.task.html +4 -4
  231. data/manual/html/listitem.column.html +4 -4
  232. data/manual/html/listtype.column.html +4 -4
  233. data/manual/html/loadunit.html +5 -5
  234. data/manual/html/logicalexpression.html +8 -44
  235. data/manual/html/logicalflagexpression.html +4 -4
  236. data/manual/html/macro.html +4 -4
  237. data/manual/html/managers.html +4 -4
  238. data/manual/html/mandatory.html +4 -4
  239. data/manual/html/maxend.html +4 -4
  240. data/manual/html/maximum.html +5 -5
  241. data/manual/html/maxstart.html +4 -4
  242. data/manual/html/milestone.html +4 -4
  243. data/manual/html/minend.html +4 -4
  244. data/manual/html/minimum.html +5 -5
  245. data/manual/html/minstart.html +4 -4
  246. data/manual/html/monthlymax.html +5 -5
  247. data/manual/html/monthlymin.html +5 -5
  248. data/manual/html/navbar.html +10 -4
  249. data/manual/html/navigator.html +4 -4
  250. data/manual/html/newtask.html +4 -4
  251. data/manual/html/nikureport.html +4 -4
  252. data/manual/html/note.task.html +4 -4
  253. data/manual/html/now.html +4 -4
  254. data/manual/html/numberformat.html +5 -5
  255. data/manual/html/onend.html +4 -4
  256. data/manual/html/onstart.html +4 -4
  257. data/manual/html/opennodes.html +5 -5
  258. data/manual/html/overtime.booking.html +4 -4
  259. data/manual/html/period.column.html +4 -4
  260. data/manual/html/period.limit.html +4 -4
  261. data/manual/html/period.report.html +5 -5
  262. data/manual/html/period.task.html +4 -4
  263. data/manual/html/persistent.html +4 -4
  264. data/manual/html/precedes.html +4 -4
  265. data/manual/html/priority.html +4 -4
  266. data/manual/html/priority.timesheet.html +4 -4
  267. data/manual/html/project.html +4 -4
  268. data/manual/html/projectid.html +4 -4
  269. data/manual/html/projectid.task.html +4 -4
  270. data/manual/html/projectids.html +4 -4
  271. data/manual/html/projection.html +5 -7
  272. data/manual/html/prolog.html +5 -5
  273. data/manual/html/properties.html +11 -5
  274. data/manual/html/purge.html +5 -5
  275. data/manual/html/rate.html +4 -4
  276. data/manual/html/rate.resource.html +4 -4
  277. data/manual/html/reference.extend.html +4 -4
  278. data/manual/html/remaining.html +4 -4
  279. data/manual/html/replace.html +4 -4
  280. data/manual/html/reportprefix.html +4 -4
  281. data/manual/html/resource.html +4 -10
  282. data/manual/html/resourceattributes.html +4 -4
  283. data/manual/html/resourceprefix.html +4 -4
  284. data/manual/html/resourcereport.html +28 -10
  285. data/manual/html/resourceroot.html +5 -5
  286. data/manual/html/resources.limit.html +4 -4
  287. data/manual/html/responsible.html +4 -4
  288. data/manual/html/richtext.extend.html +4 -4
  289. data/manual/html/right.html +5 -5
  290. data/manual/html/rollupaccount.html +44 -9
  291. data/manual/html/rollupresource.html +44 -9
  292. data/manual/html/rolluptask.html +44 -9
  293. data/manual/html/scale.column.html +4 -4
  294. data/manual/html/scenario.html +4 -22
  295. data/manual/html/scenario.ical.html +4 -4
  296. data/manual/html/scenarios.export.html +4 -4
  297. data/manual/html/scenarios.html +5 -5
  298. data/manual/html/scenariospecific.extend.html +4 -4
  299. data/manual/html/scheduled.html +4 -4
  300. data/manual/html/scheduling.html +4 -4
  301. data/manual/html/select.html +4 -4
  302. data/manual/html/selfcontained.html +5 -5
  303. data/manual/html/shift.allocate.html +4 -4
  304. data/manual/html/shift.html +4 -4
  305. data/manual/html/shift.resource.html +5 -5
  306. data/manual/html/shift.task.html +4 -4
  307. data/manual/html/shift.timesheet.html +4 -4
  308. data/manual/html/shifts.allocate.html +4 -4
  309. data/manual/html/shifts.resource.html +4 -4
  310. data/manual/html/shifts.task.html +4 -4
  311. data/manual/html/shorttimeformat.html +4 -4
  312. data/manual/html/sloppy.booking.html +4 -4
  313. data/manual/html/sloppy.projection.html +5 -5
  314. data/manual/html/sortaccounts.html +5 -5
  315. data/manual/html/sortjournalentries.html +5 -5
  316. data/manual/html/sortresources.html +5 -5
  317. data/manual/html/sorttasks.html +5 -5
  318. data/manual/html/start.column.html +4 -4
  319. data/manual/html/start.html +4 -4
  320. data/manual/html/start.limit.html +4 -4
  321. data/manual/html/start.report.html +5 -5
  322. data/manual/html/startcredit.html +4 -4
  323. data/manual/html/status.statussheet.html +4 -4
  324. data/manual/html/status.timesheet.html +4 -4
  325. data/manual/html/statussheet.html +4 -4
  326. data/manual/html/statussheetreport.html +4 -4
  327. data/manual/html/strict.projection.html +5 -5
  328. data/manual/html/summary.html +4 -4
  329. data/manual/html/supplement.html +4 -4
  330. data/manual/html/supplement.resource.html +4 -10
  331. data/manual/html/supplement.task.html +4 -28
  332. data/manual/html/tagfile.html +4 -4
  333. data/manual/html/task.html +4 -28
  334. data/manual/html/task.statussheet.html +4 -4
  335. data/manual/html/task.timesheet.html +4 -4
  336. data/manual/html/taskattributes.html +4 -4
  337. data/manual/html/taskprefix.html +4 -4
  338. data/manual/html/taskreport.html +28 -10
  339. data/manual/html/taskroot.html +5 -5
  340. data/manual/html/text.extend.html +4 -4
  341. data/manual/html/textreport.html +27 -9
  342. data/manual/html/timeformat.html +5 -5
  343. data/manual/html/timeoff.nikureport.html +4 -4
  344. data/manual/html/timesheet.html +4 -4
  345. data/manual/html/timesheetreport.html +23 -5
  346. data/manual/html/timezone.export.html +4 -4
  347. data/manual/html/timezone.html +4 -4
  348. data/manual/html/timezone.report.html +5 -5
  349. data/manual/html/timezone.shift.html +4 -4
  350. data/manual/html/timingresolution.html +4 -4
  351. data/manual/html/title.column.html +4 -4
  352. data/manual/html/title.html +5 -5
  353. data/manual/html/toc.html +207 -179
  354. data/manual/html/tooltip.column.html +45 -10
  355. data/manual/html/tracereport.html +405 -0
  356. data/manual/html/trackingscenario.html +6 -6
  357. data/manual/html/treelevel.html +4 -4
  358. data/manual/html/vacation.html +4 -4
  359. data/manual/html/vacation.resource.html +4 -4
  360. data/manual/html/vacation.shift.html +4 -4
  361. data/manual/html/warn.html +43 -8
  362. data/manual/html/weeklymax.html +5 -5
  363. data/manual/html/weeklymin.html +5 -5
  364. data/manual/html/weekstartsmonday.html +4 -4
  365. data/manual/html/weekstartssunday.html +6 -6
  366. data/manual/html/width.column.html +6 -6
  367. data/manual/html/width.html +72 -0
  368. data/manual/html/work.html +4 -4
  369. data/manual/html/workinghours.project.html +4 -4
  370. data/manual/html/workinghours.resource.html +4 -4
  371. data/manual/html/workinghours.shift.html +4 -4
  372. data/manual/html/yearlyworkingdays.html +4 -4
  373. data/spec/Color_spec.rb +60 -0
  374. data/spec/ProjectBroker_spec.rb +3 -2
  375. data/spec/StatusSheets_spec.rb +5 -4
  376. data/spec/TableColumnSorter_spec.rb +78 -0
  377. data/spec/TimeSheets_spec.rb +6 -2
  378. data/spec/Tj3Daemon_spec.rb +2 -2
  379. data/spec/TraceReport_spec.rb +117 -0
  380. data/taskjuggler.gemspec +1 -1
  381. data/test/MessageChecker.rb +3 -1
  382. data/test/ReferenceGenerator.rb +1 -1
  383. data/test/TestSuite/CSV-Reports/Leave.tjp +1 -1
  384. data/test/TestSuite/CSV-Reports/refs/resourcereport_with_tasks.csv +3 -0
  385. data/test/TestSuite/CSV-Reports/refs/taskcounter.csv +9 -0
  386. data/test/TestSuite/CSV-Reports/refs/taskreport_with_resources.csv +19 -16
  387. data/test/TestSuite/CSV-Reports/refs/weekly.csv +1 -0
  388. data/test/TestSuite/Export-Reports/refs/LogicalExpression.tjp +14 -2
  389. data/test/TestSuite/Export-Reports/refs/tutorial.tjp +98 -86
  390. data/test/TestSuite/Scheduler/Correct/Leaves.tjp +25 -0
  391. data/test/TestSuite/Syntax/Correct/Leave.tjp +1 -1
  392. data/test/TestSuite/Syntax/Correct/LogicalExpression.tjp +9 -1
  393. data/test/TestSuite/Syntax/Correct/TraceReport.tjp +10 -0
  394. data/test/TestSuite/Syntax/Correct/tutorial.tjp +10 -4
  395. data/test/test_CSV-Reports.rb +3 -3
  396. data/test/test_Export-Reports.rb +91 -86
  397. data/test/test_Journal.rb +15 -12
  398. data/test/test_Limits.rb +3 -3
  399. data/test/test_Project.rb +1 -2
  400. data/test/test_ProjectFileScanner.rb +1 -1
  401. data/test/test_PropertySet.rb +1 -1
  402. data/test/test_Query.rb +5 -6
  403. data/test/test_ReportGenerator.rb +15 -7
  404. data/test/test_RichText.rb +4 -3
  405. data/test/test_Scheduler.rb +19 -7
  406. data/test/test_ShiftAssignments.rb +2 -2
  407. data/test/test_SimpleQueryExpander.rb +29 -2
  408. data/test/test_Syntax.rb +14 -5
  409. metadata +49 -10
  410. data/lib/taskjuggler/LogFile.rb +0 -73
@@ -23,12 +23,17 @@ class TaskJuggler
23
23
  def initialize(name, attributes = {}, selfClosing = false, &block)
24
24
  if (name.nil? && attributes.length > 0) ||
25
25
  (!name.nil? && !name.is_a?(String))
26
- raise "Name must be nil or a String "
26
+ raise ArgumentError, "Name must be nil or a String "
27
27
  end
28
28
  @name = name
29
29
  attributes.each do |n, v|
30
30
  if n.nil? || v.nil?
31
- raise "Attribute name (#{n}) or value (#{v}) may not be nil"
31
+ raise ArgumentError,
32
+ "Attribute name (#{n}) or value (#{v}) may not be nil"
33
+ end
34
+ unless v.is_a?(String)
35
+ raise ArgumentError,
36
+ "Attribute value of #{n} must be a String"
32
37
  end
33
38
  end
34
39
  @attributes = attributes
@@ -91,6 +96,8 @@ class TaskJuggler
91
96
 
92
97
  # Add or change _attribute_ to _value_.
93
98
  def []=(attribute, value)
99
+ raise ArgumentError,
100
+ "Attribute value #{value} is not a String" unless value.is_a?(String)
94
101
  @attributes[attribute] = value
95
102
  end
96
103
 
@@ -35,6 +35,8 @@ class TaskJuggler
35
35
  @checkSyntax = false
36
36
  # Don't generate reports when previous errors have been found.
37
37
  @forceReports = false
38
+ # Don't generate trace reports by default
39
+ @generateTraces = false
38
40
  # Should a booking file be generated?
39
41
  @freeze = false
40
42
  # The cut-off date for the freeze
@@ -87,7 +89,8 @@ EOT
87
89
  begin
88
90
  @freezeDate = TjTime.new(arg).align(3600)
89
91
  rescue TjException => msg
90
- error("Invalid freeze date: #{msg.message}")
92
+ error('tj3_ivld_freeze_date',
93
+ "Invalid freeze date: #{msg.message}")
91
94
  end
92
95
  end
93
96
  @opts.on('--freezebytask',
@@ -117,6 +120,10 @@ EOT
117
120
  'reports.')) do
118
121
  @noReports = true
119
122
  end
123
+ @opts.on('--add-trace',
124
+ format('Append a current data set to all trace reports.')) do
125
+ @generateTraces = true
126
+ end
120
127
  @opts.on('--abort-on-warnings',
121
128
  format('Abort program on warnings like we do on errors.')) do
122
129
  @abortOnWarning = true
@@ -133,49 +140,48 @@ EOT
133
140
  end
134
141
 
135
142
  def appMain(files)
136
- begin
137
- if files.empty?
138
- error('You must provide at least one .tjp file', 1)
139
- end
140
- if @outputDir != '' && !Dir.exists?(@outputDir)
141
- error("Output directory #{@outputDir} does not exist!")
142
- end
143
-
144
- tj = TaskJuggler.new(true)
145
- tj.maxCpuCores = @maxCpuCores
146
- tj.warnTsDeltas = @warnTsDeltas
147
- tj.messageHandler.abortOnWarning = @abortOnWarning
148
- keepParser = !@timeSheets.empty? || !@statusSheets.empty?
149
- return 1 unless tj.parse(files, keepParser)
143
+ if files.empty?
144
+ error('tj3_tjp_file_missing',
145
+ 'You must provide at least one .tjp file')
146
+ end
147
+ if @outputDir != '' && !File.directory?(@outputDir)
148
+ error('tj3_outdir_missing',
149
+ "Output directory #{@outputDir} does not exist or is not " +
150
+ "a directory!")
151
+ end
150
152
 
151
- return 0 if @checkSyntax
153
+ tj = TaskJuggler.new
154
+ tj.maxCpuCores = @maxCpuCores
155
+ tj.warnTsDeltas = @warnTsDeltas
156
+ tj.generateTraces = @generateTraces
157
+ MessageHandlerInstance.instance.abortOnWarning = @abortOnWarning
158
+ keepParser = !@timeSheets.empty? || !@statusSheets.empty?
159
+ return 1 unless tj.parse(files, keepParser)
152
160
 
153
- if !tj.schedule
154
- return 1 unless @forceReports
155
- end
161
+ return 0 if @checkSyntax
156
162
 
157
- # The checks of time and status sheets is probably only used for
158
- # debugging. Normally, this function is provided by tj3client.
159
- @timeSheets.each do |ts|
160
- return 1 if !tj.checkTimeSheet(ts) || tj.errors > 0
161
- end
162
- @statusSheets.each do |ss|
163
- return 1 if !tj.checkStatusSheet(ss) || tj.errors > 0
164
- end
163
+ if !tj.schedule
164
+ return 1 unless @forceReports
165
+ end
165
166
 
166
- # Check for freeze mode and generate the booking file if requested.
167
- if @freeze
168
- return 1 unless tj.freeze(@freezeDate, @freezeByTask) &&
169
- tj.errors == 0
170
- end
167
+ # The checks of time and status sheets is probably only used for
168
+ # debugging. Normally, this function is provided by tj3client.
169
+ @timeSheets.each do |ts|
170
+ return 1 if !tj.checkTimeSheet(ts) || tj.errors > 0
171
+ end
172
+ @statusSheets.each do |ss|
173
+ return 1 if !tj.checkStatusSheet(ss) || tj.errors > 0
174
+ end
171
175
 
172
- return 0 if @noReports
176
+ # Check for freeze mode and generate the booking file if requested.
177
+ if @freeze
178
+ return 1 unless tj.freeze(@freezeDate, @freezeByTask) &&
179
+ tj.errors == 0
180
+ end
173
181
 
174
- return 1 if !tj.generateReports(@outputDir) || tj.errors > 0
182
+ return 0 if @noReports
175
183
 
176
- rescue TjRuntimeError
177
- return 1
178
- end
184
+ return 1 if !tj.generateReports(@outputDir) || tj.errors > 0
179
185
 
180
186
  0
181
187
  end
@@ -14,7 +14,7 @@
14
14
  require 'drb'
15
15
  require 'drb/acl'
16
16
  require 'taskjuggler/Tj3AppBase'
17
- require 'taskjuggler/LogFile'
17
+ require 'taskjuggler/daemon/DaemonConnector'
18
18
 
19
19
  # Name of the application
20
20
  AppConfig.appName = 'tj3client'
@@ -28,6 +28,8 @@ class TaskJuggler
28
28
  # requires a properly configured tj3d to work.
29
29
  class Tj3Client < Tj3AppBase
30
30
 
31
+ include DaemonConnectorMixin
32
+
31
33
  def initialize
32
34
  super
33
35
 
@@ -136,8 +138,8 @@ EOT
136
138
  @uriFile = arg
137
139
  end
138
140
  @opts.on('-r', '--regexp',
139
- format('The report IDs are not fixed but regular expressions ' +
140
- 'that match a set of reports')) do |arg|
141
+ format('The report IDs are not fixed but regular ' +
142
+ 'expressions that match a set of reports')) do |arg|
141
143
  @regExpMode = true
142
144
  end
143
145
  @opts.on('--unsafe',
@@ -151,8 +153,8 @@ EOT
151
153
  format('Request the report to be generated in the specified' +
152
154
  'format. Use multiple options to request multiple ' +
153
155
  'formats. Supported formats are csv, html, niku and ' +
154
- 'tjp. By default, the formats specified in the report ' +
155
- 'definition are used.')) do |arg|
156
+ 'tjp. By default, the formats specified in the ' +
157
+ 'report definition are used.')) do |arg|
156
158
  @formats = [] unless @formats
157
159
  @formats << arg
158
160
  end
@@ -160,21 +162,18 @@ EOT
160
162
  end
161
163
 
162
164
  def appMain(args)
163
- begin
164
- # Run a first check of the non-optional command line arguments.
165
- checkCommand(args)
166
- # Read some configuration variables. Except for the authKey, they are
167
- # all optional.
168
- @rc.configure(self, 'global')
169
-
170
- connectDaemon
171
- retVal = executeCommand(args[0], args[1..-1])
172
- disconnectDaemon
173
-
174
- return retVal
175
- rescue TjRuntimeError
176
- return 1
177
- end
165
+ # Run a first check of the non-optional command line arguments.
166
+ checkCommand(args)
167
+ # Read some configuration variables. Except for the authKey, they are
168
+ # all optional.
169
+ @rc.configure(self, 'global')
170
+
171
+ @broker = connectDaemon
172
+ retVal = executeCommand(args[0], args[1..-1])
173
+ disconnectDaemon
174
+ @broker = nil
175
+
176
+ retVal
178
177
  end
179
178
 
180
179
  private
@@ -205,64 +204,7 @@ EOT
205
204
  end
206
205
  end
207
206
 
208
- error(errorMessage)
209
- end
210
-
211
- def connectDaemon
212
- unless @authKey
213
- $stderr.puts <<'EOT'
214
- You must set an authentication key in the configuration file. Create a file
215
- named .taskjugglerrc or taskjuggler.rc that contains at least the following
216
- lines. Replace 'your_secret_key' with some random character sequence.
217
-
218
- _global:
219
- authKey: your_secret_key
220
- EOT
221
- end
222
-
223
- uri = "druby://#{@host}:#{@port}"
224
- if @port == 0
225
- # If the @port is configured to 0, we need to read the URI to connect
226
- # to the server from the .tj3d.uri file that has been generated by the
227
- # server.
228
- begin
229
- uri = File.read(@uriFile).chomp
230
- rescue
231
- error('The server port is configured to be 0, but no ' +
232
- ".tj3d.uri file can be found: #{$!}")
233
- end
234
- end
235
-
236
- # We try to play it safe here. The client also starts a DRb server, so
237
- # we need to make sure it's constricted to localhost only. We require
238
- # the DRb server for the standard IO redirection to work.
239
- $SAFE = 1 unless @unsafeMode
240
- DRb.install_acl(ACL.new(%w[ deny all
241
- allow 127.0.0.1 ]))
242
- DRb.start_service('druby://127.0.0.1:0')
243
-
244
- begin
245
- # Get the ProjectBroker object from the tj3d.
246
- @broker = DRbObject.new(nil, uri)
247
- # Client and server should always come from the same Gem. Since we
248
- # restict communication to localhost, that's probably not a problem.
249
- if (check = @broker.apiVersion(@authKey, 1)) < 0
250
- error('This client is too old for the server. Please ' +
251
- 'upgrade to a more recent version of the software.')
252
- elsif check == 0
253
- error('Authentication failed. Please check your authentication ' +
254
- 'key to match the server key.')
255
- end
256
- rescue
257
- error("TaskJuggler server on host '#{@host}' port " +
258
- "#{@port} is not responding")
259
- end
260
- end
261
-
262
- def disconnectDaemon
263
- @broker = nil
264
-
265
- DRb.stop_service
207
+ error('tjc_cmd_error', errorMessage)
266
208
  end
267
209
 
268
210
  def executeCommand(command, args)
@@ -271,22 +213,28 @@ EOT
271
213
  $stdout.puts callDaemon(:status, [])
272
214
  when 'terminate'
273
215
  callDaemon(:stop, [])
274
- info('Daemon terminated')
216
+ info('tjc_daemon_term', 'Daemon terminated')
275
217
  when 'add'
276
218
  res = callDaemon(:addProject, [ Dir.getwd, args,
277
219
  $stdout, $stderr, $stdin, @silent ])
278
- info("Project(s) #{args.join(', ')} added")
279
- return res ? 0 : 1
220
+ if res
221
+ info('tjc_proj_added', "Project(s) #{args.join(', ')} added")
222
+ return 0
223
+ else
224
+ warning('tjc_proj_adding_failed',
225
+ "Projects(s) #{args.join(', ')} could not be added")
226
+ return 1
227
+ end
280
228
  when 'remove'
281
229
  args.each do |arg|
282
230
  unless callDaemon(:removeProject, arg)
283
- error("Project '#{arg}' not found in list")
231
+ error('tjc_prj_not_found', "Project '#{arg}' not found in list")
284
232
  end
285
233
  end
286
- info('Project removed')
234
+ info('tjc_prj_removed', 'Project removed')
287
235
  when 'update'
288
236
  callDaemon(:update, [])
289
- info('Reload requested')
237
+ info('tjc_reload_req', 'Reload requested')
290
238
  when 'report'
291
239
  # The first value of args is the project ID. The following values
292
240
  # could be either report IDs or TJI file # names ('.' or '*.tji').
@@ -298,17 +246,22 @@ EOT
298
246
  reportIds, tjiFiles = splitIdsAndFiles(args)
299
247
  if reportIds.empty?
300
248
  disconnectReportServer
301
- error('You must provide at least one report ID')
249
+ error('tjc_no_rep_id', 'You must provide at least one report ID')
302
250
  end
303
251
  # Send the provided .tji files to the ReportServer.
304
252
  failed = !addFiles(tjiFiles)
305
253
  # Ask the ReportServer to generate the reports with the provided IDs.
306
254
  unless failed
307
255
  reportIds.each do |reportId|
308
- unless @reportServer.generateReport(@rs_authKey, reportId,
309
- @regExpMode, @formats, nil)
310
- failed = true
311
- break
256
+ begin
257
+ unless @reportServer.generateReport(@rs_authKey, reportId,
258
+ @regExpMode, @formats, nil)
259
+ failed = true
260
+ break
261
+ end
262
+ rescue
263
+ error('tjc_gen_rep_failed',
264
+ "Could not generate report #{reportId}: #{$!}")
312
265
  end
313
266
  end
314
267
  end
@@ -334,9 +287,15 @@ EOT
334
287
  # Ask the ReportServer to generate the reports with the provided IDs.
335
288
  unless failed
336
289
  reportIds.each do |reportId|
337
- unless @reportServer.listReports(@rs_authKey, reportId, @regExpMode)
338
- failed = true
339
- break
290
+ begin
291
+ unless @reportServer.listReports(@rs_authKey, reportId,
292
+ @regExpMode)
293
+ failed = true
294
+ break
295
+ end
296
+ rescue
297
+ error('tjc_report_list_failed',
298
+ "Getting report list failed: #{$!}")
340
299
  end
341
300
  end
342
301
  end
@@ -348,7 +307,7 @@ EOT
348
307
  begin
349
308
  res = @reportServer.checkTimeSheet(@rs_authKey, args[1])
350
309
  rescue
351
- error("Time sheet check failed: #{$!}")
310
+ error('tjc_tschck_failed', "Time sheet check failed: #{$!}")
352
311
  end
353
312
  disconnectReportServer
354
313
  return res ? 0 : 1
@@ -357,7 +316,7 @@ EOT
357
316
  begin
358
317
  res = @reportServer.checkStatusSheet(@rs_authKey, args[1])
359
318
  rescue
360
- error("Status sheet check failed: #{$!}")
319
+ error('tjc_sschck_failed', "Status sheet check failed: #{$!}")
361
320
  end
362
321
  disconnectReportServer
363
322
  return res ? 0 : 1
@@ -370,19 +329,19 @@ EOT
370
329
  def connectToReportServer(projectId)
371
330
  @ps_uri, @ps_authKey = callDaemon(:getProject, projectId)
372
331
  if @ps_uri.nil?
373
- error("No project with ID #{projectId} loaded")
332
+ error('tjc_prj_id_not_loaded', "No project with ID #{projectId} loaded")
374
333
  end
375
334
  begin
376
335
  @projectServer = DRbObject.new(nil, @ps_uri)
377
336
  @rs_uri, @rs_authKey = @projectServer.getReportServer(@ps_authKey)
378
337
  @reportServer = DRbObject.new(nil, @rs_uri)
379
338
  rescue
380
- error("Cannot get report server")
339
+ error('tjc_no_rep_srv', "Cannot get report server: #{$!}")
381
340
  end
382
341
  begin
383
342
  @reportServer.connect(@rs_authKey, $stdout, $stderr, $stdin, @silent)
384
343
  rescue
385
- error("Can't connect IO: #{$!}")
344
+ error('tjc_no_io_connect', "Can't connect IO: #{$!}")
386
345
  end
387
346
  end
388
347
 
@@ -390,12 +349,12 @@ EOT
390
349
  begin
391
350
  @reportServer.disconnect(@rs_authKey)
392
351
  rescue
393
- error("Can't disconnect IO: #{$!}")
352
+ error('tjc_no_io_disconnect', "Can't disconnect IO: #{$!}")
394
353
  end
395
354
  begin
396
355
  @reportServer.terminate(@rs_authKey)
397
356
  rescue
398
- error("Report server termination failed: #{$!}")
357
+ error('tjc_srv_term_failed', "Report server termination failed: #{$!}")
399
358
  end
400
359
  @reportServer = nil
401
360
  @rs_uri = nil
@@ -411,7 +370,8 @@ EOT
411
370
  begin
412
371
  return @broker.command(@authKey, command, args)
413
372
  rescue
414
- error("Call to TaskJuggler server on host '#{@host}' " +
373
+ error('tjc_call_srv_failed',
374
+ "Call to TaskJuggler server on host '#{@host}' " +
415
375
  "port #{@port} failed: #{$!}")
416
376
  end
417
377
  end
@@ -445,23 +405,13 @@ EOT
445
405
  return false
446
406
  end
447
407
  rescue
448
- error("Cannot add file #{file} to ReportServer")
408
+ error('tjc_canont_add_file',
409
+ "Cannot add file #{file} to ReportServer")
449
410
  end
450
411
  end
451
412
  true
452
413
  end
453
414
 
454
- def info(message)
455
- return if @silent
456
- $stdout.puts "#{message}"
457
- end
458
-
459
- def error(message, exitVal = 1)
460
- $stderr.puts "ERROR: #{message}"
461
- # Don't call exit in unsafe mode. Raise a StandardError instead.
462
- raise TjRuntimeError
463
- end
464
-
465
415
  end
466
416
 
467
417
  end
@@ -13,7 +13,7 @@
13
13
 
14
14
  require 'drb'
15
15
  require 'taskjuggler/Tj3AppBase'
16
- require 'taskjuggler/LogFile'
16
+ require 'taskjuggler/MessageHandler'
17
17
  require 'taskjuggler/daemon/ProjectBroker'
18
18
 
19
19
  # Name of the application
@@ -27,14 +27,17 @@ class TaskJuggler
27
27
  super
28
28
  @mandatoryArgs = '[<tjp file> [<tji file> ...] ...]'
29
29
 
30
- @log = LogFile.instance
31
- @log.logFile = File.join(Dir.getwd, "/#{AppConfig.appName}.log")
32
- @log.appName = AppConfig.appName
30
+ @mhi = MessageHandlerInstance.instance
31
+ @mhi.logFile = File.join(Dir.getwd, "/#{AppConfig.appName}.log")
32
+ @mhi.appName = AppConfig.appName
33
+ # By default show only warnings and more serious messages.
34
+ @mhi.outputLevel = :warning
33
35
  @daemonize = true
34
36
  @uriFile = File.join(Dir.getwd, '.tj3d.uri')
35
37
  @port = nil
36
38
  @webServer = false
37
- @webServerPort = nil
39
+ @webServerPort = 8080
40
+ @webdPidFile = File.join(Dir.getwd, ".tj3webd-#{$$}.pid").untaint
38
41
  end
39
42
 
40
43
  def processArguments(argv)
@@ -69,33 +72,65 @@ EOT
69
72
  'requests (Default: 8080).')) do |arg|
70
73
  @webServerPort = arg
71
74
  end
75
+
72
76
  end
73
77
  end
74
78
 
75
79
  def appMain(files)
76
- begin
77
- broker = ProjectBroker.new
78
- @rc.configure(self, 'global')
79
- @rc.configure(@log, 'global.log')
80
- @rc.configure(broker, 'global')
81
- @rc.configure(broker, 'daemon')
82
-
83
- # Set some config variables if corresponding data was provided via the
84
- # command line.
85
- broker.port = @port if @port
86
- broker.uriFile = @uriFile.untaint
87
- broker.enableWebServer = @webServer
88
- broker.webServerPort = @webServerPort if @webServerPort
89
- broker.projectFiles = sortInputFiles(files) unless files.empty?
90
- broker.daemonize = @daemonize
91
- # Create log files for standard IO for each child process if the daemon
92
- # is not disconnected from the terminal.
93
- broker.logStdIO = !@daemonize
94
-
95
- return broker.start
96
- rescue TjRuntimeError
97
- return 1
80
+ broker = ProjectBroker.new
81
+ @rc.configure(self, 'global')
82
+ @rc.configure(@mhi, 'global.log')
83
+ @rc.configure(broker, 'global')
84
+ @rc.configure(broker, 'daemon')
85
+
86
+ # Set some config variables if corresponding data was provided via the
87
+ # command line.
88
+ broker.port = @port if @port
89
+ broker.uriFile = @uriFile.untaint
90
+ broker.projectFiles = sortInputFiles(files) unless files.empty?
91
+ broker.daemonize = @daemonize
92
+ # Create log files for standard IO for each child process if the daemon
93
+ # is not disconnected from the terminal.
94
+ broker.logStdIO = !@daemonize
95
+
96
+ if @webServer
97
+ webdCommand = "tj3webd --webserver-port #{@webServerPort} " +
98
+ "--pidfile #{@webdPidFile}"
99
+ # Also start the web server as a separate process. We keep the PID, so
100
+ # we can terminate that process again when we exit the daemon.
101
+ begin
102
+ `#{webdCommand}`
103
+ rescue
104
+ error('tj3webd_start_failed', "Could not start tj3webd: #{$!}")
105
+ end
106
+ info('web_server_started', "Web server started as '#{webdCommand}'")
98
107
  end
108
+
109
+ broker.start
110
+
111
+ if @webServer
112
+ pid = nil
113
+ begin
114
+ # Read the PID of the web server from the PID file.
115
+ File.open(@webdPidFile, 'r') do |f|
116
+ pid = f.read.to_i
117
+ end
118
+ rescue
119
+ warning('cannot_read_webd_pidfile',
120
+ "Cannot read tj3webd PID file (#{@webdPidFile}): #{$!}")
121
+ end
122
+ # If we have started the web server, we are also trying to terminate
123
+ # that process again.
124
+ begin
125
+ Process.kill("TERM", pid)
126
+ rescue
127
+ warning('tj3webd_term_failed',
128
+ "Could not terminate web server: #{$!}")
129
+ end
130
+ info('web_server_terminated', "Web server with PID #{pid} terminated")
131
+ end
132
+
133
+ 0
99
134
  end
100
135
 
101
136
  private
@@ -128,11 +163,13 @@ EOT
128
163
  # .tji files are optional. But if they are specified, they must
129
164
  # always follow the master file in the list.
130
165
  if project.nil?
131
- error("You must specify a '.tjp' file before the '.tji' files")
166
+ error('tj3d_tji_before_tjp',
167
+ "You must specify a '.tjp' file before the '.tji' files")
132
168
  end
133
169
  project << file
134
170
  else
135
- error("Project files must have a '.tjp' or '.tji' extension")
171
+ error('tj3d_no_file_Ext',
172
+ "Project files must have a '.tjp' or '.tji' extension")
136
173
  end
137
174
  end
138
175