rda-python-dsupdt 2.0.4__py3-none-any.whl

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.
@@ -0,0 +1,2454 @@
1
+ #!/usr/bin/env python3
2
+ #
3
+ ##################################################################################
4
+ #
5
+ # Title: dsupdt
6
+ # Author: Zaihua Ji, zji@ucar.edu
7
+ # Date: 10/10/2020
8
+ # 2025-02-05 transferred to package rda_python_dsupdt from
9
+ # https://github.com/NCAR/rda-utility-programs.git
10
+ # Purpose: python utility program to download remote files,
11
+ # process downloaded files and create local file, and
12
+ # archive local files onto RDA Server
13
+ # save information of web online data files or Saved files into RDADB
14
+ #
15
+ # Github: https://github.com/NCAR/rda-python-dsupdt.git
16
+ #
17
+ ##################################################################################
18
+ #
19
+ import sys
20
+ import os
21
+ import re
22
+ from os import path as op
23
+ from rda_python_common import PgLOG
24
+ from rda_python_common import PgSIG
25
+ from rda_python_common import PgLock
26
+ from rda_python_common import PgCMD
27
+ from rda_python_common import PgFile
28
+ from rda_python_common import PgUtil
29
+ from rda_python_common import PgOPT
30
+ from rda_python_common import PgDBI
31
+ from rda_python_common import PgSplit
32
+ from . import PgUpdt
33
+
34
+ TEMPINFO = {}
35
+ TOPMSG = SUBJECT = ACTSTR = None
36
+ ALLCNT = 0
37
+ DEFTYPES = {'WT' : 'D', 'ST' : 'P', 'QT' : 'B'}
38
+
39
+ #
40
+ # main function to run dsupdt
41
+ #
42
+ def main():
43
+
44
+ global SUBJECT
45
+ PgOPT.parsing_input('dsupdt')
46
+ PgUpdt.check_enough_options(PgOPT.PGOPT['CACT'], PgOPT.PGOPT['ACTS'])
47
+ start_action()
48
+
49
+ if SUBJECT and 'NE' not in PgOPT.params and (PgLOG.PGLOG['ERRCNT'] or 'EE' not in PgOPT.params):
50
+ SUBJECT += " on " + PgLOG.PGLOG['HOSTNAME']
51
+ PgLOG.set_email("{}: {}".format(SUBJECT, TOPMSG), PgLOG.EMLTOP)
52
+ if ACTSTR: SUBJECT = "{} for {}".format(ACTSTR, SUBJECT)
53
+ if PgSIG.PGSIG['PPID'] > 1: SUBJECT += " in CPID {}".format(PgSIG.PGSIG['PID'])
54
+ if PgLOG.PGLOG['ERRCNT'] > 0: SUBJECT += " With Error"
55
+ if PgLOG.PGLOG['DSCHECK']:
56
+ PgDBI.build_customized_email("dscheck", "einfo", "cindex = {}".format(PgLOG.PGLOG['DSCHECK']['cindex']),
57
+ SUBJECT, PgOPT.PGOPT['wrnlog'])
58
+ elif PgOPT.PGOPT['UCNTL']:
59
+ PgDBI.build_customized_email("dcupdt", "einfo", "cindex = {}".format(PgOPT.PGOPT['UCNTL']['cindex']),
60
+ SUBJECT, PgOPT.PGOPT['wrnlog'])
61
+ else:
62
+ PgLOG.pglog(SUBJECT, PgOPT.PGOPT['wrnlog']|PgLOG.SNDEML)
63
+
64
+ if PgLOG.PGLOG['DSCHECK']:
65
+ if PgLOG.PGLOG['ERRMSG']:
66
+ PgDBI.record_dscheck_error(PgLOG.PGLOG['ERRMSG'])
67
+ else:
68
+ PgCMD.record_dscheck_status("D")
69
+
70
+ if PgOPT.OPTS[PgOPT.PGOPT['CACT']][2]: PgLOG.cmdlog() # log end time if not getting only action
71
+
72
+ PgLOG.pgexit(0)
73
+
74
+ #
75
+ # start action of dsupdt
76
+ #
77
+ def start_action():
78
+
79
+ global ALLCNT
80
+
81
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['CU'][0]:
82
+ if 'CI' in PgOPT.params:
83
+ if PgUpdt.cache_update_control(PgOPT.params['CI'][0], 1):
84
+ check_dataset_status()
85
+ else:
86
+ ALLCNT = PgOPT.get_option_count(["ED", "EH"])
87
+ check_dataset_status(0)
88
+ elif PgOPT.PGOPT['ACTS'] == PgOPT.OPTS['DL'][0]:
89
+ if 'CI' in PgOPT.params:
90
+ ALLCNT = len(PgOPT.params['CI'])
91
+ delete_control_info()
92
+ elif 'RF' in PgOPT.params:
93
+ ALLCNT = len(PgOPT.params['RF'])
94
+ delete_remote_info()
95
+ else:
96
+ ALLCNT = len(PgOPT.params['LI'])
97
+ delete_local_info()
98
+ elif PgOPT.OPTS[PgOPT.PGOPT['CACT']][0]&PgOPT.OPTS['GA'][0]:
99
+ get_update_info()
100
+ elif PgOPT.PGOPT['CACT'] == 'PC':
101
+ process_update_controls()
102
+ elif PgOPT.PGOPT['ACTS'] == PgOPT.OPTS['SA'][0]:
103
+ if 'IF' not in PgOPT.params:
104
+ PgOPT.action_error("Missing input file via Option -IF")
105
+ if PgOPT.get_input_info(PgOPT.params['IF'], 'DCUPDT'):
106
+ PgUpdt.check_enough_options('SC', PgOPT.OPTS['SC'][0])
107
+ ALLCNT = len(PgOPT.params['CI'])
108
+ set_control_info()
109
+ if PgOPT.get_input_info(PgOPT.params['IF'], 'DLUPDT'):
110
+ PgUpdt.check_enough_options('SL', PgOPT.OPTS['SL'][0])
111
+ ALLCNT = len(PgOPT.params['LI'])
112
+ set_local_info()
113
+ if PgOPT.get_input_info(PgOPT.params['IF'], 'DRUPDT') and PgOPT.params['RF']:
114
+ PgUpdt.check_enough_options('SR', PgOPT.OPTS['SR'][0])
115
+ ALLCNT = len(PgOPT.params['RF']) if 'RF' in PgOPT.params else 0
116
+ set_remote_info()
117
+ elif PgOPT.PGOPT['ACTS'] == PgOPT.OPTS['SC'][0]:
118
+ ALLCNT = len(PgOPT.params['CI'])
119
+ set_control_info()
120
+ elif PgOPT.PGOPT['ACTS'] == PgOPT.OPTS['SL'][0]:
121
+ ALLCNT = len(PgOPT.params['LI'])
122
+ set_local_info()
123
+ elif PgOPT.PGOPT['ACTS'] == PgOPT.OPTS['SR'][0]:
124
+ ALLCNT = len(PgOPT.params['RF'])
125
+ set_remote_info()
126
+ elif PgOPT.PGOPT['ACTS']&PgOPT.OPTS['UF'][0]:
127
+ if 'CI' in PgOPT.params:
128
+ if PgUpdt.cache_update_control(PgOPT.params['CI'][0], 1): dataset_update()
129
+ else:
130
+ ALLCNT = PgOPT.get_option_count(["ED", "EH"])
131
+ dataset_update()
132
+ elif PgOPT.PGOPT['ACTS'] == PgOPT.OPTS['UL'][0]:
133
+ if 'CI' in PgOPT.params:
134
+ ALLCNT = len(PgOPT.params['CI'])
135
+ unlock_control_info()
136
+ if 'LI' in PgOPT.params:
137
+ ALLCNT = len(PgOPT.params['LI'])
138
+ unlock_update_info()
139
+
140
+ #
141
+ # delete update control records for given dsid and control indices
142
+ #
143
+ def delete_control_info():
144
+
145
+ s = 's' if ALLCNT > 1 else ''
146
+ PgLOG.pglog("Delete {} update control record{} ...".format(ALLCNT, s), PgLOG.WARNLG)
147
+
148
+ delcnt = modcnt = 0
149
+ for i in range(ALLCNT):
150
+ cidx = PgLock.lock_update_control(PgOPT.params['CI'][i], 2, PgOPT.PGOPT['extlog'])
151
+ if cidx <= 0: continue
152
+ ccnd = "cindex = {}".format(cidx)
153
+ delcnt += PgDBI.pgdel("dcupdt", ccnd, PgOPT.PGOPT['extlog'])
154
+ modcnt += PgDBI.pgexec("UPDATE dlupdt SET cindex = 0 WHERE " + ccnd, PgOPT.PGOPT['extlog'])
155
+
156
+ PgLOG.pglog("{} of {} update control record{} deleted".format(delcnt, ALLCNT, s), PgOPT.PGOPT['wrnlog'])
157
+ if modcnt > 0:
158
+ s = 's' if modcnt > 1 else ''
159
+ PgLOG.pglog("{} associated local file record{} modified".format(modcnt, s), PgOPT.PGOPT['wrnlog'])
160
+
161
+ #
162
+ # delete local files for given dsid and locfile indices
163
+ #
164
+ def delete_local_info():
165
+
166
+ s = 's' if ALLCNT > 1 else ''
167
+ PgLOG.pglog("Delete {} Locfile record{} ...".format(ALLCNT, s), PgLOG.WARNLG)
168
+
169
+ dcnt = delcnt = 0
170
+ for i in range(ALLCNT):
171
+ lidx = PgOPT.params['LI'][i]
172
+ lcnd = "lindex = {}".format(lidx)
173
+ if PgLock.lock_update(lidx, None, 2, PgOPT.PGOPT['errlog']) <= 0: continue
174
+ cnt = PgDBI.pgget("drupdt", "", lcnd, PgOPT.PGOPT['extlog'])
175
+ if cnt > 0:
176
+ ss = 's' if cnt > 1 else ''
177
+ PgLOG.pglog("Delete {} associated remote file record{} for Locfile index {} ...".format(cnt, ss, lidx), PgLOG.WARNLG)
178
+ dcnt += PgDBI.pgdel("drupdt", lcnd, PgOPT.PGOPT['extlog'])
179
+ delcnt += PgDBI.pgdel("dlupdt", lcnd, PgOPT.PGOPT['extlog'])
180
+
181
+ PgLOG.pglog("{} of {} Locfile record{} deleted".format(delcnt, ALLCNT, s), PgOPT.PGOPT['wrnlog'])
182
+ if dcnt > 0:
183
+ s = "s" if (dcnt > 1) else ""
184
+ PgLOG.pglog("{} associated Remote file record{} deleted too".format(dcnt, s), PgOPT.PGOPT['wrnlog'])
185
+
186
+ #
187
+ # delete update remote files for given dsid and remote files/locfile indices
188
+ #
189
+ def delete_remote_info():
190
+
191
+ s = 's' if ALLCNT > 1 else ''
192
+ PgLOG.pglog("Delete {} remote file record{} ...".format(ALLCNT, s), PgLOG.WARNLG)
193
+
194
+ PgOPT.validate_multiple_options(ALLCNT, ["LI", "DO"])
195
+ delcnt = 0
196
+ for i in range(ALLCNT):
197
+ lcnd = "lindex = {} AND remotefile = '{}'".format(PgOPT.params['LI'][i], PgOPT.params['RF'][i])
198
+ if 'DO' in PgOPT.params: lcnd += " AND dindex = {}".format(PgOPT.params['DO'][i])
199
+ delcnt += PgDBI.pgdel("drupdt", lcnd, PgOPT.PGOPT['extlog'])
200
+
201
+ PgLOG.pglog("{} of {} remote file record{} deleted".format(delcnt, ALLCNT, s), PgOPT.PGOPT['wrnlog'])
202
+
203
+ #
204
+ # get update control information
205
+ #
206
+ def get_control_info():
207
+
208
+ tname = "dcupdt"
209
+ hash = PgOPT.TBLHASH[tname]
210
+ PgLOG.pglog("Get update control info of {} from RDADB ...".format(PgOPT.params['DS']), PgLOG.WARNLG)
211
+
212
+ lens = fnames = None
213
+ if 'FN' in PgOPT.params: fnames = PgOPT.params['FN']
214
+ fnames = PgDBI.fieldname_string(fnames, PgOPT.PGOPT[tname], PgOPT.PGOPT['dcall'])
215
+ onames = PgOPT.params['ON'] if 'ON' in PgOPT.params else "C"
216
+ condition = PgUpdt.file_condition(tname) + PgOPT.get_order_string(onames, tname)
217
+ pgrecs = PgDBI.pgmget(tname, "*", condition, PgOPT.PGOPT['extlog'])
218
+ if pgrecs and 'FO' in PgOPT.params: lens = PgUtil.all_column_widths(pgrecs, fnames, hash)
219
+ PgOPT.OUTPUT.write("{}{}{}\n".format(PgOPT.OPTS['DS'][1], PgOPT.params['ES'], PgOPT.params['DS']))
220
+ if PgOPT.PGOPT['CACT'] == "GA": PgOPT.OUTPUT.write("[{}]\n".format(tname.upper()))
221
+ PgOPT.OUTPUT.write(PgOPT.get_string_titles(fnames, hash, lens) + "\n")
222
+ if pgrecs:
223
+ cnt = PgOPT.print_column_format(pgrecs, fnames, hash, lens)
224
+ s = 's' if cnt > 1 else ''
225
+ PgLOG.pglog("{} update control record{} retrieved".format(cnt, s), PgOPT.PGOPT['wrnlog'])
226
+ else:
227
+ PgLOG.pglog("no update control record retrieved", PgOPT.PGOPT['wrnlog'])
228
+
229
+ #
230
+ # get local file update information
231
+ #
232
+ def get_local_info():
233
+
234
+ tname = "dlupdt"
235
+ hash = PgOPT.TBLHASH[tname]
236
+ PgLOG.pglog("Get local file update info of {} from RDADB ...".format(PgOPT.params['DS']), PgLOG.WARNLG)
237
+
238
+ lens = fnames = None
239
+ if 'FN' in PgOPT.params: fnames = PgOPT.params['FN']
240
+ fnames = PgDBI.fieldname_string(fnames, PgOPT.PGOPT[tname], PgOPT.PGOPT['dlall'])
241
+ onames = PgOPT.params['ON'] if 'ON' in PgOPT.params else "XL"
242
+ condition = PgUpdt.file_condition(tname) + PgOPT.get_order_string(onames, tname)
243
+ pgrecs = PgDBI.pgmget(tname, "*", condition, PgOPT.PGOPT['extlog'])
244
+ if pgrecs and 'FO' in PgOPT.params: lens = PgUtil.all_column_widths(pgrecs, fnames, hash)
245
+ if PgOPT.PGOPT['CACT'] == "GL":
246
+ PgOPT.OUTPUT.write("{}{}{}\n".format(PgOPT.OPTS['DS'][1], PgOPT.params['ES'], PgOPT.params['DS']))
247
+ else:
248
+ PgOPT.OUTPUT.write("[{}]\n".format(tname.upper()))
249
+ PgOPT.OUTPUT.write(PgOPT.get_string_titles(fnames, hash, lens) + "\n")
250
+ if pgrecs:
251
+ cnt = PgOPT.print_column_format(pgrecs, fnames, hash, lens)
252
+ s = 's' if cnt > 1 else ''
253
+ PgLOG.pglog("{} locfile record{} retrieved".format(cnt, s), PgOPT.PGOPT['wrnlog'])
254
+ else:
255
+ PgLOG.pglog("no locfile record retrieved", PgOPT.PGOPT['wrnlog'])
256
+
257
+ #
258
+ # get remote file update information
259
+ #
260
+ def get_remote_info():
261
+
262
+ tname = "drupdt"
263
+ hash = PgOPT.TBLHASH[tname]
264
+ PgLOG.pglog("Get remote file update info of {} from RDADB ...".format(PgOPT.params['DS']), PgLOG.WARNLG)
265
+
266
+ lens = fnames = None
267
+ if 'FN' in PgOPT.params: fnames = PgOPT.params['FN']
268
+ fnames = PgDBI.fieldname_string(fnames, PgOPT.PGOPT[tname], PgOPT.PGOPT['drall'])
269
+ onames = PgOPT.params['ON'] if 'ON' in PgOPT.params else "LDF"
270
+ condition = PgUpdt.file_condition(tname) + PgOPT.get_order_string(onames, tname)
271
+ pgrecs = PgDBI.pgmget(tname, "*", condition, PgOPT.PGOPT['extlog'])
272
+ if pgrecs and 'FO' in PgOPT.params: lens = PgUtil.all_column_widths(pgrecs, fnames, hash)
273
+ if PgOPT.PGOPT['CACT'] == "GR":
274
+ PgOPT.OUTPUT.write("{}{}{}\n".format(PgOPT.OPTS['DS'][1], PgOPT.params['ES'], PgOPT.params['DS']))
275
+ else:
276
+ PgOPT.OUTPUT.write("[{}]\n".format(tname.upper()))
277
+ PgOPT.OUTPUT.write(PgOPT.get_string_titles(fnames, hash, lens) + "\n")
278
+ if pgrecs:
279
+ cnt = PgOPT.print_column_format(pgrecs, fnames, hash, lens)
280
+ s = 's' if cnt > 1 else ''
281
+ PgLOG.pglog("{} remote file record{} retrieved".format(cnt, s), PgOPT.PGOPT['wrnlog'])
282
+ else:
283
+ PgLOG.pglog("no remote file record retrieved", PgOPT.PGOPT['wrnlog'])
284
+
285
+ #
286
+ # add or modify update control information
287
+ #
288
+ def set_control_info():
289
+
290
+ tname = 'dcupdt'
291
+ s = 's' if ALLCNT > 1 else ''
292
+ PgLOG.pglog("Set {} update control record{} ...".format(ALLCNT, s), PgLOG.WARNLG)
293
+
294
+ addcnt = modcnt = 0
295
+ flds = PgOPT.get_field_keys(tname, None, 'C')
296
+ if not flds: return PgLOG.pglog("Nothing to set for update control!", PgOPT.PGOPT['errlog'])
297
+ PgOPT.validate_multiple_values(tname, ALLCNT, flds)
298
+ fields = PgOPT.get_string_fields(flds, tname)
299
+
300
+ for i in range(ALLCNT):
301
+ cidx = PgOPT.params['CI'][i]
302
+ if cidx > 0:
303
+ if PgLock.lock_update_control(cidx, 2, PgOPT.PGOPT['errlog']) <= 0: continue
304
+ cnd = "cindex = {}".format(cidx)
305
+ pgrec = PgDBI.pgget(tname, fields, cnd, PgOPT.PGOPT['errlog'])
306
+ if not pgrec: PgOPT.action_error("Error get update control record for " + cnd)
307
+ else:
308
+ pgrec = None
309
+
310
+ record = PgOPT.build_record(flds, pgrec, tname, i)
311
+ if record:
312
+ if 'pindex' in record and record['pindex'] and not PgDBI.pgget("dcupdt", "", "cindex = {}".format(record['pindex'])):
313
+ PgOPT.action_error("Parent control Index {} is not in RDADB".format(record['pindex']))
314
+ if 'action' in record and not re.match(r'^({})$'.format(PgOPT.PGOPT['UPDTACTS']), record['action']):
315
+ PgOPT.action_error("Action Name '{}' must be one of dsupdt Actions ({})".format(record['action'], PgOPT.PGOPT['UPDTACTS']))
316
+ if pgrec:
317
+ record['pid'] = 0
318
+ record['lockhost'] = ''
319
+ modcnt += PgDBI.pgupdt(tname, record, cnd, PgOPT.PGOPT['errlog']|PgLOG.DODFLT)
320
+ else:
321
+ record['dsid'] = PgOPT.params['DS']
322
+ if 'specialist' not in record: record['specialist'] = PgOPT.params['LN']
323
+ addcnt += PgDBI.pgadd(tname, record, PgOPT.PGOPT['errlog']|PgLOG.DODFLT)
324
+ elif cidx: # unlock
325
+ PgLock.lock_update_control(cidx, 0, PgOPT.PGOPT['errlog'])
326
+
327
+ PgLOG.pglog("{}/{} of {} control record{} added/modified".format(addcnt, modcnt, ALLCNT, s), PgOPT.PGOPT['wrnlog'])
328
+
329
+ #
330
+ # add or modify local file update information
331
+ #
332
+ def set_local_info():
333
+
334
+ tname = 'dlupdt'
335
+ s = 's' if ALLCNT > 1 else ''
336
+ PgLOG.pglog("Set {} local file record{} ...".format(ALLCNT, s), PgLOG.WARNLG)
337
+
338
+ addcnt = modcnt = 0
339
+ flds = PgOPT.get_field_keys(tname, None, 'L')
340
+ if 'RO' in PgOPT.params and 'XO' not in PgOPT.params: flds += 'X'
341
+ if not flds: return PgLOG.pglog("Nothing to set for update local file!", PgOPT.PGOPT['errlog'])
342
+ PgOPT.validate_multiple_values(tname, ALLCNT, flds)
343
+ fields = PgOPT.get_string_fields(flds, tname)
344
+
345
+ for i in range(ALLCNT):
346
+ lidx = PgOPT.params['LI'][i]
347
+ if lidx > 0:
348
+ if PgLock.lock_update(lidx, None, 2, PgOPT.PGOPT['errlog']) <= 0: continue
349
+ cnd = "lindex = {}".format(lidx)
350
+ pgrec = PgDBI.pgget(tname, fields, cnd, PgOPT.PGOPT['errlog'])
351
+ if not pgrec: PgOPT.action_error("Error get Local file record for " + cnd)
352
+ else:
353
+ pgrec = None
354
+
355
+ if 'RO' in PgOPT.params: PgOPT.params['XO'][i] = PgUpdt.get_next_exec_order(PgOPT.params['DS'], 0)
356
+ record = PgOPT.build_record(flds, pgrec, tname, i)
357
+ if record:
358
+ if 'cindex' in record and record['cindex'] and not PgDBI.pgget("dcupdt", "", "cindex = {}".format(record['cindex'])):
359
+ PgOPT.action_error("Update control Index {} is not in RDADB".format(record['cindex']))
360
+ if 'action' in record and not re.match(r'^({})$'.format(PgOPT.PGOPT['ARCHACTS']), record['action']):
361
+ PgOPT.action_error("Action Name '{}' must be one of dsarch Actions ({})".format(record['action'], PgOPT.PGOPT['ARCHACTS']))
362
+
363
+ if pgrec:
364
+ if 'VI' in record and not record['VI'] and pgrec['missdate']: record['missdate'] = record['misshour'] = None
365
+ record['pid'] = 0
366
+ record['hostname'] = 0
367
+ modcnt += PgDBI.pgupdt(tname, record, cnd, PgOPT.PGOPT['errlog']|PgLOG.DODFLT)
368
+ else:
369
+ record['dsid'] = PgOPT.params['DS']
370
+ if 'specialist' not in record: record['specialist'] = PgOPT.params['LN']
371
+ if 'execorder' not in record: record['execorder'] = PgUpdt.get_next_exec_order(PgOPT.params['DS'], 1)
372
+ addcnt += PgDBI.pgadd(tname, record, PgOPT.PGOPT['errlog']|PgLOG.DODFLT)
373
+ elif lidx: # unlock
374
+ PgLock.lock_update(lidx, None, 0, PgOPT.PGOPT['errlog'])
375
+
376
+ PgLOG.pglog("{}/{} of {} Locfile record{} added/modified".format(addcnt, modcnt, ALLCNT, s), PgOPT.PGOPT['wrnlog'])
377
+
378
+ #
379
+ # add or modify remote file update information
380
+ #
381
+ def set_remote_info():
382
+
383
+ tname = 'drupdt'
384
+ s = 's' if ALLCNT > 1 else ''
385
+ PgLOG.pglog("Set {} update remote file{} ...".format(ALLCNT, s), PgLOG.WARNLG)
386
+
387
+ addcnt = modcnt = 0
388
+ flds = PgOPT.get_field_keys(tname)
389
+ if not flds: return PgLOG.pglog("Nothing to set for update remote file!", PgOPT.PGOPT['errlog'])
390
+ PgOPT.validate_multiple_values(tname, ALLCNT, flds)
391
+ fields = PgOPT.get_string_fields(flds, tname)
392
+
393
+ for i in range(ALLCNT):
394
+ lidx = PgOPT.params['LI'][i]
395
+ didx = PgOPT.params['DO'][i] if 'DO' in PgOPT.params else 0
396
+ cnd = "lindex = {} AND remotefile = '{}' AND dindex = {}".format(lidx, PgOPT.params['RF'][i], didx)
397
+ pgrec = PgDBI.pgget("drupdt", fields, cnd, PgOPT.PGOPT['errlog'])
398
+ record = PgOPT.build_record(flds, pgrec, tname, i)
399
+ if record:
400
+ if 'lindex' in record and record['lindex'] and not PgDBI.pgget("dlupdt", "", "lindex = {}".format(record['lindex'])):
401
+ PgOPT.action_error("Local file Index {} is not in RDADB".format(record['lindex']))
402
+
403
+ if pgrec:
404
+ modcnt += PgDBI.pgupdt("drupdt", record, cnd, PgOPT.PGOPT['errlog']|PgLOG.DODFLT)
405
+ else:
406
+ record['lindex'] = lidx
407
+ record['dsid'] = PgOPT.params['DS']
408
+ addcnt += PgDBI.pgadd("drupdt", record, PgOPT.PGOPT['errlog']|PgLOG.DODFLT)
409
+
410
+ PgLOG.pglog("{}/{} of {} remote file record{} added/modified".format(addcnt, modcnt, ALLCNT, s), PgOPT.PGOPT['wrnlog'])
411
+
412
+ #
413
+ # unlock update records for given locfile indices
414
+ #
415
+ def unlock_update_info():
416
+
417
+ s = 's' if ALLCNT > 1 else ''
418
+ PgLOG.pglog("Unlock {} update locfile{} ...".format(ALLCNT, s), PgLOG.WARNLG)
419
+
420
+ modcnt = 0
421
+ for lidx in PgOPT.params['LI']:
422
+ cnd = "lindex = {}".format(lidx)
423
+ pgrec = PgDBI.pgget("dlupdt", "pid, hostname", cnd, PgOPT.PGOPT['extlog'])
424
+ if not pgrec:
425
+ PgLOG.pglog("{}: Local File Not exists".format(lidx), PgOPT.PGOPT['errlog'])
426
+ elif not pgrec['pid']:
427
+ PgLOG.pglog("{}: Local File Not locked".format(lidx), PgOPT.PGOPT['wrnlog'])
428
+ elif PgLock.lock_update(lidx, None, -1, PgOPT.PGOPT['errlog']) > 0:
429
+ modcnt += 1
430
+ PgLOG.pglog("{}: Local File Unlocked {}/{}".format(lidx, pgrec['pid'], pgrec['hostname']), PgOPT.PGOPT['wrnlog'])
431
+ elif (PgFile.check_host_down(None, pgrec['hostname']) and
432
+ PgLock.lock_update(lidx, None, -2, PgOPT.PGOPT['errlog']) > 0):
433
+ modcnt += 1
434
+ PgLOG.pglog("{}: Local File Force unlocked {}/{}".format(lidx, pgrec['pid'], pgrec['hostname']), PgOPT.PGOPT['wrnlog'])
435
+ else:
436
+ PgLOG.pglog("{}: Local File Unable to unlock {}/{}".format(lidx, pgrec['pid'], pgrec['hostname']), PgOPT.PGOPT['wrnlog'])
437
+
438
+ PgLOG.pglog("{} of {} local file record{} unlocked from RDADB".format(modcnt, ALLCNT, s), PgLOG.LOGWRN)
439
+
440
+ #
441
+ # unlock update control records for given locfile indices
442
+ #
443
+ def unlock_control_info():
444
+
445
+ s = 's' if ALLCNT > 1 else ''
446
+ PgLOG.pglog("Unlock {} update control{} ...".format(ALLCNT, s), PgLOG.WARNLG)
447
+
448
+ modcnt = 0
449
+ for cidx in PgOPT.params['CI']:
450
+ pgrec = PgDBI.pgget("dcupdt", "pid, lockhost", "cindex = {}".format(cidx), PgOPT.PGOPT['extlog'])
451
+ if not pgrec:
452
+ PgLOG.pglog("{}: Update Control Not exists".format(cidx), PgOPT.PGOPT['errlog'])
453
+ elif not pgrec['pid']:
454
+ PgLOG.pglog("{}: Update Control Not locked".format(cidx), PgOPT.PGOPT['wrnlog'])
455
+ elif PgLock.lock_update_control(cidx, -1, PgOPT.PGOPT['extlog']) > 0:
456
+ modcnt += 1
457
+ PgLOG.pglog("{}: Update Control Unlocked {}/{}".format(cidx, pgrec['pid'], pgrec['lockhost']), PgOPT.PGOPT['wrnlog'])
458
+ elif (PgFile.check_host_down(None, pgrec['lockhost']) and
459
+ PgLock.lock_update_control(cidx, -2, PgOPT.PGOPT['extlog']) > 0):
460
+ modcnt += 1
461
+ PgLOG.pglog("{}: Update Control Force unlocked {}/{}".format(cidx, pgrec['pid'], pgrec['lockhost']), PgOPT.PGOPT['wrnlog'])
462
+ else:
463
+ PgLOG.pglog("{}: Undate Control Unable to unlock {}/{}".format(cidx, pgrec['pid'], pgrec['lockhost']), PgOPT.PGOPT['wrnlog'])
464
+
465
+ PgLOG.pglog("{} of {} update control record{} unlocked from RDADB".format(modcnt, ALLCNT, s), PgLOG.LOGWRN)
466
+
467
+ #
468
+ # get update info of local and remote files owned by login name
469
+ #
470
+ def get_update_info():
471
+
472
+ if 'DS' in PgOPT.params:
473
+ dsids = {'dsid' : [PgOPT.params['DS']]}
474
+ dscnt = 1
475
+ else:
476
+ tname = "dlupdt"
477
+ cnd = PgUpdt.file_condition(tname, None, None, 1)
478
+ if not cnd:
479
+ PgOPT.set_default_value("SN", PgOPT.params['LN'])
480
+ cnd = PgUpdt.file_condition(tname, None, None, 1)
481
+ dsids = PgDBI.pgmget(tname, "DISTINCT dsid", cnd, PgOPT.PGOPT['extlog'])
482
+ dscnt = len(dsids['dsid']) if dsids else 0
483
+ if dscnt == 0:
484
+ return PgLOG.pglog("NO dataset identified for giving condition", PgOPT.PGOPT['wrnlog'])
485
+ elif dscnt > 1:
486
+ PgLOG.pglog("Get Update Info for {} datasets".format(dscnt), PgOPT.PGOPT['wrnlog'])
487
+
488
+ PgOPT.PGOPT['AUTODS'] = dscnt
489
+
490
+ for i in range(dscnt):
491
+ PgOPT.params['DS'] = dsids['dsid'][i]
492
+ if PgOPT.PGOPT['ACTS'] == PgOPT.OPTS['GC'][0]:
493
+ get_control_info()
494
+ elif PgOPT.PGOPT['ACTS'] == PgOPT.OPTS['GL'][0]:
495
+ get_local_info()
496
+ elif PgOPT.PGOPT['ACTS'] == PgOPT.OPTS['GR'][0]:
497
+ get_remote_info()
498
+ else:
499
+ if 'ON' in PgOPT.params: del PgOPT.params['ON'] # use default order string
500
+ if 'FN' not in PgOPT.params: PgOPT.params['FN'] = 'ALL'
501
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['GC'][0]: get_control_info()
502
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['GL'][0]: get_local_info()
503
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['GR'][0]: get_remote_info()
504
+
505
+ if dscnt > 1: PgLOG.pglog("Update Info of {} datasets retrieved".format(dscnt), PgOPT.PGOPT['wrnlog'])
506
+
507
+ #
508
+ # gather due datasets for data update
509
+ #
510
+ def dataset_update():
511
+
512
+ global SUBJECT, TOPMSG, ACTSTR
513
+
514
+ actcnd = "specialist = '{}'".format(PgOPT.params['LN'])
515
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['AF'][0]: actcnd += " AND action IN ('AW', 'AS', 'AQ')"
516
+ (PgOPT.PGOPT['CURDATE'], PgOPT.PGOPT['CURHOUR']) = PgUtil.curdatehour()
517
+ if 'CD' not in PgOPT.params: PgOPT.params['CD'] = PgOPT.PGOPT['CURDATE'] # default to current date
518
+ if 'CH' not in PgOPT.params: PgOPT.params['CH'] = PgOPT.PGOPT['CURHOUR'] # default to current hour
519
+ if ALLCNT > 1 and PgOPT.params['MU']: del PgOPT.params['MU']
520
+ if 'CN' in PgOPT.params and 'RD' in PgOPT.params: del PgOPT.params['CN']
521
+ if 'CN' in PgOPT.params or 'RD' in PgOPT.params or 'RA' in PgOPT.params:
522
+ if 'MO' in PgOPT.params: del PgOPT.params['MO']
523
+ elif 'MO' not in PgOPT.params and PgOPT.PGOPT['CACT'] == "UF":
524
+ PgOPT.params['MO'] = -1
525
+
526
+ if 'DS' in PgOPT.params:
527
+ dsids = [PgOPT.params['DS']]
528
+ dscnt = 1
529
+ else:
530
+ if 'CI' not in PgOPT.params: actcnd += " AND cindex = 0"
531
+ loccnd = PgUpdt.file_condition('dlupdt', "LQFIXA", None, 1)
532
+ dscnd = actcnd
533
+ if loccnd: dscnd += " AND " + loccnd
534
+ pgrecs = PgDBI.pgmget("dlupdt", "DISTINCT dsid", dscnd, PgOPT.PGOPT['extlog'])
535
+ dsids = pgrecs['dsid'] if pgrecs else []
536
+ dscnt = len(dsids)
537
+ if not dscnt: return PgLOG.pglog("NO dataset is due for update on {} for {}".format(PgOPT.params['CD'], PgOPT.params['LN']), PgOPT.PGOPT['wrnlog'])
538
+ PgOPT.PGOPT['AUTODS'] = dscnt
539
+ actcnd += " ORDER BY execorder, lindex"
540
+
541
+ if PgLOG.PGLOG['DSCHECK']:
542
+ fcnt = 0
543
+ for i in range(dscnt):
544
+ PgOPT.params['DS'] = dsids[i]
545
+ loccnd = PgUpdt.file_condition('dlupdt', "LQFIXA")
546
+ locrecs = PgDBI.pgmget("dlupdt", "*", "{} AND {}".format(loccnd, actcnd), PgOPT.PGOPT['extlog'])
547
+ loccnt = len(locrecs['locfile']) if locrecs else 0
548
+ if loccnt == 0: continue
549
+ for j in range(loccnt):
550
+ locrec = PgUtil.onerecord(locrecs, j)
551
+ if (loccnt == 1 and 'LI' in PgOPT.params and 'LF' in PgOPT.params and
552
+ len(PgOPT.params['LF']) == 1 and PgOPT.params['LF'][0] != locrec['locfile']):
553
+ locrec['locfile'] = PgOPT.params['LF'][0]
554
+ fcnt += file_update(locrec, PgLOG.LOGWRN, 1)
555
+ PgCMD.set_dscheck_fcount(fcnt, PgLOG.LOGERR)
556
+
557
+ # check and update data for each dataset
558
+ logact = PgOPT.PGOPT['emllog']
559
+ acnt = ucnt = 0
560
+ for i in range(dscnt):
561
+ PgOPT.params['DS'] = dsids[i]
562
+ loccnd = PgUpdt.file_condition('dlupdt', "LQFIXA")
563
+ locrecs = PgDBI.pgmget("dlupdt", "*", "{} AND {}".format(loccnd, actcnd), PgOPT.PGOPT['extlog'])
564
+ loccnt = len(locrecs['locfile']) if locrecs else 0
565
+ if loccnt == 0:
566
+ s = "-UC{}".format(PgOPT.params['CI'][0]) if ('CI' in PgOPT.params and len(PgOPT.params['CI']) == 1) else ""
567
+ PgLOG.pglog("{}{}: no config record of local file found to update for '{}'".format(PgOPT.params['DS'], s, PgOPT.params['LN']), PgOPT.PGOPT['wrnlog'])
568
+ continue
569
+ s = 's' if loccnt > 1 else ''
570
+ PgLOG.pglog("{}: {} for {} update record{}".format(PgOPT.params['DS'], PgOPT.PGOPT['CACT'], loccnt, s), logact)
571
+ logact = PgOPT.PGOPT['emlsep']
572
+ for j in range(loccnt):
573
+ locrec = PgUtil.onerecord(locrecs, j)
574
+ if (loccnt == 1 and 'LI' in PgOPT.params and 'LF' in PgOPT.params and
575
+ len(PgOPT.params['LF']) == 1 and PgOPT.params['LF'][0] != locrec['locfile']):
576
+ locrec['locfile'] = PgOPT.params['LF'][0]
577
+ if locrec['cindex']:
578
+ if 'CI' not in PgOPT.params:
579
+ PgOPT.params['CI'] = [locrec['cindex']]
580
+ PgUpdt.cache_update_control(locrec['cindex'], 0)
581
+ if 'CN' in PgOPT.params and 'RD' in PgOPT.params: del PgOPT.params['CN']
582
+ if 'CN' in PgOPT.params or 'RD' in PgOPT.params or 'RA' in PgOPT.params:
583
+ if 'MO' in PgOPT.params: del PgOPT.params['MO']
584
+ elif 'MO' not in PgOPT.params and PgOPT.PGOPT['CACT'] == "UF":
585
+ PgOPT.params['MO'] = -1
586
+ elif locrec['cindex'] != PgOPT.params['CI'][0]:
587
+ PgLOG.pglog("{}-{}: Skipped due to control index {} mismatches {}".format(PgOPT.params['DS'], locrec['lindex'], locrec['cindex'], PgOPT.params['CI'][0]), PgOPT.PGOPT['emlerr'])
588
+ continue
589
+
590
+ PgOPT.PGOPT['rstat'] = 1 # reset remote download status for each local file
591
+ if PgSIG.PGSIG['MPROC'] > 1: acnt += 1
592
+ fcnt = file_update(locrec, logact)
593
+ if PgSIG.PGSIG['PPID'] > 1:
594
+ if PgOPT.PGOPT['AUTODS'] > 1: PgOPT.PGOPT['AUTODS'] = dscnt = 1
595
+ acnt = ucnt = 0 # reinitialize counts for child process
596
+ break # stop loop in child
597
+ if PgSIG.PGSIG['MPROC'] > 1:
598
+ if fcnt == 0:
599
+ break # quit
600
+ else:
601
+ if fcnt > 0: ucnt += 1 # record update count, s is either -1 or 1
602
+ continue # non-daemon parent
603
+ if 'QE' in PgOPT.params and fcnt <= 0: break
604
+
605
+ if PgOPT.PGOPT['vcnt'] > 0:
606
+ renew_internal_version(PgOPT.params['DS'], PgOPT.PGOPT['vcnt'])
607
+ PgOPT.PGOPT['vcnt'] = 0
608
+ if PgSIG.PGSIG['MPROC'] > 1:
609
+ if not PgSIG.PGSIG['QUIT'] and j == loccnt: continue
610
+ break
611
+ if PgOPT.PGOPT['rcnt']:
612
+ if PgOPT.PGOPT['CACT'] == "DR":
613
+ acnt += PgOPT.PGOPT['rcnt']
614
+ ucnt += PgOPT.PGOPT['dcnt']
615
+ s = 's' if PgOPT.PGOPT['rcnt'] > 1 else ''
616
+ if loccnt > 1:
617
+ PgLOG.pglog("{}: {} of {} rfile{} gotten!".format(PgOPT.params['DS'], PgOPT.PGOPT['dcnt'], PgOPT.PGOPT['rcnt'], s), PgOPT.PGOPT['emllog'])
618
+ PgOPT.PGOPT['rcnt'] = PgOPT.PGOPT['dcnt'] = 0
619
+ if PgOPT.PGOPT['lcnt']:
620
+ if PgOPT.PGOPT['CACT'] == "BL" or PgOPT.PGOPT['CACT'] == "PB":
621
+ acnt += PgOPT.PGOPT['lcnt']
622
+ ucnt += PgOPT.PGOPT['bcnt']
623
+ s = 's' if PgOPT.PGOPT['lcnt'] > 1 else ''
624
+ if loccnt > 1 and PgOPT.PGOPT['bcnt'] > 0:
625
+ PgLOG.pglog("{}: {} of {} lfile{} built!".format(PgOPT.params['DS'], PgOPT.PGOPT['bcnt'], PgOPT.PGOPT['lcnt'], s), PgOPT.PGOPT['emllog'])
626
+ PgOPT.PGOPT['lcnt'] = PgOPT.PGOPT['bcnt'] = 0
627
+ if PgOPT.PGOPT['acnt']:
628
+ acnt += PgOPT.PGOPT['acnt']
629
+ ucnt += PgOPT.PGOPT['ucnt']
630
+ s = 's' if PgOPT.PGOPT['acnt'] > 1 else ''
631
+ PgLOG.pglog("{}: {} of {} local file{} archived!".format(PgOPT.params['DS'], PgOPT.PGOPT['ucnt'], PgOPT.PGOPT['acnt'], s),
632
+ (PgOPT.PGOPT['emlsum'] if dscnt > 1 else PgOPT.PGOPT['emllog']))
633
+ PgOPT.PGOPT['acnt'] = PgOPT.PGOPT['ucnt'] = 0
634
+
635
+ if PgSIG.PGSIG['PPID'] > 1: break # stop loop child
636
+
637
+ if acnt > 0:
638
+ TOPMSG = detail = ""
639
+ if PgSIG.PGSIG['MPROC'] > 1:
640
+ s = 's' if acnt > 1 else ''
641
+ ACTSTR = "{} of {} CPIDs{} for 'dsupdt {}' started".format(ucnt, acnt, s, PgOPT.PGOPT['CACT'])
642
+ else:
643
+ s = 's' if ucnt > 1 else ''
644
+ TOPMSG = ""
645
+ if PgOPT.PGOPT['CACT'] == "DR":
646
+ atype = "remote file{} gotten".format(s)
647
+ elif PgOPT.PGOPT['CACT'] == "BL" or PgOPT.PGOPT['CACT'] == "PB":
648
+ atype = "local file{} built".format(s)
649
+ else:
650
+ atype = "local file{} archived".format(s)
651
+ if PgOPT.PGOPT['rdcnt'] > 0:
652
+ s = 's' if PgOPT.PGOPT['rdcnt'] > 1 else ''
653
+ TOPMSG = "{} remote server file{} downloaded and ".format(PgOPT.PGOPT['rdcnt'], s)
654
+ if PgOPT.PGOPT['udcnt'] > 0:
655
+ if detail: detail += " & "
656
+ detail += "{} Web Online".format(PgOPT.PGOPT['udcnt'])
657
+ if PgOPT.PGOPT['uncnt'] > 0:
658
+ if detail: detail += " & "
659
+ detail += "{} Glade Only".format(PgOPT.PGOPT['uncnt'])
660
+ if PgOPT.PGOPT['uwcnt'] > 0:
661
+ if detail: detail += " & "
662
+ detail += "{} Web".format(PgOPT.PGOPT['uwcnt'])
663
+ if PgOPT.PGOPT['uscnt'] > 0:
664
+ if detail: detail += " & "
665
+ detail += "{} Saved".format(PgOPT.PGOPT['uscnt'])
666
+ if PgOPT.PGOPT['qbcnt'] > 0:
667
+ if detail: detail += " & "
668
+ detail += "{} Quasar Backup".format(PgOPT.PGOPT['qbcnt'])
669
+ if PgOPT.PGOPT['qdcnt'] > 0:
670
+ if detail: detail += " & "
671
+ detail += "{} Quasar Drdata".format(PgOPT.PGOPT['qdcnt'])
672
+ ACTSTR = "{} {}".format(ucnt, atype)
673
+
674
+ TOPMSG += ACTSTR
675
+ if detail: TOPMSG += " ({})".format(detail)
676
+ if dscnt > 1:
677
+ PgLOG.pglog("{} datasets: {}".format(dscnt, TOPMSG), PgOPT.PGOPT['emlsum'])
678
+ SUBJECT = "DSUPDT of "
679
+ if PgOPT.PGOPT['AUTODS'] < 2:
680
+ SUBJECT += PgOPT.params['DS'].upper()
681
+ else:
682
+ SUBJECT += "{} Datasets".format(PgOPT.PGOPT['AUTODS'])
683
+
684
+ if PgOPT.PGOPT['UCNTL']:
685
+ PgUpdt.reset_control_time()
686
+ if SUBJECT: SUBJECT += "-C{}".format(PgOPT.PGOPT['UCNTL']['cindex'])
687
+
688
+ # renew internal version number for given dataset
689
+ def renew_internal_version(dsid, vcnt):
690
+
691
+ s = 's' if vcnt > 1 else ''
692
+ cmd = "dsarch {} SV -NV -DE '{} Data file{} rearchived'".format(dsid, vcnt, s)
693
+ if PgLOG.pgsystem(cmd, PgOPT.PGOPT['emerol'], 5): # 1 + 4
694
+ pgrec = PgDBI.pgget('dsvrsn', '*', "dsid = '{}' and status = 'A'".format(dsid), PgOPT.PGOPT['emerol'])
695
+ if pgrec:
696
+ vmsg = "set to {} for DOI {}".format(pgrec['iversion'], pgrec['doi'])
697
+ else:
698
+ vmsg = 'renewed'
699
+
700
+ PgLOG.pglog("{}: {} Data file{} rearchived, Internal version number {}".format(dsid, vcnt, s, vmsg), PgOPT.PGOPT['emlsum'])
701
+
702
+ #
703
+ # cach the total count of files to be archived
704
+ #
705
+ def count_caching(locrec, locinfo):
706
+
707
+ files = PgUpdt.expand_serial_pattern(locrec['locfile'])
708
+ scnt = len(files) if files else 1
709
+
710
+ if ALLCNT > 1:
711
+ ecnt = ALLCNT
712
+ else:
713
+ tinfo = TEMPINFO[locrec['lindex']] = get_tempinfo(locrec, locinfo, 0)
714
+ ecnt = len(tinfo['ED']) if tinfo else 1
715
+
716
+ return ecnt * scnt
717
+
718
+ #
719
+ # gather/archive due data file for update of each local file
720
+ #
721
+ def file_update(locrec, logact, caching = 0):
722
+
723
+ lfile = locrec['locfile']
724
+ endonly = retcnt = 0
725
+ lindex = locrec['lindex']
726
+ loccnd = "lindex = {}".format(lindex)
727
+ locinfo = "{}-L{}".format(locrec['dsid'], lindex)
728
+ if not lfile:
729
+ if caching:
730
+ return None
731
+ else:
732
+ return PgLOG.pglog(locinfo + ": local file name NOT specified", PgOPT.PGOPT['emlerr'])
733
+ locinfo += "-" + lfile
734
+ if locrec['specialist'] != PgOPT.params['LN']:
735
+ if caching:
736
+ return None
737
+ else:
738
+ return PgLOG.pglog("{}: owner '{}', NOT '{}'".format(locinfo, locrec['specialist'], PgOPT.params['LN']), PgOPT.PGOPT['emlerr'])
739
+
740
+ if caching: return count_caching(locrec, locinfo)
741
+ tempinfo = TEMPINFO[lindex] if lindex in TEMPINFO else get_tempinfo(locrec, locinfo, 0)
742
+ if not tempinfo: return 0 # simply return if miss temporal info for update
743
+
744
+ rmtcnd = loccnd
745
+ rcnd = PgUpdt.file_condition('drupdt', ('D' if 'DO' in PgOPT.params else "RS"), None, 1)
746
+ if rcnd: rmtcnd += " AND " + rcnd
747
+ rmtrecs = PgDBI.pgmget("drupdt", "*", rmtcnd + " ORDER BY dindex, remotefile", PgOPT.PGOPT['extlog'])
748
+ rcnt = len(rmtrecs['remotefile']) if rmtrecs else 0
749
+ if rcnt == 0:
750
+ if rcnd and PgDBI.pgget("drupdt", "", loccnd):
751
+ return PgLOG.pglog("{}: NO remote file record matched for {}".format(locinfo, rcnd), PgOPT.PGOPT['emlerr'])
752
+ # create a empty record remote file
753
+ rcnt = 1
754
+
755
+ rmtrecs = {'lindex' : [lindex], 'dindex' : [0]}
756
+ rflds = ['remotefile', 'serverfile', 'download', 'begintime', 'endtime', 'tinterval']
757
+ for rfld in rflds: rmtrecs[rfld] = [None]
758
+ if rcnt == 1:
759
+ if 'RF' in PgOPT.params and len(PgOPT.params['RF']) == 1 and not (rmtrecs['remotefile'][0] and PgOPT.params['RF'][0] == rmtrecs['remotefile'][0]):
760
+ rmtrecs['remotefile'][0] = PgOPT.params['RF'][0]
761
+ if 'SF' in PgOPT.params and len(PgOPT.params['SF']) == 1 and not (rmtrecs['serverfile'][0] and PgOPT.params['SF'][0] == rmtrecs['serverfile'][0]):
762
+ rmtrecs['serverfile'][0] = PgOPT.params['SF'][0]
763
+ ecnt = ALLCNT if ALLCNT > 1 else len(tempinfo['ED']) # should be at least one
764
+
765
+ if PgSIG.PGSIG['MPROC'] > 1:
766
+ pname = "updt{}".format(lindex)
767
+ pid = PgSIG.start_child(pname, PgOPT.PGOPT['wrnlog'], 1) # try to start a child process
768
+ if pid <= 0: return pid # failed to start a child process
769
+ if PgSIG.PGSIG['PPID'] > 1:
770
+ PgLOG.set_email() # empty email in child process
771
+ PgOPT.PGOPT['acnt'] = PgOPT.PGOPT['ucnt'] = 0
772
+ else:
773
+ edate = tempinfo['ED'][0]
774
+ ehour = tempinfo['EH'][0]
775
+ lfile = PgUpdt.replace_pattern(locrec['locfile'], edate, ehour, tempinfo['FQ'])
776
+ locinfo = "{}-L{}-{}".format(locrec['dsid'], lindex, lfile)
777
+ if ecnt > 1: locinfo += ", {} Update Periods".format(ecnt)
778
+ PgLOG.pglog("CPID {} for 'dsupdt {}' of {}".format(PgSIG.pname2cpid(pname), PgOPT.PGOPT['CACT'], locinfo), PgOPT.PGOPT['emllog'])
779
+ return 1 # no further action in non-daemon program
780
+
781
+ if PgLock.lock_update(lindex, locinfo, 1, PgOPT.PGOPT['emllog']) <= 0: return 0
782
+ PgOPT.PGOPT['lindex'] = lindex
783
+ tempinfo['prcmd'] = PgOPT.params['PR'][0] if 'PR' in PgOPT.params else locrec['processremote']
784
+ tempinfo['blcmd'] = PgOPT.params['BC'][0] if 'BC' in PgOPT.params else locrec['buildcmd']
785
+ postcnt = -1
786
+ if PgOPT.PGOPT['UCNTL'] and PgOPT.PGOPT['CACT'] == PgOPT.PGOPT['UCNTL']['action']:
787
+ tempinfo['postcmd'] = PgOPT.params['XC'][0] if 'XC' in PgOPT.params else PgOPT.PGOPT['UCNTL']['execcmd']
788
+ if tempinfo['postcmd']: postcnt = 0
789
+
790
+ setmiss = 1 if tempinfo['VD'] else 0
791
+ ufile = uinfo = None
792
+ rscnt = ucnt = lcnt = 0
793
+
794
+ for i in range(ecnt):
795
+ if ALLCNT > 1 and i > 0:
796
+ tempinfo = get_tempinfo(locrec, locinfo, i)
797
+ if not tempinfo: break
798
+ edate = tempinfo['ED'][0]
799
+ ehour = tempinfo['EH'][0]
800
+ else:
801
+ edate = tempinfo['ED'][i]
802
+ ehour = tempinfo['EH'][i]
803
+ if 'RE' in PgOPT.params and i and PgUtil.diffdatehour(edate, ehour, tempinfo['edate'], tempinfo['ehour']) <= 0:
804
+ continue
805
+ if ucnt and tempinfo['RS'] == 1 and i%20 == 0: refresh_metadata(locrec['dsid'])
806
+ tempinfo['edate'] = edate
807
+ if ehour != None:
808
+ tempinfo['einfo'] = "end data date:hour {}:{:02}".format(edate, ehour)
809
+ tempinfo['ehour'] = ehour
810
+ else:
811
+ tempinfo['einfo'] = "end data date {}".format(edate)
812
+ tempinfo['ehour'] = None
813
+ if 'GZ' in PgOPT.params: tempinfo['einfo'] += "(UTC)"
814
+
815
+ locfiles = PgUpdt.get_local_names(locrec['locfile'], tempinfo)
816
+ lcnt = len(locfiles) if locfiles else 0
817
+ if not lcnt: break
818
+ rmtcnt = acnt = ccnt = ut = 0
819
+ rfiles = rfile = None
820
+ if tempinfo['RS'] == 0 and lcnt > 2: tempinfo['RS'] = 1
821
+
822
+ for l in range(lcnt):
823
+ if PgLOG.PGLOG['DSCHECK'] and ((l+1)%20) == 0:
824
+ PgCMD.add_dscheck_dcount(20, 0, PgOPT.PGOPT['extlog'])
825
+ lfile = locfiles[l]
826
+ locinfo = "{}-L{}-{}".format(locrec['dsid'], lindex, lfile)
827
+ tempinfo['gotnew'] = tempinfo['archived'] = 0
828
+ tempinfo['ainfo'] = None
829
+ tempinfo['ainfo'] = file_archive_info(lfile, locrec, tempinfo)
830
+ if not tempinfo['ainfo']: continue
831
+ if tempinfo['ainfo']['archived'] == tempinfo['ainfo']['archcnt']:
832
+ ufile = "{} at {} {}".format(lfile, tempinfo['ainfo']['adate'], tempinfo['ainfo']['atime'])
833
+ tempinfo['archived'] = 1
834
+ if 'MO' in PgOPT.params:
835
+ if PgOPT.params['MO'] < 0:
836
+ PgLOG.pglog("{}: {} already for {}".format(locinfo, PgOPT.PGOPT['CACT'], tempinfo['einfo']), PgOPT.PGOPT['emlsum'])
837
+ if i == 0: PgLOG.pglog("Add Mode option -RA if you want to re-archive", PgOPT.PGOPT['wrnlog'])
838
+ if 'UT' in PgOPT.params or 'ED' not in PgOPT.params: ut = 1
839
+ retcnt += 1
840
+ continue
841
+ else:
842
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['AF'][0]: uinfo = locinfo
843
+ PgLOG.pglog("{}: {} for {}".format(locinfo, PgOPT.PGOPT['CACT'], tempinfo['einfo']), logact)
844
+ if not change_workdir(locrec['workdir'], locinfo, tempinfo['edate'], tempinfo['ehour'], tempinfo['FQ']):
845
+ break
846
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['AF'][0]: PgOPT.PGOPT['acnt'] += 1
847
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['BL'][0]: PgOPT.PGOPT['lcnt'] += 1
848
+ opt = 1 if tempinfo['AQ'] else 65 # 1+64(remove small file)
849
+ linfo = PgFile.check_local_file(lfile, opt, PgOPT.PGOPT['emerol'])
850
+ cnt = -1
851
+ if rmtcnt > 0:
852
+ cnt = rmtcnt
853
+ rfile = rfiles[l]
854
+ else:
855
+ dr = 1 if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['PB'][0] else 0
856
+ if linfo and PgOPT.PGOPT['CACT'] == "BL" and not tempinfo['prcmd']: dr = 0 # skip download for BL only
857
+ if dr:
858
+ dfiles = None
859
+ for j in range(rcnt): # processs each remote record
860
+ pgrec = PgUtil.onerecord(rmtrecs, j)
861
+ if dfiles and pgrec['remotefile'] == rfile and not PgOPT.PGOPT['mcnt']:
862
+ continue # skip
863
+ rfile = pgrec['remotefile']
864
+ act = 0 if locrec['action'] == 'AQ' else PgOPT.PGOPT['ACTS']&PgOPT.OPTS['DR'][0]
865
+ dfiles = download_remote_files(pgrec, lfile, linfo, locrec, locinfo, tempinfo, act)
866
+ if PgOPT.PGOPT['rstat'] < 0:
867
+ i = ecnt
868
+ break
869
+ if dfiles: rfiles = PgUtil.joinarray(rfiles, dfiles)
870
+
871
+ rmtcnt = len(rfiles) if rfiles else 0
872
+ if rmtcnt > 0:
873
+ if lcnt > 1 and rmtcnt != lcnt:
874
+ PgLOG.pglog("{}: {} files found for {} local files".format(locrec['locinfo'], rmtcnt, lcnt), PgOPT.PGOPT['emlerr'])
875
+ i = ecnt
876
+ break
877
+ cnt = rmtcnt
878
+ rfile = rfiles[l] if lcnt > 1 else rfiles[rmtcnt-1] # record the break remote file name
879
+ else:
880
+ rfile = None
881
+ if linfo and PgOPT.PGOPT['rstat'] == 0: PgOPT.PGOPT['rstat'] = 1
882
+
883
+ if cnt != 0 and PgOPT.PGOPT['rstat'] > 0:
884
+ if PgOPT.PGOPT['ACTS']&(PgOPT.OPTS['BL'][0]|PgOPT.OPTS['AF'][0]):
885
+ if cnt < 0 and linfo:
886
+ if tempinfo['archived'] and PgOPT.PGOPT['CACT'] == "UF" and not tempinfo['gotnew']:
887
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['AF'][0] and 'RA' not in PgOPT.params:
888
+ PgLOG.pglog(lfile + ": local file archived already", PgOPT.PGOPT['emllog'])
889
+ cnt = 0
890
+ else:
891
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['BL'][0]:
892
+ PgLOG.pglog(lfile + ": local file exists already", PgOPT.PGOPT['emllog'])
893
+ cnt = 1
894
+ elif rmtcnt == lcnt and lfile == rfile:
895
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['BL'][0]:
896
+ PgLOG.pglog(lfile + ": local file same as remote file", PgOPT.PGOPT['emllog'])
897
+ elif not (PgOPT.PGOPT['ACTS']&PgOPT.OPTS['BL'][0]):
898
+ PgLOG.pglog(lfile + ": local file not built yet", PgOPT.PGOPT['emlerr'])
899
+ cnt = 0
900
+ else:
901
+ cnt = build_local_file(rfiles, lfile, linfo, locrec, tempinfo, lcnt, l)
902
+ if cnt and 'lfile' in tempinfo:
903
+ lfile = tempinfo['lfile']
904
+ del tempinfo['lfile']
905
+
906
+ if cnt != 0 and (PgOPT.PGOPT['ACTS']&PgOPT.OPTS['AF'][0]):
907
+ file_status_info(lfile, rfile, tempinfo)
908
+ cnt = archive_data_file(lfile, locrec, tempinfo, i)
909
+ if cnt > 0:
910
+ ucnt += 1
911
+ if tempinfo['RS'] == 1: rscnt += 1
912
+ if postcnt > -1: postcnt += 1
913
+ elif cnt > 0:
914
+ cnt = 0
915
+
916
+ if cnt > 0 and PgOPT.PGOPT['rstat'] > 0:
917
+ ccnt += 1
918
+ elif 'UT' in PgOPT.params or tempinfo['archived']:
919
+ ut = 1
920
+ if cnt > 0: acnt += 1
921
+
922
+ if PgLOG.PGLOG['DSCHECK']:
923
+ PgCMD.add_dscheck_dcount(lcnt%20, 0, PgOPT.PGOPT['extlog'])
924
+ if ccnt == lcnt and (PgOPT.PGOPT['ACTS']&PgOPT.OPTS['CF'][0]) and locrec['cleancmd']:
925
+ if tempinfo['CVD'] and PgUtil.diffdate(edate, tempinfo['CVD']) > 0:
926
+ clean_older_files(locrec['cleancmd'], locrec['workdir'], locinfo, tempinfo['CVD'], locrec['locfile'], rmtrecs, rcnt, tempinfo)
927
+ else:
928
+ if not rfiles and rcnt and locrec['cleancmd'].find(' -RF') > -1:
929
+ rfiles = get_all_remote_files(rmtrecs, rcnt, tempinfo, edate)
930
+ clean_files(locrec['cleancmd'], edate, ehour, locfiles, rfiles, tempinfo['FQ'])
931
+ if PgOPT.PGOPT['ACTS']&PgOPT.OPTS['AF'][0] or PgOPT.PGOPT['UCNTL'] and PgOPT.PGOPT['CACT'] == PgOPT.PGOPT['UCNTL']['action']:
932
+ rmonly = 1 if PgOPT.PGOPT['rstat'] > 0 else 0
933
+ if ccnt == lcnt:
934
+ PgUpdt.reset_update_time(locinfo, locrec, tempinfo, ccnt, endonly)
935
+ elif ut:
936
+ PgUpdt.reset_update_time(locinfo, locrec, tempinfo, acnt, endonly)
937
+ else:
938
+ if PgOPT.PGOPT['rstat'] == 0:
939
+ if tempinfo['VD'] and PgUtil.diffdatehour(edate, ehour, tempinfo['VD'], tempinfo['VH']) < 0:
940
+ PgUpdt.reset_update_time(locinfo, locrec, tempinfo, 0, endonly) # skip update
941
+ PgOPT.PGOPT['rstat'] = 1 # reset remote download status
942
+ elif 'IE' in PgOPT.params:
943
+ if tempinfo['VD'] and PgUtil.diffdatehour(edate, ehour, tempinfo['VD'], tempinfo['VH']) >= 0:
944
+ endonly = 1
945
+ PgUpdt.reset_update_time(locinfo, locrec, tempinfo, 0, endonly) # skip update
946
+ PgOPT.PGOPT['rstat'] = 1 # reset remote download status
947
+ if setmiss: setmiss = PgUpdt.set_miss_time(lfile, locrec, tempinfo, rmonly)
948
+
949
+ if postcnt > 0:
950
+ postcmd = PgUpdt.executable_command(PgUpdt.replace_pattern(tempinfo['postcmd'], edate, ehour, tempinfo['FQ']),
951
+ lfile, PgOPT.params['DS'], edate, ehour)
952
+ PgLOG.pgsystem(postcmd, PgOPT.PGOPT['emllog'], 5)
953
+ postcnt = 0
954
+ if rscnt >= PgOPT.PGOPT['RSMAX']:
955
+ refresh_metadata(locrec['dsid'])
956
+ rscnt = 0
957
+ if PgOPT.PGOPT['rstat'] < -1 or PgOPT.PGOPT['rstat'] < 0 and 'QE' in PgOPT.params: break # unrecoverable errors
958
+
959
+ if rscnt > 0: refresh_metadata(locrec['dsid'])
960
+ if ufile and uinfo and ucnt == 0:
961
+ PgLOG.pglog("{}: Last successful update - {}".format(uinfo, ufile), PgOPT.PGOPT['emlsum'])
962
+ PgLock.lock_update(lindex, locinfo, 0, PgOPT.PGOPT['errlog'])
963
+ PgOPT.PGOPT['lindex'] = 0
964
+
965
+ return retcnt
966
+
967
+ #
968
+ # refresh the gathered metadata with speed up option -R and -S
969
+ #
970
+ def refresh_metadata(dsid):
971
+
972
+ sx = "{} -d {} -r".format(PgOPT.PGOPT['scm'], dsid)
973
+ if PgOPT.PGOPT['wtidx']:
974
+ if 0 in PgOPT.PGOPT['wtidx']:
975
+ PgLOG.pgsystem(sx + 'w all', PgOPT.PGOPT['emllog'], 5)
976
+ else:
977
+ for tidx in PgOPT.PGOPT['wtidx']:
978
+ PgLOG.pgsystem("{}w {}".format(sx, tidx), PgOPT.PGOPT['emllog'], 5)
979
+ PgOPT.PGOPT['wtidx'] = {}
980
+
981
+ #
982
+ # retrieve remote files
983
+ # act: > 0 - create filenames and get data files physically; 0 - create filenames only
984
+ #
985
+ def download_remote_files(rmtrec, lfile, linfo, locrec, locinfo, tempinfo, act = 0):
986
+
987
+ emlsum = PgOPT.PGOPT['emlsum'] if PgOPT.PGOPT['CACT'] == "DR" else PgOPT.PGOPT['emllog']
988
+ rfile = rmtrec['remotefile']
989
+ rmtinfo = locinfo
990
+ dfiles = []
991
+ if not rfile:
992
+ rfile = lfile
993
+ rcnt = 1
994
+ if rfile != locrec['locfile']: rmtinfo += "-" + rfile
995
+ if act:
996
+ tempinfo['DC'] = (PgOPT.params['DC'][0] if 'DC' in PgOPT.params and PgOPT.params['DC'][0] else
997
+ (rmtrec['download'] if rmtrec['download'] else locrec['download']))
998
+
999
+ rfiles = PgUpdt.get_remote_names(rfile, rmtrec, rmtinfo, tempinfo)
1000
+ rcnt = len(rfiles) if rfiles else 0
1001
+ if rcnt == 0:
1002
+ PgOPT.PGOPT['rstat'] = -2
1003
+ return PgLOG.pglog(rmtinfo + ": NO remote file name identified", PgOPT.PGOPT['emlerr'])
1004
+
1005
+ PgOPT.PGOPT['rcnt'] += rcnt # accumulate remote file counts
1006
+ if tempinfo['DC']: tempinfo['DC'] = None
1007
+
1008
+ if act: # get file names on remote server and create download command
1009
+ sfile = rmtrec['serverfile']
1010
+ if sfile and sfile != rfile:
1011
+ sfiles = PgUpdt.get_remote_names(sfile, rmtrec, rmtinfo, tempinfo)
1012
+ scnt = len(sfiles) if sfiles else 0
1013
+ if scnt != rcnt:
1014
+ PgOPT.PGOPT['rstat'] = -2
1015
+ return PgLOG.pglog("{}/{}: {}/{} MISS match file counts".format(rmtinfo, sfile, rcnt, scnt), PgOPT.PGOPT['emlerr'])
1016
+ else:
1017
+ sfiles = rfiles
1018
+ scnt = rcnt
1019
+
1020
+ if tempinfo['AQ']:
1021
+ tstr = tempinfo['AQ']
1022
+ if tstr == 'Web':
1023
+ rpath = "{}/{}/".format(PgLOG.PGLOG['DSDHOME'], PgOPT.params['DS'])
1024
+ else:
1025
+ rpath = "{}/{}/{}/".format(PgLOG.PGLOG['DECSHOME'], PgOPT.params['DS'], tempinfo['ST'])
1026
+ else:
1027
+ tstr = 'Remote'
1028
+ rpath = ''
1029
+
1030
+ ks = 1 if 'KS' in PgOPT.params else 0
1031
+ PgOPT.PGOPT['mcnt'] = ocnt = ecnt = scnt = dcnt = ncnt = 0
1032
+ omsize = PgLOG.PGLOG['MINSIZE']
1033
+ if 'VS' in tempinfo and 'VS' not in PgOPT.params: PgLOG.PGLOG['MINSIZE'] = tempinfo['VS']
1034
+ for i in range(rcnt):
1035
+ rfile = rfiles[i]
1036
+ rname = rfile['fname']
1037
+ rcmd = rfile['rcmd']
1038
+ rinfo = PgFile.check_local_file(rpath + rname, 65, PgOPT.PGOPT['emerol']) # 65 = 1 + 64
1039
+ gotnew = 0
1040
+ if not act:
1041
+ if rinfo:
1042
+ dfiles.append(rname)
1043
+ dcnt += 1
1044
+ else:
1045
+ ecnt += 1
1046
+ if rfile['amiss']:
1047
+ PgLOG.pglog(rname + ": SKIP for NOT gotten {} file yet".format(tstr), PgOPT.PGOPT['emlerr'])
1048
+ PgOPT.PGOPT['mcnt'] += 1
1049
+ elif 'IE' in PgOPT.params:
1050
+ PgLOG.pglog(rname + ": NOT gotten {} file yet".format(tstr), PgOPT.PGOPT['emlerr'])
1051
+ PgOPT.PGOPT['rstat'] = -1
1052
+ else:
1053
+ PgLOG.pglog(rname + ": ERROR for NOT gotten {} file yet".format(tstr), PgOPT.PGOPT['emlerr'])
1054
+ PgOPT.PGOPT['rstat'] = -2
1055
+ break
1056
+ continue
1057
+ elif rinfo and 'RD' not in PgOPT.params:
1058
+ if not rcmd:
1059
+ dfiles.append(rname)
1060
+ dcnt += 1
1061
+ if tempinfo['archived']:
1062
+ if 'CN' not in PgOPT.params:
1063
+ ocnt += 1
1064
+ elif PgUtil.cmptime(rinfo['date_modified'], rinfo['time_modified'], tempinfo['ainfo']['adate'], tempinfo['ainfo']['atime']) < 1:
1065
+ ocnt += 1
1066
+ PgLOG.pglog("{}: ARCHIVED, NO newer remote file {} found".format(lfile, rname), PgOPT.PGOPT['emllog'])
1067
+ continue
1068
+ elif 'CN' in PgOPT.params:
1069
+ if rfile['ready'] == -1: # out of check new period already
1070
+ dfiles.append(rname)
1071
+ dcnt += 1
1072
+ if tempinfo['archived']: ocnt += 1
1073
+ continue
1074
+ elif PgUtil.cmptime(rinfo['date_modified'], rinfo['time_modified'], rfile['date'], rfile['time']) >= 0:
1075
+ dfiles.append(rname)
1076
+ dcnt += 1
1077
+ if tempinfo['archived']:
1078
+ ocnt += 1
1079
+ else:
1080
+ PgLOG.pglog(rname + ": IS local already", PgOPT.PGOPT['emllog'])
1081
+ continue
1082
+
1083
+ sfile = sfiles[i]
1084
+ sname = sfile['fname']
1085
+ sinfo = rinfo if sname == rname else PgFile.check_local_file(sname, 65, PgOPT.PGOPT['emerol'])
1086
+ dact = get_download_action(rcmd)
1087
+ rdcnt = 1 if re.search(r'(ncftpget|wget) ', dact) else 0
1088
+ dcmd = derr = ""
1089
+ info0 = cfile = pcmd = bname = None
1090
+ ftype = "remote" if sname == rname else "server"
1091
+ if sinfo:
1092
+ if rcmd:
1093
+ if 'RD' in PgOPT.params:
1094
+ PgLOG.pglog(sname + ": ftype file is local, Try dact again", PgOPT.PGOPT['emllog'])
1095
+ elif ('CN' not in PgOPT.params and
1096
+ PgUtil.cmptime(sinfo['date_modified'], sinfo['time_modified'], sfile['date'], sfile['time']) >= 0):
1097
+ rcmd = None # do not need download again
1098
+ else:
1099
+ PgLOG.pglog("{}: USE the local copy of {} file for NO download command".format(sname, ftype), PgOPT.PGOPT['emllog'])
1100
+ elif not rcmd:
1101
+ if tempinfo['archived']:
1102
+ ocnt += 1
1103
+ PgLOG.pglog("{}: ARCHIVED, NO need get {} file {} again for NO download command".format(lfile, ftype, sname), emlsum)
1104
+ else:
1105
+ ecnt += 1
1106
+ if rfile['amiss']:
1107
+ PgLOG.pglog(rname + ": SKIP missing remote file for NO download command", PgOPT.PGOPT['emlerr'])
1108
+ PgOPT.PGOPT['mcnt'] += 1
1109
+ elif 'IE' in PgOPT.params:
1110
+ PgLOG.pglog(rname + ": MISS remote file for NO download command", PgOPT.PGOPT['emlerr'])
1111
+ PgOPT.PGOPT['rstat'] = -1
1112
+ else:
1113
+ PgLOG.pglog(rname + ": ERROR missing remote file for NO download command", PgOPT.PGOPT['emlerr'])
1114
+ PgOPT.PGOPT['rstat'] = -2
1115
+ break
1116
+ continue
1117
+
1118
+ if rcmd: # try to download now
1119
+ if not sfile['ready']:
1120
+ PgOPT.PGOPT['rstat'] = 0
1121
+ PgLOG.pglog("{}: {} file NOT Ready yet".format(sname, ftype), PgOPT.PGOPT['emllog'])
1122
+ ecnt += 1
1123
+ break
1124
+ if 'CN' in PgOPT.params:
1125
+ if sinfo:
1126
+ cfile = sname
1127
+ elif rinfo:
1128
+ cfile = rname
1129
+ info0 = rinfo
1130
+ elif rcnt == 1 and linfo:
1131
+ cfile = lfile
1132
+ info0 = linfo
1133
+ elif tempinfo['archived']:
1134
+ cfile = ''
1135
+
1136
+ dcmd = PgUpdt.executable_command(rcmd, sname, PgOPT.params['DS'], sfile['date'], sfile['hour'])
1137
+ if tempinfo['AT']:
1138
+ stat = check_agetime(dcmd, sname, tempinfo['AT'])
1139
+ if stat <= 0:
1140
+ PgOPT.PGOPT['rstat'] = stat
1141
+ ecnt += 1
1142
+ break
1143
+ if cfile != None:
1144
+ stat = check_newer_file(dcmd, cfile, tempinfo['ainfo'])
1145
+ if stat > 0:
1146
+ if cfile != sname:
1147
+ if stat < 3: PgLOG.pglog("{}: Found newer {} file {}".format(cfile, ftype, sname), emlsum)
1148
+ else:
1149
+ if stat < 3: PgLOG.pglog("{}: Found newer {} file".format(cfile, ftype), emlsum)
1150
+ if stat == 2: # file redlownloaded, reget file info
1151
+ sinfo = PgFile.check_local_file(sname, 64, PgOPT.PGOPT['emerol'])
1152
+ else: # force download file
1153
+ cfile = None
1154
+ else:
1155
+ if stat < 0:
1156
+ if PgOPT.PGOPT['STATUS']:
1157
+ if cfile != sname:
1158
+ PgLOG.pglog("{}: Error check newer {} file {}\n{}".format(cfile, ftype, sname, PgOPT.PGOPT['STATUS']), PgOPT.PGOPT['emlerr'])
1159
+ else:
1160
+ PgLOG.pglog("{}: Error check newer {} file\n{}".format(cfile, ftype, PgOPT.PGOPT['STATUS']), PgOPT.PGOPT['emlerr'])
1161
+ else:
1162
+ if cfile != sname:
1163
+ PgLOG.pglog("{}: Cannot check newer {} file {} via {}".format(cfile, ftype, sname, dcmd), PgOPT.PGOPT['emlsum'])
1164
+ else:
1165
+ PgLOG.pglog("{}: Cannot check newer {} file via {}".format(cfile, ftype, dcmd), PgOPT.PGOPT['emlsum'])
1166
+
1167
+ if stat < -1: # uncrecoverable error
1168
+ PgOPT.PGOPT['rstat'] = stat
1169
+ ecnt += 1
1170
+ break
1171
+ elif cfile and cfile != sname:
1172
+ PgLOG.pglog("{}: NO newer {} file {} found\n{}".format(cfile, ftype, sname, PgOPT.PGOPT['STATUS']), emlsum)
1173
+ else:
1174
+ PgLOG.pglog("{}: NO newer {} file found\n{}".format(sname, ftype, PgOPT.PGOPT['STATUS']), emlsum)
1175
+
1176
+ if tempinfo['archived']:
1177
+ ncnt += 1
1178
+ if rcnt == 1: continue
1179
+ if not info0: info0 = sinfo
1180
+ sinfo = None
1181
+
1182
+ if not cfile:
1183
+ if op.isfile(sname) and PgLOG.pgsystem("mv -f {} {}.rd".format(sname, sname), PgOPT.PGOPT['emerol'], 4):
1184
+ bname = sname + ".rd"
1185
+ if not info0: info0 = PgFile.check_local_file(bname, 64, PgOPT.PGOPT['emerol'])
1186
+ if dcmd.find('wget ') > -1: PgUpdt.slow_web_access(dcmd)
1187
+ PgLOG.pgsystem(dcmd, PgOPT.PGOPT['wrnlog'], 257) # 1 + 256
1188
+ derr = PgLOG.PGLOG['SYSERR']
1189
+ sinfo = PgFile.check_local_file(sname, 70, PgOPT.PGOPT['emerol'])
1190
+ if sinfo:
1191
+ mode = 0o664 if sinfo['isfile'] else 0o775
1192
+ if mode != sinfo['mode']: PgFile.set_local_mode(sname, sinfo['isfile'], mode, sinfo['mode'], sinfo['logname'], PgOPT.PGOPT['emerol'])
1193
+
1194
+ (stat, derr) = PgUpdt.parse_download_error(derr, dact, sinfo)
1195
+ if stat < -1: # uncrecoverable error
1196
+ PgLOG.pglog("{}: error {}\n{}".format(sname, dcmd, derr), PgOPT.PGOPT['emlerr'])
1197
+ PgOPT.PGOPT['rstat'] = stat
1198
+ ecnt += 1
1199
+ break
1200
+ elif stat > 0 and PgLOG.PGLOG['DSCHECK'] and sinfo:
1201
+ PgCMD.add_dscheck_dcount(0, sinfo['data_size'], PgOPT.PGOPT['extlog'])
1202
+
1203
+ if sinfo:
1204
+ if info0:
1205
+ if info0['data_size'] == sinfo['data_size'] and bname:
1206
+ if PgFile.compare_md5sum(bname, sname, PgOPT.PGOPT['emlsum']):
1207
+ PgLOG.pglog("{}: GOT same size, but different content, {} file via {}".format(sname, ftype, dact), PgOPT.PGOPT['emlsum'])
1208
+ tempinfo['gotnew'] = gotnew = 1
1209
+ PgOPT.PGOPT['rdcnt'] += rdcnt
1210
+ scnt += 1
1211
+ else:
1212
+ PgLOG.pglog("{}: GOT same {} file via {}".format(sname, ftype, dact), emlsum)
1213
+ if rinfo and rname != sname and 'KS' not in PgOPT.params:
1214
+ PgLOG.pgsystem("rm -f " + sname, PgOPT.PGOPT['emllog'], 5)
1215
+ sinfo = None
1216
+ if tempinfo['archived']:
1217
+ ncnt += 1
1218
+ else:
1219
+ PgLOG.pglog("{}: GOT different {} file via {}".format(sname, ftype, dact), PgOPT.PGOPT['emlsum'])
1220
+ tempinfo['gotnew'] = gotnew = 1
1221
+ PgOPT.PGOPT['rdcnt'] += rdcnt
1222
+ scnt += 1
1223
+ if bname: PgLOG.pgsystem("rm -rf " + bname, PgOPT.PGOPT['emerol'], 4)
1224
+ elif rcmd:
1225
+ PgLOG.pglog("{}: GOT {} file via {}".format(sname, ftype, dact), emlsum)
1226
+ PgOPT.PGOPT['rdcnt'] += rdcnt
1227
+ scnt += 1
1228
+
1229
+ PgOPT.PGOPT['dcnt'] += 1
1230
+ if tempinfo['prcmd']: pcmd = tempinfo['prcmd']
1231
+ elif info0:
1232
+ if bname:
1233
+ PgLOG.pglog("{}: RETAIN the older {} file".format(sname, ftype), emlsum)
1234
+ PgLOG.pgsystem("mv -f {} {}".format(bname, sname), PgOPT.PGOPT['emerol'], 4)
1235
+ if tempinfo['prcmd']: pcmd = tempinfo['prcmd']
1236
+ sinfo = info0
1237
+ elif cfile:
1238
+ if tempinfo['archived']:
1239
+ ocnt += 1
1240
+ elif rcnt == 1:
1241
+ if tempinfo['prcmd']: pcmd = tempinfo['prcmd']
1242
+ if cfile == sname:
1243
+ sinfo = info0
1244
+ elif not rinfo and cfile == lfile:
1245
+ continue
1246
+ elif not cfile:
1247
+ ecnt += 1
1248
+ if sfile['amiss']:
1249
+ PgLOG.pglog("{}: SKIP {} file for FAIL {}\n{}".format(sname, ftype, dact, derr), PgOPT.PGOPT['emlsum'])
1250
+ PgOPT.PGOPT['mcnt'] += 1
1251
+ else:
1252
+ PgOPT.PGOPT['rstat'] = 0 if 'IE' in PgOPT.params else -1
1253
+ if not derr or derr and derr.find(PgLOG.PGLOG['MISSFILE']) > -1:
1254
+ msg = "{}: NOT Available for {}\n".format(sname, dact)
1255
+ PgLOG.set_email(msg, PgOPT.PGOPT['emlsum'])
1256
+ if derr: PgLOG.pglog(derr, PgOPT.PGOPT['emllog'])
1257
+ else:
1258
+ PgLOG.pglog("{}: ERROR {}\n{}".format(sname, dact, derr), PgOPT.PGOPT['emlerr'])
1259
+ if PgOPT.PGOPT['rstat'] < 0: break
1260
+ continue
1261
+ else:
1262
+ ecnt += 1
1263
+ if sfile['amiss']: PgOPT.PGOPT['mcnt'] += 1
1264
+ continue
1265
+
1266
+ if sinfo:
1267
+ if rname == sname:
1268
+ rinfo = sinfo
1269
+ elif not rinfo or gotnew:
1270
+ if rinfo: PgLOG.pgsystem("rm -f " + rname, PgOPT.PGOPT['emerol'], 5)
1271
+ if PgFile.convert_files(rname, sname, ks, PgOPT.PGOPT['emerol']):
1272
+ rinfo = PgFile.check_local_file(rname, 64, PgOPT.PGOPT['emerol'])
1273
+ else:
1274
+ PgOPT.PGOPT['rstat'] = -1
1275
+ ecnt += 1
1276
+ break
1277
+
1278
+ if not rinfo:
1279
+ ecnt += 1
1280
+ if sfile['amiss']:
1281
+ PgLOG.pglog(rname + ": SKIP missing remote file", PgOPT.PGOPT['emlsum'])
1282
+ PgOPT.PGOPT['mcnt'] += 1
1283
+ elif 'IE' in PgOPT.params:
1284
+ PgLOG.pglog(rname + ": MISS remote file", PgOPT.PGOPT['emlerr'])
1285
+ PgOPT.PGOPT['rstat'] = -1
1286
+ else:
1287
+ PgLOG.pglog(rname + ": ERROR missing remote file", PgOPT.PGOPT['emlerr'])
1288
+ PgOPT.PGOPT['rstat'] = -2
1289
+ break
1290
+ continue
1291
+
1292
+ if pcmd:
1293
+ pcmd = PgUpdt.executable_command(PgUpdt.replace_pattern(pcmd, rfile['date'], rfile['hour'], tempinfo['FQ']),
1294
+ rname, PgOPT.params['DS'], rfile['date'], rfile['hour'])
1295
+ if not PgLOG.pgsystem(pcmd, PgOPT.PGOPT['emllog'], 259):
1296
+ if PgLOG.PGLOG['SYSERR']: PgLOG.pglog(PgLOG.PGLOG['SYSERR'], PgOPT.PGOPT['emlerr'])
1297
+ PgOPT.PGOPT['rstat'] = -1
1298
+ ecnt += 1
1299
+ break
1300
+ dfiles.append(rname)
1301
+ dcnt += 1
1302
+
1303
+ PgLOG.PGLOG['MINSIZE'] = omsize
1304
+ if ncnt == rcnt:
1305
+ PgOPT.PGOPT['rstat'] = 0
1306
+ if dcnt > 0: dcnt = 0
1307
+ elif ecnt > 0:
1308
+ s = 's' if rcnt > 1 else ''
1309
+ if dcnt > scnt:
1310
+ PgLOG.pglog("{}/{} of {} rfile{} obtained/at local".format(scnt, dcnt, rcnt, s), PgOPT.PGOPT['emllog'])
1311
+ else:
1312
+ PgLOG.pglog("{} of {} rfile{} obtained".format(scnt, rcnt, s), PgOPT.PGOPT['emllog'])
1313
+ if dcnt > 0 and ocnt > 0: dcnt = 0
1314
+ elif ocnt == rcnt:
1315
+ PgOPT.PGOPT['rstat'] = 0
1316
+
1317
+ return dfiles if PgOPT.PGOPT['rstat'] == 1 and dcnt > 0 else None
1318
+
1319
+ #
1320
+ # build up local files
1321
+ #
1322
+ def build_local_file(rfiles, lfile, linfo, locrec, tempinfo, lcnt, l):
1323
+
1324
+ emlsum = PgOPT.PGOPT['emlsum'] if (PgOPT.PGOPT['ACTS'] == PgOPT.OPTS['BL'][0]) else PgOPT.PGOPT['emllog']
1325
+
1326
+ if lcnt > 1:
1327
+ rcnt = 1
1328
+ rmax = l + 1
1329
+ else:
1330
+ rmax = rcnt = len(rfiles) if rfiles else 0
1331
+
1332
+ rbfile = None
1333
+ if linfo:
1334
+ if rcnt == 1 and lfile == rfiles[l]: return 1
1335
+ if PgLOG.pgsystem("mv -f {} {}".format(lfile, rbfile), PgOPT.PGOPT['emerol'], 4):
1336
+ rbfile = lfile + '.rb'
1337
+ else:
1338
+ s = op.dirname(lfile)
1339
+ if s and not op.isdir(s): PgFile.make_local_directory(s, PgOPT.PGOPT['emllog']|PgLOG.EXITLG)
1340
+
1341
+ cext = None
1342
+ if locrec['options']:
1343
+ ms = re.search(r'-AF\s+([\w\.]+)', locrec['options'], re.I)
1344
+ if ms:
1345
+ fmt = ms.group(1)
1346
+ ms = re.search(r'(\w+)\.TAR(\.|$)', fmt, re.I)
1347
+ if ms: # check compression before tarring
1348
+ fmt = ms.group(1)
1349
+ ms = re.match(r'^({})$'.format(PgFile.CMPSTR), fmt, re.I)
1350
+ if ms: cext = '.' + fmt
1351
+
1352
+ if tempinfo['blcmd']:
1353
+ blcmd = PgUpdt.executable_command(PgUpdt.replace_pattern(tempinfo['blcmd'], tempinfo['edate'], tempinfo['ehour'], tempinfo['FQ']),
1354
+ lfile, PgOPT.params['DS'], tempinfo['edate'], tempinfo['ehour'])
1355
+ if not PgLOG.pgsystem(blcmd, PgOPT.PGOPT['emllog']) or PgFile.local_file_size(lfile, 2, PgOPT.PGOPT['emerol']) <= 0:
1356
+ ret = PgLOG.pglog("{}: error build {}".format(blcmd, lfile), PgOPT.PGOPT['emlerr'])
1357
+ else:
1358
+ PgOPT.PGOPT['bcnt'] += 1
1359
+ ret = 1
1360
+
1361
+ if rbfile:
1362
+ if ret:
1363
+ PgLOG.pgsystem("rm -rf " + rbfile, PgOPT.PGOPT['emerol'], 4)
1364
+ else:
1365
+ PgLOG.pglog(lfile + ": RETAIN the older local file", emlsum)
1366
+ PgLOG.pgsystem("mv -f {} {}".format(rbfile, lfile), PgOPT.PGOPT['emerol'], 4)
1367
+ return ret
1368
+
1369
+ if lfile[0] == '!': # executable for build up local file name
1370
+ blcmd = PgUpdt.executable_command(lfile[1:], None, PgOPT.params['DS'], tempinfo['edate'], tempinfo['ehour'])
1371
+ lfile = PgLOG.pgsystem(blcmd, PgOPT.PGOPT['emllog'], 21)
1372
+ if lfile and PgFile.local_file_size(lfile, 2, PgOPT.PGOPT['emerol']) > 0:
1373
+ tempinfo['lfile'] = lfile
1374
+ return 1
1375
+ else:
1376
+ return PgLOG.pglog("{}: error build {}".format(blcmd, lfile), PgOPT.PGOPT['emlerr'])
1377
+
1378
+ if rcnt == 0 and not linfo: return 0 # no remote file found to build local file
1379
+
1380
+ ret = 1
1381
+ kr = 1 if 'KR' in PgOPT.params else 0
1382
+ if rcnt == 1 and not op.isdir(rfiles[l]):
1383
+ rfile = rfiles[l]
1384
+ else:
1385
+ ms = re.match(r'^(.+)\.({})$'.format(PgFile.CMPSTR), lfile, re.I)
1386
+ rfile = ms.group(1) if ms else lfile
1387
+ fd = None
1388
+ if tempinfo['AQ']:
1389
+ if not PgOPT.validate_one_infile(rfile, PgOPT.params['DS']): return 0
1390
+ fd = open(rfile, 'w')
1391
+ fd.write(tempinfo['AQ'] + "File\n")
1392
+
1393
+ for i in range(rmax):
1394
+ tfile = rfiles[i]
1395
+ if fd:
1396
+ fd.write(tfile + "\n")
1397
+ continue
1398
+
1399
+ if op.isfile(tfile) and cext and not re.search(r'{}$'.format(cext), tfile, re.I):
1400
+ ms = re.match(r'^(.+)\.({})$'.format(PgFile.CMPSTR), tfile, re.I)
1401
+ if ms: tfile = ms.group(1)
1402
+ tfile += cext
1403
+ if not PgFile.convert_files(tfile, rfiles[i], kr, PgOPT.PGOPT['emllog']):
1404
+ if op.exists(rfile): PgLOG.pgsystem("rm -f " + rfile, PgOPT.PGOPT['emllog'])
1405
+ ret = PgLOG.pglog("{}: QUIT converting file from {}".format(rfile, tfile), PgOPT.PGOPT['emllog'])
1406
+ break
1407
+ cmd = "tar -{}vf {} {}".format('u' if i else 'c', rfile, tfile)
1408
+ ret = PgLOG.pgsystem(cmd, PgOPT.PGOPT['emllog'])
1409
+ if not ret: break
1410
+
1411
+ if fd:
1412
+ ret = -1
1413
+ fd.close()
1414
+
1415
+ if op.exists(rfile):
1416
+ s = "s" if rcnt > 1 else ""
1417
+ if tempinfo['AQ']:
1418
+ PgLOG.pglog("{}: input file CREATED for backing up {} {} file{}".format(rfile, rcnt, tempinfo['AQ'], s), emlsum)
1419
+ else:
1420
+ PgLOG.pglog("{}: tar file CREATED from {} file{}".format(rfile, rcnt, s), emlsum)
1421
+ else:
1422
+ ret = PgLOG.pglog(rfile + ": ERROR creating tar file", PgOPT.PGOPT['emlerr'])
1423
+
1424
+ if ret > 0:
1425
+ if lfile != rfile:
1426
+ ret = PgFile.convert_files(lfile, rfile, kr, PgOPT.PGOPT['emllog'])
1427
+ if ret: PgLOG.pglog("{}: BUILT from {}".format(lfile, rfile), emlsum)
1428
+ if ret:
1429
+ fsize = PgFile.local_file_size(lfile, 3, PgOPT.PGOPT['emerol'])
1430
+ if fsize > 0:
1431
+ PgOPT.PGOPT['bcnt'] += 1
1432
+ if PgLOG.PGLOG['DSCHECK']: PgCMD.add_dscheck_dcount(0, fsize, PgOPT.PGOPT['extlog'])
1433
+ else:
1434
+ ret = 0
1435
+
1436
+ if rbfile:
1437
+ if ret:
1438
+ PgLOG.pgsystem("rm -rf " + rbfile, PgOPT.PGOPT['emerol'], 4)
1439
+ else:
1440
+ PgLOG.pglog(lfile + ": RETAIN the older local file", emlsum)
1441
+ PgLOG.pgsystem("mv -f {} {}".format(rbfile, lfile), PgOPT.PGOPT['emerol'], 4)
1442
+
1443
+ return 1 if ret else 0
1444
+
1445
+
1446
+ #
1447
+ # append data type to options for given type name if not in options
1448
+ #
1449
+ def append_data_type(tname, options):
1450
+
1451
+ mp = r'(^|\s)-{}(\s|$)'.format(tname)
1452
+ if not re.search(mp, options, re.I): options += " -{} {}".format(tname, DEFTYPES[tname])
1453
+ return options
1454
+
1455
+ #
1456
+ # get data type from options for given type name, and default one if not in options
1457
+ #
1458
+ def get_data_type(tname, options):
1459
+
1460
+ mp = r'(^|\s)-{}\s+(\w)(\s|$)'.format(tname)
1461
+ ms = re.search(mp, options, re.I)
1462
+ return ms.group(2) if ms else DEFTYPES[tname]
1463
+
1464
+ #
1465
+ # archive a data file
1466
+ #
1467
+ def archive_data_file(lfile, locrec, tempinfo, eidx):
1468
+
1469
+ growing = -1
1470
+ if tempinfo['ainfo']:
1471
+ ainfo = tempinfo['ainfo']
1472
+ if ainfo['vindex']: growing = PgUpdt.is_growing_file(locrec['locfile'], tempinfo['FQ'])
1473
+ tempinfo['ainfo'] = None # clean the archive info recorded earlier
1474
+ else:
1475
+ ainfo = {'archived' : 0, 'note' : None} # reference to empty hash
1476
+
1477
+ PgLOG.pglog("{}: start {} for {}".format(lfile, locrec['action'], tempinfo['einfo']), PgOPT.PGOPT['emllog'])
1478
+
1479
+ options = locrec['options'] if locrec['options'] else ""
1480
+ act = locrec['action']
1481
+ archfile = None
1482
+ if locrec['archfile']: archfile = PgUpdt.replace_pattern(locrec['archfile'], tempinfo['edate'], tempinfo['ehour'], tempinfo['FQ'])
1483
+ if act == 'AW':
1484
+ if archfile and 'wfile' not in ainfo: ainfo['wfile'] = archfile
1485
+ options = append_data_type('WT', options)
1486
+ elif act == 'AS':
1487
+ if archfile and 'sfile' not in ainfo: ainfo['sfile'] = archfile
1488
+ options = append_data_type('ST', options)
1489
+ elif act == 'AQ':
1490
+ if archfile and 'bfile' not in ainfo: ainfo['bfile'] = archfile
1491
+ options = append_data_type('QT', options)
1492
+
1493
+ if tempinfo['archived'] and not ('RA' in PgOPT.params and growing > 0):
1494
+ if (ainfo['chksm'] and ainfo['chksm'] == PgOPT.PGOPT['chksm'] or
1495
+ ainfo['asize'] and ainfo['asize'] == PgOPT.PGOPT['fsize'] and
1496
+ PgUtil.cmptime(PgOPT.PGOPT['fdate'], PgOPT.PGOPT['ftime'], ainfo['adate'], ainfo['atime']) >= 0):
1497
+ if 'RA' not in PgOPT.params:
1498
+ amsg = "{}: ARCHIVED by {}".format(lfile, ainfo['adate'])
1499
+ if tempinfo['ehour'] != None: amsg += ":{:02}".format(ainfo['ahour'])
1500
+ PgLOG.pglog(amsg, PgOPT.PGOPT['emllog'])
1501
+ if eidx == 0: PgLOG.pglog("Add Mode option -RA if you want to re-archive", PgOPT.PGOPT['emllog'])
1502
+ return -1
1503
+ elif growing == 0:
1504
+ growing = -1
1505
+
1506
+ if growing == 0: tempinfo['archived'] = move_archived_file(ainfo, tempinfo['archived'])
1507
+
1508
+ if tempinfo['AQ']:
1509
+ ifopt = 'IF'
1510
+ else:
1511
+ ifopt = 'LF'
1512
+ acmd = "dsarch {} {} -{} {}".format(PgOPT.params['DS'], act, ifopt, lfile)
1513
+ if 'wfile' in ainfo: acmd += " -WF " + ainfo['wfile']
1514
+ if 'sfile' in ainfo: acmd += " -SF " + ainfo['sfile']
1515
+ if 'bfile' in ainfo: acmd += " -QF " + ainfo['bfile']
1516
+ if PgOPT.PGOPT['chksm']: acmd += " -MC " + PgOPT.PGOPT['chksm']
1517
+
1518
+ if growing > 0 and not re.search(r'(^|\s)-GF(\s|$)', options, re.I): acmd += " -GF"
1519
+ if 'MD' in PgOPT.params and not re.search(r'(^|\s)-MD(\s|$)', options, re.I): acmd += " -MD"
1520
+ if not re.search(r'(^|\s)-NE(\s|$)', options, re.I): acmd += " -NE" # no email in dsarch
1521
+ if tempinfo['gotnew'] and not re.search(r'(^|\s)-OE(\s|$)', options, re.I): acmd += " -OE"
1522
+ if 'VS' in PgOPT.params:
1523
+ acmd += " -VS {}".format(PgOPT.params['VS'])
1524
+ if 'VS' in tempinfo: options = re.sub('-VS\s+\d+(\s+|$)', '', options, flags=re.I)
1525
+ if tempinfo['RS'] == 1: acmd += " -RS"
1526
+
1527
+ fnote = None
1528
+ if locrec['note'] and not re.search(r'(^|\s)-DE(\s|$)', options, re.I):
1529
+ note = build_data_note(ainfo['note'], lfile, locrec, tempinfo)
1530
+ if note:
1531
+ if re.search(r'(\n|\"|\')', note): # if found \n or ' or ", create temporary input file
1532
+ fnote = PgOPT.params['DS'] + ".note"
1533
+ nd = open(fnote, 'w')
1534
+ nd.write("DE<:>\n{}<:>\n".format(note))
1535
+ nd.close()
1536
+ acmd += " -IF " + fnote
1537
+ else:
1538
+ acmd += " -DE '{}'".format(note)
1539
+
1540
+ if options:
1541
+ if locrec['cleancmd']: options = re.sub(r'(^-NW\s+|\s+-NW$)', '', options, 1, re.I)
1542
+ acmd += " " + PgUpdt.replace_pattern(options, tempinfo['edate'], tempinfo['ehour'], tempinfo['FQ'])
1543
+
1544
+ ret = PgLOG.pgsystem(acmd, PgOPT.PGOPT['emerol'], 69) # 1 + 4 + 64
1545
+ if fnote: PgLOG.pgsystem("rm -f " + fnote, PgOPT.PGOPT['emerol'], 4)
1546
+
1547
+ tempinfo['ainfo'] = file_archive_info(lfile, locrec, tempinfo)
1548
+ note = count_update_files(ainfo, tempinfo['ainfo'], ret, tempinfo['RS'])
1549
+ PgLOG.pglog("{}: UPDATED({}) for {}".format(lfile, locrec['action'], tempinfo['einfo']), PgOPT.PGOPT['emlsum'])
1550
+
1551
+ return ret
1552
+
1553
+ #
1554
+ # count files updated
1555
+ #
1556
+ def count_update_files(oinfo, ninfo, success, rsopt):
1557
+
1558
+ nrecs = ninfo['types'] if ninfo else {}
1559
+ orecs = oinfo['types'] if oinfo else {}
1560
+ astrs = []
1561
+ astr = ""
1562
+
1563
+ for type in nrecs:
1564
+ nrec = nrecs[type]
1565
+ orec = orecs[type] if type in orecs else None
1566
+
1567
+ if 'sfile' in nrec:
1568
+ atype = "Saved {} File".format(PgOPT.STYPE[type])
1569
+ elif 'bfile' in nrec:
1570
+ atype = "Quasar backup {} File".format(PgOPT.BTYPE[type])
1571
+ else:
1572
+ atype = "RDA {} File".format(PgOPT.WTYPE[type])
1573
+ if rsopt == 1:
1574
+ tidx = nrec['tindex'] if nrec['tindex'] else 0
1575
+ PgOPT.PGOPT['wtidx'][tidx] = 1
1576
+
1577
+ if (not orec or
1578
+ nrec['data_size'] != orec['data_size'] or
1579
+ PgUtil.cmptime(orec['date_modified'], orec['time_modified'], nrec['date_modified'], nrec['time_modified']) or
1580
+ not (nrec['checksum'] and orec['checksum'] and nrec['checksum'] == orec['checksum'])):
1581
+ if 'sfile' in nrec:
1582
+ PgOPT.PGOPT['uscnt'] += 1
1583
+ elif 'bfile' in nrec:
1584
+ if type == 'D': PgOPT.PGOPT['qdcnt'] += 1
1585
+ PgOPT.PGOPT['qbcnt'] += 1
1586
+ elif type == 'D':
1587
+ PgOPT.PGOPT['udcnt'] += 1
1588
+ elif type == 'N':
1589
+ PgOPT.PGOPT['uncnt'] += 1
1590
+ else:
1591
+ PgOPT.PGOPT['uwcnt'] += 1
1592
+
1593
+ astrs.append("{} {}rchived".format(atype, "Re-a" if orec else "A"))
1594
+ if PgLOG.PGLOG['DSCHECK']:
1595
+ PgCMD.add_dscheck_dcount(0, nrec['data_size'], PgOPT.PGOPT['extlog'])
1596
+
1597
+ if astrs:
1598
+ PgOPT.PGOPT['ucnt'] += 1
1599
+ if len(astrs) < ninfo['archcnt']:
1600
+ if success:
1601
+ astr = " Successful, but only "
1602
+ else:
1603
+ astr = " Partially finished, "
1604
+ astr += ', '.join(astrs)
1605
+ else:
1606
+ if success:
1607
+ astr = " Successful, but NO file Re-archived"
1608
+ else:
1609
+ astr = " Failed, NO file {}rchived".format('Re-a' if oinfo['present'] == ninfo['archcnt'] else "A")
1610
+
1611
+ if astr:
1612
+ s = "s" if ninfo['archcnt'] > 1 else ""
1613
+ astr += " of {} archfile{}".format(ninfo['archcnt'], s)
1614
+
1615
+ return astr
1616
+
1617
+ #
1618
+ # get the temporal info in local and remote file names and the possible values
1619
+ # between the break update and the current date
1620
+ # BTW, change to working directory
1621
+ #
1622
+ def get_tempinfo(locrec, locinfo, eidx = 0):
1623
+
1624
+ # get data end date for update action
1625
+ edate = PgOPT.params['ED'][eidx] if ('ED' in PgOPT.params and PgOPT.params['ED'][eidx]) else locrec['enddate']
1626
+ if not edate: return PgLOG.pglog(locinfo + ": MISS End Data Date for local update", PgOPT.PGOPT['emlerr'])
1627
+ ehour = PgOPT.params['EH'][eidx] if ('EH' in PgOPT.params and PgOPT.params['EH'][eidx] != None) else locrec['endhour']
1628
+ if not isinstance(edate, str): edate = str(edate)
1629
+
1630
+ if ehour is None and PgDBI.pgget('drupdt', '', "lindex = {} and tinterval like '%H'".format(locrec['lindex'])):
1631
+ return PgLOG.pglog(locinfo + ": MISS End Data Hour for hourly remote update", PgOPT.PGOPT['emlerr'])
1632
+
1633
+ if locrec['validint']:
1634
+ val = locrec['validint']
1635
+ elif PgOPT.PGOPT['UCNTL'] and PgOPT.PGOPT['UCNTL']['validint']:
1636
+ val = PgOPT.PGOPT['UCNTL']['validint']
1637
+ else:
1638
+ val = None
1639
+
1640
+ tempinfo = {'AT' : None, 'DC' : None, 'ED' : [], 'EH' : [], 'VI' : None,
1641
+ 'VD' : None, 'VH' : None, 'CVD' : None, 'NX' : None, 'FQ' : None,
1642
+ 'QU' : None, 'EP' : 0, 'RS' : -1, 'AQ' : None}
1643
+
1644
+ if val: val = PgUpdt.get_control_time(val, "Valid Internal")
1645
+ if val:
1646
+ tempinfo['VI'] = val
1647
+ if ehour is None and val[3]: ehour = 0
1648
+
1649
+ val = PgUpdt.get_control_time(locrec['agetime'], "File Age Time")
1650
+ if val:
1651
+ tempinfo['AT'] = val
1652
+ if ehour is None and val[3]: ehour = 0
1653
+
1654
+ frequency = PgOPT.params['FQ'][0] if 'FQ' in PgOPT.params else locrec['frequency']
1655
+ if frequency: # get data update frequency info
1656
+ (val, unit) = PgOPT.get_control_frequency(frequency)
1657
+ if val:
1658
+ tempinfo['FQ'] = val
1659
+ tempinfo['QU'] = unit # update frequency unit of meassure
1660
+ else:
1661
+ locinfo = PgUpdt.replace_pattern(locinfo, edate, ehour)
1662
+ return PgLOG.pglog("{}: {}".format(locinfo, unit), PgOPT.PGOPT['emlerr'])
1663
+ if locrec['endperiod']: tempinfo['EP'] = locrec['endperiod']
1664
+ if val[3] and ehour is None: ehour = 0
1665
+ edate = PgUtil.enddate(edate, tempinfo['EP'], unit, tempinfo['FQ'][6])
1666
+ elif 'MU' in PgOPT.params or 'CP' in PgOPT.params:
1667
+ locinfo = PgUpdt.replace_pattern(locinfo, edate, ehour)
1668
+ return PgLOG.pglog(locinfo + ": MISS frequency for Update", PgOPT.PGOPT['emlerr'])
1669
+
1670
+ val = PgUpdt.get_control_time(locrec['nextdue'], "Due Internval")
1671
+ if val:
1672
+ tempinfo['NX'] = val
1673
+ if ehour is None and val[3]: ehour = 0
1674
+
1675
+ # check if allow missing remote file
1676
+ if 'MR' in PgOPT.params and PgOPT.params['MR'][0]:
1677
+ tempinfo['amiss'] = PgOPT.params['MR'][0]
1678
+ elif locrec['missremote']:
1679
+ tempinfo['amiss'] = locrec['missremote']
1680
+ else:
1681
+ tempinfo['amiss'] = 'N'
1682
+
1683
+ options = locrec['options']
1684
+ if locrec['action'] == 'AQ':
1685
+ if options:
1686
+ ms = re.search(r'-(ST|WT)\s+(\w)', options)
1687
+ if ms:
1688
+ if ms.group(1) == 'ST':
1689
+ tempinfo['AQ'] = 'Saved'
1690
+ tempinfo['ST'] = ms.group(2)
1691
+ else:
1692
+ tempinfo['AQ'] = 'Web'
1693
+ else:
1694
+ return PgLOG.pglog("{}: MISS -ST or -WT to backup {}".format(options, locinfo), PgOPT.PGOPT['emlerr'])
1695
+ else:
1696
+ return PgLOG.pglog("Set -ST or -WT in Options to backup {}".format(locinfo), PgOPT.PGOPT['emlerr'])
1697
+ if (options and re.search(r'(^|\s)-GX(\s|$)', options, re.I) and
1698
+ not re.search(r'(^|\s)-RS(\s|$)', options, re.I)):
1699
+ tempinfo['RS'] = 0 # set to 1 if need pass -RS to dsarch
1700
+ ddate = edate
1701
+ dhour = ehour
1702
+ dcnt = 0
1703
+ PgOPT.PGOPT['wtidx'] = {}
1704
+
1705
+ if options:
1706
+ ms = re.search(r'-VS\s+(\d+)', options, re.I)
1707
+ if ms: tempinfo['VS'] = int(ms.group(1))
1708
+
1709
+ if tempinfo['VI']:
1710
+ if tempinfo['VI'][3]:
1711
+ (vdate, vhour) = PgUtil.adddatehour(PgOPT.PGOPT['CURDATE'], PgOPT.PGOPT['CURHOUR'], -tempinfo['VI'][0],
1712
+ -tempinfo['VI'][1], -tempinfo['VI'][2], -tempinfo['VI'][3])
1713
+ else:
1714
+ vdate = PgUtil.adddate(PgOPT.PGOPT['CURDATE'], -tempinfo['VI'][0], -tempinfo['VI'][1], -tempinfo['VI'][2])
1715
+ vhour = PgOPT.PGOPT['CURHOUR']
1716
+
1717
+ if 'CN' in PgOPT.params and locrec['cleancmd']:
1718
+ tempinfo['CVD'] = PgUtil.adddate(PgOPT.PGOPT['CURDATE'], -tempinfo['VI'][0], -tempinfo['VI'][1], -(1+tempinfo['VI'][2]))
1719
+ tempinfo['setmiss'] = 1
1720
+ if PgUtil.diffdatehour(edate, ehour, vdate, vhour) < 0:
1721
+ vdate = edate
1722
+ vhour = ehour
1723
+ if tempinfo['amiss'] == 'N' and locrec['missdate']:
1724
+ dhour = PgUtil.diffdatehour(vdate, vhour, locrec['missdate'], locrec['misshour'])
1725
+ if dhour > 0:
1726
+ if dhour > 240:
1727
+ record = {'missdate' : None, 'misshour' : None}
1728
+ PgDBI.pgupdt("dlupdt", record, "lindex = {}".format(locrec['lindex']))
1729
+ else:
1730
+ vdate = locrec['missdate']
1731
+ vhour = locrec['misshour']
1732
+
1733
+ if vdate and not isinstance(vdate, str): vdate = str(vdate)
1734
+ tempinfo['VD'] = vdate
1735
+ tempinfo['VH'] = vhour
1736
+ if 'ED' not in PgOPT.params and PgUtil.diffdatehour(edate, ehour, vdate, vhour) > 0:
1737
+ edate = vdate
1738
+ if tempinfo['FQ']:
1739
+ if tempinfo['EP'] or tempinfo['QU'] == 'M':
1740
+ edate = PgUtil.enddate(edate, tempinfo['EP'], tempinfo['QU'], tempinfo['FQ'][6])
1741
+ while True:
1742
+ (udate, uhour) = PgUpdt.addfrequency(edate, ehour, tempinfo['FQ'], -1)
1743
+ if PgUtil.diffdatehour(udate, uhour, vdate, vhour) < 0: break
1744
+ edate = udate
1745
+ ehour = uhour
1746
+ if tempinfo['EP'] or tempinfo['QU'] == 'M':
1747
+ edate = PgUtil.enddate(edate, tempinfo['EP'], tempinfo['QU'], tempinfo['FQ'][6])
1748
+
1749
+ vdate = PgOPT.params['CD']
1750
+ vhour = PgOPT.params['CH']
1751
+ if tempinfo['NX']:
1752
+ if tempinfo['NX'][3]:
1753
+ (udate, uhour) = PgUtil.adddatehour(PgOPT.PGOPT['CURDATE'], vhour, -tempinfo['NX'][0],
1754
+ -tempinfo['NX'][1], -tempinfo['NX'][2], -tempinfo['NX'][3])
1755
+ else:
1756
+ udate = PgUtil.adddate(PgOPT.PGOPT['CURDATE'], -tempinfo['NX'][0], -tempinfo['NX'][1], -tempinfo['NX'][2])
1757
+ uhour = vhour
1758
+ if PgUtil.diffdatehour(udate, uhour, vdate, vhour) <= 0:
1759
+ vdate = udate
1760
+ vhour = uhour
1761
+
1762
+ if 'CP' in PgOPT.params: (vdate, vhour) = PgUpdt.addfrequency(vdate, vhour, tempinfo['FQ'], 1)
1763
+
1764
+ fupdate = 1 if 'FU' in PgOPT.params else 0
1765
+ while fupdate or PgUtil.diffdatehour(edate, ehour, vdate, vhour) <= 0:
1766
+ tempinfo['ED'].append(edate)
1767
+ if ehour != None and tempinfo['QU'] != 'H':
1768
+ tempinfo['EH'].append(23)
1769
+ else:
1770
+ tempinfo['EH'].append(ehour)
1771
+ if 'MU' not in PgOPT.params: break
1772
+ if tempinfo['RS'] == 0 and dcnt < 3:
1773
+ if PgUtil.diffdatehour(edate, ehour, ddate, dhour) >= 0: dcnt += 1
1774
+ (edate, ehour) = PgUpdt.addfrequency(edate, ehour, tempinfo['FQ'], 1)
1775
+ edate = PgUtil.enddate(edate, tempinfo['EP'], tempinfo['QU'], tempinfo['FQ'][6])
1776
+ fupdate = 0
1777
+
1778
+ if tempinfo['RS'] == 0 and dcnt > 2: tempinfo['RS'] = 1
1779
+ if not tempinfo['ED']: # no end time found, update not due yet
1780
+ if tempinfo['NX']:
1781
+ (udate, uhour) = PgUtil.adddatehour(edate, ehour, tempinfo['NX'][0], tempinfo['NX'][1], tempinfo['NX'][2], tempinfo['NX'][3])
1782
+ else:
1783
+ udate = edate
1784
+ uhour = ehour
1785
+ locinfo = PgUpdt.replace_pattern(locinfo, edate, ehour, tempinfo['FQ'])
1786
+ vdate = PgOPT.params['CD']
1787
+ val = "Update data"
1788
+ if tempinfo['NX']: val += " due"
1789
+ if uhour is None:
1790
+ locinfo += ": {} on {}".format(val, udate)
1791
+ else:
1792
+ locinfo += ": {} at {}:{:02}".format(val, udate, uhour)
1793
+ vdate += ":{:02}".format(PgOPT.params['CH'])
1794
+
1795
+ return PgLOG.pglog("{} NOT due yet by {}".format(locinfo, vdate), PgOPT.PGOPT['emllog'])
1796
+
1797
+ return tempinfo
1798
+
1799
+ #
1800
+ # get archived file info
1801
+ #
1802
+ def file_archive_info(lfile, locrec, tempinfo):
1803
+
1804
+ if tempinfo['ainfo'] != None: return tempinfo['ainfo']
1805
+
1806
+ edate = tempinfo['edate']
1807
+ ehour = tempinfo['ehour']
1808
+ ainfo = {'archcnt' : 0, 'archived' : 0, 'present' : 0, 'vindex' : 0, 'types' : {}, 'note' : None}
1809
+ growing = PgUpdt.is_growing_file(locrec['locfile'], tempinfo['FQ'])
1810
+ if growing:
1811
+ if tempinfo['NX']:
1812
+ (udate, uhour) = PgUtil.adddatehour(edate, ehour, tempinfo['NX'][0], tempinfo['NX'][1], tempinfo['NX'][2], tempinfo['NX'][3])
1813
+ else:
1814
+ udate = edate
1815
+ uhour = ehour
1816
+ if PgLOG.PGLOG['GMTZ'] and uhour != None: # convert to local times
1817
+ (udate, uhour) = PgUtil.adddatehour(udate, uhour, 0, 0, 0, -PgLOG.PGLOG['GMTZ'])
1818
+
1819
+ options = locrec['options'] if locrec['options'] else ""
1820
+ act = locrec['action']
1821
+ locrec['gindex'] = PgUpdt.get_group_index(options, edate, ehour, tempinfo['FQ'])
1822
+ dsid = PgOPT.params['DS']
1823
+ gcnd = "gindex = {}".format(locrec['gindex'])
1824
+ cnd = "dsid = '{}' AND {}".format(dsid, gcnd)
1825
+ mmiss = 0
1826
+ if re.match(r'^A(B|W)$', act): # check existing web files
1827
+ ainfo['archcnt'] = 1
1828
+ ms = re.search(r'(^|\s)-WT\s+(\w)(\s|$)', options, re.I)
1829
+ type = get_data_type('WT', options)
1830
+ if locrec['archfile']:
1831
+ afile = PgUpdt.replace_pattern(locrec['archfile'], edate, ehour, tempinfo['FQ'])
1832
+ else:
1833
+ afile = lfile if re.search(r'(^|\s)-KP(\s|$)', lfile, re.I) else op.basename(lfile)
1834
+ ms =re.search(r'(^|\s)-WP\s+(\S+)', options, re.I)
1835
+ if ms:
1836
+ path = PgUpdt.replace_pattern(ms.group(2), edate, ehour, tempinfo['FQ'])
1837
+ else:
1838
+ path = PgDBI.get_group_field_path(locrec['gindex'], dsid, 'webpath')
1839
+ if path: afile = PgLOG.join_paths(path, afile)
1840
+
1841
+ wrec = PgSplit.pgget_wfile(dsid, "*", "{} AND type = '{}' AND wfile = '{}'".format(gcnd, type, afile), PgOPT.PGOPT['extlog'])
1842
+ if wrec:
1843
+ ainfo['wfile'] = wrec['wfile']
1844
+ adate = ainfo['adate'] = str(wrec['date_modified'])
1845
+ atime = ainfo['atime'] = str(wrec['time_modified'])
1846
+ ahour = None
1847
+ if atime:
1848
+ ms = re.match(r'^(\d+):', atime)
1849
+ if ms: ahour = int(ms.group(1))
1850
+ ainfo['ahour'] = ahour
1851
+ ainfo['asize'] = wrec['data_size']
1852
+ ainfo['chksm'] = wrec['checksum'] if wrec['checksum'] else ''
1853
+ ainfo['note'] = wrec['note']
1854
+ ainfo['types'][type] = wrec
1855
+ ainfo['wtype'] = type
1856
+ if not growing or PgUtil.diffdatehour(udate, uhour, adate, ahour) <= 0: ainfo['archived'] += 1
1857
+ if wrec['vindex']: ainfo['vindex'] = wrec['vindex']
1858
+ ainfo['present'] += 1
1859
+
1860
+ if act == 'AS': # check existing save files
1861
+ ainfo['archcnt'] = 1
1862
+ type = get_data_type('ST', options)
1863
+ if locrec['archfile']:
1864
+ afile = PgUpdt.replace_pattern(locrec['archfile'], edate, ehour, tempinfo['FQ'])
1865
+ else:
1866
+ afile = lfile if re.search(r'(^|\s)-KP(\s|$)', options, re.I) else op.basename(lfile)
1867
+ ms = re.search(r'(^|\s)-SP\s+(\S+)', options, re.I)
1868
+ if ms:
1869
+ path = PgUpdt.replace_pattern(ms.group(2), edate, ehour, tempinfo['FQ'])
1870
+ else:
1871
+ path = PgDBI.get_group_field_path(locrec['gindex'], PgOPT.params['DS'], 'savedpath')
1872
+ if path: afile = PgLOG.join_paths(path, afile)
1873
+
1874
+ srec = PgDBI.pgget("sfile", "*", "{} AND type = '{}' AND sfile = '{}'".format(cnd, type, afile), PgOPT.PGOPT['extlog'])
1875
+ if srec:
1876
+ ainfo['sfile'] = srec['sfile']
1877
+ adate = ainfo['adate'] = str(srec['date_modified'])
1878
+ atime = ainfo['atime'] = str(srec['time_modified'])
1879
+ ahour = None
1880
+ if atime:
1881
+ ms = re.match(r'^(\d+):', atime)
1882
+ if ms: ahour = int(ms.group(1))
1883
+ ainfo['asize'] = srec['data_size']
1884
+ ainfo['chksm'] = srec['checksum'] if srec['checksum'] else ''
1885
+ ainfo['note'] = srec['note']
1886
+ ainfo['types'][type] = srec
1887
+ ainfo['stype'] = type
1888
+ if not growing or PgUtil.diffdatehour(udate, uhour, adate, ahour) <= 0: ainfo['archived'] += 1
1889
+ if srec['vindex']: ainfo['vindex'] = srec['vindex']
1890
+ ainfo['present'] += 1
1891
+
1892
+ if act == 'AQ': # check existing quasar backup files
1893
+ ainfo['archcnt'] = 1
1894
+ type = get_data_type('QT', options)
1895
+ if locrec['archfile']:
1896
+ afile = PgUpdt.replace_pattern(locrec['archfile'], edate, ehour, tempinfo['FQ'])
1897
+ else:
1898
+ return PgLOG.pglog(lfile + ": Miss Backup file name via (FA|FileArchived)", PgOPT.PGOPT['emlerr'])
1899
+
1900
+ brec = PgDBI.pgget("bfile", "*", "dsid = '{}' AND type = '{}' AND bfile = '{}'".format(PgOPT.params['DS'], type, afile), PgOPT.PGOPT['extlog'])
1901
+ if brec:
1902
+ ainfo['bfile'] = brec['bfile']
1903
+ adate = ainfo['adate'] = str(brec['date_modified'])
1904
+ atime = ainfo['atime'] = str(brec['time_modified'])
1905
+ ahour = None
1906
+ if atime:
1907
+ ms = re.match(r'^(\d+):', atime)
1908
+ if ms: ahour = int(ms.group(1))
1909
+ ainfo['asize'] = brec['data_size']
1910
+ ainfo['chksm'] = brec['checksum'] if brec['checksum'] else ''
1911
+ ainfo['note'] = brec['note']
1912
+ ainfo['types'][type] = brec
1913
+ ainfo['btype'] = type
1914
+ if not growing or PgUtil.diffdatehour(udate, uhour, adate, ahour) <= 0: ainfo['archived'] += 1
1915
+ ainfo['present'] += 1
1916
+
1917
+ if ainfo['archcnt'] == 0:
1918
+ PgLOG.pglog("{}: unknown archive action {}".format(lfile, act), PgOPT.PGOPT['extlog'])
1919
+
1920
+ return ainfo # always returns a hash reference for archiving info
1921
+
1922
+ #
1923
+ # build up data note based on temporal info, keep the begin timestamp
1924
+ # for existing record; change end timestamp only if new data added
1925
+ # return None if no change for existing note
1926
+ #
1927
+ def build_data_note(onote, lfile, locrec, tempinfo):
1928
+
1929
+ note = locrec['note']
1930
+ if not note: return onote
1931
+
1932
+ seps = PgOPT.params['PD']
1933
+ match = "[^{}]+".format(seps[1])
1934
+ edate = tempinfo['edate']
1935
+ ehour = tempinfo['ehour']
1936
+
1937
+ if note[0] == '!': # executable for build up data note
1938
+ cmd = PgUpdt.executable_command(1, None, None, edate)
1939
+ if not cmd: return 0
1940
+ return PgLOG.pgsystem(cmd, PgOPT.PGOPT['emllog'], 21)
1941
+
1942
+ # repalce generic patterns first
1943
+ note = PgUpdt.replace_pattern(note, None) # replace generic patterns first
1944
+
1945
+ # get temporal patterns
1946
+ patterns = re.findall(r'{}({}){}'.format(seps[0], match, seps[1]), note)
1947
+ pcnt = len(patterns)
1948
+ if pcnt == 0: return note # no pattern temporal matches
1949
+ if pcnt > 2:
1950
+ PgLOG.pglog("{}-{}: TOO many ({}) temporal patterns".format(lfile, note, pcnt), PgOPT.PGOPT['emllog'])
1951
+ return onote
1952
+
1953
+ if pcnt == 2: # replace start time
1954
+ if onote: # get start time from existing note
1955
+ replace = "{}{}{}".format(seps[0], patterns[0], seps[1])
1956
+ ms = re.match(r'^(.*){}(.*){}'.format(replace, PgOPT.params['PD'][0]), note)
1957
+ if ms:
1958
+ init = ms.group(1)
1959
+ sp = ms.group(2)
1960
+ ms = re.search(r'{}(.+){}'.format(init, sp), onote)
1961
+ if ms:
1962
+ sdate = ms.group(1)
1963
+ note = re.sub(replace, sdate, note, 1)
1964
+ elif tempinfo['FQ']: # get start time
1965
+ (sdate, shour) = PgUpdt.addfrequency(edate, ehour, tempinfo['FQ'], 0)
1966
+ note = PgUpdt.replace_pattern(note, sdate, shour, None, 1)
1967
+
1968
+ return PgUpdt.replace_pattern(note, edate, ehour) # repalce end time now
1969
+
1970
+ #
1971
+ # get data file status info
1972
+ #
1973
+ def file_status_info(lfile, rfile, tempinfo):
1974
+
1975
+ # check and cache new data info
1976
+ finfo = PgFile.check_local_file(lfile, 33, PgOPT.PGOPT['wrnlog']) # 33 = 1 + 32
1977
+ if not finfo:
1978
+ PgOPT.PGOPT['chksm'] = ''
1979
+ PgOPT.PGOPT['fsize'] = 0
1980
+ return
1981
+
1982
+ fdate = finfo['date_modified']
1983
+ ftime = finfo['time_modified']
1984
+ fhour = None
1985
+ ms = re.match(r'^(\d+):', ftime)
1986
+ if ms: four = int(ms.group(1))
1987
+ PgOPT.PGOPT['fsize'] = finfo['data_size']
1988
+ PgOPT.PGOPT['chksm'] = finfo['checksum']
1989
+
1990
+ if rfile and lfile != rfile:
1991
+ finfo = PgFile.check_local_file(rfile, 1, PgOPT.PGOPT['wrnlog'])
1992
+ if finfo and PgUtil.cmptime(finfo['date_modified'], finfo['time_modified'], fdate, ftime) < 0:
1993
+ fdate = finfo['date_modified']
1994
+ ftime = finfo['time_modified']
1995
+ ms = re.match(r'^(\d+):', ftime)
1996
+ if ms: four = int(ms.group(1))
1997
+
1998
+ PgOPT.PGOPT['fdate'] = fdate
1999
+ PgOPT.PGOPT['ftime'] = ftime
2000
+ PgOPT.PGOPT['fhour'] = fhour
2001
+
2002
+ if 'RE' in PgOPT.params: # reset end data/time/hour
2003
+ if tempinfo['NX']:
2004
+ if tempinfo['NX'][3]:
2005
+ (fdate, fhour) = PgUtil.adddatehour(fdate, fhour, -tempinfo['NX'][0], -tempinfo['NX'][1],
2006
+ -tempinfo['NX'][2], -tempinfo['NX'][3])
2007
+ else:
2008
+ fdate = PgUtil.adddate(fdate, -tempinfo['NX'][0], -tempinfo['NX'][1], -tempinfo['NX'][2])
2009
+
2010
+ while True:
2011
+ (edate, ehour) = PgUpdt.addfrequency(tempinfo['edate'], tempinfo['ehour'], tempinfo['FQ'], 1)
2012
+ edate = PgUtil.enddate(edate, tempinfo['EP'], tempinfo['QU'], tempinfo['FQ'][6])
2013
+ if PgUtil.diffdatehour(edate, ehour, fdate, fhour) > 0: break
2014
+ tempinfo['edate'] = edate
2015
+ tempinfo['ehour'] = ehour
2016
+
2017
+ #
2018
+ # check if a Server file is aged enough for download
2019
+ # return 1 if valid, 0 if not aged enough, -1 if cannot check
2020
+ #
2021
+ def check_agetime(dcmd, sfile, atime):
2022
+
2023
+ info = PgUpdt.check_server_file(dcmd, 1)
2024
+ if not info:
2025
+ sact = get_download_action(dcmd)
2026
+ (stat, derr) = PgUpdt.parse_download_error(PgOPT.PGOPT['STATUS'], sact)
2027
+ PgOPT.PGOPT['STATUS'] = derr
2028
+ PgLOG.pglog("{}: cannot check file age\n{}".format(sfile, PgOPT.PGOPT['STATUS']), PgOPT.PGOPT['emlerr'])
2029
+ return stat
2030
+
2031
+ ahour = None
2032
+ if atime[3]:
2033
+ ms = re.match(r'^(\d+):', info['time_modified'])
2034
+ if ms: ahour = int(ms.group(1))
2035
+ (adate, ahour) = PgUtil.adddatehour(info['date_modified'], ahour, atime[0], atime[1], atime[2], atime[3])
2036
+ if PgUtil.diffdatehour(PgOPT.params['CD'], PgOPT.params['CH'], adate, ahour) >= 0:
2037
+ return 1
2038
+
2039
+ if ahour is None:
2040
+ PgLOG.pglog(("{}: original {} file ready by {}\n".format(sfile, info['ftype'], info['date_modified']) +
2041
+ "but NOT aged enough for retrieving yet by " + PgOPT.params['CD']), PgOPT.PGOPT['emllog'])
2042
+ else:
2043
+ PgLOG.pglog(("{}: original {} file ready by {}:{:02}\n".format(sfile, info['ftype'], info['date_modified'], ahour) +
2044
+ "but NOT aged enough for retrieving yet by {}:{:02}".format(PgOPT.params['CD'], PgOPT.params['CH'])), PgOPT.PGOPT['emllog'])
2045
+
2046
+ return 0 # otherwise server file is not aged enough
2047
+
2048
+ #
2049
+ # check if a Server file is changed with different size
2050
+ # return 1 - file changed, 2 - new file retrieved, 3 - force redlownload,
2051
+ # 0 - no change , -1 - error check, -2 - cannot check
2052
+ #
2053
+ def check_newer_file(dcmd, cfile, ainfo):
2054
+
2055
+ if cfile:
2056
+ finfo = PgFile.check_local_file(cfile, 33, PgOPT.PGOPT['wrnlog'])
2057
+ if not finfo: return 3 # download if can not check newer
2058
+ else:
2059
+ finfo = {'isfile' : 0, 'checksum' : ainfo['chksm'], 'data_size' : ainfo['asize'],
2060
+ 'date_modified' : ainfo['adate'], 'time_modified' : ainfo['atime']}
2061
+
2062
+ cinfo = PgUpdt.check_server_file(dcmd, 33, cfile)
2063
+ if not cinfo:
2064
+ sact = get_download_action(dcmd)
2065
+ (stat, derr) = PgUpdt.parse_download_error(PgOPT.PGOPT['STATUS'], sact)
2066
+ PgOPT.PGOPT['STATUS'] = derr
2067
+ return stat
2068
+
2069
+ stat = 2 if cinfo['ftype'] == "WGET" else 1
2070
+ if finfo['isfile'] and cfile == cinfo['fname'] and finfo['data_size'] and cinfo['data_size'] and cinfo['data_size'] != finfo['data_size']:
2071
+ return stat
2072
+
2073
+ PgOPT.PGOPT['STATUS'] = ''
2074
+ if (finfo['data_size'] != cinfo['data_size'] or 'checksum' not in cinfo or
2075
+ 'checksum' not in finfo or finfo['checksum'] != cinfo['checksum']):
2076
+ if 'HO' in PgOPT.params and cinfo['ftype'] == "FTP":
2077
+ (cdate, ctime) = PgUtil.addhour(cinfo['date_modified'], cinfo['time_modified'], -PgOPT.params['HO'][0])
2078
+ else:
2079
+ cdate = cinfo['date_modified']
2080
+ ctime = cinfo['time_modified']
2081
+
2082
+ if PgUtil.cmptime(cdate, ctime, finfo['date_modified'], finfo['time_modified']) > 0:
2083
+ msg = "{} Newer {} {}: {} {} {}".format(PgOPT.params['DS'], cinfo['ftype'], cinfo['fname'], cdate, ctime, cinfo['data_size'])
2084
+ if 'checksum' in cinfo: msg += " " + cinfo['checksum']
2085
+ msg += "; {}: ".format(cfile if cfile else "archived")
2086
+ msg += "{} {} {}".format(finfo['date_modified'], finfo['time_modified'], finfo['data_size'])
2087
+ if 'checksum' in finfo: msg += " " + finfo['checksum']
2088
+ PgLOG.pglog(msg, PgOPT.PGOPT['wrnlog'])
2089
+ return stat
2090
+
2091
+ if 'adate' in ainfo:
2092
+ PgOPT.PGOPT['STATUS'] = "archived: {} {}".format(ainfo['adate'], ainfo['atime'])
2093
+ elif cfile:
2094
+ PgOPT.PGOPT['STATUS'] += "local copy timestamp: {} {}".format(finfo['date_modified'], finfo['time_modified'])
2095
+
2096
+ if 'note' in cinfo:
2097
+ PgOPT.PGOPT['STATUS'] += "\n" + cinfo['note']
2098
+
2099
+ return 0
2100
+
2101
+ #
2102
+ # get download action name
2103
+ #
2104
+ def get_download_action(dcmd):
2105
+
2106
+ if not dcmd: return "download"
2107
+
2108
+ dact = "DOWNLOAD"
2109
+ ms = re.search(r'(^|\S\/)tar\s+-(\w+)\s', dcmd)
2110
+ if ms:
2111
+ taropt = ms.group(2)
2112
+ dact = "UNTAR" if taropt.find('x') > -1 else "TAR"
2113
+ else:
2114
+ ms = re.match(r'^\s*(\S+)', dcmd)
2115
+ if ms:
2116
+ dact = op.basename(ms.group(1))
2117
+ if dact == "wc":
2118
+ ms = re.search(r'\|\s*(\S+)', dcmd)
2119
+ if ms: dact = op.basename(ms.group(1))
2120
+
2121
+ return dact
2122
+
2123
+ #
2124
+ # change to working directory if not there yet
2125
+ #
2126
+ def change_workdir(wdir, locinfo, edate, ehour, FQ):
2127
+
2128
+ if 'WD' in PgOPT.params and PgOPT.params['WD'][0]: wdir = PgOPT.params['WD'][0]
2129
+ if not wdir:
2130
+ return PgLOG.pglog(locinfo + ": MISS working directory", PgOPT.PGOPT['emlerr'])
2131
+ else:
2132
+ wdir = PgLOG.replace_environments(wdir)
2133
+ wdir = PgUpdt.replace_pattern(wdir, edate, ehour, FQ)
2134
+ if not PgFile.change_local_directory(wdir, PgOPT.PGOPT['emllog']): return 0
2135
+
2136
+ return 1
2137
+
2138
+ #
2139
+ # clean the working copies of remote and local files/directories
2140
+ #
2141
+ def clean_files(cleancmd, edate, ehour, lfiles, rfiles, freq):
2142
+
2143
+ lfile = ' '.join(lfiles) if lfiles else ''
2144
+ cleancmd = PgUpdt.replace_pattern(cleancmd, edate, ehour, freq)
2145
+ cleancmd = PgUpdt.executable_command(cleancmd, lfile, None, None, None, rfiles)
2146
+ PgLOG.PGLOG['ERR2STD'] = [PgLOG.PGLOG['MISSFILE']]
2147
+ PgLOG.pgsystem(cleancmd, PgOPT.PGOPT['emllog'], 5)
2148
+ PgLOG.PGLOG['ERR2STD'] = []
2149
+
2150
+ #
2151
+ # clean files rematching pattern on given date/hour
2152
+ #
2153
+ def clean_older_files(cleancmd, workdir, locinfo, edate, locfile, rmtrecs, rcnt, tempinfo):
2154
+
2155
+ rfiles = None
2156
+ lfiles = PgUpdt.get_local_names(locfile, tempinfo, edate)
2157
+ change_workdir(workdir, locinfo, edate, tempinfo['ehour'], tempinfo['FQ'])
2158
+
2159
+ if rcnt and cleancmd.find(' -RF') > 0:
2160
+ rfiles = get_all_remote_files(rmtrecs, rcnt, tempinfo, edate)
2161
+ clean_files(cleancmd, edate, tempinfo['ehour'], lfiles, rfiles, tempinfo['FQ'])
2162
+
2163
+ #
2164
+ # get all remote file names for one update period
2165
+ #
2166
+ def get_all_remote_files(rmtrecs, rcnt, tempinfo, edate):
2167
+
2168
+ rfiles = []
2169
+ for i in range(rcnt): # processs each remote record
2170
+ rmtrec = PgUtil.onerecord(rmtrecs, i)
2171
+ file = rmtrec['remotefile']
2172
+ if not file: continue
2173
+ files = PgUpdt.get_remote_names(file, rmtrec, file, tempinfo, edate)
2174
+ if files: rfiles.extend(files)
2175
+
2176
+ return rfiles
2177
+
2178
+ #
2179
+ # check remote file status and sed email to specialist for irregular update cases
2180
+ #
2181
+ def check_dataset_status():
2182
+
2183
+ if 'CD' in PgOPT.params:
2184
+ PgOPT.params['CD'] = PgUtil.format_date(PgOPT.params['CD']) # standard format in case not yet
2185
+ else:
2186
+ PgOPT.params['CD'] = PgUtil.curdate() # default to current date
2187
+
2188
+ condition = "specialist = '{}'".format(PgOPT.params['LN'])
2189
+ if 'ED' not in PgOPT.params: condition += " AND enddate < '{}'".format(PgOPT.params['CD'])
2190
+ if 'DS' in PgOPT.params: condition += " AND dsid = '{}'".format(PgOPT.params['DS'])
2191
+ s = PgUpdt.file_condition('dlupdt', ('L' if 'LI' in PgOPT.params else "FIXA"), None, 1)
2192
+ if s: condition += " AND " + s
2193
+ condition += " ORDER BY dsid, execorder, lindex"
2194
+ locrecs = PgDBI.pgmget("dlupdt", "*", condition, PgOPT.PGOPT['extlog'])
2195
+ loccnt = len(locrecs['locfile']) if locrecs else 0
2196
+ if not loccnt: return PgLOG.pglog("No Update record found for checking update status on {} for '{}'".format(PgOPT.params['CD'], PgOPT.params['LN']), PgOPT.PGOPT['wrnlog'])
2197
+
2198
+ s = "s" if loccnt > 1 else ""
2199
+ PgLOG.pglog("Check {} record{} for update status...".format(loccnt, s), PgOPT.PGOPT['wrnlog'])
2200
+ for i in range(loccnt):
2201
+ locrec = PgUtil.onerecord(locrecs, i)
2202
+ if loccnt == 1 and 'LI' in PgOPT.params and 'LF' in PgOPT.params and len(PgOPT.params['LF']) == 1 and PgOPT.params['LF'][0] != locrec['locfile']:
2203
+ locrec['locfile'] = PgOPT.params['LF'][0]
2204
+ check_locfile_status(locrec)
2205
+
2206
+ if PgOPT.PGOPT['lcnt'] or PgLOG.PGLOG['ERRMSG']:
2207
+ if PgOPT.PGOPT['lcnt']:
2208
+ loccnt = PgOPT.PGOPT['lcnt']
2209
+ s = "s" if (loccnt > 1) else ""
2210
+ SUBJECT = "DSUPDT Status of {} update record{}".format(loccnt, s)
2211
+ if 'DS' in PgOPT.params: SUBJECT += " for {}".format(PgOPT.params['DS'])
2212
+ TOPMSG = " ready for update of {} local file{}".format(loccnt, s)
2213
+ s = "s" if (PgOPT.PGOPT['rcnt'] > 1) else ""
2214
+ TOPMSG = "{}/{} remote{}{}".format(PgOPT.PGOPT['ucnt'], PgOPT.PGOPT['rcnt'], s, TOPMSG)
2215
+ else:
2216
+ PgLOG.pglog("No local file ready for checking {} on {} for {}".format(SUBJECT, PgOPT.params['CD'], PgOPT.params['LN']), PgOPT.PGOPT['wrnlog'])
2217
+ SUBJECT = TOPMSG = None
2218
+
2219
+ if PgOPT.PGOPT['UCNTL']:
2220
+ PgUpdt.reset_control_time()
2221
+ if SUBJECT: SUBJECT += "-C{}".format(PgOPT.PGOPT['UCNTL']['cindex'])
2222
+
2223
+ #
2224
+ # check update status for a given local file
2225
+ #
2226
+ def check_locfile_status(locrec):
2227
+
2228
+ loccnd = "lindex = {}".format(locrec['lindex'])
2229
+ lfile = locrec['locfile']
2230
+ locinfo = "{}-L{}".format(locrec['dsid'], locrec['lindex'])
2231
+ if not lfile: return PgLOG.pglog(locinfo + ": local file name NOT specified", PgOPT.PGOPT['emlerr'])
2232
+ locinfo += "-" + lfile
2233
+ tempinfo = get_tempinfo(locrec, locinfo, 0)
2234
+ if not tempinfo: return 0 # simply return if miss temporal info for update
2235
+
2236
+ rmtcnd = loccnd
2237
+ rcnd = PgUpdt.file_condition('drupdt', ('D' if 'DO' in PgOPT.params else "RS"), None, 1)
2238
+ if rcnd: rmtcnd += " AND " + rcnd
2239
+ rmtrecs = PgDBI.pgmget("drupdt", "*", rmtcnd + " ORDER BY dindex, remotefile", PgOPT.PGOPT['extlog'])
2240
+ rcnt = len(rmtrecs['remotefile']) if rmtrecs else 0
2241
+ if rcnt == 0:
2242
+ if rcnd and PgDBI.pgget("drupdt", "", loccnd):
2243
+ return PgLOG.pglog("{}: NO remote file record matched for {}".format(locinfo, rcnd), PgOPT.PGOPT['emlerr'])
2244
+ rcnt = 1 # create a empty record remote file
2245
+ rmtrecs = {'lindex' : locrec['lindex'], 'remotefile' : None, 'serverfile' : None}
2246
+
2247
+ if rcnt == 1:
2248
+ if 'RF' in PgOPT.params and len(PgOPT.params['RF']) == 1 and not (rmtrecs['remotefile'][0] and PgOPT.params['RF'][0] == rmtrecs['remotefile'][0]):
2249
+ rmtrecs['remotefile'][0] = PgOPT.params['RF'][0]
2250
+ if 'SF' in PgOPT.params and len(PgOPT.params['SF']) == 1 and not (rmtrecs['serverfile'][0] and PgOPT.params['SF'][0] == rmtrecs['serverfile'][0]):
2251
+ rmtrecs['serverfile'][0] = PgOPT.params['SF'][0]
2252
+
2253
+ ecnt = len(tempinfo['ED'])
2254
+ PgOPT.PGOPT['lindex'] = locrec['lindex']
2255
+ logact = PgOPT.PGOPT['emllog']
2256
+
2257
+ retcnt = 0
2258
+ for i in range(ecnt):
2259
+ if ALLCNT > 1 and i > 0:
2260
+ tempinfo = get_tempinfo(locrec, locinfo, i)
2261
+ if not tempinfo: break
2262
+ edate = tempinfo['ED'][0]
2263
+ ehour = tempinfo['EH'][0]
2264
+ else:
2265
+ edate = tempinfo['ED'][i]
2266
+ ehour = tempinfo['EH'][i]
2267
+ tempinfo['edate'] = edate
2268
+ if ehour != None:
2269
+ tempinfo['einfo'] = "end data date:hour {}:{:02}".format(edate, ehour)
2270
+ tempinfo['ehour'] = ehour
2271
+ else:
2272
+ tempinfo['einfo'] = "end data date {}".format(edate)
2273
+ tempinfo['ehour'] = None
2274
+
2275
+ if 'GZ' in PgOPT.params: tempinfo['einfo'] += "(UTC)"
2276
+ lfile = PgUpdt.replace_pattern(locrec['locfile'], edate, ehour, tempinfo['FQ'])
2277
+ locinfo = "{}-L{}-{}".format(locrec['dsid'], locrec['lindex'], lfile)
2278
+ PgLOG.pglog("{}: Check Update Status for {}".format(locinfo, tempinfo['einfo']), logact)
2279
+ logact = PgOPT.PGOPT['emlsep']
2280
+ PgOPT.PGOPT['lcnt'] += 1
2281
+ j = 0
2282
+ while j < rcnt: # check each remote record, stop checking if error
2283
+ pgrec = PgUtil.onerecord(rmtrecs, j)
2284
+ if not check_remote_status(pgrec, lfile, locrec, locinfo, tempinfo) and 'CA' not in PgOPT.params:
2285
+ break
2286
+ j += 1
2287
+ if j == 0: break
2288
+
2289
+ PgOPT.PGOPT['lindex'] = 0
2290
+
2291
+ return (1 if retcnt > 0 else 0)
2292
+
2293
+ #
2294
+ # check update status for given remote file
2295
+ #
2296
+ def check_remote_status(rmtrec, lfile, locrec, locinfo, tempinfo):
2297
+
2298
+ rfile = rmtrec['remotefile']
2299
+ rmtinfo = locinfo
2300
+ if not rfile:
2301
+ rfile = lfile
2302
+ rcnt = 1
2303
+
2304
+ if rfile != locrec['locfile']: rmtinfo += "-" + rfile
2305
+ tempinfo['DC'] = (PgOPT.params['DC'][0] if ('DC' in PgOPT.params and PgOPT.params['DC'][0]) else
2306
+ (rmtrec['download'] if rmtrec['download'] else locrec['download']))
2307
+ rfiles = PgUpdt.get_remote_names(rfile, rmtrec, rmtinfo, tempinfo)
2308
+ rcnt = len(rfiles) if rfiles else 0
2309
+ if not rcnt: return PgLOG.pglog(rmtinfo + ": NO remote file name identified", PgOPT.PGOPT['emlerr'])
2310
+
2311
+ PgOPT.PGOPT['rcnt'] += rcnt # accumulate remote file counts
2312
+ if tempinfo['DC']:
2313
+ PgOPT.PGOPT['PCNT'] = PgUpdt.count_pattern_path(tempinfo['DC'])
2314
+ tempinfo['DC'] = None
2315
+
2316
+ sfile = rmtrec['serverfile']
2317
+ if sfile and sfile != rfile:
2318
+ sfiles = PgUpdt.get_remote_names(sfile, rmtrec, rmtinfo, tempinfo)
2319
+ scnt = len(sfiles) if sfiles else 0
2320
+ if scnt != rcnt:
2321
+ PgOPT.PGOPT['rstat'] = -2
2322
+ return PgLOG.pglog("{}/{}: {}/{} MISS match file counts".format(rmtinfo, sfile, rcnt, scnt), PgOPT.PGOPT['emlerr'])
2323
+ else:
2324
+ sfiles = rfiles
2325
+ scnt = rcnt
2326
+
2327
+ dcnt = 0
2328
+ for i in range(rcnt):
2329
+ rmtinfo = locinfo
2330
+ rfile = rfiles[i]
2331
+ if rfile['fname'] != lfile: rmtinfo += "-" + rfile['fname']
2332
+ sfile = sfiles[i]
2333
+ if sfile['fname'] != rfile['fname']: rmtinfo += "-" + sfile['fname']
2334
+ rcmd = rfile['rcmd']
2335
+ if not rcmd:
2336
+ return PgLOG.pglog(rmtinfo + ": Missing download command", PgOPT.PGOPT['emlerr'])
2337
+ elif not sfile['ready']:
2338
+ PgLOG.pglog(rmtinfo + ": NOT Ready yet for update", PgOPT.PGOPT['emllog'])
2339
+ break
2340
+ dcnt += 1
2341
+
2342
+ return 1 if dcnt else 0
2343
+
2344
+ #
2345
+ # process the update control records
2346
+ #
2347
+ def process_update_controls():
2348
+
2349
+ global ALLCNT
2350
+ ctime = PgUtil.curtime(1)
2351
+ if not ('CI' in PgOPT.params or 'DS' in PgOPT.params):
2352
+ PgOPT.set_default_value("SN", PgOPT.params['LN'])
2353
+
2354
+ condition = ("(pid = 0 OR lockhost = '{}') AND cntltime <= '{}'".format(PgLOG.PGLOG['HOSTNAME'], ctime) +
2355
+ PgOPT.PgOPT.get_hash_condition('dcupdt') + " ORDER BY hostname DESC, cntltime")
2356
+ pgrecs = PgDBI.pgmget("dcupdt", "*", condition, PgOPT.PGOPT['extlog'])
2357
+
2358
+ ALLCNT = len(pgrecs['cindex']) if pgrecs else 0
2359
+ if ALLCNT == 0:
2360
+ return PgLOG.pglog("No update control record idetified due for process", PgLOG.LOGWRN)
2361
+
2362
+ s = 's' if ALLCNT > 1 else ''
2363
+ PgLOG.pglog("Process {} update control record{} ...".format(ALLCNT, s), PgLOG.WARNLG)
2364
+
2365
+ pcnt = 0
2366
+ for i in range(ALLCNT):
2367
+ pcnt += process_one_control(PgUtil.onerecord(pgrecs, i))
2368
+ if pcnt > 1 and not ('CI' in PgOPT.params or 'DS' in PgOPT.params): break
2369
+ rmsg = "{} of {} update control{} reprocessed by {}".format(pcnt, ALLCNT, s, PgLOG.PGLOG['CURUID'])
2370
+ if PgLOG.PGLOG['CURUID'] != PgOPT.params['LN']: rmsg += " for " + PgOPT.params['LN']
2371
+ PgLOG.pglog(rmsg, PgOPT.PGOPT['wrnlog'])
2372
+
2373
+ #
2374
+ # process one update control
2375
+ #
2376
+ def process_one_control(pgrec):
2377
+
2378
+ cidx = pgrec['cindex']
2379
+ cstr = "Control Index {}".format(cidx)
2380
+ if not pgrec['action']: return PgLOG.pglog(cstr + ": Miss update action", PgOPT.PGOPT['errlog'])
2381
+ if not (PgOPT.OPTS[pgrec['action']][0]&PgOPT.PGOPT['CNTLACTS']):
2382
+ return PgLOG.pglog("{}: Invalid dsupdt action '{}'".format(cstr, pgrec['action']), PgOPT.PGOPT['errlog'])
2383
+ if not pgrec['frequency']: return PgLOG.pglog(cstr + ": Miss update Frequency", PgOPT.PGOPT['errlog'])
2384
+ if pgrec['pid'] > 0 and PgSIG.check_process(pgrec['pid']):
2385
+ if 'CI' in PgOPT.params: PgLOG.pglog("{}: Under processing {}/{}".format(cstr, pgrec['pid'], PgLOG.PGLOG['HOSTNAME']), PgOPT.PGOPT['wrnlog'])
2386
+ return 0
2387
+ if pgrec['specialist'] != PgOPT.params['LN']:
2388
+ return PgLOG.pglog("{}: must be specialist '{}' to process".format(cstr, pgrec['specialist']), PgOPT.PGOPT['errlog'])
2389
+ if not ('ED' in PgOPT.params or PgOPT.valid_data_time(pgrec, cstr, PgOPT.PGOPT['wrnlog'])):
2390
+ return 0
2391
+ cmd = "dsupdt "
2392
+ if pgrec['dsid']: cmd += pgrec['dsid'] + ' '
2393
+ cmd += "{} -CI {} ".format(pgrec['action'], cidx)
2394
+ if PgLOG.PGLOG['CURUID'] != PgOPT.params['LN']: cmd += "-LN " + PgOPT.params['LN']
2395
+ cmd += "-d -b"
2396
+
2397
+ # make sure it is not locked
2398
+ if PgLock.lock_update_control(cidx, 0, PgOPT.PGOPT['errlog']) <= 0: return 0
2399
+ PgLOG.pglog("{}-{}{}: {}".format(PgLOG.PGLOG['HOSTNAME'], pgrec['specialist'], PgLOG.current_datetime(), cmd), PgLOG.LOGWRN|PgLOG.FRCLOG)
2400
+ os.system(cmd + " &")
2401
+ return 1
2402
+
2403
+ #
2404
+ # move the previous archived version controlled files
2405
+ #
2406
+ def move_archived_file(ainfo, archived):
2407
+
2408
+ stat = 0
2409
+ if 'wfile' in ainfo:
2410
+ type = ainfo['wtype']
2411
+ pgrec = ainfo['types'][type]
2412
+ if pgrec and pgrec['vindex']:
2413
+ tofile = fromfile = ainfo['wfile']
2414
+ ftype = "Web"
2415
+ ttype = " Saved"
2416
+ i = 0
2417
+ while True: # create tofile name
2418
+ if i > 0: tofile = "{}.vbu{}".format(fromfile, i)
2419
+ if not PgDBI.pgget("sfile", "", "dsid = '{}' AND sfile = '{}'".format(PgOPT.params['DS'], tofile), PgOPT.PGOPT['extlog']):
2420
+ break
2421
+ i += 1
2422
+ stat = PgLOG.pgsystem("dsarch {} MV -WF {} -WT {} -SF {} -ST V -KM -TS".format(PgOPT.params['DS'], fromfile, type, tofile), PgOPT.PGOPT['emerol'], 5)
2423
+
2424
+ if stat == 0 and ainfo['sfile']:
2425
+ type = ainfo['stype']
2426
+ pgrec = ainfo['types'][type]
2427
+ if pgrec and pgrec['vindex']:
2428
+ fromfile = ainfo['sfile']
2429
+ ftype = "Saved"
2430
+ ttype = ''
2431
+ i = 0
2432
+ while True: # create tofile name
2433
+ tofile = "{}.vbu{}".format(fromfile, i)
2434
+ if not PgDBI.pgget("sfile", "", "dsid = '{}' AND sfile = '{}'".format(PgOPT.params['DS'], tofile), PgOPT.PGOPT['extlog']):
2435
+ break
2436
+ i += 1
2437
+ stat = PgLOG.pgsystem("dsarch {} MV -RF {} -OT {} -SF {} -ST V".format(PgOPT.params['DS'], fromfile, type, tofile), PgOPT.PGOPT['emerol'], 5)
2438
+
2439
+ if stat:
2440
+ PgOPT.PGOPT['vcnt'] += 1
2441
+ if 'NE' in PgOPT.params or 'EE' in PgOPT.params:
2442
+ if 'NE' in PgOPT.params: del PgOPT.params['NE']
2443
+ if 'EE' in PgOPT.params: del PgOPT.params['EE']
2444
+ PgOPT.params['SE'] = 1 # email summary at least
2445
+ PgOPT.PGOPT['emllog'] |= PgLOG.EMEROL
2446
+ PgLOG.pglog("{}-{}-{}: Found newer version-conrolled {} file; move to{} type V {}".format(PgOPT.params['DS'], type, fromfile, ftype, ttype, tofile), PgOPT.PGOPT['emlsum'])
2447
+ archived = 0
2448
+
2449
+ return archived
2450
+
2451
+ #
2452
+ # call main() to start program
2453
+ #
2454
+ if __name__ == "__main__": main()