1 | TMGPAT3 ;TMG/kst/Patching tools ;09/17/08
|
---|
2 | ;;1.0;TMG-LIB;**1**;09/17/08
|
---|
3 | ;
|
---|
4 | ;"Kevin Toppenberg MD
|
---|
5 | ;"GNU General Public License (GPL) applies
|
---|
6 | ;"9/26/08
|
---|
7 |
|
---|
8 | ;"=======================================================================
|
---|
9 | ;" API -- Public Functions.
|
---|
10 | ;"=======================================================================
|
---|
11 | ;"NEWPACK -- Install a new package from ftp server.
|
---|
12 | ;"CONSOLE --show how many patches for a package are available and have not been installed yet
|
---|
13 | ;"RESCAN -- show how many patches for a package are available and have not been installed yet
|
---|
14 | ;"ShowPatches(PckInit,Ver) -- show installed patches, using scroll box.
|
---|
15 | ;"EditNotes -- launch an editor for editing notes about patching.
|
---|
16 |
|
---|
17 | ;"=======================================================================
|
---|
18 | ;"Private Functions
|
---|
19 | ;"=======================================================================
|
---|
20 | ;"PrepAvail(pArray,Option) -- prepair an array with patch status, for use with Scroller^TMGUSRIF
|
---|
21 | ;"HndOnSel(pArray,Option,Info) -- handle ON SELECT event from Scroller^TMGUSRIF
|
---|
22 | ;"HndOnCmd(pArray,Option,Info) -- handle ON SELECT event from Scroller
|
---|
23 | ;"StoreMissing(PckInit,pArray) store the list of missing patches with the pending patches
|
---|
24 | ;"DownPck(PatchName,Option,Msg) -- Given a package name, ensure all pending patches are local.
|
---|
25 | ;"$$Rpt1Avail^TMGPAT3(PatchName)
|
---|
26 | ;"$$RptAvail^TMGPAT3(PckInit)
|
---|
27 | ;"Scan4New(MaxDays,Option) -- scan all packages and determine how many patches are pending for each
|
---|
28 | ;"Scan41(PckInit,MaxDays,Option) -- scan one package and determine how many patches are pending
|
---|
29 | ;"Scan41a1Ver(PckInit,Ver,MaxDays,Option) -- scan one package and determine how many patches are pending
|
---|
30 | ;"GetNew(PckInit,Ver,pArray,RefreshNeeded,Option) -- Get array of **just** patches still to be installed for a given package/version
|
---|
31 | ;"GetAvail(PckInit,Ver,pArray,RefreshNeeded,Option) -- return array of all patches for a given package/version
|
---|
32 | ;"GetPList(PckInit,Ver,pArray) -- get a list of applied patches, from PACKAGE file, into Array
|
---|
33 | ;"PrepPatchList(PckInit,Ver,pShowArray,ByPatchNum) -- prepair the patch list for display in scroll box.
|
---|
34 | ;"HndOnPCmd(pArray,Option,Info) -- handle ON SELECT event from Scroller
|
---|
35 | ;"ShowAvail -- Show data that tallies the available patches.
|
---|
36 | ;"IncLineCt(lineCount,pageLen)
|
---|
37 | ;"=======================================================================
|
---|
38 | ;"=======================================================================
|
---|
39 |
|
---|
40 | ;"NOTE: This Module should be re-written. Rather than store the data in the global ^TMG(...
|
---|
41 | ;" the Fileman file 22709 should be used. As it is now, it is a duplication of organization.
|
---|
42 |
|
---|
43 | NEWPACK
|
---|
44 | ;"Purpose: Install a new package from ftp server.
|
---|
45 |
|
---|
46 | new %,DIR,PckInit,Ver,X,Y,Msg
|
---|
47 |
|
---|
48 | do Logo^TMGPAT1
|
---|
49 | set %=1
|
---|
50 | write "Install a NEW PACKAGE from ftp.va.gov" do YN^DICN write !
|
---|
51 | if %'=1 goto NPDone
|
---|
52 | set DIR(0)="F^2:4"
|
---|
53 | set DIR("A")="Enter PACKAGE prefix (? for help)"
|
---|
54 | set DIR("?")="Enter Namespace initials."
|
---|
55 | set DIR("?",1)="Enter namespace package prefix initials."
|
---|
56 | set DIR("?",2)="E.g. for Fileman, enter: DI"
|
---|
57 | set DIR("?",3)="Enter ^ to abort."
|
---|
58 | do ^DIR write ! ;"results in X and Y
|
---|
59 | if Y="^" goto NPDone
|
---|
60 | set PckInit=Y
|
---|
61 |
|
---|
62 | new Array,result
|
---|
63 | write "Fetching info from VA ftp server..."
|
---|
64 | set result=$$GetPckList^TMGKERNL(PckInit,.Array)
|
---|
65 | write " Done.",!
|
---|
66 | if result=0 goto NPDone
|
---|
67 | new IEN9d4 set IEN9d4=+$order(^DIC(9.4,"C",PckInit,""))
|
---|
68 | if IEN9d4'>0 do goto NPDone
|
---|
69 | . do AddMsg^TMGPAT2("Can't find PACKAGE named '"_PckInit_"'",1,.Msg)
|
---|
70 |
|
---|
71 | NPDone
|
---|
72 | if $$ShowMsg^TMGPAT2(.Msg)
|
---|
73 | write "Goodbye.",!
|
---|
74 | quit
|
---|
75 |
|
---|
76 | ;"====================================================================
|
---|
77 |
|
---|
78 | CONSOLE
|
---|
79 | new Array,Option
|
---|
80 | do PrepAvail("Array",.Option)
|
---|
81 | set Option("FOOTER",1,1)="^ Exit"
|
---|
82 | set Option("FOOTER",1,2)="? Help"
|
---|
83 | set Option("FOOTER",1,3)="[F1] SHOW Compl"
|
---|
84 | set Option("FOOTER",1,4)="[F3] Hx"
|
---|
85 | set Option("FOOTER",1,5)="[F4] Downld Pak"
|
---|
86 | set Option("FOOTER",1,6)="[F5] Notes"
|
---|
87 | set Option("FOOTER",1,7)="[F6] Add Waiting"
|
---|
88 | set Option("ON SELECT")="HndOnSel^TMGPAT3"
|
---|
89 | set Option("ON CMD")="HndOnCmd^TMGPAT3"
|
---|
90 | write #
|
---|
91 | do Scroller^TMGUSRIF("Array",.Option)
|
---|
92 | quit
|
---|
93 |
|
---|
94 | PrepAvail(pArray,Option)
|
---|
95 | ;"Purpose: To prepair an array with patch status, for use with Scroller^TMGUSRIF
|
---|
96 | ;"Input: pArray -- PASS BY NAME. Array to put info into. Prior data is killed.
|
---|
97 | ;" Option -- PASS BY REFERENCE. Prior data is NOT killed. See Scroller^TMGUSRIF for details
|
---|
98 | ;" Option("HIDE EMPTY")=0 OPTIONAL. Default is 0. If 1 then, entries with no patches.
|
---|
99 | ;" Also-- Uses global variable...
|
---|
100 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version)=Count
|
---|
101 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"DATE REFRESHED")=Last date server checked.
|
---|
102 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"PATCHES",######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
103 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"PATCHES",######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
104 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,"FULL NAME")=Package name
|
---|
105 | ;"Results: None
|
---|
106 |
|
---|
107 | set pArray=$get(pArray) goto:(pArray="") pAvDone
|
---|
108 | kill @pArray
|
---|
109 | new Hinder,Blocked
|
---|
110 | new oneLine,lineCt set lineCt=1
|
---|
111 | new PckInit set PckInit=""
|
---|
112 | new grandTotal set grandTotal=0
|
---|
113 | new hideEmpty set hideEmpty=$get(Option("HIDE EMPTY"),1)
|
---|
114 | for set PckInit=$order(^TMG("KIDS","PENDING PATCHES",PckInit)) quit:(PckInit="") do
|
---|
115 | . new total set total=0
|
---|
116 | . new Ver set Ver=""
|
---|
117 | . new PackageName set PackageName=$get(^TMG("KIDS","PENDING PATCHES",PckInit,"FULL NAME"))
|
---|
118 | . for set Ver=$order(^TMG("KIDS","PENDING PATCHES",PckInit,Ver)) quit:(+Ver'>0) do
|
---|
119 | . . set total=total+$get(^TMG("KIDS","PENDING PATCHES",PckInit,Ver))
|
---|
120 | . set grandTotal=grandTotal+total
|
---|
121 | . if (total=0)&(hideEmpty=1) quit
|
---|
122 | . set oneLine="("_PckInit_") "_PackageName_" "
|
---|
123 | . set oneLine=$$LJ^XLFSTR($extract(oneLine,1,40),40)_"--> "_$$RJ^XLFSTR(total,3)_" patches. "
|
---|
124 | . new tempArray,current,maxVer
|
---|
125 | . set maxVer=0,Ver="",current=""
|
---|
126 | . for set Ver=$order(^TMG("KIDS","PENDING PATCHES",PckInit,Ver)) quit:(+Ver'>0) do
|
---|
127 | . . if Ver'>maxVer quit
|
---|
128 | . . new temp set temp=$$GetLastPackage^TMGPAT1(PckInit,Ver)
|
---|
129 | . . if temp'="" set maxVer=Ver,current=temp
|
---|
130 | . set oneLine=oneLine_"Currently @ "_current
|
---|
131 | . set @pArray@(lineCt,oneLine)=$piece(current,"*",1,2)
|
---|
132 | . set lineCt=lineCt+1
|
---|
133 | . new i set i=""
|
---|
134 | . for set i=$order(^TMG("KIDS","PENDING PATCHES",PckInit,"WAITING FOR",i)) quit:(i="") do
|
---|
135 | . . set oneLine=" Waiting for "_i
|
---|
136 | . . set @pArray@(lineCt,oneLine)=$piece(i,"*",1,2)
|
---|
137 | . . set lineCt=lineCt+1
|
---|
138 | . . new init set init=$piece(i,"*",1)
|
---|
139 | . . set Hinder(init,PckInit)=""
|
---|
140 | . . set Blocked(PckInit)=1
|
---|
141 |
|
---|
142 | if '$data(Hinder) goto pAV2
|
---|
143 |
|
---|
144 | new count for count=1:1:5 do
|
---|
145 | . set init="" for set init=$order(Hinder(init)) quit:(init="") do
|
---|
146 | . . new init1,init2 set init1=init,init2=""
|
---|
147 | . . for set init2=$order(Hinder(init,init2)) quit:(init2="") do
|
---|
148 | . . . quit:(init2=init)
|
---|
149 | . . . merge Hinder(init,init2)=Hinder(init2)
|
---|
150 |
|
---|
151 | set @pArray@(lineCt,"--- SUMMARY ------------------------------")=""
|
---|
152 | set lineCt=lineCt+1
|
---|
153 | new spaces set $piece(spaces," ",20)=" "
|
---|
154 | new ref set ref="Hinder"
|
---|
155 | new hideArray
|
---|
156 | set init=""
|
---|
157 | for set ref=$query(@ref) quit:(ref="") do
|
---|
158 | . if $$OREF^DILF($query(@ref))[$$OREF^DILF(ref) quit
|
---|
159 | . new count,node,done set done=0
|
---|
160 | . for count=1:1:$qlength(ref) do quit:done
|
---|
161 | . . set node=$qsubscript(ref,count)
|
---|
162 | . . set oneLine=$select((count=1):"#",1:"")
|
---|
163 | . . set oneLine=oneLine_$extract(spaces,1,count*3)_"Package "_node
|
---|
164 | . . if (count=1)&($get(Blocked(node))=1) set done=1 quit
|
---|
165 | . . if count=1 set oneLine=oneLine_" is hindering..."
|
---|
166 | . . else if count<$qlength(ref) set oneLine=oneLine_", which is hindering..."
|
---|
167 | . . if $get(hideArray(count))=oneLine quit
|
---|
168 | . . set hideArray(count)=oneLine
|
---|
169 | . . set @pArray@(lineCt,oneLine)="",lineCt=lineCt+1
|
---|
170 |
|
---|
171 | pAV2 set Option("HEADER",1)="TMG Patch Helper-- "_grandTotal_" Patches to be installed in all packages."
|
---|
172 |
|
---|
173 | pAvDone
|
---|
174 | quit
|
---|
175 |
|
---|
176 |
|
---|
177 | HndOnSel(pArray,Option,Info)
|
---|
178 | ;"Purpose: handle ON SELECT event from Scroller^TMGUSRIF
|
---|
179 | ;"Input: pArray,Option,Info -- see documentation in Scroller^TMGUSRIF
|
---|
180 | ;" Info has this:
|
---|
181 | ;" Info("CURRENT LINE","NUMBER")=number currently highlighted line
|
---|
182 | ;" Info("CURRENT LINE","TEXT")=Text of currently highlighted line
|
---|
183 | ;" Info("CURRENT LINE","RETURN")=return value of currently highlighted line
|
---|
184 |
|
---|
185 | new PatchName,PckInit,Ver
|
---|
186 | set PatchName=$get(Info("CURRENT LINE","RETURN"))
|
---|
187 | do ParsePatchName^TMGPAT2(PatchName,.PckInit,.Ver)
|
---|
188 | if (PckInit="")&(Ver="") do goto HOSDone
|
---|
189 | . write "?? The line selected specify any command ??",!
|
---|
190 | do DONEXTPK^TMGPAT1(PckInit,Ver)
|
---|
191 | do PrepAvail(pArray,.Option)
|
---|
192 | HOSDone
|
---|
193 | do PressToCont^TMGUSRIF
|
---|
194 | write #
|
---|
195 | quit
|
---|
196 |
|
---|
197 |
|
---|
198 | HndOnCmd(pArray,Option,Info) ;"Part of TestScrl
|
---|
199 | ;"Purpose: handle ON SELECT event from Scroller
|
---|
200 | ;"Input: pArray,Option,Info -- see documentation in Scroller
|
---|
201 | ;" Info has this:
|
---|
202 | ;" Info("USER INPUT")=input
|
---|
203 | ;" Info("CURRENT LINE","NUMBER")=number currently highlighted line
|
---|
204 | ;" Info("CURRENT LINE","TEXT")=Text of currently highlighted line
|
---|
205 | ;" Info("CURRENT LINE","RETURN")=return value of currently highlighted line
|
---|
206 |
|
---|
207 | new input set input=$$UP^XLFSTR($get(Info("USER INPUT")))
|
---|
208 | if input["F2" do
|
---|
209 | . set Option("FOOTER",1,3)="[F1] SHOW compl"
|
---|
210 | . set Option("HIDE EMPTY")=1
|
---|
211 | else if input="RESCAN" do
|
---|
212 | . do RESCAN
|
---|
213 | else if input["F1" do
|
---|
214 | . set Option("FOOTER",1,3)="[F2] HIDE compl"
|
---|
215 | . set Option("HIDE EMPTY")=0
|
---|
216 | else if input["F3" do
|
---|
217 | . new PatchName set PatchName=$get(Info("CURRENT LINE","RETURN")) quit:(PatchName="")
|
---|
218 | . new PckInit,Ver
|
---|
219 | . do ParsePatchName^TMGPAT2(PatchName,.PckInit,.Ver)
|
---|
220 | . if $$ShowPatches(PckInit,Ver)
|
---|
221 | else if input["F4" do
|
---|
222 | . new PatchName set PatchName=$get(Info("CURRENT LINE","RETURN")) quit:(PatchName="")
|
---|
223 | . new Option set Option("VERBOSE")=1
|
---|
224 | . new % set %=1
|
---|
225 | . write "Ensure that all pending patches for ",PatchName," have been downloaded"
|
---|
226 | . do YN^DICN write !
|
---|
227 | . if %'=1 quit
|
---|
228 | . do DownPck(PatchName,.Option)
|
---|
229 | . do PressToCont^TMGUSRIF
|
---|
230 | else if input["F5" do
|
---|
231 | . do EditNotes
|
---|
232 | . do PressToCont^TMGUSRIF
|
---|
233 | else if input["F6" do ;"Add Waiting"
|
---|
234 | . if Info("CURRENT LINE","TEXT")'["-->" do quit
|
---|
235 | . . write !,"Please first select containing '-->'",!
|
---|
236 | . . do PressToCont^TMGUSRIF
|
---|
237 | . new PatchName set PatchName=$get(Info("CURRENT LINE","RETURN")) quit:(PatchName="")
|
---|
238 | . new PckInit set PckInit=$piece(PatchName,"*",1)
|
---|
239 | . new % set %=1
|
---|
240 | . write !,"Manually add a 'Waiting For' entry for ",PatchName
|
---|
241 | . do YN^DICN write !
|
---|
242 | . if %'=1 quit
|
---|
243 | . new DIR,DIRUT set DIR(0)="F",DIR("A")="Enter what "_PatchName_" is waiting for"
|
---|
244 | . do ^DIR write ! if $data(DIRUT) quit
|
---|
245 | . do AddMissing(PckInit,Y)
|
---|
246 | . do PressToCont^TMGUSRIF
|
---|
247 | else if input="NEWPACK" do
|
---|
248 | . do NEWPACK
|
---|
249 | else if input="?" do
|
---|
250 | . write !,"Use UP and DOWN cursor keys to select package, then ENTER to work on.",!
|
---|
251 | . write "Enter 'NEWPACK' to install a NEW package.",!
|
---|
252 | . write "Enter 'RESCAN' to rescan the ftp.va.gov server",!
|
---|
253 | . write "Enter ^ at the ':' prompt to quit",!
|
---|
254 | . do PressToCont^TMGUSRIF
|
---|
255 | else if input'="" do
|
---|
256 | . write !,"Input ",$get(Info("USER INPUT"))," not recognized.",!
|
---|
257 | . do PressToCont^TMGUSRIF
|
---|
258 |
|
---|
259 | do PrepAvail(pArray,.Option)
|
---|
260 | write #
|
---|
261 | quit
|
---|
262 |
|
---|
263 |
|
---|
264 | StoreMissing(PckInit,pArray)
|
---|
265 | ;"Purpose: to store the list of missing patches with the pending patches
|
---|
266 | kill ^TMG("KIDS","PENDING PATCHES",PckInit,"WAITING FOR")
|
---|
267 | merge ^TMG("KIDS","PENDING PATCHES",PckInit,"WAITING FOR")=@pArray
|
---|
268 | quit
|
---|
269 |
|
---|
270 | AddMissing(PckInit,PatchName)
|
---|
271 | ;"Purpose: Add a missing patche to pending patches
|
---|
272 | set ^TMG("KIDS","PENDING PATCHES",PckInit,"WAITING FOR",PatchName)=""
|
---|
273 | quit
|
---|
274 |
|
---|
275 | DownPck(PatchName,Option,Msg)
|
---|
276 | ;"Purpose: given a patch name, ensure all pending patches are local.
|
---|
277 | ;"Input: PatchName -- patch name, e.g. ABC*1.0*123
|
---|
278 | ;" Option -- Optional. PASS BY REFERENCE.
|
---|
279 | ;" Option("VERBOSE")=1 --> puts output to console
|
---|
280 | ;" Msg -- PASS BY REFERANCE, an OUT PARAMETER
|
---|
281 | ;" Errors are stored in Msg("ERROR",x)=Message
|
---|
282 | ;" Msg("ERROR")=count of last error
|
---|
283 | ;" Message are store in Msg(x)=Message
|
---|
284 | ;" Msg=count of last message+1
|
---|
285 | ;"Results: none
|
---|
286 |
|
---|
287 | new PckInit,Ver,PatchNum,seqNum,Info
|
---|
288 | do ParsePatchName^TMGPAT2(PatchName,.PckInit,.Ver,.PatchNum,.seqNum)
|
---|
289 | do Scan41a1Ver(PckInit,Ver,90)
|
---|
290 | new total set total=+$get(^TMG("KIDS","PENDING PATCHES",PckInit,Ver))
|
---|
291 | new count set count=1
|
---|
292 | new patch set patch=""
|
---|
293 | for set patch=$order(^TMG("KIDS","PENDING PATCHES",PckInit,Ver,"PATCHES",patch)) quit:(patch="") do
|
---|
294 | . new patchName set patchName=$get(^TMG("KIDS","PENDING PATCHES",PckInit,Ver,"PATCHES",patch))
|
---|
295 | . if $get(Option("VERBOSE"))=1 write count,"/",total,". ---- ",patchName," ----",!
|
---|
296 | . new IENS set IENS=$$GetIENS^TMGPAT2(patchName) quit:(IENS="")
|
---|
297 | . if $$EnsureLocal^TMGPAT2(IENS,.Info,.Msg,.Option)=0 do
|
---|
298 | . . do AddMsg^TMGPAT2("Unable to download patch to local file system.",1,Msg)
|
---|
299 | . set count=count+1
|
---|
300 |
|
---|
301 | if $get(Option("VERBOSE"))=1 do
|
---|
302 | . if $$ShowMsg^TMGPAT2(.Msg)
|
---|
303 |
|
---|
304 | quit
|
---|
305 |
|
---|
306 | Rpt1Avail(PatchName)
|
---|
307 | ;"Purpose: given a patch name (e.g. ABC*1.0*123), return pending patches.
|
---|
308 | new PckInit,Ver,PatchNum,seqNum
|
---|
309 | new count set count=-1
|
---|
310 | do ParsePatchName^TMGPAT2(PatchName,.PckInit,.Ver,.PatchNum,.seqNum)
|
---|
311 | if ($get(PckInit)="")!($get(Ver)="") goto Rpt1Done
|
---|
312 | do Scan41a1Ver(PckInit,Ver,90)
|
---|
313 | set count=+$get(^TMG("KIDS","PENDING PATCHES",PckInit,Ver))
|
---|
314 | Rpt1Done
|
---|
315 | quit count
|
---|
316 |
|
---|
317 | RptAvail(PckInit)
|
---|
318 | ;"Purpose: given a package (e.g. ABC), return pending patches.
|
---|
319 | new total set total=0
|
---|
320 | new Ver set Ver=""
|
---|
321 | for set Ver=$order(^TMG("KIDS","PENDING PATCHES",PckInit,Ver)) quit:(+Ver'>0) do
|
---|
322 | . set total=total+$get(^TMG("KIDS","PENDING PATCHES",PckInit,Ver))
|
---|
323 | quit total
|
---|
324 |
|
---|
325 | RESCAN
|
---|
326 | ;"Purpose: To show how many patches for a package are available and have not been installed yet
|
---|
327 | write !
|
---|
328 | new DUOUT,DIR
|
---|
329 | set DIR("A")="Search ftp server if data is older than __ days old? (SLOW!)"
|
---|
330 | set DIR("B")=90
|
---|
331 | set DIR(0)="N^0:999:0"
|
---|
332 | do ^DIR write !
|
---|
333 | new Option
|
---|
334 | set Option("VERBOSE")=0
|
---|
335 | if $get(DUOUT) quit
|
---|
336 | do Scan4New(+Y,.Option)
|
---|
337 | ;"if '$get(DUOUT) do ShowAvail
|
---|
338 | SADone quit
|
---|
339 |
|
---|
340 |
|
---|
341 |
|
---|
342 | Scan4New(MaxDays,Option)
|
---|
343 | ;"Purpose: to scan all packages and determine how many patches are pending for each
|
---|
344 | ;"Input: MaxDays -- the number of days that old days can be used. If last refresh
|
---|
345 | ;" was greater than this number, then ftp.va.gov is queried again.
|
---|
346 | ;" Option -- Optional. PASS BY REFERENCE.
|
---|
347 | ;" Option("VERBOSE")=1 --> puts output to console
|
---|
348 | ;"Output: Results will be stored:
|
---|
349 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version)=Count
|
---|
350 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"DATE REFRESHED")=Last date server checked.
|
---|
351 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"PATCHES",######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
352 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"PATCHES",######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
353 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,"FULL NAME")=Package name
|
---|
354 | ;"
|
---|
355 | ;"Results: none
|
---|
356 |
|
---|
357 | ;"NOTE: This function should be re-written. Rather than store the data in the global ^TMG(...
|
---|
358 | ;" the Fileman file 22709 should be used. As it is now, it is a duplication of organization.
|
---|
359 |
|
---|
360 | set MaxDays=+$get(MaxDays)
|
---|
361 | new PackageName set PackageName=""
|
---|
362 | for set PackageName=$order(^DIC(9.4,"B",PackageName)) quit:(PackageName="") do
|
---|
363 | . new IEN9d4 set IEN9d4=+$order(^DIC(9.4,"B",PackageName,"")) quit:(IEN9d4'>0)
|
---|
364 | . new PckInit set PckInit=$piece($get(^DIC(9.4,IEN9d4,0)),"^",2) ;"0;2 = Package prefix
|
---|
365 | . do Scan41(PckInit,MaxDays,.Option)
|
---|
366 |
|
---|
367 | quit
|
---|
368 |
|
---|
369 | Scan41(PckInit,MaxDays,Option)
|
---|
370 | ;"Purpose: to scan one package and determine how many patches are pending
|
---|
371 | ;"Input: PckInit -- Package Initials/prefix
|
---|
372 | ;" MaxDays -- the cutoff for when to requery the server
|
---|
373 | ;" Option -- PASS BY REFERENCE.
|
---|
374 | ;" Option("VERBOSE")=1 to be verbose.
|
---|
375 | ;"Output: Results will be stored:
|
---|
376 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version)=Count
|
---|
377 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"DATE REFRESHED")=Last date server checked.
|
---|
378 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"PATCHES",######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
379 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"PATCHES",######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
380 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,"FULL NAME")=Package name
|
---|
381 | ;"Results: none
|
---|
382 |
|
---|
383 | new IEN9d4 set IEN9d4=+$order(^DIC(9.4,"C",PckInit,""))
|
---|
384 | new PackageName set PackageName=""
|
---|
385 | if IEN9d4>0 set PackageName=$piece($get(^DIC(9.4,IEN9d4,0)),"^",1)
|
---|
386 | if $get(Option("VERBOSE"))=1 write "Checking Package: ",PackageName," (",PckInit,")...",!
|
---|
387 | set ^TMG("KIDS","PENDING PATCHES",PckInit,"FULL NAME")=PackageName
|
---|
388 | ;"kill ^TMG("KIDS","PENDING PATCHES",PckInit,"DATE REFRESHED") ;"force refresh
|
---|
389 | set Ver=""
|
---|
390 | for set Ver=$order(^DIC(9.4,IEN9d4,22,"B",Ver)) quit:(Ver="") do
|
---|
391 | . do Scan41a1Ver(PckInit,Ver,MaxDays,.Option)
|
---|
392 |
|
---|
393 | quit
|
---|
394 |
|
---|
395 |
|
---|
396 | Scan41a1Ver(PckInit,Ver,MaxDays,Option)
|
---|
397 | ;"Purpose: to scan one package and determine how many patches are pending
|
---|
398 | ;"Input: PckInit -- Package Initials/prefix
|
---|
399 | ;" Ver -- The version of the Package
|
---|
400 | ;" MaxDays -- the cutoff for when to requery the server
|
---|
401 | ;" Option -- PASS BY REFERENCE.
|
---|
402 | ;" Option("VERBOSE")=1 to be verbose.
|
---|
403 | ;"Output: Results will be stored:
|
---|
404 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version)=Count
|
---|
405 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"DATE REFRESHED")=Last date server checked.
|
---|
406 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"PATCHES",######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
407 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,Version,"PATCHES",######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
408 | ;" ^TMG("KIDS","PENDING PATCHES",PackageInitials,"FULL NAME")=Package name
|
---|
409 | ;"Results: none
|
---|
410 |
|
---|
411 | ;"kill ^TMG("KIDS","PENDING PATCHES",PckInit,"DATE REFRESHED") ;"force refresh
|
---|
412 | if $get(PckInit)="" goto S41Done
|
---|
413 | if $get(Ver)="" goto S41Done
|
---|
414 | set MaxDays=+$get(MaxDays,90)
|
---|
415 | if $get(Option("VERBOSE"))=1 write " Ver: ",Ver," ",!
|
---|
416 | new RefreshNeeded
|
---|
417 | new lastCheck set lastCheck=$get(^TMG("KIDS","PENDING PATCHES",PckInit,"DATE REFRESHED"))
|
---|
418 | if lastCheck'="" do
|
---|
419 | . new X,Y,%DT,X1,X2
|
---|
420 | . set X=lastCheck,%DT="TS"
|
---|
421 | . do ^%DT ;"result in Y
|
---|
422 | . set X=0
|
---|
423 | . do NOW^%DTC ;"returns date in X
|
---|
424 | . set X1=X,X2=Y
|
---|
425 | . do ^%DTC ;"returns X=X1-X2
|
---|
426 | . set RefreshNeeded=(X>MaxDays)
|
---|
427 | else set RefreshNeeded=1
|
---|
428 | new pArray set pArray=$name(^TMG("KIDS","PENDING PATCHES",PckInit,Ver,"PATCHES"))
|
---|
429 | new count set count=$$GetNew(PckInit,Ver,pArray,RefreshNeeded,.Option)
|
---|
430 | if $get(Option("VERBOSE"))=1 write " ",count," patches to be installed.",!
|
---|
431 | set ^TMG("KIDS","PENDING PATCHES",PckInit,Ver)=count
|
---|
432 | if RefreshNeeded do
|
---|
433 | . new %,%I,X,Y
|
---|
434 | . do NOW^%DTC set Y=%
|
---|
435 | . X ^DD("DD") ;"result in Y
|
---|
436 | . set ^TMG("KIDS","PENDING PATCHES",PckInit,"DATE REFRESHED")=Y
|
---|
437 |
|
---|
438 | S41Done
|
---|
439 | quit
|
---|
440 |
|
---|
441 |
|
---|
442 | GetNew(PckInit,Ver,pArray,RefreshNeeded,Option)
|
---|
443 | ;"Purpose: Get array of **just** patches still to be installed for a given package/version
|
---|
444 | ;"Input: PckInit -- this is the namespace of the package to get patches for, e.g. 'DI' for fileman
|
---|
445 | ;" Ver -- the package version
|
---|
446 | ;" pArray -- PASS BY NAME. An OUT PARAMETER. Format:
|
---|
447 | ;" @pArray@(######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
448 | ;" @pArray@(######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
449 | ;" NeedsRefresh -- 0 if refreshing not needed (just ensure file exists)
|
---|
450 | ;" Option -- Optional. PASS BY REFERENCE.
|
---|
451 | ;" Option("VERBOSE")=1 --> puts output to console
|
---|
452 | ;"Results: Number of patches still to be installed.
|
---|
453 |
|
---|
454 | new count set count=0
|
---|
455 |
|
---|
456 | do GetAvail(PckInit,Ver,pArray,.RefreshNeeded,.Option)
|
---|
457 | new LastPck set LastPck=$$GetLastPackage^TMGPAT1(PckInit,Ver)
|
---|
458 | new lastSeq set lastSeq=+$piece(LastPck,"SEQ #",2)
|
---|
459 | if lastSeq="" kill @pArray goto GNDone
|
---|
460 | new i set i=""
|
---|
461 | for set i=$order(@pArray@(i)) quit:(i="") do
|
---|
462 | . if +i'>lastSeq kill @pArray@(i) quit
|
---|
463 | . set count=count+1
|
---|
464 | GNDone
|
---|
465 | quit count
|
---|
466 |
|
---|
467 |
|
---|
468 |
|
---|
469 | GetAvail(PckInit,Ver,pArray,RefreshNeeded,Option)
|
---|
470 | ;"Purpose: return array of all patches for a given package/version
|
---|
471 | ;"Input: PckInit -- this is the namespace of the package to get patches for, e.g. 'DI' for fileman
|
---|
472 | ;" Ver -- the package version
|
---|
473 | ;" pArray -- PASS BY NAME. An OUT PARAMETER. Format:
|
---|
474 | ;" @pArray@(######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
475 | ;" @pArray@(######)=AAAA*NN.NN*NNNN SEQ #1234"
|
---|
476 | ;" NeedsRefresh -- 0 if refreshing not needed (just ensure file exists)
|
---|
477 | ;" Option -- Optional. PASS BY REFERENCE.
|
---|
478 | ;" Option("VERBOSE")=1 --> puts output to console
|
---|
479 | ;"results: none
|
---|
480 |
|
---|
481 | kill @pArray
|
---|
482 | if $$RefreshPackge^TMGPAT2(PckInit,.Msg,.RefreshNeeded,.Option)
|
---|
483 |
|
---|
484 | new IEN9d4 set IEN9d4=+$order(^DIC(9.4,"C",PckInit,""))
|
---|
485 | if IEN9d4'>0 goto GADone
|
---|
486 | new PckIEN set PckIEN=+$order(^TMG(22709,"B",IEN9d4,""))
|
---|
487 | if PckIEN'>0 goto GADone
|
---|
488 | new VerIEN set VerIEN=+$order(^TMG(22709,PckIEN,1,"B",Ver,""))
|
---|
489 | if VerIEN'>0 set VerIEN=+$order(^TMG(22709,PckIEN,1,"B",$piece(Ver,".0",1),""))
|
---|
490 | if VerIEN'>0 goto GADone
|
---|
491 |
|
---|
492 | new patchIEN,nextSeq
|
---|
493 | set patchIEN=0
|
---|
494 | for set patchIEN=$order(^TMG(22709,PckIEN,1,VerIEN,1,patchIEN)) quit:(patchIEN'>0) do
|
---|
495 | . new node0 set node0=$get(^TMG(22709,PckIEN,1,VerIEN,1,patchIEN,0)) quit:(node0="")
|
---|
496 | . new patchNum set patchNum=$piece(node0,"^",2)
|
---|
497 | . new oneSeqNum set oneSeqNum=$piece(node0,"^",2)
|
---|
498 | . if oneSeqNum'>0 set oneSeqNum=0
|
---|
499 | . set @pArray@($$RJ^XLFSTR(oneSeqNum,6,"0"))=PckInit_"*"_Ver_"*"_patchNum_" SEQ #"_oneSeqNum
|
---|
500 |
|
---|
501 | GADone
|
---|
502 | quit
|
---|
503 |
|
---|
504 |
|
---|
505 | TestPList ;"temp function.
|
---|
506 | new PckInit,Ver,Array
|
---|
507 | do GetPckVer^TMGPAT1(.PckInit,.Ver)
|
---|
508 | if Ver="^" goto TPLDone
|
---|
509 | if $$GetPList(PckInit,Ver,"Array")=0 goto TPLDone
|
---|
510 | zwr Array(*)
|
---|
511 | TPLDone quit
|
---|
512 |
|
---|
513 |
|
---|
514 | GetPList(PckInit,Ver,pArray)
|
---|
515 | ;"Purpose: to get a list of applied patches, from PACKAGE file, into Array
|
---|
516 | ;"Input:
|
---|
517 | ;"Input: PckInit -- this is the namespace of the package to get patches for, e.g. 'DI' for fileman
|
---|
518 | ;" Ver -- the package version
|
---|
519 | ;" pArray -- PASS BY NAME. An OUT PARAMETER. Format:
|
---|
520 | ;" @pArray@(OrderNum)=PatchName
|
---|
521 | ;" @pArray@(OrderNum,"i",".01")=PatchName
|
---|
522 | ;" @pArray@(OrderNum,"i",".02")=Patch Date
|
---|
523 | ;" @pArray@(OrderNum,"i",".03")=Applied By
|
---|
524 | ;" @pArray@(OrderNum)=PatchName
|
---|
525 | ;"Results: 1 if OK, 0 if error
|
---|
526 | ;
|
---|
527 | new result set result=1
|
---|
528 | ;
|
---|
529 | new IEN9d4,IEN9d49
|
---|
530 | if $$GetPVIEN^TMGPAT1(PckInit,Ver,.IEN9d4,.IEN9d49)=0 set result=0 goto GPLDone
|
---|
531 | ;
|
---|
532 | new orderNum set orderNum=1
|
---|
533 | new patchIEN set patchIEN=0
|
---|
534 | for set patchIEN=$order(^DIC(9.4,IEN9d4,22,IEN9d49,"PAH",patchIEN)) quit:(+patchIEN'>0) do
|
---|
535 | . new s set s=$get(^DIC(9.4,IEN9d4,22,IEN9d49,"PAH",patchIEN,0))
|
---|
536 | . set @pArray@(orderNum)=$piece(s,"^",1) ;"0;1=.01 --PATCH APPLICATION HISTORY
|
---|
537 | . new IENS set IENS=patchIEN_","_IEN9d49_","_IEN9d4_","
|
---|
538 | . new TMGDATA,TMGMSG
|
---|
539 | . do GETS^DIQ(9.4901,IENS,".01;.02;.03","","TMGDATA","TMGMSG")
|
---|
540 | . merge @pArray@(orderNum,"i")=TMGDATA("9.4901",IENS)
|
---|
541 | . ;"zwr TMGDATA(*)
|
---|
542 | . set orderNum=orderNum+1
|
---|
543 | ;
|
---|
544 | GPLDone quit result
|
---|
545 |
|
---|
546 |
|
---|
547 | SHOWPLST
|
---|
548 | ;"Purpose: query user for package and version, then show patches.
|
---|
549 | new PckInit,Ver,Array
|
---|
550 | do GetPckVer^TMGPAT1(.PckInit,.Ver)
|
---|
551 | if Ver="^" goto SLPDone
|
---|
552 | if $$ShowPatches(PckInit,Ver)
|
---|
553 | SLPDone quit
|
---|
554 |
|
---|
555 |
|
---|
556 | ShowPatches(PckInit,Ver)
|
---|
557 | ;"Purpose: to show installed patches, using scroll box.
|
---|
558 | ;"Input: PckInit -- this is the namespace of the package to get patches for, e.g. 'DI' for fileman
|
---|
559 | ;" Ver -- the package version
|
---|
560 | ;"Results: 1 if OK, 0 if error
|
---|
561 |
|
---|
562 | new TMGPCKI set TMGPCKI=PckInit ;"used in HndOnPCmd^TMGPAT3
|
---|
563 | new TMGPVER set TMGPVER=Ver ;"used in HndOnPCmd^TMGPAT3
|
---|
564 | new TMGSORT set TMGSORT=2 ;"sort by SEQ number. Used in HndOnPCmd^TMGPAT3
|
---|
565 | new TMGSARRAY
|
---|
566 | set TMGSARRAY(0)="SORT by IEN order"
|
---|
567 | set TMGSARRAY(1)="SORT by PATCH num"
|
---|
568 | set TMGSARRAY(2)="SORT by SEQ num"
|
---|
569 | new Option,ShowArray,result
|
---|
570 | set Option("HEADER",1)="Applied patches for package "_PckInit_" "_TMGSARRAY(TMGSORT)
|
---|
571 | set Option("FOOTER",1,1)="^ Done"
|
---|
572 | set Option("FOOTER",1,2)="? Help"
|
---|
573 | set Option("FOOTER",1,3)="[F1] "_TMGSARRAY(0)
|
---|
574 | set Option("FOOTER",1,4)="[F2] Fix Missing PATCH"
|
---|
575 | set Option("FOOTER",1,5)="[F3] Fix Missing SEQ"
|
---|
576 | set Option("ON CMD")="HndOnPCmd^TMGPAT3"
|
---|
577 | set Option("SHOW INDEX")=1
|
---|
578 |
|
---|
579 | do PrepPatchList(PckInit,Ver,"ShowArray",TMGSORT)
|
---|
580 | if $data(ShowArray)=0 do
|
---|
581 | . do AskVer^TMGPAT1(PckInit,.Ver)
|
---|
582 | . do PrepPatchList(PckInit,Ver,"ShowArray",TMGSORT)
|
---|
583 |
|
---|
584 | write #
|
---|
585 | do Scroller^TMGUSRIF("ShowArray",.Option)
|
---|
586 |
|
---|
587 | SPDone quit 1
|
---|
588 |
|
---|
589 | PrepPatchList(PckInit,Ver,pShowArray,Mode)
|
---|
590 | ;"Purpose: to prepair the patch list for display in scroll box.
|
---|
591 | ;"Input: PckInit -- this is the namespace of the package to get patches for, e.g. 'DI' for fileman
|
---|
592 | ;" Ver -- the package version
|
---|
593 | ;" pShowArray -- PASS BY NAME, an OUT PARAMATER
|
---|
594 | ;" Mode -- OPTIONAL. 0: Otherwise by IEN order
|
---|
595 | ;" 1: Then sorted by patch number,
|
---|
596 | ;" 2: Otherwise by SEQ Num
|
---|
597 |
|
---|
598 | set ByPatchNum=+$get(ByPatchNum)
|
---|
599 | new index set index=1
|
---|
600 | new showI set showI=1
|
---|
601 | kill @pShowArray
|
---|
602 | new Array,tempA
|
---|
603 | if $$GetPList(.PckInit,.Ver,"Array")=0 goto PPLDone
|
---|
604 | if Mode=0 goto PPL2
|
---|
605 |
|
---|
606 | new Num
|
---|
607 | for set index=$order(Array(index)) quit:(index="") do
|
---|
608 | . if Mode=1 set Num=+$piece(Array(index)," ",1)
|
---|
609 | . else set Num=+$piece(Array(index),"SEQ #",2)
|
---|
610 | . new s,patch
|
---|
611 | . set patch=PckInit_"*"_Ver_"*"_$get(Array(index))
|
---|
612 | . set s=$$LJ^XLFSTR(patch,25)
|
---|
613 | . set s=s_" Applied: "_$get(Array(index,"i",".02"))_" "
|
---|
614 | . set s=s_" By: "_$get(Array(index,"i",".03"))
|
---|
615 | . set tempA(Num)=s
|
---|
616 | set Num=""
|
---|
617 | for set Num=$order(tempA(Num)) quit:(Num="") do
|
---|
618 | . new s set s=$get(tempA(Num)) quit:(s="")
|
---|
619 | . set @pShowArray@(showI,s)=$piece(s," Applied",1)
|
---|
620 | . set showI=showI+1
|
---|
621 | goto PPLDone
|
---|
622 |
|
---|
623 | PPL2 for set index=$order(Array(index)) quit:(index="") do
|
---|
624 | . new s,patch
|
---|
625 | . set patch=PckInit_"*"_Ver_"*"_$get(Array(index))
|
---|
626 | . set s=$$LJ^XLFSTR(patch,25)
|
---|
627 | . set s=s_" Applied: "_$get(Array(index,"i",".02"))_" "
|
---|
628 | . set s=s_" By: "_$get(Array(index,"i",".03"))
|
---|
629 | . set @pShowArray@(showI,s)=patch
|
---|
630 | . set showI=showI+1
|
---|
631 |
|
---|
632 | PPLDone quit
|
---|
633 |
|
---|
634 | HndOnPCmd(pArray,Option,Info)
|
---|
635 | ;"Purpose: handle ON SELECT event from Scroller
|
---|
636 | ;"Input: pArray,Option,Info -- see documentation in Scroller
|
---|
637 | ;" Info has this: Info("USER INPUT")=input
|
---|
638 | ;"NOTE: uses global-scope vars set up in ShowPatches:
|
---|
639 | ;" TMGPCKI,TMGPVER,TMGSORT
|
---|
640 |
|
---|
641 | new input set input=$$UP^XLFSTR($get(Info("USER INPUT")))
|
---|
642 | if input["F1" do
|
---|
643 | . set Option("HEADER",1)="Applied patches for package "_PckInit_" "_TMGSARRAY(TMGSORT)
|
---|
644 | . do PrepPatchList(TMGPCKI,TMGPVER,pArray,TMGSORT)
|
---|
645 | . set TMGSORT=TMGSORT+1
|
---|
646 | . if TMGSORT=3 set TMGSORT=0
|
---|
647 | . set Option("FOOTER",1,3)="[F1] "_TMGSARRAY(TMGSORT)
|
---|
648 | else if input["F2" do
|
---|
649 | . do FixMisInit^TMGPAT1(TMGPCKI,TMGPVER,0)
|
---|
650 | . do PressToCont^TMGUSRIF
|
---|
651 | else if input["F3" do
|
---|
652 | . do FixMisInit^TMGPAT1(TMGPCKI,TMGPVER,1)
|
---|
653 | . do PrepPatchList(TMGPCKI,TMGPVER,pArray,TMGSORT)
|
---|
654 | . do PressToCont^TMGUSRIF
|
---|
655 | else if input="?" do
|
---|
656 | . write !,"Use UP and DOWN cursor keys to scroll.",!
|
---|
657 | . write "Press F1 or F2 to change sorting",!
|
---|
658 | . write "Enter ^ at the ':' prompt when done",!
|
---|
659 | . do PressToCont^TMGUSRIF
|
---|
660 | else if input'="" do
|
---|
661 | . write !,"Input ",$get(Info("USER INPUT"))," not recognized.",!
|
---|
662 | . do PressToCont^TMGUSRIF
|
---|
663 |
|
---|
664 | write #
|
---|
665 | quit
|
---|
666 |
|
---|
667 | EditNotes
|
---|
668 | ;"Purpose: to launch an editor for editing notes about patching.
|
---|
669 | new FPName set FPName=$get(^TMG("KIDS","PATCH DIR"),"/tmp/")_"Patch_Notes.txt"
|
---|
670 | if $$EditHFSFile^TMGKERNL(FPName)
|
---|
671 | quit
|
---|