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
@@ -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