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.
- data/CHANGELOG +44 -0
- data/bin/tj3webd +4 -0
- data/data/css/tjreport.css +14 -5
- data/data/tjp.vim +22 -7
- data/examples/Fedora-20/reports.tji +2 -4
- data/examples/Scrum/Product Burndown.csv +26 -0
- data/examples/Scrum/Sprint 1 Burndown.csv +26 -0
- data/examples/Scrum/Sprint 2 Burndown.csv +26 -0
- data/examples/Scrum/Sprint 3 Burndown.csv +26 -0
- data/examples/Scrum/scrum.tjp +141 -0
- data/examples/Tutorial/tutorial.tjp +13 -7
- data/lib/taskjuggler/Attributes.rb +2 -3
- data/lib/taskjuggler/HTMLDocument.rb +25 -18
- data/lib/taskjuggler/Journal.rb +85 -65
- data/lib/taskjuggler/KeywordDocumentation.rb +25 -13
- data/lib/taskjuggler/LeaveList.rb +1 -1
- data/lib/taskjuggler/Limits.rb +3 -5
- data/lib/taskjuggler/MessageHandler.rb +173 -19
- data/lib/taskjuggler/Painter.rb +75 -0
- data/lib/taskjuggler/Painter/BasicShapes.rb +76 -0
- data/lib/taskjuggler/Painter/Color.rb +273 -0
- data/lib/taskjuggler/Painter/Element.rb +56 -0
- data/lib/taskjuggler/Painter/FontData.rb +221 -0
- data/lib/taskjuggler/Painter/FontMetrics.rb +125 -0
- data/lib/taskjuggler/Painter/FontMetricsData.rb +151 -0
- data/lib/taskjuggler/Painter/Group.rb +77 -0
- data/lib/taskjuggler/Painter/Points.rb +47 -0
- data/lib/taskjuggler/Painter/Primitives.rb +100 -0
- data/lib/taskjuggler/Painter/SVGSupport.rb +36 -0
- data/lib/taskjuggler/Painter/Text.rb +36 -0
- data/lib/taskjuggler/Project.rb +46 -29
- data/lib/taskjuggler/ProjectFileParser.rb +24 -22
- data/lib/taskjuggler/ProjectFileScanner.rb +2 -2
- data/lib/taskjuggler/PropertyTreeNode.rb +26 -34
- data/lib/taskjuggler/Query.rb +8 -5
- data/lib/taskjuggler/RealFormat.rb +3 -0
- data/lib/taskjuggler/Resource.rb +3 -5
- data/lib/taskjuggler/ResourceScenario.rb +19 -7
- data/lib/taskjuggler/RichText.rb +4 -6
- data/lib/taskjuggler/RichText/FunctionExample.rb +1 -1
- data/lib/taskjuggler/RichText/FunctionHandler.rb +5 -6
- data/lib/taskjuggler/RichText/Parser.rb +4 -6
- data/lib/taskjuggler/RichText/RTFNavigator.rb +1 -1
- data/lib/taskjuggler/RichText/RTFQuery.rb +2 -3
- data/lib/taskjuggler/RichText/RTFReport.rb +1 -1
- data/lib/taskjuggler/RichText/RTFReportLink.rb +1 -2
- data/lib/taskjuggler/RichText/RTFWithQuerySupport.rb +1 -1
- data/lib/taskjuggler/RichText/Scanner.rb +6 -6
- data/lib/taskjuggler/RichText/Snip.rb +1 -2
- data/lib/taskjuggler/RuntimeConfig.rb +9 -6
- data/lib/taskjuggler/ScenarioData.rb +4 -3
- data/lib/taskjuggler/Scoreboard.rb +6 -0
- data/lib/taskjuggler/SheetHandlerBase.rb +25 -8
- data/lib/taskjuggler/SimpleQueryExpander.rb +14 -5
- data/lib/taskjuggler/SyntaxReference.rb +1 -2
- data/lib/taskjuggler/TableColumnSorter.rb +84 -0
- data/lib/taskjuggler/Task.rb +3 -5
- data/lib/taskjuggler/TaskJuggler.rb +36 -29
- data/lib/taskjuggler/TaskScenario.rb +154 -66
- data/lib/taskjuggler/TextParser.rb +24 -17
- data/lib/taskjuggler/TextParser/Scanner.rb +16 -11
- data/lib/taskjuggler/TextParser/SourceFileInfo.rb +20 -15
- data/lib/taskjuggler/TimeSheets.rb +6 -12
- data/lib/taskjuggler/Tj3AppBase.rb +35 -16
- data/lib/taskjuggler/Tj3Config.rb +1 -1
- data/lib/taskjuggler/TjpSyntaxRules.rb +239 -49
- data/lib/taskjuggler/XMLElement.rb +9 -2
- data/lib/taskjuggler/apps/Tj3.rb +43 -37
- data/lib/taskjuggler/apps/Tj3Client.rb +62 -112
- data/lib/taskjuggler/apps/Tj3Daemon.rb +66 -29
- data/lib/taskjuggler/apps/Tj3Man.rb +5 -5
- data/lib/taskjuggler/apps/Tj3SsReceiver.rb +10 -13
- data/lib/taskjuggler/apps/Tj3SsSender.rb +13 -16
- data/lib/taskjuggler/apps/Tj3TsReceiver.rb +10 -13
- data/lib/taskjuggler/apps/Tj3TsSender.rb +12 -15
- data/lib/taskjuggler/apps/Tj3TsSummary.rb +12 -15
- data/lib/taskjuggler/apps/Tj3WebD.rb +99 -0
- data/lib/taskjuggler/daemon/Daemon.rb +50 -10
- data/lib/taskjuggler/daemon/DaemonConnector.rb +127 -0
- data/lib/taskjuggler/daemon/ProcessIntercom.rb +36 -21
- data/lib/taskjuggler/daemon/ProjectBroker.rb +122 -112
- data/lib/taskjuggler/daemon/ProjectServer.rb +78 -46
- data/lib/taskjuggler/daemon/ReportServer.rb +52 -28
- data/lib/taskjuggler/daemon/ReportServlet.rb +92 -21
- data/lib/taskjuggler/daemon/WebServer.rb +75 -22
- data/lib/taskjuggler/daemon/WelcomePage.rb +1 -0
- data/lib/taskjuggler/reports/AccountListRE.rb +3 -3
- data/lib/taskjuggler/reports/CSVFile.rb +9 -2
- data/lib/taskjuggler/reports/ChartPlotter.rb +453 -0
- data/lib/taskjuggler/reports/Navigator.rb +1 -0
- data/lib/taskjuggler/reports/NikuReport.rb +4 -4
- data/lib/taskjuggler/reports/Report.rb +6 -18
- data/lib/taskjuggler/reports/ReportBase.rb +9 -9
- data/lib/taskjuggler/reports/ReportContext.rb +2 -2
- data/lib/taskjuggler/reports/StatusSheetReport.rb +6 -6
- data/lib/taskjuggler/reports/TableReport.rb +24 -15
- data/lib/taskjuggler/reports/TimeSheetReport.rb +5 -5
- data/lib/taskjuggler/reports/TraceReport.rb +251 -0
- data/lib/tj3webd.rb +17 -0
- data/manual/Day_To_Day_Juggling +10 -3
- data/manual/Installation +38 -19
- data/manual/Software +25 -19
- data/manual/Tutorial +119 -110
- data/manual/html/Day_To_Day_Juggling.html +7 -5
- data/manual/html/Getting_Started.html +4 -4
- data/manual/html/How_To_Contribute.html +4 -4
- data/manual/html/Installation.html +19 -11
- data/manual/html/Intro.html +4 -4
- data/manual/html/Reporting_Bugs.html +4 -4
- data/manual/html/Rich_Text_Attributes.html +4 -4
- data/manual/html/Software.html +15 -11
- data/manual/html/TaskJuggler_2x_Migration.html +4 -4
- data/manual/html/TaskJuggler_Internals.html +4 -4
- data/manual/html/The_TaskJuggler_Syntax.html +4 -4
- data/manual/html/Tutorial.html +41 -32
- data/manual/html/account.html +4 -4
- data/manual/html/account.task.html +4 -4
- data/manual/html/accountprefix.html +4 -4
- data/manual/html/accountreport.html +27 -9
- data/manual/html/accountroot.html +5 -5
- data/manual/html/active.html +4 -4
- data/manual/html/adopt.task.html +4 -4
- data/manual/html/aggregate.html +4 -4
- data/manual/html/alert.html +4 -4
- data/manual/html/alertlevels.html +4 -4
- data/manual/html/allocate.html +5 -5
- data/manual/html/alphabet.html +4 -4
- data/manual/html/alternative.html +4 -4
- data/manual/html/author.html +4 -4
- data/manual/html/balance.html +5 -5
- data/manual/html/booking.resource.html +4 -4
- data/manual/html/booking.task.html +4 -4
- data/manual/html/caption.html +5 -5
- data/manual/html/cellcolor.column.html +43 -8
- data/manual/html/celltext.column.html +4 -4
- data/manual/html/center.html +5 -5
- data/manual/html/charge.html +4 -4
- data/manual/html/chargeset.html +4 -4
- data/manual/html/columnid.html +27 -15
- data/manual/html/columns.html +5 -5
- data/manual/html/complete.html +4 -4
- data/manual/html/copyright.html +4 -4
- data/manual/html/credits.html +4 -4
- data/manual/html/css/tjreport.css +14 -5
- data/manual/html/currency.html +4 -4
- data/manual/html/currencyformat.html +5 -5
- data/manual/html/dailymax.html +5 -5
- data/manual/html/dailymin.html +5 -5
- data/manual/html/dailyworkinghours.html +4 -4
- data/manual/html/date.extend.html +4 -4
- data/manual/html/date.html +5 -5
- data/manual/html/definitions.html +4 -4
- data/manual/html/depends.html +4 -4
- data/manual/html/details.html +4 -4
- data/manual/html/disabled.html +4 -4
- data/manual/html/duration.html +4 -4
- data/manual/html/efficiency.html +4 -4
- data/manual/html/effort.html +4 -4
- data/manual/html/email.html +4 -4
- data/manual/html/enabled.html +4 -4
- data/manual/html/end.column.html +4 -4
- data/manual/html/end.html +4 -4
- data/manual/html/end.limit.html +4 -4
- data/manual/html/end.report.html +5 -5
- data/manual/html/end.timesheet.html +4 -4
- data/manual/html/endcredit.html +4 -4
- data/manual/html/epilog.html +5 -5
- data/manual/html/export.html +4 -4
- data/manual/html/extend.html +4 -4
- data/manual/html/fail.html +43 -8
- data/manual/html/fdl.html +4 -4
- data/manual/html/flags.account.html +4 -4
- data/manual/html/flags.html +4 -4
- data/manual/html/flags.journalentry.html +4 -4
- data/manual/html/flags.report.html +5 -5
- data/manual/html/flags.resource.html +4 -4
- data/manual/html/flags.statussheet.html +4 -4
- data/manual/html/flags.task.html +4 -4
- data/manual/html/flags.timesheet.html +4 -4
- data/manual/html/fontcolor.column.html +43 -8
- data/manual/html/footer.html +5 -5
- data/manual/html/formats.html +5 -5
- data/manual/html/functions.html +4 -4
- data/manual/html/gapduration.html +4 -4
- data/manual/html/gaplength.html +4 -4
- data/manual/html/halign.center.html +4 -4
- data/manual/html/halign.column.html +43 -8
- data/manual/html/halign.left.html +4 -4
- data/manual/html/halign.right.html +4 -4
- data/manual/html/hasalert.html +4 -4
- data/manual/html/header.html +5 -5
- data/manual/html/headline.html +7 -7
- data/manual/html/height.html +72 -0
- data/manual/html/hideaccount.html +46 -11
- data/manual/html/hidejournalentry.html +5 -5
- data/manual/html/hidereport.html +43 -8
- data/manual/html/hideresource.html +44 -9
- data/manual/html/hidetask.html +44 -9
- data/manual/html/icalreport.html +4 -4
- data/manual/html/include.macro.html +4 -4
- data/manual/html/include.project.html +4 -4
- data/manual/html/include.properties.html +4 -4
- data/manual/html/index.html +2 -1
- data/manual/html/inherit.extend.html +4 -4
- data/manual/html/interval1.html +4 -4
- data/manual/html/interval2.html +4 -4
- data/manual/html/interval3.html +4 -4
- data/manual/html/interval4.html +4 -4
- data/manual/html/isactive.html +4 -4
- data/manual/html/ischildof.html +4 -4
- data/manual/html/isdependencyof.html +4 -4
- data/manual/html/isdutyof.html +4 -4
- data/manual/html/isfeatureof.html +4 -4
- data/manual/html/isleaf.html +4 -4
- data/manual/html/ismilestone.html +4 -4
- data/manual/html/isongoing.html +4 -4
- data/manual/html/isresource.html +4 -4
- data/manual/html/isresponsibilityof.html +4 -4
- data/manual/html/istask.html +4 -4
- data/manual/html/journalattributes.html +11 -7
- data/manual/html/journalentry.html +4 -4
- data/manual/html/journalmode.html +5 -5
- data/manual/html/leaveallowance.html +5 -5
- data/manual/html/leaves.html +5 -6
- data/manual/html/left.html +5 -5
- data/manual/html/length.html +4 -4
- data/manual/html/limits.allocate.html +4 -4
- data/manual/html/limits.html +4 -4
- data/manual/html/limits.resource.html +4 -4
- data/manual/html/limits.task.html +4 -4
- data/manual/html/listitem.column.html +4 -4
- data/manual/html/listtype.column.html +4 -4
- data/manual/html/loadunit.html +5 -5
- data/manual/html/logicalexpression.html +8 -44
- data/manual/html/logicalflagexpression.html +4 -4
- data/manual/html/macro.html +4 -4
- data/manual/html/managers.html +4 -4
- data/manual/html/mandatory.html +4 -4
- data/manual/html/maxend.html +4 -4
- data/manual/html/maximum.html +5 -5
- data/manual/html/maxstart.html +4 -4
- data/manual/html/milestone.html +4 -4
- data/manual/html/minend.html +4 -4
- data/manual/html/minimum.html +5 -5
- data/manual/html/minstart.html +4 -4
- data/manual/html/monthlymax.html +5 -5
- data/manual/html/monthlymin.html +5 -5
- data/manual/html/navbar.html +10 -4
- data/manual/html/navigator.html +4 -4
- data/manual/html/newtask.html +4 -4
- data/manual/html/nikureport.html +4 -4
- data/manual/html/note.task.html +4 -4
- data/manual/html/now.html +4 -4
- data/manual/html/numberformat.html +5 -5
- data/manual/html/onend.html +4 -4
- data/manual/html/onstart.html +4 -4
- data/manual/html/opennodes.html +5 -5
- data/manual/html/overtime.booking.html +4 -4
- data/manual/html/period.column.html +4 -4
- data/manual/html/period.limit.html +4 -4
- data/manual/html/period.report.html +5 -5
- data/manual/html/period.task.html +4 -4
- data/manual/html/persistent.html +4 -4
- data/manual/html/precedes.html +4 -4
- data/manual/html/priority.html +4 -4
- data/manual/html/priority.timesheet.html +4 -4
- data/manual/html/project.html +4 -4
- data/manual/html/projectid.html +4 -4
- data/manual/html/projectid.task.html +4 -4
- data/manual/html/projectids.html +4 -4
- data/manual/html/projection.html +5 -7
- data/manual/html/prolog.html +5 -5
- data/manual/html/properties.html +11 -5
- data/manual/html/purge.html +5 -5
- data/manual/html/rate.html +4 -4
- data/manual/html/rate.resource.html +4 -4
- data/manual/html/reference.extend.html +4 -4
- data/manual/html/remaining.html +4 -4
- data/manual/html/replace.html +4 -4
- data/manual/html/reportprefix.html +4 -4
- data/manual/html/resource.html +4 -10
- data/manual/html/resourceattributes.html +4 -4
- data/manual/html/resourceprefix.html +4 -4
- data/manual/html/resourcereport.html +28 -10
- data/manual/html/resourceroot.html +5 -5
- data/manual/html/resources.limit.html +4 -4
- data/manual/html/responsible.html +4 -4
- data/manual/html/richtext.extend.html +4 -4
- data/manual/html/right.html +5 -5
- data/manual/html/rollupaccount.html +44 -9
- data/manual/html/rollupresource.html +44 -9
- data/manual/html/rolluptask.html +44 -9
- data/manual/html/scale.column.html +4 -4
- data/manual/html/scenario.html +4 -22
- data/manual/html/scenario.ical.html +4 -4
- data/manual/html/scenarios.export.html +4 -4
- data/manual/html/scenarios.html +5 -5
- data/manual/html/scenariospecific.extend.html +4 -4
- data/manual/html/scheduled.html +4 -4
- data/manual/html/scheduling.html +4 -4
- data/manual/html/select.html +4 -4
- data/manual/html/selfcontained.html +5 -5
- data/manual/html/shift.allocate.html +4 -4
- data/manual/html/shift.html +4 -4
- data/manual/html/shift.resource.html +5 -5
- data/manual/html/shift.task.html +4 -4
- data/manual/html/shift.timesheet.html +4 -4
- data/manual/html/shifts.allocate.html +4 -4
- data/manual/html/shifts.resource.html +4 -4
- data/manual/html/shifts.task.html +4 -4
- data/manual/html/shorttimeformat.html +4 -4
- data/manual/html/sloppy.booking.html +4 -4
- data/manual/html/sloppy.projection.html +5 -5
- data/manual/html/sortaccounts.html +5 -5
- data/manual/html/sortjournalentries.html +5 -5
- data/manual/html/sortresources.html +5 -5
- data/manual/html/sorttasks.html +5 -5
- data/manual/html/start.column.html +4 -4
- data/manual/html/start.html +4 -4
- data/manual/html/start.limit.html +4 -4
- data/manual/html/start.report.html +5 -5
- data/manual/html/startcredit.html +4 -4
- data/manual/html/status.statussheet.html +4 -4
- data/manual/html/status.timesheet.html +4 -4
- data/manual/html/statussheet.html +4 -4
- data/manual/html/statussheetreport.html +4 -4
- data/manual/html/strict.projection.html +5 -5
- data/manual/html/summary.html +4 -4
- data/manual/html/supplement.html +4 -4
- data/manual/html/supplement.resource.html +4 -10
- data/manual/html/supplement.task.html +4 -28
- data/manual/html/tagfile.html +4 -4
- data/manual/html/task.html +4 -28
- data/manual/html/task.statussheet.html +4 -4
- data/manual/html/task.timesheet.html +4 -4
- data/manual/html/taskattributes.html +4 -4
- data/manual/html/taskprefix.html +4 -4
- data/manual/html/taskreport.html +28 -10
- data/manual/html/taskroot.html +5 -5
- data/manual/html/text.extend.html +4 -4
- data/manual/html/textreport.html +27 -9
- data/manual/html/timeformat.html +5 -5
- data/manual/html/timeoff.nikureport.html +4 -4
- data/manual/html/timesheet.html +4 -4
- data/manual/html/timesheetreport.html +23 -5
- data/manual/html/timezone.export.html +4 -4
- data/manual/html/timezone.html +4 -4
- data/manual/html/timezone.report.html +5 -5
- data/manual/html/timezone.shift.html +4 -4
- data/manual/html/timingresolution.html +4 -4
- data/manual/html/title.column.html +4 -4
- data/manual/html/title.html +5 -5
- data/manual/html/toc.html +207 -179
- data/manual/html/tooltip.column.html +45 -10
- data/manual/html/tracereport.html +405 -0
- data/manual/html/trackingscenario.html +6 -6
- data/manual/html/treelevel.html +4 -4
- data/manual/html/vacation.html +4 -4
- data/manual/html/vacation.resource.html +4 -4
- data/manual/html/vacation.shift.html +4 -4
- data/manual/html/warn.html +43 -8
- data/manual/html/weeklymax.html +5 -5
- data/manual/html/weeklymin.html +5 -5
- data/manual/html/weekstartsmonday.html +4 -4
- data/manual/html/weekstartssunday.html +6 -6
- data/manual/html/width.column.html +6 -6
- data/manual/html/width.html +72 -0
- data/manual/html/work.html +4 -4
- data/manual/html/workinghours.project.html +4 -4
- data/manual/html/workinghours.resource.html +4 -4
- data/manual/html/workinghours.shift.html +4 -4
- data/manual/html/yearlyworkingdays.html +4 -4
- data/spec/Color_spec.rb +60 -0
- data/spec/ProjectBroker_spec.rb +3 -2
- data/spec/StatusSheets_spec.rb +5 -4
- data/spec/TableColumnSorter_spec.rb +78 -0
- data/spec/TimeSheets_spec.rb +6 -2
- data/spec/Tj3Daemon_spec.rb +2 -2
- data/spec/TraceReport_spec.rb +117 -0
- data/taskjuggler.gemspec +1 -1
- data/test/MessageChecker.rb +3 -1
- data/test/ReferenceGenerator.rb +1 -1
- data/test/TestSuite/CSV-Reports/Leave.tjp +1 -1
- data/test/TestSuite/CSV-Reports/refs/resourcereport_with_tasks.csv +3 -0
- data/test/TestSuite/CSV-Reports/refs/taskcounter.csv +9 -0
- data/test/TestSuite/CSV-Reports/refs/taskreport_with_resources.csv +19 -16
- data/test/TestSuite/CSV-Reports/refs/weekly.csv +1 -0
- data/test/TestSuite/Export-Reports/refs/LogicalExpression.tjp +14 -2
- data/test/TestSuite/Export-Reports/refs/tutorial.tjp +98 -86
- data/test/TestSuite/Scheduler/Correct/Leaves.tjp +25 -0
- data/test/TestSuite/Syntax/Correct/Leave.tjp +1 -1
- data/test/TestSuite/Syntax/Correct/LogicalExpression.tjp +9 -1
- data/test/TestSuite/Syntax/Correct/TraceReport.tjp +10 -0
- data/test/TestSuite/Syntax/Correct/tutorial.tjp +10 -4
- data/test/test_CSV-Reports.rb +3 -3
- data/test/test_Export-Reports.rb +91 -86
- data/test/test_Journal.rb +15 -12
- data/test/test_Limits.rb +3 -3
- data/test/test_Project.rb +1 -2
- data/test/test_ProjectFileScanner.rb +1 -1
- data/test/test_PropertySet.rb +1 -1
- data/test/test_Query.rb +5 -6
- data/test/test_ReportGenerator.rb +15 -7
- data/test/test_RichText.rb +4 -3
- data/test/test_Scheduler.rb +19 -7
- data/test/test_ShiftAssignments.rb +2 -2
- data/test/test_SimpleQueryExpander.rb +29 -2
- data/test/test_Syntax.rb +14 -5
- metadata +49 -10
- data/lib/taskjuggler/LogFile.rb +0 -73
|
@@ -16,9 +16,8 @@ require 'drb/acl'
|
|
|
16
16
|
require 'monitor'
|
|
17
17
|
require 'taskjuggler/daemon/ProcessIntercom'
|
|
18
18
|
require 'taskjuggler/daemon/ReportServer'
|
|
19
|
-
require 'taskjuggler/
|
|
19
|
+
require 'taskjuggler/MessageHandler'
|
|
20
20
|
require 'taskjuggler/TaskJuggler'
|
|
21
|
-
require 'taskjuggler/Log'
|
|
22
21
|
require 'taskjuggler/TjTime'
|
|
23
22
|
|
|
24
23
|
class TaskJuggler
|
|
@@ -79,7 +78,7 @@ class TaskJuggler
|
|
|
79
78
|
rd, wr = IO.pipe
|
|
80
79
|
|
|
81
80
|
if (@pid = fork) == -1
|
|
82
|
-
|
|
81
|
+
fatal('ps_fork_failed', 'ProjectServer fork failed')
|
|
83
82
|
elsif @pid.nil?
|
|
84
83
|
# This is the child
|
|
85
84
|
if @logConsole
|
|
@@ -91,13 +90,12 @@ class TaskJuggler
|
|
|
91
90
|
begin
|
|
92
91
|
$SAFE = 1
|
|
93
92
|
DRb.install_acl(ACL.new(%w[ deny all allow 127.0.0.1 ]))
|
|
94
|
-
DRb.start_service
|
|
95
93
|
iFace = ProjectServerIface.new(self)
|
|
96
94
|
begin
|
|
97
95
|
@uri = DRb.start_service('druby://127.0.0.1:0', iFace).uri
|
|
98
|
-
|
|
96
|
+
debug('', "Project server is listening on #{@uri}")
|
|
99
97
|
rescue
|
|
100
|
-
|
|
98
|
+
error('ps_cannot_start_drb', "ProjectServer can't start DRb: #{$!}")
|
|
101
99
|
end
|
|
102
100
|
|
|
103
101
|
# Send the URI of the newly started DRb server to the parent process.
|
|
@@ -114,12 +112,15 @@ class TaskJuggler
|
|
|
114
112
|
|
|
115
113
|
# Cleanup the DRb threads
|
|
116
114
|
DRb.thread.join
|
|
117
|
-
|
|
115
|
+
debug('', 'Project server terminated')
|
|
118
116
|
exit 0
|
|
119
|
-
rescue
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
117
|
+
rescue => exception
|
|
118
|
+
# TjRuntimeError exceptions are simply passed through.
|
|
119
|
+
if exception.is_a?(TjRuntimeError)
|
|
120
|
+
raise TjRuntimeError, $!
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
error('ps_cannot_start_drb', "ProjectServer can't start DRb: #{$!}")
|
|
123
124
|
end
|
|
124
125
|
else
|
|
125
126
|
# This is the parent
|
|
@@ -144,28 +145,37 @@ class TaskJuggler
|
|
|
144
145
|
@modifiedCheck = TjTime.new
|
|
145
146
|
|
|
146
147
|
updateState(:loading, dirAndFiles, false)
|
|
147
|
-
|
|
148
|
+
begin
|
|
149
|
+
@tj = TaskJuggler.new
|
|
150
|
+
# Make sure that trace reports get CSV formats included so there
|
|
151
|
+
# reports can be generated on request.
|
|
152
|
+
@tj.generateTraces = true
|
|
153
|
+
|
|
154
|
+
# Parse all project files
|
|
155
|
+
unless @tj.parse(args, true)
|
|
156
|
+
warning('parse_failed', "Parsing of #{args.join(' ')} failed")
|
|
157
|
+
updateState(:failed, nil, false)
|
|
158
|
+
@terminate = true
|
|
159
|
+
return false
|
|
160
|
+
end
|
|
148
161
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
162
|
+
# Then schedule the project
|
|
163
|
+
unless @tj.schedule
|
|
164
|
+
warning('schedule_failed',
|
|
165
|
+
"Scheduling of project #{@tj.projectId} failed")
|
|
166
|
+
updateState(:failed, @tj.projectId, false)
|
|
167
|
+
@terminate = true
|
|
168
|
+
return false
|
|
169
|
+
end
|
|
170
|
+
rescue TjRuntimeError
|
|
152
171
|
updateState(:failed, nil, false)
|
|
153
172
|
@terminate = true
|
|
154
173
|
return false
|
|
155
174
|
end
|
|
156
175
|
|
|
157
|
-
# Then schedule the project
|
|
158
|
-
unless @tj.schedule
|
|
159
|
-
@log.error("Scheduling of project #{@tj.projectId} failed")
|
|
160
|
-
updateState(:failed, @tj.projectId, false)
|
|
161
|
-
Log.exit('scheduler')
|
|
162
|
-
@terminate = true
|
|
163
|
-
return false
|
|
164
|
-
end
|
|
165
|
-
|
|
166
176
|
# Great, everything went fine. We've got a project to work with.
|
|
167
177
|
updateState(:ready, @tj.projectId, false)
|
|
168
|
-
|
|
178
|
+
debug('', "Project #{@tj.projectId} loaded")
|
|
169
179
|
restartTimer
|
|
170
180
|
true
|
|
171
181
|
end
|
|
@@ -201,7 +211,7 @@ class TaskJuggler
|
|
|
201
211
|
# find it in the @reportServers list, we create a unique tag to identify
|
|
202
212
|
# it.
|
|
203
213
|
tag = rand(99999999999999)
|
|
204
|
-
|
|
214
|
+
debug('', "Pushing #{tag} onto report server request queue")
|
|
205
215
|
@reportServerRequests.push(tag)
|
|
206
216
|
|
|
207
217
|
# Now wait until the new ReportServer shows up in the list.
|
|
@@ -216,8 +226,8 @@ class TaskJuggler
|
|
|
216
226
|
sleep 0.1 if reportServer.nil?
|
|
217
227
|
end
|
|
218
228
|
|
|
219
|
-
|
|
220
|
-
|
|
229
|
+
debug('', "Got report server with URI #{reportServer.uri} for " +
|
|
230
|
+
"tag #{tag}")
|
|
221
231
|
restartTimer
|
|
222
232
|
[ reportServer.uri, reportServer.authKey ]
|
|
223
233
|
end
|
|
@@ -249,9 +259,16 @@ class TaskJuggler
|
|
|
249
259
|
def updateState(state, filesOrId, modified)
|
|
250
260
|
begin
|
|
251
261
|
@daemon = DRbObject.new(nil, @daemonURI) unless @daemon
|
|
252
|
-
@daemon.updateState(@daemonAuthKey, @authKey, filesOrId, state,
|
|
253
|
-
|
|
254
|
-
|
|
262
|
+
@daemon.updateState(@daemonAuthKey, @authKey, filesOrId, state,
|
|
263
|
+
modified)
|
|
264
|
+
rescue => exception
|
|
265
|
+
# TjRuntimeError exceptions are simply passed through.
|
|
266
|
+
if exception.is_a?(TjRuntimeError)
|
|
267
|
+
raise TjRuntimeError, $!
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
error('cannot_update_daemon_state',
|
|
271
|
+
"Can't update state with daemon: #{$!}")
|
|
255
272
|
end
|
|
256
273
|
@stateLock.synchronize do
|
|
257
274
|
@state = state
|
|
@@ -265,6 +282,9 @@ class TaskJuggler
|
|
|
265
282
|
Thread.new do
|
|
266
283
|
begin
|
|
267
284
|
loop do
|
|
285
|
+
# Exit this thread if the @terminate flag is set.
|
|
286
|
+
break if @terminate
|
|
287
|
+
|
|
268
288
|
# Was the project data provided during object creation?
|
|
269
289
|
# Then we load the data here.
|
|
270
290
|
if @projectData
|
|
@@ -280,7 +300,7 @@ class TaskJuggler
|
|
|
280
300
|
@stateLock.synchronize { @modifiedCheck = TjTime.new }
|
|
281
301
|
|
|
282
302
|
if @tj.project.inputFiles.modified?
|
|
283
|
-
|
|
303
|
+
debug('', "Project #{@tj.projectId} has been modified")
|
|
284
304
|
updateState(:ready, @tj.projectId, true)
|
|
285
305
|
end
|
|
286
306
|
end
|
|
@@ -288,17 +308,17 @@ class TaskJuggler
|
|
|
288
308
|
# Check for pending requests for new ReportServers.
|
|
289
309
|
unless @reportServerRequests.empty?
|
|
290
310
|
tag = @reportServerRequests.pop
|
|
291
|
-
|
|
311
|
+
debug('', "Popped #{tag}")
|
|
292
312
|
# Create an new entry for the @reportServers list.
|
|
293
313
|
rsr = ReportServerRecord.new(tag)
|
|
294
|
-
|
|
314
|
+
debug('', "RSR created")
|
|
295
315
|
# Create a new ReportServer object that runs as a separate
|
|
296
316
|
# process. The constructor will tell us the URI and authentication
|
|
297
317
|
# key of the new ReportServer.
|
|
298
318
|
rs = ReportServer.new(@tj, @logConsole)
|
|
299
319
|
rsr.uri = rs.uri
|
|
300
320
|
rsr.authKey = rs.authKey
|
|
301
|
-
|
|
321
|
+
debug('', "Adding ReportServer with URI #{rsr.uri} to list")
|
|
302
322
|
# Add the new ReportServer to our list.
|
|
303
323
|
@reportServers.synchronize do
|
|
304
324
|
@reportServers << rsr
|
|
@@ -309,25 +329,31 @@ class TaskJuggler
|
|
|
309
329
|
# can die during the transaction, the server might hang in some
|
|
310
330
|
# states. Here we define timeout for each state. If the timeout is
|
|
311
331
|
# not 0 and exceeded, we immediately terminate the process.
|
|
312
|
-
timeouts = { :new =>
|
|
332
|
+
timeouts = { :new => 30, :loading => 15 * 60, :failed => 60,
|
|
313
333
|
:ready => 0 }
|
|
314
334
|
if timeouts[@state] > 0 &&
|
|
315
335
|
TjTime.new - @stateUpdated > timeouts[@state]
|
|
316
|
-
|
|
336
|
+
error('state_timeout',
|
|
337
|
+
"Reached timeout for state #{@state}. Terminating.")
|
|
317
338
|
end
|
|
318
339
|
|
|
319
340
|
# If we have not received a ping from the ProjectBroker for 2
|
|
320
341
|
# minutes, we assume it has died and terminate as well.
|
|
321
342
|
if TjTime.new - @lastPing > 180
|
|
322
|
-
|
|
343
|
+
error('daemon_heartbeat_lost',
|
|
344
|
+
'Heartbeat from daemon lost. Terminating.')
|
|
323
345
|
end
|
|
324
346
|
sleep 1
|
|
325
347
|
end
|
|
326
|
-
rescue
|
|
348
|
+
rescue => exception
|
|
349
|
+
# TjRuntimeError exceptions are simply passed through.
|
|
350
|
+
if exception.is_a?(TjRuntimeError)
|
|
351
|
+
raise TjRuntimeError, $!
|
|
352
|
+
end
|
|
353
|
+
|
|
327
354
|
# Make sure we get a backtrace for this thread.
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
@log.fatal("ProjectServer housekeeping error: #{$!}")
|
|
355
|
+
fatal('ps_housekeeping_error',
|
|
356
|
+
"ProjectServer housekeeping error: #{$!}")
|
|
331
357
|
end
|
|
332
358
|
end
|
|
333
359
|
end
|
|
@@ -381,6 +407,8 @@ class TaskJuggler
|
|
|
381
407
|
# the ProjectServer.
|
|
382
408
|
class ReportServerRecord
|
|
383
409
|
|
|
410
|
+
include MessageHandler
|
|
411
|
+
|
|
384
412
|
attr_reader :tag
|
|
385
413
|
attr_accessor :uri, :authKey
|
|
386
414
|
|
|
@@ -393,7 +421,6 @@ class TaskJuggler
|
|
|
393
421
|
@authKey = nil
|
|
394
422
|
# The DRbObject of the ReportServer.
|
|
395
423
|
@reportServer = nil
|
|
396
|
-
@log = LogFile.instance
|
|
397
424
|
end
|
|
398
425
|
|
|
399
426
|
# Send a ping to the ReportServer process to check that it is still
|
|
@@ -402,14 +429,19 @@ class TaskJuggler
|
|
|
402
429
|
def ping
|
|
403
430
|
return true unless @uri
|
|
404
431
|
|
|
405
|
-
|
|
432
|
+
debug('', "Sending ping to ReportServer #{@uri}")
|
|
406
433
|
begin
|
|
407
434
|
@reportServer = DRbObject.new(nil, @uri) unless @reportServer
|
|
408
435
|
@reportServer.ping(@authKey)
|
|
409
|
-
rescue
|
|
436
|
+
rescue => exception
|
|
437
|
+
# TjRuntimeError exceptions are simply passed through.
|
|
438
|
+
if exception.is_a?(TjRuntimeError)
|
|
439
|
+
raise TjRuntimeError, $!
|
|
440
|
+
end
|
|
441
|
+
|
|
410
442
|
# ReportServer processes terminate on request of their clients. Not
|
|
411
443
|
# responding to a ping is a normal event.
|
|
412
|
-
|
|
444
|
+
debug('', "ReportServer (#{@uri}) has terminated")
|
|
413
445
|
return false
|
|
414
446
|
end
|
|
415
447
|
true
|
|
@@ -43,7 +43,7 @@ class TaskJuggler
|
|
|
43
43
|
rd, wr = IO.pipe
|
|
44
44
|
|
|
45
45
|
if (@pid = fork) == -1
|
|
46
|
-
|
|
46
|
+
fatal('rs_fork_failed', 'ReportServer fork failed')
|
|
47
47
|
elsif @pid.nil?
|
|
48
48
|
if logConsole
|
|
49
49
|
# If the Broker wasn't daemonized, log stdout and stderr to PID
|
|
@@ -56,13 +56,13 @@ class TaskJuggler
|
|
|
56
56
|
$SAFE = 1
|
|
57
57
|
DRb.install_acl(ACL.new(%w[ deny all
|
|
58
58
|
allow 127.0.0.1 ]))
|
|
59
|
-
DRb.start_service
|
|
60
59
|
iFace = ReportServerIface.new(self)
|
|
61
60
|
begin
|
|
62
61
|
uri = DRb.start_service('druby://127.0.0.1:0', iFace).uri
|
|
63
|
-
|
|
62
|
+
debug('', "Report server is listening on #{uri}")
|
|
64
63
|
rescue
|
|
65
|
-
|
|
64
|
+
error('rs_cannot_start_drb',
|
|
65
|
+
"ReportServer can't start DRb: #{$!}")
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
# Send the URI of the newly started DRb server to the parent process.
|
|
@@ -77,12 +77,16 @@ class TaskJuggler
|
|
|
77
77
|
|
|
78
78
|
# Cleanup the DRb threads
|
|
79
79
|
DRb.thread.join
|
|
80
|
-
|
|
80
|
+
debug('', 'Report server terminated')
|
|
81
81
|
exit 0
|
|
82
|
-
rescue
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
82
|
+
rescue => exception
|
|
83
|
+
# TjRuntimeError exceptions are simply passed through.
|
|
84
|
+
if exception.is_a?(TjRuntimeError)
|
|
85
|
+
raise TjRuntimeError, $!
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
error('rs_unexp_excp',
|
|
89
|
+
"ReportServer caught unexpected exception: #{$!}")
|
|
86
90
|
end
|
|
87
91
|
else
|
|
88
92
|
Process.detach(@pid)
|
|
@@ -100,7 +104,7 @@ class TaskJuggler
|
|
|
100
104
|
def addFile(file)
|
|
101
105
|
begin
|
|
102
106
|
@tj.parseFile(file, :reportPropertiesFile)
|
|
103
|
-
rescue
|
|
107
|
+
rescue TjRuntimeError
|
|
104
108
|
return false
|
|
105
109
|
end
|
|
106
110
|
restartTimer
|
|
@@ -108,40 +112,58 @@ class TaskJuggler
|
|
|
108
112
|
end
|
|
109
113
|
|
|
110
114
|
def generateReport(id, regExpMode, formats, dynamicAttributes)
|
|
111
|
-
|
|
115
|
+
info('generating_report', "Generating report #{id}")
|
|
112
116
|
startTime = Time.now
|
|
113
|
-
|
|
114
|
-
@
|
|
115
|
-
|
|
116
|
-
|
|
117
|
+
begin
|
|
118
|
+
if (ok = @tj.generateReport(id, regExpMode, formats, dynamicAttributes))
|
|
119
|
+
info('report_id_generated',
|
|
120
|
+
"Report #{id} generated in #{Time.now - startTime} seconds")
|
|
121
|
+
else
|
|
122
|
+
error('report_generation_failed', "Report generation of #{id} failed")
|
|
123
|
+
end
|
|
124
|
+
rescue TjRuntimeError
|
|
125
|
+
return false
|
|
117
126
|
end
|
|
118
127
|
restartTimer
|
|
119
128
|
ok
|
|
120
129
|
end
|
|
121
130
|
|
|
122
131
|
def listReports(id, regExpMode)
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
@
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
info('listing_report_id', "Listing report #{id}")
|
|
133
|
+
begin
|
|
134
|
+
if (ok = @tj.listReports(id, regExpMode))
|
|
135
|
+
debug('', "Report list for #{id} generated")
|
|
136
|
+
else
|
|
137
|
+
error('repor_list_comp_failed',
|
|
138
|
+
"Report list compilation of #{id} failed")
|
|
139
|
+
end
|
|
140
|
+
rescue TjRuntimeError
|
|
141
|
+
return false
|
|
128
142
|
end
|
|
129
143
|
restartTimer
|
|
130
144
|
ok
|
|
131
145
|
end
|
|
132
146
|
|
|
133
147
|
def checkTimeSheet(sheet)
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
148
|
+
info('check_time_sheet', "Checking time sheet #{sheet}")
|
|
149
|
+
begin
|
|
150
|
+
ok = @tj.checkTimeSheet(sheet)
|
|
151
|
+
debug('', "Time sheet #{sheet} is #{ok ? '' : 'not '}ok")
|
|
152
|
+
rescue TjRuntimeError
|
|
153
|
+
return false
|
|
154
|
+
end
|
|
137
155
|
restartTimer
|
|
138
156
|
ok
|
|
139
157
|
end
|
|
140
158
|
|
|
141
159
|
def checkStatusSheet(sheet)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
160
|
+
info('check_status_sheet', "Checking status sheet #{sheet}")
|
|
161
|
+
begin
|
|
162
|
+
ok = @tj.checkStatusSheet(sheet)
|
|
163
|
+
debug('', "Status sheet #{sheet} is #{ok ? '' : 'not '}ok")
|
|
164
|
+
rescue TjRuntimeError
|
|
165
|
+
return false
|
|
166
|
+
end
|
|
145
167
|
restartTimer
|
|
146
168
|
ok
|
|
147
169
|
end
|
|
@@ -152,7 +174,8 @@ class TaskJuggler
|
|
|
152
174
|
Thread.new do
|
|
153
175
|
loop do
|
|
154
176
|
if TjTime.new - @lastPing > 120
|
|
155
|
-
|
|
177
|
+
error('ps_heartbeat_lost',
|
|
178
|
+
'Heartbeat from ProjectServer lost. Terminating.')
|
|
156
179
|
end
|
|
157
180
|
sleep 30
|
|
158
181
|
end
|
|
@@ -181,7 +204,8 @@ class TaskJuggler
|
|
|
181
204
|
trap { @server.addFile(file) }
|
|
182
205
|
end
|
|
183
206
|
|
|
184
|
-
def generateReport(authKey, reportId, regExpMode, formats,
|
|
207
|
+
def generateReport(authKey, reportId, regExpMode, formats,
|
|
208
|
+
dynamicAttributes)
|
|
185
209
|
return false unless @server.checkKey(authKey, 'generateReport')
|
|
186
210
|
|
|
187
211
|
trap do
|
|
@@ -12,29 +12,43 @@
|
|
|
12
12
|
#
|
|
13
13
|
|
|
14
14
|
require 'webrick'
|
|
15
|
+
require 'taskjuggler/MessageHandler'
|
|
16
|
+
require 'taskjuggler/RichText'
|
|
17
|
+
require 'taskjuggler/HTMLDocument'
|
|
18
|
+
require 'taskjuggler/daemon/DaemonConnector'
|
|
15
19
|
|
|
16
20
|
class TaskJuggler
|
|
17
21
|
|
|
18
22
|
class ReportServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
19
23
|
|
|
20
|
-
def initialize(config,
|
|
24
|
+
def initialize(config, options)
|
|
21
25
|
super
|
|
22
|
-
@
|
|
26
|
+
@authKey = options[0]
|
|
27
|
+
@host = options[1]
|
|
28
|
+
@port = options[2]
|
|
29
|
+
@uri = options[3]
|
|
23
30
|
end
|
|
24
31
|
|
|
25
32
|
def self.get_instance(config, options)
|
|
26
|
-
self.new(config,
|
|
33
|
+
self.new(config, options)
|
|
27
34
|
end
|
|
28
35
|
|
|
29
36
|
def do_GET(req, res)
|
|
37
|
+
debug('', "Serving URL #{req}")
|
|
30
38
|
@req = req
|
|
31
39
|
@res = res
|
|
32
40
|
begin
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
41
|
+
# WEBrick is returning the query elements as FormData objects. We must
|
|
42
|
+
# use to_s to explicitely convert them to String objects.
|
|
43
|
+
projectId = req.query['project'].to_s
|
|
44
|
+
debug('', "Project ID: #{projectId}")
|
|
45
|
+
reportId = req.query['report'].to_s
|
|
46
|
+
debug('', "Report ID: #{reportId}")
|
|
47
|
+
if projectId.empty? || reportId.empty?
|
|
48
|
+
debug('', "Project welcome page requested")
|
|
36
49
|
generateWelcomePage(projectId)
|
|
37
50
|
else
|
|
51
|
+
debug('', "Report #{reportId} of project #{projectId} requested")
|
|
38
52
|
attributes = req.query['attributes'] || ''
|
|
39
53
|
attributes = URLParameter.decode(attributes) unless attributes.empty?
|
|
40
54
|
generateReport(projectId, reportId, attributes)
|
|
@@ -45,11 +59,32 @@ class TaskJuggler
|
|
|
45
59
|
|
|
46
60
|
private
|
|
47
61
|
|
|
62
|
+
def connectToBroker
|
|
63
|
+
begin
|
|
64
|
+
broker = DaemonConnector.new(@authKey, @host, @port, @uri)
|
|
65
|
+
rescue
|
|
66
|
+
error('cannot_connect_broker',
|
|
67
|
+
"Cannot connect to the TaskJuggler daemon: #{$!}\n" +
|
|
68
|
+
"Please make sure you have tj3d running and listening " +
|
|
69
|
+
"on port #{@port} or URI '#{@uri}'.")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
broker
|
|
73
|
+
end
|
|
74
|
+
|
|
48
75
|
def generateReport(projectId, reportId, attributes)
|
|
76
|
+
broker = connectToBroker
|
|
77
|
+
|
|
49
78
|
# Request the Project credentials from the ProbjectBroker.
|
|
50
|
-
|
|
79
|
+
begin
|
|
80
|
+
@ps_uri, @ps_authKey = broker.getProject(projectId)
|
|
81
|
+
rescue
|
|
82
|
+
error('cannot_get_project_server',
|
|
83
|
+
"Cannot get project server for ID #{projectId}: #{$!}")
|
|
84
|
+
end
|
|
85
|
+
|
|
51
86
|
if @ps_uri.nil?
|
|
52
|
-
error("No project with ID #{projectId} loaded")
|
|
87
|
+
error('ps_uri_nil', "No project with ID #{projectId} loaded")
|
|
53
88
|
end
|
|
54
89
|
# Get the responsible ReportServer that can generate the report.
|
|
55
90
|
begin
|
|
@@ -57,7 +92,8 @@ class TaskJuggler
|
|
|
57
92
|
@rs_uri, @rs_authKey = @projectServer.getReportServer(@ps_authKey)
|
|
58
93
|
@reportServer = DRbObject.new(nil, @rs_uri)
|
|
59
94
|
rescue
|
|
60
|
-
error(
|
|
95
|
+
error('cannot_get_report_server',
|
|
96
|
+
"Cannot get report server: #{$!}")
|
|
61
97
|
end
|
|
62
98
|
# Create two StringIO buffers that will receive the $stdout and $stderr
|
|
63
99
|
# text from the report server. This buffer will contain the generated
|
|
@@ -70,8 +106,13 @@ class TaskJuggler
|
|
|
70
106
|
|
|
71
107
|
begin
|
|
72
108
|
@reportServer.connect(@rs_authKey, stdOut, stdErr, $stdin, true)
|
|
73
|
-
rescue
|
|
74
|
-
|
|
109
|
+
rescue => exception
|
|
110
|
+
# TjRuntimeError exceptions are simply passed through.
|
|
111
|
+
if exception.is_a?(TjRuntimeError)
|
|
112
|
+
raise TjRuntimeError, $!
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
error('rs_io_connect_failed', "Can't connect IO: #{$!}")
|
|
75
116
|
end
|
|
76
117
|
|
|
77
118
|
# Ask the ReportServer to generate the reports with the provided ID.
|
|
@@ -81,21 +122,24 @@ class TaskJuggler
|
|
|
81
122
|
rescue
|
|
82
123
|
stdOut.rewind
|
|
83
124
|
stdErr.rewind
|
|
84
|
-
error(
|
|
125
|
+
error('rs_generate_report_failed',
|
|
126
|
+
"Report server crashed: #{$!}\n#{stdErr.read}\n#{stdOut.read}")
|
|
85
127
|
end
|
|
86
128
|
# Disconnect the ReportServer
|
|
87
129
|
begin
|
|
88
130
|
@reportServer.disconnect(@rs_authKey)
|
|
89
131
|
rescue
|
|
90
|
-
error("Can't disconnect IO: #{$!}")
|
|
132
|
+
error('rs_io_disconnect_failed', "Can't disconnect IO: #{$!}")
|
|
91
133
|
end
|
|
92
134
|
# And send a termination request.
|
|
93
135
|
begin
|
|
94
136
|
@reportServer.terminate(@rs_authKey)
|
|
95
137
|
rescue
|
|
96
|
-
error(
|
|
138
|
+
error('report_server_term_failed',
|
|
139
|
+
"Report server termination failed: #{$!}")
|
|
97
140
|
end
|
|
98
141
|
@reportServer = nil
|
|
142
|
+
broker.disconnect
|
|
99
143
|
|
|
100
144
|
@res['content-type'] = 'text/html'
|
|
101
145
|
stdErr.rewind
|
|
@@ -107,7 +151,14 @@ class TaskJuggler
|
|
|
107
151
|
end
|
|
108
152
|
|
|
109
153
|
def generateWelcomePage(projectId)
|
|
110
|
-
|
|
154
|
+
broker = connectToBroker
|
|
155
|
+
|
|
156
|
+
begin
|
|
157
|
+
projects = broker.getProjectList
|
|
158
|
+
rescue
|
|
159
|
+
error('cannot_get_project_list',
|
|
160
|
+
"Cannot get project list from daemon: #{$!}")
|
|
161
|
+
end
|
|
111
162
|
|
|
112
163
|
text = "== Welcome to the TaskJuggler Project Server ==\n----\n"
|
|
113
164
|
projects.each do |id|
|
|
@@ -128,6 +179,10 @@ class TaskJuggler
|
|
|
128
179
|
text << "* [/taskjuggler?project=#{id} #{getProjectName(id)}]\n"
|
|
129
180
|
end
|
|
130
181
|
end
|
|
182
|
+
|
|
183
|
+
# We no longer need the broker.
|
|
184
|
+
broker.disconnect
|
|
185
|
+
|
|
131
186
|
rt = RichText.new(text)
|
|
132
187
|
rti = rt.generateIntermediateFormat
|
|
133
188
|
rti.sectionNumbers = false
|
|
@@ -139,26 +194,42 @@ class TaskJuggler
|
|
|
139
194
|
end
|
|
140
195
|
|
|
141
196
|
def getProjectName(id)
|
|
142
|
-
|
|
197
|
+
broker = connectToBroker
|
|
198
|
+
|
|
199
|
+
uri, authKey = broker.getProject(id)
|
|
143
200
|
return nil unless uri
|
|
144
201
|
projectServer = DRbObject.new(nil, uri)
|
|
145
202
|
return nil unless projectServer
|
|
146
|
-
projectServer.getProjectName(authKey)
|
|
203
|
+
res = projectServer.getProjectName(authKey)
|
|
204
|
+
|
|
205
|
+
broker.disconnect
|
|
206
|
+
|
|
207
|
+
res
|
|
147
208
|
end
|
|
148
209
|
|
|
149
210
|
def getReportList(id)
|
|
150
|
-
|
|
211
|
+
broker = connectToBroker
|
|
212
|
+
|
|
213
|
+
uri, authKey = broker.getProject(id)
|
|
151
214
|
return [] unless uri
|
|
152
215
|
projectServer = DRbObject.new(nil, uri)
|
|
153
216
|
return [] unless projectServer
|
|
154
|
-
projectServer.getReportList(authKey)
|
|
217
|
+
res = projectServer.getReportList(authKey)
|
|
218
|
+
|
|
219
|
+
broker.disconnect
|
|
220
|
+
|
|
221
|
+
res
|
|
155
222
|
end
|
|
156
223
|
|
|
157
|
-
def error(message)
|
|
224
|
+
def error(id, message)
|
|
158
225
|
@res.status = 412
|
|
159
226
|
@res.body = "ERROR: #{message}"
|
|
160
227
|
@res['content-type'] = 'text/plain'
|
|
161
|
-
|
|
228
|
+
MessageHandlerInstance.instance.error(id, message)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def debug(id, message)
|
|
232
|
+
MessageHandlerInstance.instance.debug(id, message)
|
|
162
233
|
end
|
|
163
234
|
|
|
164
235
|
end
|