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
|
@@ -71,17 +71,17 @@ EOT
|
|
|
71
71
|
else
|
|
72
72
|
requestedKeywords.each do |keyword|
|
|
73
73
|
if (kws = @keywords[keyword, true]).nil?
|
|
74
|
-
|
|
75
|
-
exit 1
|
|
74
|
+
error('tj3man_no_matches', "No matches found for '#{keyword}'")
|
|
76
75
|
elsif kws.length == 1 || kws.include?(keyword)
|
|
77
76
|
showManual(keyword)
|
|
78
77
|
else
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
warning('tj3man_multi_match',
|
|
79
|
+
"Multiple matches found for '#{keyword}':\n" +
|
|
80
|
+
"#{kws.join(', ')}")
|
|
82
81
|
end
|
|
83
82
|
end
|
|
84
83
|
end
|
|
84
|
+
|
|
85
85
|
0
|
|
86
86
|
end
|
|
87
87
|
|
|
@@ -38,19 +38,16 @@ EOT
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def appMain(argv)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
rescue TjRuntimeError
|
|
52
|
-
return 1
|
|
53
|
-
end
|
|
41
|
+
ts = TaskJuggler::StatusSheetReceiver.new('tj3ss_receiver')
|
|
42
|
+
@rc.configure(ts, 'global')
|
|
43
|
+
@rc.configure(ts, 'statussheets')
|
|
44
|
+
@rc.configure(ts, 'statussheets.receiver')
|
|
45
|
+
ts.workingDir = @workingDir if @workingDir
|
|
46
|
+
ts.dryRun = @dryRun
|
|
47
|
+
|
|
48
|
+
ts.processEmail
|
|
49
|
+
|
|
50
|
+
0
|
|
54
51
|
end
|
|
55
52
|
|
|
56
53
|
end
|
|
@@ -68,23 +68,20 @@ EOT
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def appMain(argv)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
ts.hideResource = @hideResource if @hideResource
|
|
71
|
+
ts = StatusSheetSender.new('tj3ss_sender')
|
|
72
|
+
@rc.configure(ts, 'global')
|
|
73
|
+
@rc.configure(ts, 'statussheets')
|
|
74
|
+
@rc.configure(ts, 'statussheets.sender')
|
|
75
|
+
ts.workingDir = @workingDir if @workingDir
|
|
76
|
+
ts.dryRun = @dryRun
|
|
77
|
+
ts.force = @force
|
|
78
|
+
ts.intervalDuration = @intervalDuration if @intervalDuration
|
|
79
|
+
ts.date = @date if @date
|
|
80
|
+
ts.hideResource = @hideResource if @hideResource
|
|
82
81
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
return 1
|
|
87
|
-
end
|
|
82
|
+
ts.sendTemplates(@resourceList)
|
|
83
|
+
|
|
84
|
+
0
|
|
88
85
|
end
|
|
89
86
|
|
|
90
87
|
end
|
|
@@ -41,19 +41,16 @@ EOT
|
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def appMain(argv)
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
rescue TjRuntimeError
|
|
55
|
-
return 1
|
|
56
|
-
end
|
|
44
|
+
ts = TimeSheetReceiver.new('tj3ts_receiver')
|
|
45
|
+
@rc.configure(ts, 'global')
|
|
46
|
+
@rc.configure(ts, 'timesheets')
|
|
47
|
+
@rc.configure(ts, 'timesheets.receiver')
|
|
48
|
+
ts.workingDir = @workingDir if @workingDir
|
|
49
|
+
ts.dryRun = @dryRun
|
|
50
|
+
|
|
51
|
+
ts.processEmail
|
|
52
|
+
|
|
53
|
+
0
|
|
57
54
|
end
|
|
58
55
|
|
|
59
56
|
end
|
|
@@ -56,22 +56,19 @@ EOT
|
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
def appMain(argv)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
ts.date = @date if @date
|
|
59
|
+
ts = TimeSheetSender.new('tj3ts_sender')
|
|
60
|
+
@rc.configure(ts, 'global')
|
|
61
|
+
@rc.configure(ts, 'timesheets')
|
|
62
|
+
@rc.configure(ts, 'timesheets.sender')
|
|
63
|
+
ts.workingDir = @workingDir if @workingDir
|
|
64
|
+
ts.dryRun = @dryRun
|
|
65
|
+
ts.force = @force
|
|
66
|
+
ts.intervalDuration = @intervalDuration if @intervalDuration
|
|
67
|
+
ts.date = @date if @date
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
return 1
|
|
74
|
-
end
|
|
69
|
+
ts.sendTemplates(@resourceList)
|
|
70
|
+
|
|
71
|
+
0
|
|
75
72
|
end
|
|
76
73
|
|
|
77
74
|
end
|
|
@@ -65,22 +65,19 @@ EOT
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
def appMain(argv)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
ts.digestRecipients += @digestRecipients
|
|
68
|
+
ts = TimeSheetSummary.new
|
|
69
|
+
@rc.configure(ts, 'global')
|
|
70
|
+
@rc.configure(ts, 'timesheets')
|
|
71
|
+
@rc.configure(ts, 'timesheets.summary')
|
|
72
|
+
ts.workingDir = @workingDir if @workingDir
|
|
73
|
+
ts.dryRun = @dryRun
|
|
74
|
+
ts.date = @date if @date
|
|
75
|
+
ts.sheetRecipients += @sheetRecipients
|
|
76
|
+
ts.digestRecipients += @digestRecipients
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
return 1
|
|
83
|
-
end
|
|
78
|
+
ts.sendSummary(@resourceList)
|
|
79
|
+
|
|
80
|
+
0
|
|
84
81
|
end
|
|
85
82
|
|
|
86
83
|
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -w
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
#
|
|
4
|
+
# = Tj3Daemon.rb -- The TaskJuggler III Project Management Software
|
|
5
|
+
#
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
|
+
# by Chris Schlaeger <chris@linux.com>
|
|
8
|
+
#
|
|
9
|
+
# This program is free software; you can redistribute it and/or modify
|
|
10
|
+
# it under the terms of version 2 of the GNU General Public License as
|
|
11
|
+
# published by the Free Software Foundation.
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
require 'drb'
|
|
15
|
+
require 'taskjuggler/Tj3AppBase'
|
|
16
|
+
require 'taskjuggler/MessageHandler'
|
|
17
|
+
require 'taskjuggler/daemon/WebServer'
|
|
18
|
+
|
|
19
|
+
# Name of the application
|
|
20
|
+
AppConfig.appName = 'tj3webd'
|
|
21
|
+
|
|
22
|
+
class TaskJuggler
|
|
23
|
+
|
|
24
|
+
class Tj3WebD < Tj3AppBase
|
|
25
|
+
|
|
26
|
+
def initialize
|
|
27
|
+
super
|
|
28
|
+
|
|
29
|
+
@mhi = MessageHandlerInstance.instance
|
|
30
|
+
@mhi.logFile = File.join(Dir.getwd, "/#{AppConfig.appName}.log")
|
|
31
|
+
@mhi.appName = AppConfig.appName
|
|
32
|
+
# By default show only warnings and more serious messages.
|
|
33
|
+
@mhi.outputLevel = :warning
|
|
34
|
+
@daemonize = true
|
|
35
|
+
@uriFile = File.join(Dir.getwd, '.tj3d.uri')
|
|
36
|
+
@port = nil
|
|
37
|
+
@webServerPort = nil
|
|
38
|
+
@pidFile = nil
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def processArguments(argv)
|
|
42
|
+
super do
|
|
43
|
+
@opts.banner += <<'EOT'
|
|
44
|
+
The TaskJuggler web server can be used to serve the HTTP reports of
|
|
45
|
+
TaskJuggler projects to be viewed by any HTML5 compliant web browser. It uses
|
|
46
|
+
the TaskJuggler daemon (tj3d) for data hosting and report generation.
|
|
47
|
+
EOT
|
|
48
|
+
@opts.on('-d', '--dont-daemonize',
|
|
49
|
+
format("Don't put program into daemon mode. Keep it " +
|
|
50
|
+
'connected to the terminal and show debug output.')) do
|
|
51
|
+
@daemonize = false
|
|
52
|
+
end
|
|
53
|
+
@opts.on('-p', '--port <NUMBER>', Integer,
|
|
54
|
+
format('Use the specified TCP/IP port to connect to the ' +
|
|
55
|
+
'TaskJuggler daemon (Default: 8474).')) do |arg|
|
|
56
|
+
@port = arg
|
|
57
|
+
end
|
|
58
|
+
@opts.on('--pidfile <FILE NAME>', String,
|
|
59
|
+
format('Write the process ID of the daemon to the ' +
|
|
60
|
+
'specified file.')) do |arg|
|
|
61
|
+
@pidFile = arg
|
|
62
|
+
end
|
|
63
|
+
@opts.on('--urifile', String,
|
|
64
|
+
format('If the port is 0, use this file to read the URI ' +
|
|
65
|
+
'of the TaskJuggler daemon.')) do |arg|
|
|
66
|
+
@uriFile = arg
|
|
67
|
+
end
|
|
68
|
+
@opts.on('--webserver-port <NUMBER>', Integer,
|
|
69
|
+
format('Use the specified TCP/IP port to serve web browser ' +
|
|
70
|
+
'requests (Default: 8080).')) do |arg|
|
|
71
|
+
@webServerPort = arg
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def appMain(files)
|
|
77
|
+
@rc.configure(self, 'global')
|
|
78
|
+
@rc.configure(@mhi, 'global.log')
|
|
79
|
+
webServer = WebServer.new
|
|
80
|
+
@rc.configure(webServer, 'global')
|
|
81
|
+
@rc.configure(webServer, 'webd')
|
|
82
|
+
|
|
83
|
+
# Set some config variables if corresponding data was provided via the
|
|
84
|
+
# command line.
|
|
85
|
+
webServer.port = @port if @port
|
|
86
|
+
webServer.uriFile = @uriFile.untaint
|
|
87
|
+
webServer.webServerPort = @webServerPort if @webServerPort
|
|
88
|
+
webServer.daemonize = @daemonize
|
|
89
|
+
webServer.pidFile = @pidFile
|
|
90
|
+
debug('', "pidFile 1: #{@pidFile}")
|
|
91
|
+
|
|
92
|
+
webServer.start
|
|
93
|
+
0
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
# published by the Free Software Foundation.
|
|
12
12
|
#
|
|
13
13
|
|
|
14
|
-
require 'taskjuggler/
|
|
14
|
+
require 'taskjuggler/MessageHandler'
|
|
15
15
|
|
|
16
16
|
class TaskJuggler
|
|
17
17
|
|
|
@@ -20,27 +20,29 @@ class TaskJuggler
|
|
|
20
20
|
# this class and call the start() method.
|
|
21
21
|
class Daemon
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
include MessageHandler
|
|
24
|
+
|
|
25
|
+
attr_accessor :pidFile, :daemonize
|
|
25
26
|
|
|
26
27
|
def initialize
|
|
27
28
|
# You can set this flag to false to prevent the program from
|
|
28
29
|
# disconnecting from the current terminal. This is useful for debugging
|
|
29
30
|
# purposes.
|
|
30
31
|
@daemonize = true
|
|
31
|
-
|
|
32
|
+
# Save the PID of the running daemon as number into this file.
|
|
33
|
+
@pidFile = nil
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
# Call this method to turn the process into a background process.
|
|
35
37
|
def start
|
|
36
|
-
return unless @daemonize
|
|
38
|
+
return 0 unless @daemonize
|
|
37
39
|
|
|
38
40
|
# Fork and have the parent exit
|
|
39
41
|
if (pid = fork) == -1
|
|
40
|
-
|
|
42
|
+
fatal('first_fork_failed', 'First fork failed')
|
|
41
43
|
elsif !pid.nil?
|
|
42
44
|
# This is the parent. We can exit now.
|
|
43
|
-
|
|
45
|
+
debug('', "Forked a child process with PID #{pid}")
|
|
44
46
|
exit! 0
|
|
45
47
|
end
|
|
46
48
|
|
|
@@ -48,15 +50,17 @@ class TaskJuggler
|
|
|
48
50
|
Process.setsid
|
|
49
51
|
# Fork again to make sure we lose the controlling terminal
|
|
50
52
|
if (pid = fork) == -1
|
|
51
|
-
|
|
53
|
+
fatal('second_fork_failed', 'Second fork failed')
|
|
52
54
|
elsif !pid.nil?
|
|
53
55
|
# This is the parent. We can exit now.
|
|
54
|
-
|
|
56
|
+
debug('', "Forked a child process with PID #{pid}")
|
|
55
57
|
exit! 0
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
@pid = Process.pid
|
|
59
61
|
|
|
62
|
+
writePidFile
|
|
63
|
+
|
|
60
64
|
# Change current working directory to the file system root
|
|
61
65
|
Dir.chdir '/'
|
|
62
66
|
# Make sure we can create files with any permission
|
|
@@ -67,13 +71,49 @@ class TaskJuggler
|
|
|
67
71
|
$stdout.reopen('/dev/null', 'a')
|
|
68
72
|
$stderr.reopen($stdout)
|
|
69
73
|
|
|
70
|
-
|
|
74
|
+
info('daemon_pid',
|
|
75
|
+
"The process is running as daemon now with PID #{@pid}")
|
|
76
|
+
|
|
71
77
|
0
|
|
72
78
|
end
|
|
73
79
|
|
|
74
80
|
# This method may provide some cleanup functionality in the future. You
|
|
75
81
|
# better call it before you exit.
|
|
76
82
|
def stop
|
|
83
|
+
if @pidFile
|
|
84
|
+
begin
|
|
85
|
+
File.delete(@pidFile)
|
|
86
|
+
rescue
|
|
87
|
+
warning('cannot_delete_pidfile',
|
|
88
|
+
"Cannote delete the PID file (#{@pidFile}): #{$!}")
|
|
89
|
+
end
|
|
90
|
+
info('daemon_deleted_pidfile', "PID file #{@pidFile} deleted")
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def writePidFile
|
|
97
|
+
if @pidFile
|
|
98
|
+
# Prepend the current working dir to @pidFile unless it's already an
|
|
99
|
+
# absolute path. The working dir is changed to '/' later. We need the
|
|
100
|
+
# absolute name to be able to delete it on exit again.
|
|
101
|
+
if @pidFile[0] != '/'
|
|
102
|
+
@pidFile = File.join(Dir.getwd, @pidFile)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# If requested, write the PID of the daemon to the specified file.
|
|
106
|
+
begin
|
|
107
|
+
File.open(@pidFile, 'w') do |f|
|
|
108
|
+
f.puts @pid
|
|
109
|
+
end
|
|
110
|
+
rescue
|
|
111
|
+
warning('cannot_save_pidfile', "Cannot write PID to #{@pidFile}")
|
|
112
|
+
end
|
|
113
|
+
info('daemon_wrote_pidfile',
|
|
114
|
+
"PID file #{@pidFile} written with PID #{@pid}")
|
|
115
|
+
end
|
|
116
|
+
|
|
77
117
|
end
|
|
78
118
|
|
|
79
119
|
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env ruby -w
|
|
2
|
+
# encoding: UTF-8
|
|
3
|
+
#
|
|
4
|
+
# = DaemonConnector.rb -- The TaskJuggler III Project Management Software
|
|
5
|
+
#
|
|
6
|
+
# Copyright (c) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
|
7
|
+
# by Chris Schlaeger <chris@linux.com>
|
|
8
|
+
#
|
|
9
|
+
# This program is free software; you can redistribute it and/or modify
|
|
10
|
+
# it under the terms of version 2 of the GNU General Public License as
|
|
11
|
+
# published by the Free Software Foundation.
|
|
12
|
+
#
|
|
13
|
+
|
|
14
|
+
require 'drb'
|
|
15
|
+
require 'drb/acl'
|
|
16
|
+
require 'taskjuggler/MessageHandler'
|
|
17
|
+
|
|
18
|
+
class TaskJuggler
|
|
19
|
+
|
|
20
|
+
module DaemonConnectorMixin
|
|
21
|
+
|
|
22
|
+
include MessageHandler
|
|
23
|
+
|
|
24
|
+
def connectDaemon
|
|
25
|
+
unless @authKey
|
|
26
|
+
error('missing_auth_key', <<'EOT'
|
|
27
|
+
You must set an authentication key in the configuration file. Create a file
|
|
28
|
+
named .taskjugglerrc or taskjuggler.rc that contains at least the following
|
|
29
|
+
lines. Replace 'your_secret_key' with some random character sequence.
|
|
30
|
+
|
|
31
|
+
_global:
|
|
32
|
+
authKey: your_secret_key
|
|
33
|
+
EOT
|
|
34
|
+
)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
uri = "druby://#{@host}:#{@port}"
|
|
38
|
+
if @port == 0
|
|
39
|
+
# If the @port is configured to 0, we need to read the URI to connect
|
|
40
|
+
# to the server from the .tj3d.uri file that has been generated by the
|
|
41
|
+
# server.
|
|
42
|
+
begin
|
|
43
|
+
uri = File.read(@uriFile).chomp
|
|
44
|
+
rescue
|
|
45
|
+
error('tjc_port_0',
|
|
46
|
+
'The server port is configured to be 0, but no ' +
|
|
47
|
+
".tj3d.uri file can be found: #{$!}")
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
debug('', "DRb URI determined as #{uri}")
|
|
51
|
+
|
|
52
|
+
# We try to play it safe here. The client also starts a DRb server, so
|
|
53
|
+
# we need to make sure it's constricted to localhost only. We require
|
|
54
|
+
# the DRb server for the standard IO redirection to work.
|
|
55
|
+
$SAFE = 1 unless @unsafeMode
|
|
56
|
+
DRb.install_acl(ACL.new(%w[ deny all
|
|
57
|
+
allow 127.0.0.1 ]))
|
|
58
|
+
DRb.start_service('druby://127.0.0.1:0')
|
|
59
|
+
debug('', 'DRb service started')
|
|
60
|
+
|
|
61
|
+
broker = nil
|
|
62
|
+
begin
|
|
63
|
+
# Get the ProjectBroker object from the tj3d.
|
|
64
|
+
broker = DRbObject.new_with_uri(uri)
|
|
65
|
+
# Client and server should always come from the same Gem. Since we
|
|
66
|
+
# restict communication to localhost, that's probably not a problem.
|
|
67
|
+
if (check = broker.apiVersion(@authKey, 1)) < 0
|
|
68
|
+
error('tjc_too_old',
|
|
69
|
+
'This client is too old for the server. Please ' +
|
|
70
|
+
'upgrade to a more recent version of the software.')
|
|
71
|
+
elsif check == 0
|
|
72
|
+
error('tjc_auth_fail',
|
|
73
|
+
'Authentication failed. Please check your authentication ' +
|
|
74
|
+
'key to match the server key.')
|
|
75
|
+
end
|
|
76
|
+
debug('', "Connection with report broker on #{uri} established")
|
|
77
|
+
rescue => e
|
|
78
|
+
# If we ended up here due to a previously reported TjRuntimeError, we
|
|
79
|
+
# just pass it through.
|
|
80
|
+
if e.is_a?(TjRuntimeError)
|
|
81
|
+
raise TjRuntimeError, $!
|
|
82
|
+
end
|
|
83
|
+
error('tjc_srv_not_responding',
|
|
84
|
+
"TaskJuggler server (tj3d) on URI '#{uri}' is not " +
|
|
85
|
+
"responding:\n#{$!}")
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
broker
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def disconnectDaemon
|
|
92
|
+
DRb.stop_service
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
class DaemonConnector
|
|
98
|
+
|
|
99
|
+
include DaemonConnectorMixin
|
|
100
|
+
|
|
101
|
+
def initialize(authKey, host, port, uri)
|
|
102
|
+
@authKey = authKey
|
|
103
|
+
@host = host
|
|
104
|
+
@port = port
|
|
105
|
+
@uri = uri
|
|
106
|
+
@unsafeMode = true
|
|
107
|
+
|
|
108
|
+
@broker = connectDaemon
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def disconnect
|
|
112
|
+
disconnectDaemon
|
|
113
|
+
@broker = nil
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def getProject(projectId)
|
|
117
|
+
@broker.getProject(@authKey, projectId)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def getProjectList
|
|
121
|
+
@broker.getProjectList(@authKey)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
127
|
+
|