taskjuggler 3.1.0 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|