taskjuggler 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -11,24 +11,36 @@
11
11
  # published by the Free Software Foundation.
12
12
  #
13
13
 
14
+ require 'taskjuggler/AppConfig'
14
15
  require 'taskjuggler/Log'
15
- require 'taskjuggler/LogFile'
16
+ require 'taskjuggler/MessageHandler'
16
17
 
17
18
  class TaskJuggler
18
19
 
19
20
  module ProcessIntercomIface
20
21
 
22
+ include MessageHandler
23
+
21
24
  # This function catches all unhandled exceptions in the passed block.
22
25
  def trap
23
- log = LogFile.instance
24
-
25
26
  begin
26
- yield
27
- rescue
28
- $stderr.print $!.to_s
29
- $stderr.print $!.backtrace.join("\n")
30
- log.debug($!.backtrace.join("\n"))
31
- log.fatal("Unexpected exception: #{$!}")
27
+ MessageHandlerInstance.instance.trapSetup = true
28
+ res = yield
29
+ MessageHandlerInstance.instance.trapSetup = false
30
+ res
31
+ rescue => e
32
+ # Any exception here is a fata error. We try hard to terminate the DRb
33
+ # thread and then exit the program.
34
+ begin
35
+ fatal('pi_crash_trap', "#{e}\n#{e.backtrace.join("\n")}\n\n" +
36
+ "#{'*' * 79}\nYou have triggered a bug in " +
37
+ "#{AppConfig.softwareName} version #{AppConfig.version}!\n" +
38
+ "Please see the user manual on how to get this bug fixed!\n" +
39
+ "#{'*' * 79}\n")
40
+ rescue RuntimeError
41
+ @server.terminate
42
+ return false
43
+ end
32
44
  end
33
45
  end
34
46
 
@@ -54,12 +66,13 @@ class TaskJuggler
54
66
 
55
67
  module ProcessIntercom
56
68
 
69
+ include MessageHandler
70
+
57
71
  def initIntercom
58
72
  # This is the authentication key that clients will need to provide to
59
73
  # execute DRb methods.
60
74
  @authKey = generateAuthKey
61
75
 
62
- @log = LogFile.instance
63
76
  # This flag will be set to true by DRb method calls to terminate the
64
77
  # process.
65
78
  @terminate = false
@@ -73,14 +86,14 @@ class TaskJuggler
73
86
  end
74
87
 
75
88
  def terminate
76
- @log.debug('Terminating on external request')
89
+ debug('', 'Terminating on external request')
77
90
  @terminate = true
78
91
  end
79
92
 
80
93
  def connect(stdout, stderr, stdin, silent)
81
94
  # Set the client lock.
82
95
  @clientConnection.lock
83
- @log.debug('Rerouting ProjectServer standard IO to client')
96
+ debug('', 'Rerouting ProjectServer standard IO to client')
84
97
  # Make sure that all output to STDOUT and STDERR is sent to the client.
85
98
  # Input is read from the client STDIN. We save a copy of the old file
86
99
  # handles so we can restore then later again.
@@ -90,18 +103,18 @@ class TaskJuggler
90
103
  $stdout = stdout if stdout
91
104
  $stderr = stderr if stdout
92
105
  $stdin = stdin if stdin
93
- @log.debug('IO is now routed to the client')
106
+ debug('', 'IO is now routed to the client')
94
107
  Log.silent = silent
95
108
  true
96
109
  end
97
110
 
98
111
  def disconnect
99
- @log.debug('Restoring IO')
112
+ debug('', 'Restoring IO')
100
113
  Log.silent = true
101
114
  $stdout = @stdout if @stdout
102
115
  $stderr = @stderr if @stderr
103
116
  $stdin = @stdin if @stdin
104
- @log.debug('Standard IO has been restored')
117
+ debug('', 'Standard IO has been restored')
105
118
  # Release the client lock
106
119
  @clientConnection.unlock
107
120
  true
@@ -113,10 +126,11 @@ class TaskJuggler
113
126
 
114
127
  def checkKey(authKey, command)
115
128
  if authKey == @authKey
116
- @log.debug("Accepted authentication key for command '#{command}'")
129
+ debug('', "Accepted authentication key for command '#{command}'")
117
130
  else
118
- @log.warning("Rejected wrong authentication key #{authKey}" +
119
- "for command '#{command}'")
131
+ warning('auth_key_rejected',
132
+ "Rejected wrong authentication key #{authKey}" +
133
+ "for command '#{command}'")
120
134
  return false
121
135
  end
122
136
  true
@@ -126,7 +140,7 @@ class TaskJuggler
126
140
  # client connection timer.
127
141
  def restartTimer
128
142
  @timeLock.synchronize do
129
- @log.debug('Reseting client connection timer')
143
+ debug('', 'Reseting client connection timer')
130
144
  @timerStart = Time.new
131
145
  end
132
146
  end
@@ -156,9 +170,10 @@ class TaskJuggler
156
170
  sleep 1
157
171
  end
158
172
  if timerExpired?
159
- @log.warning('Shutting down DRb server due to timeout')
173
+ warning('drb_timeout_shutdown',
174
+ 'Shutting down DRb server due to timeout')
160
175
  else
161
- @log.debug('Shutting down DRb server')
176
+ debug('', 'Shutting down the DRb server')
162
177
  end
163
178
  DRb.stop_service
164
179
  break
@@ -17,8 +17,8 @@ require 'drb'
17
17
  require 'drb/acl'
18
18
  require 'taskjuggler/daemon/Daemon'
19
19
  require 'taskjuggler/daemon/ProjectServer'
20
- require 'taskjuggler/daemon/WebServer'
21
20
  require 'taskjuggler/TjTime'
21
+ require 'taskjuggler/MessageHandler'
22
22
 
23
23
  class TaskJuggler
24
24
 
@@ -37,8 +37,9 @@ class TaskJuggler
37
37
  # daemon.
38
38
  class ProjectBroker < Daemon
39
39
 
40
- attr_accessor :authKey, :port, :uriFile, :enableWebServer, :webServerPort,
41
- :projectFiles, :logStdIO
40
+ include MessageHandler
41
+
42
+ attr_accessor :authKey, :port, :uriFile, :projectFiles, :logStdIO
42
43
 
43
44
  def initialize
44
45
  super
@@ -66,15 +67,6 @@ class TaskJuggler
66
67
  # will be seperate set of files for each process.
67
68
  @logStdIO = !@daemonize
68
69
 
69
- # Reference to WEBrick object.
70
- @webServer = nil
71
-
72
- # Port used by the web server
73
- @webServerPort = 8080
74
-
75
- # True if web server should be activated
76
- @enableWebServer = false
77
-
78
70
  # This flag will be set to true to terminate the daemon.
79
71
  @terminate = false
80
72
  end
@@ -83,7 +75,7 @@ class TaskJuggler
83
75
  # To ensure a certain level of security, the user must provide an
84
76
  # authentication key to authenticate the client to this server.
85
77
  unless @authKey
86
- @log.fatal(<<'EOT'
78
+ error('pb_no_auth_key', <<'EOT'
87
79
  You must set an authentication key in the configuration file. Create a file
88
80
  named .taskjugglerrc or taskjuggler.rc that contains at least the following
89
81
  lines. Replace 'your_secret_key' with some random character sequence.
@@ -96,18 +88,7 @@ EOT
96
88
 
97
89
  # In daemon mode, we fork twice and only the 2nd child continues here.
98
90
  super()
99
- @log.debug("Starting project broker")
100
-
101
- if @enableWebServer
102
- begin
103
- # The web server must be started before we turn SAFE mode on.
104
- @webServer = WebServer.new(self, @webServerPort)
105
- @log.info("TaskJuggler web server is listening on port " +
106
- "#{@webServerPort}")
107
- rescue
108
- @log.fatal("Cannot start web server: #{$!}")
109
- end
110
- end
91
+ debug('', "Starting project broker")
111
92
 
112
93
  # Setup a DRb server to handle the incomming requests from the clients.
113
94
  brokerIface = ProjectBrokerIface.new(self)
@@ -116,9 +97,9 @@ EOT
116
97
  DRb.install_acl(ACL.new(%w[ deny all
117
98
  allow 127.0.0.1 ]))
118
99
  @uri = DRb.start_service("druby://127.0.0.1:#{@port}", brokerIface).uri
119
- @log.info("TaskJuggler daemon is listening on #{@uri}")
100
+ info('daemon_uri', "TaskJuggler daemon is listening on #{@uri}")
120
101
  rescue
121
- @log.fatal("Cannot listen on port #{@port}: #{$!}")
102
+ error('port_in_use', "Cannot listen on port #{@port}: #{$!}")
122
103
  end
123
104
 
124
105
  if @port == 0 && @uriFile
@@ -127,7 +108,7 @@ EOT
127
108
  begin
128
109
  File.open(@uriFile, 'w') { |f| f.write @uri }
129
110
  rescue
130
- @log.fatal("Cannot write URI file #{@uriFile}: #{$!}")
111
+ error('cannot_write_uri', "Cannot write URI file #{@uriFile}: #{$!}")
131
112
  end
132
113
  end
133
114
 
@@ -141,19 +122,19 @@ EOT
141
122
  # some other work asynchronously.
142
123
  startHousekeeping
143
124
 
144
- # Cleanup the DRb threads
145
- DRb.thread.join
125
+ debug('', 'Shutting down ProjectBroker DRb server')
126
+ DRb.stop_service
146
127
 
147
128
  # If we have created a URI file, we need to delete it again.
148
129
  if @port == 0 && @uriFile
149
130
  begin
150
131
  File.delete(@uriFile)
151
132
  rescue
152
- @log.fatal("Cannot delete URI file .tj3d.uri: #{$!}")
133
+ error('cannot_delete_uri', "Cannot delete URI file .tj3d.uri: #{$!}")
153
134
  end
154
135
  end
155
136
 
156
- @log.info('TaskJuggler daemon terminated')
137
+ info('daemon_terminated', 'TaskJuggler daemon terminated')
157
138
  end
158
139
 
159
140
  # All remote commands must provide the proper authentication key. Usually
@@ -161,10 +142,11 @@ EOT
161
142
  # configuration file.
162
143
  def checkKey(authKey, command)
163
144
  if authKey == @authKey
164
- @log.debug("Accepted authentication key for command '#{command}'")
145
+ debug('', "Accepted authentication key for command '#{command}'")
165
146
  else
166
- @log.warning("Rejected wrong authentication key '#{authKey}' " +
167
- "for command '#{command}'")
147
+ warning('wrong_auth_key',
148
+ "Rejected wrong authentication key '#{authKey}' " +
149
+ "for command '#{command}'")
168
150
  return false
169
151
  end
170
152
  true
@@ -172,7 +154,7 @@ EOT
172
154
 
173
155
  # This command will initiate the termination of the daemon.
174
156
  def stop
175
- @log.debug('Terminating on client request')
157
+ debug('', 'Terminating on client request')
176
158
 
177
159
  # Shut down the web server if we've started one.
178
160
  if @webServer
@@ -216,7 +198,7 @@ EOT
216
198
  # associated to. Just use a large enough random number.
217
199
  tag = rand(9999999999999)
218
200
 
219
- @log.debug("Pushing #{tag} to load Queue")
201
+ debug('', "Pushing #{tag} to load Queue")
220
202
  @projectsToLoad.push(tag)
221
203
 
222
204
  # Now we have to wait until the project shows up in the @projects
@@ -236,23 +218,23 @@ EOT
236
218
  sleep 0.1 unless pr
237
219
  end
238
220
 
239
- @log.debug("Found tag #{tag} in list of loaded projects with URI " +
240
- "#{pr.uri}")
241
- # Return the URI and the authentication key of the new ProjectServer.
242
- [ pr.uri, pr.authKey ]
221
+ debug('', "Found tag #{tag} in list of loaded projects with URI " +
222
+ "#{pr.uri}")
223
+
224
+ res = false
243
225
 
244
226
  # Open a DRb connection to the ProjectServer process
245
227
  begin
246
228
  projectServer = DRbObject.new(nil, pr.uri)
247
229
  rescue
248
- stdErr.puts "Can't get ProjectServer object: #{$!}"
230
+ warning('pb_cannot_get_ps', "Can't get ProjectServer object: #{$!}")
249
231
  return false
250
232
  end
251
233
  begin
252
234
  # Hook up IO from requestor to the ProjectServer process.
253
235
  projectServer.connect(pr.authKey, stdOut, stdErr, stdIn, silent)
254
236
  rescue
255
- stdErr.puts "Can't connect IO: #{$!}"
237
+ warning('pb_cannot_connect_io', "Can't connect IO: #{$!}")
256
238
  return false
257
239
  end
258
240
 
@@ -261,7 +243,7 @@ EOT
261
243
  begin
262
244
  res = projectServer.loadProject(pr.authKey, [ cwd, *args ])
263
245
  rescue
264
- stdErr.puts "Loading of project failed: #{$!}"
246
+ warning('pb_load_failed', "Loading of project failed: #{$!}")
265
247
  return false
266
248
  end
267
249
 
@@ -269,7 +251,7 @@ EOT
269
251
  begin
270
252
  projectServer.disconnect(pr.authKey)
271
253
  rescue
272
- stdErr.puts "Can't disconnect IO: #{$!}"
254
+ warning('pb_cannot_disconnect_io', "Can't disconnect IO: #{$!}")
273
255
  return false
274
256
  end
275
257
 
@@ -278,7 +260,8 @@ EOT
278
260
 
279
261
  def removeProject(indexOrId)
280
262
  @projects.synchronize do
281
- # Find all projects with the IDs in indexOrId and mark them as :obsolete.
263
+ # Find all projects with the IDs in indexOrId and mark them as
264
+ # :obsolete.
282
265
  if /^[0-9]$/.match(indexOrId)
283
266
  index = indexOrId.to_i - 1
284
267
  if index >= 0 && index < @projects.length
@@ -315,7 +298,7 @@ EOT
315
298
  end
316
299
 
317
300
  if project.nil?
318
- @log.debug("No project with ID #{projectId} found")
301
+ debug('', "No project with ID #{projectId} found")
319
302
  return [ nil, nil ]
320
303
  end
321
304
  [ project.uri, project.authKey ]
@@ -371,7 +354,7 @@ EOT
371
354
  # Don't accept updates for already obsolete entries.
372
355
  next if project.state == :obsolete
373
356
 
374
- @log.debug("Updating state for #{id} to #{state}")
357
+ debug('', "Updating state for #{id} to #{state}")
375
358
  # Only update the record that has the matching key
376
359
  if project.authKey == projectKey
377
360
  project.id = id if id
@@ -385,7 +368,7 @@ EOT
385
368
  @projects.each do |p|
386
369
  if p != project && p.id == id
387
370
  p.state = :obsolete
388
- @log.debug("Marking entry with ID #{id} as obsolete")
371
+ debug('', "Marking entry with ID #{id} as obsolete")
389
372
  end
390
373
  end
391
374
  project.readySince = TjTime.new
@@ -409,64 +392,64 @@ EOT
409
392
  private
410
393
 
411
394
  def startHousekeeping
412
- Thread.new do
413
- begin
414
- cntr = 0
415
- loop do
416
- if @terminate
417
- # Give the caller a chance to properly terminate the connection.
418
- sleep 0.5
419
- @log.debug('Shutting down DRb server')
420
- DRb.stop_service
421
- break
422
- elsif !@projectsToLoad.empty?
423
- loadProject(@projectsToLoad.pop)
424
- else
425
- # Send termination command to all obsolute ProjectServer
426
- # objects. To minimize the locking of @projects we collect the
427
- # obsolete items first.
428
- termList = []
429
- @projects.synchronize do
430
- @projects.each do |p|
431
- if p.state == :obsolete
432
- termList << p
433
- elsif p.state == :failed
434
- # Start removal of entries that didn't parse.
435
- p.state = :obsolete
436
- end
395
+ begin
396
+ cntr = 0
397
+ loop do
398
+ if @terminate
399
+ # Give the caller a chance to properly terminate the connection.
400
+ sleep 0.5
401
+ break
402
+ elsif !@projectsToLoad.empty?
403
+ loadProject(@projectsToLoad.pop)
404
+ else
405
+ # Send termination command to all obsolute ProjectServer
406
+ # objects. To minimize the locking of @projects we collect the
407
+ # obsolete items first.
408
+ termList = []
409
+ @projects.synchronize do
410
+ @projects.each do |p|
411
+ if p.state == :obsolete
412
+ termList << p
413
+ elsif p.state == :failed
414
+ # Start removal of entries that didn't parse.
415
+ p.state = :obsolete
437
416
  end
438
417
  end
439
- # And then send them a termination command.
440
- termList.each { |p| p.terminateServer }
441
-
442
- # Check every 10 seconds that the ProjectServer processes are
443
- # still alive. If not, remove them from the list.
444
- if (cntr += 1) > 10
445
- @projects.synchronize do
446
- @projects.each do |p|
447
- unless p.ping
448
- termList << p unless termList.include?(p)
449
- end
418
+ end
419
+ # And then send them a termination command.
420
+ termList.each { |p| p.terminateServer }
421
+
422
+ # Check every 10 seconds that the ProjectServer processes are
423
+ # still alive. If not, remove them from the list.
424
+ if (cntr += 1) > 10
425
+ @projects.synchronize do
426
+ @projects.each do |p|
427
+ unless p.ping
428
+ termList << p unless termList.include?(p)
450
429
  end
451
430
  end
452
- cntr = 0
453
431
  end
432
+ cntr = 0
433
+ end
454
434
 
455
- # The housekeeping thread rarely needs to so something. Make
456
- # sure it's sleeping most of the time.
457
- sleep 1
435
+ # The housekeeping thread rarely needs to so something. Make
436
+ # sure it's sleeping most of the time.
437
+ sleep 1
458
438
 
459
- # Remove the obsolete records from the @projects list.
460
- @projects.synchronize do
461
- @projects.delete_if { |p| termList.include?(p) }
462
- end
439
+ # Remove the obsolete records from the @projects list.
440
+ @projects.synchronize do
441
+ @projects.delete_if { |p| termList.include?(p) }
463
442
  end
464
443
  end
465
- rescue
466
- $stderr.print $!.to_s
467
- $stderr.print $!.backtrace.join("\n")
468
- @log.fatal("ProjectBroker housekeeping error: #{$!}")
469
444
  end
445
+ rescue => exception
446
+ # TjRuntimeError exceptions are simply passed through.
447
+ if exception.is_a?(TjRuntimeError)
448
+ raise TjRuntimeError, $!
449
+ end
450
+
451
+ fatal('pb_housekeeping_error',
452
+ "ProjectBroker housekeeping error: #{$!}")
470
453
  end
471
454
  end
472
455
 
@@ -475,11 +458,11 @@ EOT
475
458
  tag = rand(9999999999999)
476
459
  project = tagOrProject
477
460
  # The 2nd element of the Array is the *.tjp file name.
478
- @log.debug("Loading project #{tagOrProject[1]} with tag #{tag}")
461
+ debug('', "Loading project #{tagOrProject[1]} with tag #{tag}")
479
462
  else
480
463
  tag = tagOrProject
481
464
  project = nil
482
- @log.debug("Loading project for tag #{tag}")
465
+ debug('', "Loading project for tag #{tag}")
483
466
  end
484
467
  pr = ProjectRecord.new(tag)
485
468
  ps = ProjectServer.new(@authKey, project, @logStdIO)
@@ -500,6 +483,8 @@ EOT
500
483
  # these methods for remote access.
501
484
  class ProjectBrokerIface
502
485
 
486
+ include MessageHandler
487
+
503
488
  def initialize(broker)
504
489
  @broker = broker
505
490
  end
@@ -517,15 +502,25 @@ EOT
517
502
 
518
503
  # This function catches all unhandled exceptions in the passed block.
519
504
  def trap
520
- log = LogFile.instance
521
-
522
505
  begin
523
506
  yield
524
- rescue
525
- $stderr.print $!.to_s
526
- $stderr.print $!.backtrace.join("\n")
527
- log.debug($!.backtrace.join("\n"))
528
- log.fatal("Unexpected exception: #{$!}")
507
+ rescue => e
508
+ # TjRuntimeError exceptions are simply passed through.
509
+ if e.is_a?(TjRuntimeError)
510
+ raise TjRuntimeError, $!
511
+ end
512
+
513
+ # Any exception here is a fata error. We try hard to terminate the DRb
514
+ # thread and then exit the program.
515
+ begin
516
+ fatal('pb_crash_trap', "#{e}\n#{e.backtrace.join("\n")}\n\n" +
517
+ "#{'*' * 79}\nYou have triggered a bug in " +
518
+ "#{AppConfig.softwareName} version #{AppConfig.version}!\n" +
519
+ "Please see the user manual on how to get this bug fixed!\n" +
520
+ "#{'*' * 79}\n")
521
+ rescue RuntimeError
522
+ @broker.stop
523
+ end
529
524
  end
530
525
  end
531
526
 
@@ -549,11 +544,24 @@ EOT
549
544
  when :update
550
545
  @broker.update
551
546
  else
552
- LogFile.instance.fatal('Unknown command #{cmd} called')
547
+ fatal('unknown_command', 'Unknown command #{cmd} called')
553
548
  end
554
549
  end
555
550
  end
556
551
 
552
+ def getProjectList(authKey)
553
+ return false unless @broker.checkKey(authKey, 'getProjectList')
554
+
555
+ trap { @broker.getProjectList }
556
+ end
557
+
558
+ def getProject(authKey, id)
559
+ return false unless @broker.checkKey(authKey, 'getProject')
560
+
561
+ debug('', "PID: #{id} Class: #{id.class}")
562
+ trap { @broker.getProject(id) }
563
+ end
564
+
557
565
  def updateState(authKey, projectKey, id, status, modified)
558
566
  return false unless @broker.checkKey(authKey, 'updateState')
559
567
 
@@ -566,6 +574,8 @@ EOT
566
574
  # one entry for each project in the @projects list.
567
575
  class ProjectRecord < Monitor
568
576
 
577
+ include MessageHandler
578
+
569
579
  attr_accessor :authKey, :uri, :files, :id, :state, :readySince, :modified,
570
580
  :reloading
571
581
  attr_reader :tag
@@ -592,19 +602,18 @@ EOT
592
602
  # True if the reload has already been triggered.
593
603
  @reloading = false
594
604
 
595
- @log = LogFile.instance
596
605
  @projectServer = nil
597
606
  end
598
607
 
599
608
  def ping
600
609
  return true unless @uri
601
610
 
602
- @log.debug("Sending ping to ProjectServer #{@uri}")
611
+ debug('', "Sending ping to ProjectServer #{@uri}")
603
612
  begin
604
613
  @projectServer = DRbObject.new(nil, @uri) unless @projectServer
605
614
  @projectServer.ping(@authKey)
606
615
  rescue
607
- @log.error("Ping failed: #{$!}")
616
+ warning('ping_failed', "Ping failed: #{$!}")
608
617
  return false
609
618
  end
610
619
  true
@@ -615,11 +624,12 @@ EOT
615
624
  return unless @uri
616
625
 
617
626
  begin
618
- @log.debug("Sending termination request to ProjectServer #{@uri}")
627
+ debug('', "Sending termination request to ProjectServer #{@uri}")
619
628
  @projectServer = DRbObject.new(nil, @uri) unless @projectServer
620
629
  @projectServer.terminate(@authKey)
621
630
  rescue
622
- @log.error("Termination of ProjectServer failed: #{$!}")
631
+ error('proj_serv_term_failed',
632
+ "Termination of ProjectServer failed: #{$!}")
623
633
  end
624
634
  @uri = nil
625
635
  end