casaconfig 0.0.57__tar.gz → 0.0.60__tar.gz
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.
- {casaconfig-0.0.57/casaconfig.egg-info → casaconfig-0.0.60}/PKG-INFO +1 -1
- casaconfig-0.0.60/casaconfig/__main__.py +103 -0
- casaconfig-0.0.60/casaconfig/private/casasiteconfig.py +13 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/config_defaults_static.py +9 -5
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/data_available.py +2 -2
- casaconfig-0.0.60/casaconfig/private/data_update.py +230 -0
- casaconfig-0.0.60/casaconfig/private/do_pull_data.py +125 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/get_data_lock.py +19 -4
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/measures_update.py +40 -44
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/pull_data.py +18 -96
- {casaconfig-0.0.57 → casaconfig-0.0.60/casaconfig.egg-info}/PKG-INFO +1 -1
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig.egg-info/SOURCES.txt +3 -0
- casaconfig-0.0.60/casaconfig.egg-info/requires.txt +1 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/setup.py +2 -3
- casaconfig-0.0.57/casaconfig/private/data_update.py +0 -69
- casaconfig-0.0.57/casaconfig.egg-info/requires.txt +0 -2
- {casaconfig-0.0.57 → casaconfig-0.0.60}/LICENSE +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/MANIFEST.in +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/README.md +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/__data__/README.txt +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/__init__.py +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/config.py +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/__init__.py +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/config_defaults.py +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/get_argparser.py +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/get_config.py +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/io_redirect.py +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/measures_available.py +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/print_log_messages.py +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig/private/set_casacore_path.py +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig.egg-info/dependency_links.txt +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/casaconfig.egg-info/top_level.txt +0 -0
- {casaconfig-0.0.57 → casaconfig-0.0.60}/setup.cfg +0 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
import sys
|
2
|
+
import os
|
3
|
+
from casaconfig.private.get_argparser import get_argparser
|
4
|
+
|
5
|
+
parser = get_argparser(add_help=True)
|
6
|
+
|
7
|
+
# get_argparser supplies configfile, noconfig, nositeconfig
|
8
|
+
# add measurespath, pull-data, data-update, measures-update, update-all, reference-testing, current-data
|
9
|
+
|
10
|
+
# measurespath will default to the value in config if not set here
|
11
|
+
parser.add_argument( "--measurespath", dest='measurespath', default=None,
|
12
|
+
help="location of casarundata")
|
13
|
+
|
14
|
+
parser.add_argument( "--pull-data", dest='pulldata', action='store_const', const=True, default=False,
|
15
|
+
help="invoke pull_data() to populate measurespath with latest casarundata")
|
16
|
+
parser.add_argument( "--data-update", dest='dataupdate', action='store_const', const=True, default=False,
|
17
|
+
help="invoke data_update() to update measurespath to the latest casarundata")
|
18
|
+
parser.add_argument( "--measures-update", dest='measuresupdate', action='store_const', const=True, default=False,
|
19
|
+
help="invoke measures_update() to update measurespath to the latest measures data")
|
20
|
+
parser.add_argument( "--update-all", dest='updateall', action='store_const', const=True, default=False,
|
21
|
+
help="invokes data_update then measures_update to update measurespath to the latest casarundata and measures data")
|
22
|
+
parser.add_argument( "--reference-testing", action='store_const', const=True, dest='referencetesting', default=False,
|
23
|
+
help="set measurespath to the casarundata when this version of casa was produced, used for testing purposes")
|
24
|
+
parser.add_argument( "--current-data", dest='currentdata', action='store_const', const=True, default=False,
|
25
|
+
help="print out a summary of the current casarundata and measures data installed in measurespath and then exit")
|
26
|
+
|
27
|
+
# initialize the configuration to be used
|
28
|
+
flags,args = parser.parse_known_args(sys.argv)
|
29
|
+
from casaconfig import config
|
30
|
+
|
31
|
+
# import the casaconfig module
|
32
|
+
import casaconfig
|
33
|
+
|
34
|
+
# make sure measurespath reflects any command line value
|
35
|
+
if flags.measurespath is None:
|
36
|
+
flags.measurespath = config.measurespath
|
37
|
+
|
38
|
+
# do any expanduser and abspath
|
39
|
+
measurespath = os.path.abspath(os.path.expanduser(flags.measurespath))
|
40
|
+
|
41
|
+
if flags.currentdata:
|
42
|
+
if not os.path.exists(measurespath) or not os.path.isdir(measurespath):
|
43
|
+
print("No data installed at %s. The measurespath does not exist or is not a directory." % flags.measurespath)
|
44
|
+
else:
|
45
|
+
# casarundata
|
46
|
+
datareadme = os.path.join(measurespath,'readme.txt')
|
47
|
+
if not os.path.exists(datareadme):
|
48
|
+
print("No casarundata installed in %s (missing readme.txt)." % flags.measurespath)
|
49
|
+
else:
|
50
|
+
try:
|
51
|
+
with open(datareadme, 'r') as fid:
|
52
|
+
readme = fid.readlines()
|
53
|
+
currentVersion = readme[1].split(':')[1].strip()
|
54
|
+
currentDate = readme[2].split(':')[1].strip()
|
55
|
+
print('casarundata version %s installed on %s' % (currentVersion, currentDate))
|
56
|
+
if (len(readme)<4):
|
57
|
+
print(' casarundata appears to be too short, missing list of installed files, casarundata should be repopulated in %s' % flags.measurespath)
|
58
|
+
except:
|
59
|
+
print('There was a problem reading the casarundata readme.txt, casarundata should be repopulated in %s' % flags.measurespath)
|
60
|
+
|
61
|
+
# measures
|
62
|
+
measuresreadme = os.path.join(measurespath,'geodetic/readme.txt')
|
63
|
+
if not os.path.exists(measuresreadme):
|
64
|
+
print("No measures data installed in %s/geodetic (missing readme.txt)." % flags.measurespath)
|
65
|
+
else:
|
66
|
+
try:
|
67
|
+
with open(measuresreadme, 'r') as fid:
|
68
|
+
readme = fid.readlines()
|
69
|
+
currentVersion = readme[1].split(':')[1].strip()
|
70
|
+
currentDate = readme[2].split(':')[1].strip()
|
71
|
+
print('measures version %s installed on %s' % (currentVersion, currentDate))
|
72
|
+
except:
|
73
|
+
print('There was a problem reading the measures readme.txt, measures should be repopulated in %s' % flags.measurespath)
|
74
|
+
|
75
|
+
# ignore any other arguments
|
76
|
+
|
77
|
+
else:
|
78
|
+
if flags.referencetesting:
|
79
|
+
print("--reference-testing is not yet implemented, measurespath=%s" % flags.measurespath)
|
80
|
+
# ignore any other arguments
|
81
|
+
|
82
|
+
else:
|
83
|
+
# do pull_update first when requested
|
84
|
+
if flags.pulldata:
|
85
|
+
print("pull_data using path=%s" % flags.measurespath)
|
86
|
+
casaconfig.pull_data(flags.measurespath)
|
87
|
+
# then data_update
|
88
|
+
# if this follows a pull_data then the casarundata will be up to date and this will do nothing
|
89
|
+
if flags.dataupdate:
|
90
|
+
print("data_update using path=%s" % flags.measurespath)
|
91
|
+
casaconfig.data_update(flags.measurespath)
|
92
|
+
# then measures_update
|
93
|
+
if flags.measuresupdate:
|
94
|
+
print("measures_update using path=%s" % flags.measurespath)
|
95
|
+
casaconfig.measures_update(flags.measurespath)
|
96
|
+
# then updateall
|
97
|
+
# if this follows other update options then this may do nothing
|
98
|
+
if flags.updateall:
|
99
|
+
print("data_update then measures_update using path=%s" % flags.measurespath)
|
100
|
+
casaconfig.data_update(flags.measurespath)
|
101
|
+
casaconfig.measures_update(flags.measurespath)
|
102
|
+
|
103
|
+
sys.exit(0)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# The default site config file. This may be placed at any location in the PYTHONPATH used by CASA
|
2
|
+
|
3
|
+
# This file should be edited to set measurespath as appropriate
|
4
|
+
|
5
|
+
# Set this to point to the location where the site maintained casarundata can be found
|
6
|
+
# by default datapath will include measurespath
|
7
|
+
|
8
|
+
measurespath = None
|
9
|
+
|
10
|
+
# turn off all auto updates of data
|
11
|
+
|
12
|
+
measures_auto_update = False
|
13
|
+
data_auto_update = False
|
@@ -2,16 +2,20 @@
|
|
2
2
|
datapath = [ ]
|
3
3
|
|
4
4
|
# location of geodetic and ephemera data
|
5
|
-
measurespath = "~/.casa/
|
5
|
+
measurespath = "~/.casa/data"
|
6
6
|
|
7
|
-
#
|
8
|
-
|
7
|
+
# automatically update measures data if not current (measurespath must be owned by the user)
|
8
|
+
# when data_auto_update is True then measures_auto_update MUST also be True
|
9
|
+
measures_auto_update = True
|
10
|
+
|
11
|
+
# automatically update casarundata and measures data if not current (measurespath must be owned by the user)
|
12
|
+
data_auto_update = True
|
9
13
|
|
10
14
|
# location of the optional user's startup.py
|
11
15
|
startupfile = '~/.casa/startup.py'
|
12
16
|
|
13
|
-
#
|
14
|
-
|
17
|
+
# location of the cachedir
|
18
|
+
cachedir = '~/.casa'
|
15
19
|
|
16
20
|
# log file path/name
|
17
21
|
logfile='casa-%s.log' % _time.strftime("%Y%m%d-%H%M%S", _time.gmtime())
|
@@ -21,11 +21,11 @@ def data_available():
|
|
21
21
|
List available casarundata versions on CASA server
|
22
22
|
|
23
23
|
This returns a list of the casarundata versions available on the CASA
|
24
|
-
|
24
|
+
server. The version parameter of data_update must be one
|
25
25
|
of the values in that list if set (otherwise the most recent version
|
26
26
|
in this list is used).
|
27
27
|
|
28
|
-
|
28
|
+
A casarundata version is the filename of the tarball and look
|
29
29
|
like "casarundata.x.y.z.tar.gz"
|
30
30
|
|
31
31
|
Parameters
|
@@ -0,0 +1,230 @@
|
|
1
|
+
# Copyright 2023 AUI, Inc. Washington DC, USA
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
"""
|
15
|
+
this module will be included in the api
|
16
|
+
"""
|
17
|
+
|
18
|
+
def data_update(path, auto_update_rules=False, version=None, force=False, logger=None):
|
19
|
+
"""
|
20
|
+
Check for updates to the installed casarundata and install the update or change to
|
21
|
+
the requested version when appropriate.
|
22
|
+
|
23
|
+
A text file (readme.txt at path) records the version string, the date
|
24
|
+
when that version was installed in path, and the files installed into path. That file
|
25
|
+
must already exist in path in order to use this function. Use pull_data to install
|
26
|
+
casarundata into a new location.
|
27
|
+
|
28
|
+
If the version is None (the default) then the most recent version returned by
|
29
|
+
data_available is used.
|
30
|
+
|
31
|
+
If the version requested matches the one in that text file then this function does
|
32
|
+
nothing unless force is True.
|
33
|
+
|
34
|
+
If a specific version is not requested (the default) and the date in that text file
|
35
|
+
is today, then this function does nothing unless force is True even if there is a more
|
36
|
+
recent version available from the CASA server.
|
37
|
+
|
38
|
+
When auto_update_rules is True then path must be owned by the user, force must be
|
39
|
+
False and the version must be None. This is used by casatools initialization when
|
40
|
+
data_auto_update is True.
|
41
|
+
|
42
|
+
If an update is to be installed the previously installed files, as listed in the
|
43
|
+
readme.txt file, will first be removed and then all of the contents of the version
|
44
|
+
being installed by the update are installed. This includes the set of measures tables
|
45
|
+
that are part of that casarundata version. A data update is typically followed by a
|
46
|
+
measures_update to ensure that the most recent measures data are installed.
|
47
|
+
|
48
|
+
A file lock is used to prevent more that one data update (pull_data, measures_update,
|
49
|
+
or data_update) from updating any files in path at the same time. When locked, the
|
50
|
+
lock file (data_update.lock in path) contains information about the process that
|
51
|
+
has the lock. When data_update gets the lock it checks the readme.txt file in path
|
52
|
+
to make sure that an update is still necessary (if force is True then an update
|
53
|
+
always happens). If the lock file is not empty then a previous update of path (pull_data,
|
54
|
+
data_update, or measures_update) did not exit as expected and the contents of path are
|
55
|
+
suspect. In that case, an error will be reported and nothing will be updated. The lock
|
56
|
+
file can be checked to see the details of when that file was locked. The lock file can be
|
57
|
+
removed and data_update can be tried again. It may be safest in that case to remove path
|
58
|
+
completely or use a different path and use pull_data to install a fresh copy of the
|
59
|
+
desired version.
|
60
|
+
|
61
|
+
Some of the tables installed by data_update are only read when casatools starts. Use of
|
62
|
+
data_update should typically be followed by a restart of CASA so that any changes are seen by
|
63
|
+
the tools and task that use this data.
|
64
|
+
|
65
|
+
**Note:** data_update requires that the expected readme.txt file already exists at the top-level
|
66
|
+
directory at path. If the file does not exist or can not be interpreted as expected then
|
67
|
+
data_update will return without updating any data.
|
68
|
+
|
69
|
+
**Note:** if auto_update_rules is True the user must own path (in addition to having read and
|
70
|
+
write permissions there). The version must then also be None and the force option must be False.
|
71
|
+
|
72
|
+
**Note:** the most recent casarundata may not include the most recent measures data. A data_update
|
73
|
+
is typically followed by a measures update.
|
74
|
+
|
75
|
+
Parameters
|
76
|
+
- path (str) - Folder path to update. Must contain a valid readme.txt,
|
77
|
+
- auto_update_rules (bool=False) - If True then the user must be the owner of path, version must be None, and force must be False.
|
78
|
+
- version (str=None) - Version of casarundata to retrieve (usually in the form of casarundata-x.y.z.tar.gz, see data_available()). Default None retrieves the latest.
|
79
|
+
- force (bool=False) - If True, always re-download the casarundata. Default False will not download casarundata if already updated today unless the version parameter is specified and different from what was last downloaded.
|
80
|
+
- logger (casatools.logsink=None) - Instance of the casalogger to use for writing messages. Default None writes messages to the terminal.
|
81
|
+
|
82
|
+
Returns
|
83
|
+
None
|
84
|
+
|
85
|
+
"""
|
86
|
+
|
87
|
+
import os
|
88
|
+
from datetime import datetime
|
89
|
+
|
90
|
+
from .data_available import data_available
|
91
|
+
from .print_log_messages import print_log_messages
|
92
|
+
from .get_data_lock import get_data_lock
|
93
|
+
from .do_pull_data import do_pull_data
|
94
|
+
|
95
|
+
path = os.path.expanduser(path)
|
96
|
+
readme_path = os.path.join(path, 'readme.txt')
|
97
|
+
|
98
|
+
if auto_update_rules:
|
99
|
+
if version is not None:
|
100
|
+
print_log_messages('auto_update_rules requires that version be None', logger, True)
|
101
|
+
return
|
102
|
+
if force:
|
103
|
+
print_log_messages('force must be False when auto_update_rules is True', logger, True)
|
104
|
+
return
|
105
|
+
if (not os.path.isdir(path)) or (os.stat(path).st_uid != os.getuid()):
|
106
|
+
print_log_messages('path must exist as a directory and it must be owned by the user when auto_update_rules is True', logger, True)
|
107
|
+
return
|
108
|
+
|
109
|
+
# readme must exist
|
110
|
+
if not os.path.exists(readme_path):
|
111
|
+
print_log_messages('No readme.txt file found at path. Nothing updated or checked.', logger, True);
|
112
|
+
return
|
113
|
+
|
114
|
+
# path must be writable with execute bit set
|
115
|
+
if (not os.access(path, os.W_OK | os.X_OK)) :
|
116
|
+
print('No permission to write to path, cannot update : %s' % path, file=sys.stdout)
|
117
|
+
if logger is not None: logger.post('No permission to write to path, cannot update : %s' % path, 'ERROR')
|
118
|
+
return
|
119
|
+
|
120
|
+
# try and digest the readme file
|
121
|
+
|
122
|
+
installed_files = []
|
123
|
+
currentVersion = []
|
124
|
+
currentDate = []
|
125
|
+
try:
|
126
|
+
with open(readme_path, 'r') as fid:
|
127
|
+
readme = fid.readlines()
|
128
|
+
currentVersion = readme[1].split(':')[1].strip()
|
129
|
+
currentDate = readme[2].split(':')[1].strip()
|
130
|
+
for readme_line in readme[3:]:
|
131
|
+
if (readme_line[0] != '#'):
|
132
|
+
installed_files.append(readme_line.strip())
|
133
|
+
except:
|
134
|
+
print_log_messages('The readme.txt file at path could not be read as expected', logger, True)
|
135
|
+
print_log_messages('choose a different path or empty this path and try again using pull_data', logger, True)
|
136
|
+
# no lock has been set yet, safe to simply return here
|
137
|
+
return
|
138
|
+
|
139
|
+
if (len(installed_files) == 0):
|
140
|
+
# this shouldn't happen
|
141
|
+
print_log_messages('The readme.txt file at path did not contain the expected list of installed files', logger, True)
|
142
|
+
print_log_messages('choose a different path or empty this path and try again using pull_data', logger, True)
|
143
|
+
# no lock has been set yet, safe to simply return here
|
144
|
+
return
|
145
|
+
|
146
|
+
today_string = datetime.today().strftime('%Y-%m-%d')
|
147
|
+
if version is None and force is False and currentDate == today_string:
|
148
|
+
# if version is None, currentDate is today and force is False then return without checking for any newer versions
|
149
|
+
print_log_messages('data_update current casarundata detected in %s, using version %s' % (path, currentVersion), logger)
|
150
|
+
# no lock has been set yet, safe to simply return here
|
151
|
+
return
|
152
|
+
|
153
|
+
available_data = data_available()
|
154
|
+
requestedVersion = version
|
155
|
+
if requestedVersion is None:
|
156
|
+
requestedVersion = available_data[-1]
|
157
|
+
|
158
|
+
if requestedVersion not in available_data:
|
159
|
+
print_log_messages('Requested casarundata version %s was not found. See available_data for a list of available casarundata versions.' % requestedVersion)
|
160
|
+
# no lock has been set yet, safe to simply return here
|
161
|
+
return
|
162
|
+
|
163
|
+
# don't update if force is false and the requested version is already installed
|
164
|
+
if force is False and (currentVersion == requestedVersion):
|
165
|
+
print_log_messages('Requested casarundata is installed in %s, using version %s' % (path, currentVersion), logger)
|
166
|
+
# no lock has been set yet, safe to simply return here
|
167
|
+
return
|
168
|
+
|
169
|
+
# an update appears necessary
|
170
|
+
|
171
|
+
lock_fd = None
|
172
|
+
try:
|
173
|
+
print_log_messages('data_update using version %s, acquiring the lock ... ' % requestedVersion, logger)
|
174
|
+
|
175
|
+
lock_fd = get_data_lock(path, 'data_update')
|
176
|
+
# if lock_fd is None it means the lock file was not empty - because we know that path exists at this point
|
177
|
+
if lock_fd is None:
|
178
|
+
print_log_messages('The lock file at %s is not empty.' % path, logger, True)
|
179
|
+
print_log_messages('A previous attempt to update path may have failed or exited prematurely.', logger, True)
|
180
|
+
print_log_messages('Remove the lock file and set force to True with the desired version (default to most recent).', logger, True)
|
181
|
+
print_log_messages('It may be best to completely repopulate path using pull_data and measures_update.', logger, True)
|
182
|
+
return
|
183
|
+
|
184
|
+
do_update = True
|
185
|
+
# it's possible that another process had path locked and updated the readme with new information, re-read it
|
186
|
+
try :
|
187
|
+
readme = None
|
188
|
+
with open(readme_path, 'r') as fid:
|
189
|
+
readme = fid.readlines()
|
190
|
+
currentVersion = readme[1].split(':')[-1].strip()
|
191
|
+
currentDate = readme[2].split(':')[-1].strip()
|
192
|
+
if ((currentVersion == requestedVersion) and (not force)):
|
193
|
+
# nothing to do here, already at the expected version and an update is not being forced
|
194
|
+
do_update = False
|
195
|
+
print_log_messages('data_update requested version is already installed.', logger)
|
196
|
+
else:
|
197
|
+
installed_files = []
|
198
|
+
for readme_line in readme[3:]:
|
199
|
+
installed_files.append(readme_line.strip())
|
200
|
+
if len(installed_files) == 0:
|
201
|
+
# this shouldn't happen, do not do an update
|
202
|
+
do_update = False
|
203
|
+
print_log_messages('The readme.txt file read at path did not contain the expected list of installed files', logger, True)
|
204
|
+
print_log_messages('This should not happen unless multiple sessions are trying to update data at the same time and one experienced problems or was done out of sequence', logger, True)
|
205
|
+
print_log_messages('Check for other updates in process or choose a different path or clear out this path and try again using pull', logger, True)
|
206
|
+
except:
|
207
|
+
# this shouldn't happen, do not do an update
|
208
|
+
do_update = False
|
209
|
+
print_log_messages('Unexpected error reading readme.txt file during data_update, can not safely update to the requested version', logger, True)
|
210
|
+
print_log_messages('This should not happen unless multiple sessions are trying to update at the same time and one experienced problems or was done out of sequence', logger, True)
|
211
|
+
|
212
|
+
|
213
|
+
if do_update:
|
214
|
+
do_pull_data(path, requestedVersion, installed_files, logger)
|
215
|
+
|
216
|
+
# truncate the lock file
|
217
|
+
lock_fd.truncate(0)
|
218
|
+
|
219
|
+
except Exception as exc:
|
220
|
+
print_log_messages('ERROR! : Unexpected exception while populating casarundata version %s to %s' % (requestedVersion, path), logger, True)
|
221
|
+
print_log_messages('ERROR! : %s' % exc, logger, True)
|
222
|
+
# leave the contents of the lock file as is to aid in debugging
|
223
|
+
import traceback
|
224
|
+
traceback.print_exc()
|
225
|
+
|
226
|
+
# if the lock file is not closed, do that now to release the lock
|
227
|
+
if lock_fd is not None and not lock_fd.closed:
|
228
|
+
lock_fd.close()
|
229
|
+
|
230
|
+
return
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# Copyright 2020 AUI, Inc. Washington DC, USA
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
def do_pull_data(path, version, installed_files, logger):
|
16
|
+
"""
|
17
|
+
Pull the casarundata for the given version and install it in path, removing
|
18
|
+
the isntalled files and updating the readme.txt file when done.
|
19
|
+
|
20
|
+
This function is used by both pull_data and data_update when each has
|
21
|
+
determind that the desired version should be installed. The calling function
|
22
|
+
has already obtained the lock. No additional checking happens here. The
|
23
|
+
calling function has already examined any existing readme file and used that
|
24
|
+
to set the installed_files list as appropriate.
|
25
|
+
|
26
|
+
Parameters
|
27
|
+
- path (str) - Folder path to place casadata contents.
|
28
|
+
- version (str) - casadata version to retrieve.
|
29
|
+
- installed_files (str list) - list of installed files from the version already installed. Set to an empty list if there is no previously installed version.
|
30
|
+
- logger (casatools.logsink) - Instance of the casalogger to use for writing messages. Messages are always written to the terminal. Set to None to skip writing messages to a logger.
|
31
|
+
|
32
|
+
Returns
|
33
|
+
None
|
34
|
+
|
35
|
+
"""
|
36
|
+
|
37
|
+
import os
|
38
|
+
import sys
|
39
|
+
from datetime import datetime
|
40
|
+
import ssl
|
41
|
+
import urllib.request
|
42
|
+
import certifi
|
43
|
+
import tarfile
|
44
|
+
import shutil
|
45
|
+
|
46
|
+
from .print_log_messages import print_log_messages
|
47
|
+
|
48
|
+
readme_path = os.path.join(path, 'readme.txt')
|
49
|
+
|
50
|
+
if (len(installed_files) > 0):
|
51
|
+
# remove the previously installed files
|
52
|
+
# remove this readme file so it's not confusing if something goes wrong after this
|
53
|
+
os.remove(readme_path)
|
54
|
+
print_log_messages('Removing files using manifest from previous install of %s on %s' % (currentVersion, currentDate), logger)
|
55
|
+
for relpath in installed_files:
|
56
|
+
filepath = os.path.join(path,relpath)
|
57
|
+
# don't say anything if filepath isn't found, remove it if it is found
|
58
|
+
if os.path.exists(filepath) and os.path.isfile(filepath):
|
59
|
+
os.remove(filepath)
|
60
|
+
|
61
|
+
# remove any empty directories in path - this is recursive
|
62
|
+
def remove_empty_dirs(dirpath):
|
63
|
+
# look at all of the files in dirpath, for dirs, go down that recursively
|
64
|
+
# if there's nothing there after the dirs have all been handled, remove it
|
65
|
+
files = os.listdir(dirpath)
|
66
|
+
not_dirs = []
|
67
|
+
for f in os.listdir(dirpath):
|
68
|
+
fpath = os.path.join(dirpath, f)
|
69
|
+
if os.path.isdir(fpath):
|
70
|
+
remove_empty_dirs(fpath)
|
71
|
+
else:
|
72
|
+
not_dirs.append(f)
|
73
|
+
if len(not_dirs) == 0:
|
74
|
+
if len(os.listdir(dirpath)) == 0:
|
75
|
+
os.rmdir(dirpath)
|
76
|
+
|
77
|
+
remove_empty_dirs(path)
|
78
|
+
|
79
|
+
# okay, safe to install the requested version
|
80
|
+
|
81
|
+
dataURL = os.path.join('https://casa.nrao.edu/download/casaconfig/data',version)
|
82
|
+
context = ssl.create_default_context(cafile=certifi.where())
|
83
|
+
with urllib.request.urlopen(dataURL, context=context, timeout=400) as tstream, tarfile.open(fileobj=tstream, mode='r:gz') as tar :
|
84
|
+
l = int(tstream.headers.get('content-length', 0))
|
85
|
+
sizeString = "unknown size"
|
86
|
+
if (l>0): sizeString = ("%.0fM" % (l/(1024*1024)))
|
87
|
+
# use print directly to make use of the end argument
|
88
|
+
print('downloading casarundata contents to %s (%s) ... ' % (path,sizeString), file = sys.stdout, end="" )
|
89
|
+
sys.stdout.flush()
|
90
|
+
# also log it
|
91
|
+
if logger is not None: logger.post('downloading casarundata contents to %s ...' % path, 'INFO')
|
92
|
+
tar.extractall(path=path)
|
93
|
+
print("done", file=sys.stdout)
|
94
|
+
# the tarball has been extracted to path/version
|
95
|
+
# get the instaled files of files to be written to the readme file
|
96
|
+
versdir = os.path.join(path,version[:version.index('.tar')])
|
97
|
+
installed_files = []
|
98
|
+
wgen = os.walk(versdir)
|
99
|
+
for (dirpath, dirnames, filenames) in wgen:
|
100
|
+
for f in filenames:
|
101
|
+
installed_files.append(os.path.relpath(os.path.join(dirpath,f),versdir))
|
102
|
+
|
103
|
+
# move everything in version up a level to path
|
104
|
+
for f in os.listdir(versdir):
|
105
|
+
srcPath = os.path.join(versdir,f)
|
106
|
+
if os.path.isdir(srcPath):
|
107
|
+
# directories are first copied, then removed
|
108
|
+
# existing directories are reused, existing files are overwritten
|
109
|
+
# things in path that do not exist in srcPath are not changed
|
110
|
+
shutil.copytree(srcPath,os.path.join(path,f),dirs_exist_ok=True)
|
111
|
+
shutil.rmtree(srcPath)
|
112
|
+
else:
|
113
|
+
# assume it's a simple file, these can be moved directly, overwriting anything already there
|
114
|
+
os.rename(srcPath,os.path.join(path,f))
|
115
|
+
|
116
|
+
# safe to remove versdir, it would be a surprise if it's not empty
|
117
|
+
os.rmdir(versdir)
|
118
|
+
# update the readme.txt file
|
119
|
+
with open(readme_path,'w') as fid:
|
120
|
+
fid.write("# casarundata populated by casaconfig.pull_data\nversion : %s\ndate : %s" % (version, datetime.today().strftime('%Y-%m-%d')))
|
121
|
+
fid.write("\n#\n# manifest")
|
122
|
+
for f in installed_files:
|
123
|
+
fid.write("\n%s" % f)
|
124
|
+
|
125
|
+
print_log_messages('casarundata installed %s at %s' % (version, path), logger)
|
@@ -60,10 +60,25 @@ def get_data_lock(path, fn_name):
|
|
60
60
|
return None
|
61
61
|
|
62
62
|
# write the lock information, the seek and truncate are probably not necessary
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
63
|
+
try:
|
64
|
+
print("lock file fd obtained for %s" % lock_path)
|
65
|
+
lock_fd.seek(0)
|
66
|
+
print("seek")
|
67
|
+
lock_fd.truncate(0)
|
68
|
+
print("truncated")
|
69
|
+
print("writing lock information")
|
70
|
+
print("fn_name : %s" % fn_name)
|
71
|
+
print("os.getlogin() : %s" % os.getlogin())
|
72
|
+
print("os.uname().nodename : %s" % os.uname().nodename)
|
73
|
+
print("os.getpid() : %s" % os.getpid())
|
74
|
+
print("datetime.today : %s" % datetime.today().strftime('%Y-%m-%d:%H:%M:%S'))
|
75
|
+
lock_fd.write("locked using %s by %s on %s : pid = %s at %s" % (fn_name, os.getlogin(), os.uname().nodename, os.getpid(), datetime.today().strftime('%Y-%m-%d:%H:%M:%S')))
|
76
|
+
print("info written")
|
77
|
+
lock_fd.flush()
|
78
|
+
print("lock_fd flushed")
|
79
|
+
except:
|
80
|
+
import traceback
|
81
|
+
traceback.print_exc()
|
67
82
|
|
68
83
|
return lock_fd
|
69
84
|
|
@@ -92,9 +92,22 @@ def measures_update(path, auto_update_rules=False, version=None, force=False, lo
|
|
92
92
|
import certifi
|
93
93
|
import fcntl
|
94
94
|
|
95
|
-
|
95
|
+
from .print_log_messages import print_log_messages
|
96
|
+
from .get_data_lock import get_data_lock
|
96
97
|
|
97
98
|
path = os.path.expanduser(path)
|
99
|
+
|
100
|
+
if auto_update_rules:
|
101
|
+
if version is not None:
|
102
|
+
print_log_messages('auto_update_rules requires that version be None', logger, True)
|
103
|
+
return
|
104
|
+
if force:
|
105
|
+
print_log_messages('force must be False when auto_update_rules is True', logger, True)
|
106
|
+
return
|
107
|
+
if (not os.path.isdir(path)) or (os.stat(path).st_uid != os.getuid()):
|
108
|
+
print_log_messages('path must exist as a directory and it must be owned by the user when auto_update_rules is True', logger, True)
|
109
|
+
return
|
110
|
+
|
98
111
|
if not os.path.exists(path): os.mkdir(path)
|
99
112
|
current = None
|
100
113
|
updated = None
|
@@ -116,14 +129,12 @@ def measures_update(path, auto_update_rules=False, version=None, force=False, lo
|
|
116
129
|
# don't re-download the same data
|
117
130
|
if not force:
|
118
131
|
if ((version is not None) and (version == current)) or ((version is None) and (updated == today_string)):
|
119
|
-
|
120
|
-
if logger is not None: logger.post('casaconfig current measures detected in %s, using version %s' % (path, current), 'INFO')
|
132
|
+
print_log_messages('measures_update current measures detected in %s, using version %s' % (path, current), logger)
|
121
133
|
return
|
122
134
|
|
123
135
|
# path must be writable with execute bit set
|
124
136
|
if (not os.access(path, os.W_OK | os.X_OK)) :
|
125
|
-
|
126
|
-
if logger is not None: logger.post('No permission to write to the measures path, cannot update : %s' % path, 'ERROR')
|
137
|
+
print_log_messages('No permission to write to the measures path, cannot update : %s' % path, logger, True)
|
127
138
|
return
|
128
139
|
|
129
140
|
# an update needs to happen
|
@@ -131,20 +142,16 @@ def measures_update(path, auto_update_rules=False, version=None, force=False, lo
|
|
131
142
|
# lock the measures_update.lock file
|
132
143
|
lock_fd = None
|
133
144
|
try:
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
#
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
lock_fd.seek(0)
|
145
|
-
lock_fd.truncate(0)
|
146
|
-
lock_fd.write("locked using measures_update by %s on %s : pid = %s at %s" % (os.getlogin(), os.uname().nodename, os.getpid(), datetime.today().strftime('%Y-%m-%d:%H:%M:%S')))
|
147
|
-
lock_fd.flush()
|
145
|
+
print_log_messages('measures_update measures need to be updated, acquiring the lock ... ', logger)
|
146
|
+
|
147
|
+
lock_fd = get_data_lock(path, 'measures_update')
|
148
|
+
# if lock_fd is None it means the lock file was not empty - because we know that path exists at this point
|
149
|
+
if lock_fd is None:
|
150
|
+
print_log_messages('The lock file at %s is not empty.' % path, logger, True)
|
151
|
+
print_log_messages('A previous attempt to update path may have failed or exited prematurely.', logger, True)
|
152
|
+
print_log_messages('Remove the lock file and set force to True with the desired version (default to most recent).', logger, True)
|
153
|
+
print_log_messages('It may be best to completely repopulate path using pull_data and measures_update.', logger, True)
|
154
|
+
return
|
148
155
|
|
149
156
|
do_update = force
|
150
157
|
|
@@ -163,19 +170,16 @@ def measures_update(path, auto_update_rules=False, version=None, force=False, lo
|
|
163
170
|
|
164
171
|
if ((version is not None) and (version == current)) or ((version is None) and (updated == today_string)):
|
165
172
|
# no update will be done, version is as requested or it's already been updated today
|
166
|
-
|
167
|
-
if logger is not None: logger.post('casaconfig current measures detected in %s, using version %s' % (path, current), 'INFO')
|
173
|
+
print_log_messages('measures_update current measures detected in %s, using version %s' % (path, current), logger)
|
168
174
|
else:
|
169
175
|
# an update is needed
|
170
176
|
do_update = True
|
171
177
|
|
172
178
|
if do_update:
|
173
179
|
if force:
|
174
|
-
|
175
|
-
if logger is not None: logger.post('casaconfig a measures update has been requested by the force argument', 'INFO')
|
180
|
+
print_log_messages('meaures_update a measures update has been requested by the force argument', logger)
|
176
181
|
|
177
|
-
|
178
|
-
if logger is not None: logger.post('casconfig connecting to ftp.astron.nl ...', 'INFO')
|
182
|
+
print_log_messages('measures_update connecting to ftp.astron.nl ...', logger)
|
179
183
|
|
180
184
|
ftp = FTP('ftp.astron.nl')
|
181
185
|
rc = ftp.login()
|
@@ -185,10 +189,7 @@ def measures_update(path, auto_update_rules=False, version=None, force=False, lo
|
|
185
189
|
# target filename to download
|
186
190
|
target = files[-1] if version is None else version
|
187
191
|
if target not in files:
|
188
|
-
|
189
|
-
logger.post('casaconfig cant find specified version %s' % target, 'ERROR')
|
190
|
-
else:
|
191
|
-
print('##### ERROR: cant find specified version %s #####' % target, file=sys.stdout)
|
192
|
+
print_log_messages('measures_update cant find specified version %s' % target, logger, True)
|
192
193
|
|
193
194
|
else:
|
194
195
|
# there are files to extract, remove the readme.txt file in case this dies unexpectedly
|
@@ -196,8 +197,7 @@ def measures_update(path, auto_update_rules=False, version=None, force=False, lo
|
|
196
197
|
os.remove(readme_path)
|
197
198
|
|
198
199
|
with open(os.path.join(path,'measures.ztar'), 'wb') as fid:
|
199
|
-
|
200
|
-
if logger is not None: logger.post('casaconfig downloading %s from ASTRON server to %s ...' % (target, path), 'INFO')
|
200
|
+
print_log_messages('measures_update downloading %s from ASTRON server to %s ...' % (target, path), logger)
|
201
201
|
ftp.retrbinary('RETR ' + target, fid.write)
|
202
202
|
|
203
203
|
ftp.close()
|
@@ -217,8 +217,7 @@ def measures_update(path, auto_update_rules=False, version=None, force=False, lo
|
|
217
217
|
os.system("rm %s" % os.path.join(path, 'measures.ztar'))
|
218
218
|
|
219
219
|
# get the Observatories table from CASA
|
220
|
-
|
221
|
-
if logger is not None: logger.post('casconfig obtaining the Observatories table from CASA ...', 'INFO')
|
220
|
+
print_log_messages('measures_update obtaining the Observatories table from CASA', logger)
|
222
221
|
context = ssl.create_default_context(cafile=certifi.where())
|
223
222
|
tstream = urllib.request.urlopen('https://casa.nrao.edu/download/geodetic/observatories.tar.gz', context=context, timeout=400)
|
224
223
|
tar = tarfile.open(fileobj=tstream, mode="r:gz")
|
@@ -228,24 +227,21 @@ def measures_update(path, auto_update_rules=False, version=None, force=False, lo
|
|
228
227
|
with open(readme_path,'w') as fid:
|
229
228
|
fid.write("# measures data populated by casaconfig\nversion : %s\ndate : %s" % (target, datetime.today().strftime('%Y-%m-%d')))
|
230
229
|
|
231
|
-
|
232
|
-
if logger is not None: logger.post('casaconfig updated measures data at %s' % path, 'INFO')
|
230
|
+
print_log_messages('measures_update updated measures data at %s' % path, logger)
|
233
231
|
|
234
232
|
# closing out the do_update
|
235
233
|
|
236
234
|
# closing out the try block
|
237
235
|
# truncate the lock file
|
238
236
|
lock_fd.truncate(0)
|
239
|
-
|
240
|
-
# close the lock file to release the lock
|
241
|
-
lock_fd.close()
|
242
237
|
|
243
238
|
except Exception as exc:
|
244
|
-
|
245
|
-
|
246
|
-
#
|
247
|
-
|
248
|
-
|
249
|
-
|
239
|
+
print_log_messages("ERROR! : Unexpected exception while updating measures at %s" % path, logger, True)
|
240
|
+
print_log_messages("ERROR! : %s" % exc, logger, True)
|
241
|
+
# leave the contents of the lock file as is to aid in debugging
|
242
|
+
|
243
|
+
# if the lock file is not closed, do that now to release the lock
|
244
|
+
if lock_fd is not None and not lock_fd.closed:
|
245
|
+
lock_fd.close()
|
250
246
|
|
251
247
|
return
|
@@ -26,7 +26,7 @@ def pull_data(path, version=None, force=False, logger=None):
|
|
26
26
|
|
27
27
|
A text file (readme.txt at path) records the version string, the date
|
28
28
|
when that version was installed in path, and the files installed into path.
|
29
|
-
This file is used to determine if the contents
|
29
|
+
This file is used to determine if the contents are a previously installed
|
30
30
|
version.
|
31
31
|
|
32
32
|
If the version to be pulled matches the version in the readme.txt file then this
|
@@ -34,26 +34,26 @@ def pull_data(path, version=None, force=False, logger=None):
|
|
34
34
|
version already matches what was previously installed (no installation is then
|
35
35
|
necessary unless force is True).
|
36
36
|
|
37
|
-
The measures tables included
|
37
|
+
The measures tables included in the package data will typically
|
38
38
|
not be the most recent version. To get the most recent measures data, measures_update
|
39
39
|
should be used after pull_data.
|
40
40
|
|
41
41
|
If path contains a previously installed version then all of the files listed in
|
42
42
|
the manifest part of the readme.txt file are first removed from path.
|
43
43
|
|
44
|
-
A file lock is used to prevent more than one data update (pull_data, measures_update
|
44
|
+
A file lock is used to prevent more than one data update (pull_data, measures_update,
|
45
45
|
or data_update) from updating any files in path at the same time. When locked, the
|
46
|
-
lock file (data_update.lock in path)
|
47
|
-
has the lock. When pull_data gets the lock it
|
46
|
+
lock file (data_update.lock in path) contains information about the process that
|
47
|
+
has the lock. When pull_data gets the lock it checks the readme.txt file in path
|
48
48
|
to make sure that a copy of the data should be pulled (the version doesn't match what
|
49
49
|
was requested). If force is True an update always happens. If the lock file is not
|
50
50
|
empty then a previous update of path (pull_data, data_update, or measures_update)
|
51
51
|
did not exit as expected and the contents of path are suspect. In that case, pull_data
|
52
52
|
will report that as an error and nothing will be updated. The lock file can be checked
|
53
53
|
to see the details of when that file was locked. The lock file can be removed and
|
54
|
-
pull_data can be then be used to install the desired version.
|
55
|
-
|
56
|
-
|
54
|
+
pull_data can be then be used to install the desired version. It may be safest in that case
|
55
|
+
to remove path completely or use a different path and run pull_data to install
|
56
|
+
a fresh copy of the desired version.
|
57
57
|
|
58
58
|
Some of the tables installed by pull_data are only read when casatools starts. Use of
|
59
59
|
pull_data should typically be followed by a restart so that any changes are seen by the
|
@@ -61,9 +61,9 @@ def pull_data(path, version=None, force=False, logger=None):
|
|
61
61
|
|
62
62
|
Parameters
|
63
63
|
- path (str) - Folder path to place casadata contents. It must be empty or not exist or contain a valid, previously installed version.
|
64
|
-
- version (str=None) - casadata version to retrieve
|
64
|
+
- version (str=None) - casadata version to retrieve. Default None gets the most recent version.
|
65
65
|
- force (bool=False) - If True, re-download the data even when the requested version matches what is already installed. Default False will not download data if the installed version matches the requested version.
|
66
|
-
- logger (casatools.logsink=None) - Instance of the casalogger to use for writing messages. Default None
|
66
|
+
- logger (casatools.logsink=None) - Instance of the casalogger to use for writing messages. Messages are always written to the terminal. Default None does not write any messages to a logger.
|
67
67
|
|
68
68
|
Returns
|
69
69
|
None
|
@@ -71,17 +71,11 @@ def pull_data(path, version=None, force=False, logger=None):
|
|
71
71
|
"""
|
72
72
|
|
73
73
|
import os
|
74
|
-
import sys
|
75
|
-
from datetime import datetime
|
76
|
-
import ssl
|
77
|
-
import urllib.request
|
78
|
-
import certifi
|
79
|
-
import tarfile
|
80
|
-
import shutil
|
81
74
|
|
82
75
|
from .data_available import data_available
|
83
76
|
from .print_log_messages import print_log_messages
|
84
77
|
from .get_data_lock import get_data_lock
|
78
|
+
from .do_pull_data import do_pull_data
|
85
79
|
|
86
80
|
path = os.path.expanduser(path)
|
87
81
|
readme_path = os.path.join(path, 'readme.txt')
|
@@ -89,7 +83,7 @@ def pull_data(path, version=None, force=False, logger=None):
|
|
89
83
|
installed_files = []
|
90
84
|
available_data = None
|
91
85
|
currentVersion = None
|
92
|
-
|
86
|
+
currentDate = None
|
93
87
|
|
94
88
|
# attempt a pull if path does not exist or is empty:
|
95
89
|
do_pull = (not os.path.exists(path)) or (len(os.listdir(path))==0)
|
@@ -113,7 +107,7 @@ def pull_data(path, version=None, force=False, logger=None):
|
|
113
107
|
if (len(installed_files) == 0):
|
114
108
|
# this shouldn't happen
|
115
109
|
print_log_messages('destination path is not empty and the readme.txt file found there did not contain the expected list of installed files', logger, True)
|
116
|
-
print_log_messages('choose a different path or
|
110
|
+
print_log_messages('choose a different path or empty this path and try again', logger, True)
|
117
111
|
# no lock as been set yet, safe to simply return here
|
118
112
|
return
|
119
113
|
|
@@ -169,6 +163,7 @@ def pull_data(path, version=None, force=False, logger=None):
|
|
169
163
|
# the readme file needs to be reread here
|
170
164
|
# it's possible that another process had path locked and updated the readme file with new information
|
171
165
|
try :
|
166
|
+
readme = None
|
172
167
|
with open(readme_path, 'r') as fid:
|
173
168
|
readme = fid.readlines()
|
174
169
|
currentVersion = readme[1].split(':')[-1].strip()
|
@@ -186,89 +181,16 @@ def pull_data(path, version=None, force=False, logger=None):
|
|
186
181
|
# this shoudn't happen, do not do a pull
|
187
182
|
do_pull = False
|
188
183
|
print_log_messages('destination path is not empty and the readme.txt file found there did not contain the expected list of installed files', logger, True)
|
189
|
-
print_log_messages('This should not happen unless multiple sessions are trying to pull_data at the same time and one experienced problems
|
184
|
+
print_log_messages('This should not happen unless multiple sessions are trying to pull_data at the same time and one experienced problems or was done out of sequence', logger, True)
|
190
185
|
print_log_messages('Check for other updates in process or choose a different path or clear out this path and try again', logger, True)
|
191
186
|
except:
|
192
187
|
# this shouldn't happen, do not do a pull
|
193
188
|
do_pull = False
|
194
189
|
print_log_messages('Unexpected error reading readme.txt file during pull_data, can not safely pull the requested version', logger, True)
|
195
|
-
print_log_messages('This should not happen unless multiple sessions are trying to pull_data at the same time and one experienced problems
|
190
|
+
print_log_messages('This should not happen unless multiple sessions are trying to pull_data at the same time and one experienced problems or was done out of sequence', logger, True)
|
196
191
|
|
197
192
|
if do_pull:
|
198
|
-
|
199
|
-
# remove the previously installed files
|
200
|
-
# remove this readme file so it's not confusing if something goes wrong after this
|
201
|
-
os.remove(readme_path)
|
202
|
-
print_log_messages('Removing files using manifest from previous install of %s on %s' % (currentVersion, currentDate), logger)
|
203
|
-
for relpath in installed_files:
|
204
|
-
filepath = os.path.join(path,relpath)
|
205
|
-
# don't say anything if filepath isn't found, remove it if it is found
|
206
|
-
if os.path.exists(filepath) and os.path.isfile(filepath):
|
207
|
-
os.remove(filepath)
|
208
|
-
# remove any empty directories in path - this is recursive
|
209
|
-
def remove_empty_dirs(dirpath):
|
210
|
-
# look at all of the files in dirpath, for dirs, go down that recursively
|
211
|
-
# if there's nothing there after the dirs have all been handled, remove it
|
212
|
-
files = os.listdir(dirpath)
|
213
|
-
not_dirs = []
|
214
|
-
for f in os.listdir(dirpath):
|
215
|
-
fpath = os.path.join(dirpath, f)
|
216
|
-
if os.path.isdir(fpath):
|
217
|
-
remove_empty_dirs(fpath)
|
218
|
-
else:
|
219
|
-
not_dirs.append(f)
|
220
|
-
if len(not_dirs) == 0:
|
221
|
-
if len(os.listdir(dirpath)) == 0:
|
222
|
-
os.rmdir(dirpath)
|
223
|
-
remove_empty_dirs(path)
|
224
|
-
|
225
|
-
# okay, safe to install the requested version
|
226
|
-
|
227
|
-
dataURL = os.path.join('https://casa.nrao.edu/download/casaconfig/data',version)
|
228
|
-
context = ssl.create_default_context(cafile=certifi.where())
|
229
|
-
with urllib.request.urlopen(dataURL, context=context, timeout=400) as tstream, tarfile.open(fileobj=tstream, mode='r:gz') as tar :
|
230
|
-
l = int(tstream.headers.get('content-length', 0))
|
231
|
-
sizeString = "unknown size"
|
232
|
-
if (l>0): sizeString = ("%.0fM" % (l/(1024*1024)))
|
233
|
-
# use print directly to make use of the end argument
|
234
|
-
print('downloading casarundata contents to %s (%s) ... ' % (path,sizeString), file = sys.stdout, end="" )
|
235
|
-
sys.stdout.flush()
|
236
|
-
# also log it
|
237
|
-
if logger is not None: logger.post('downloading casarundata contents to %s ...' % path, 'INFO')
|
238
|
-
tar.extractall(path=path)
|
239
|
-
print("done", file=sys.stdout)
|
240
|
-
# the tarball has been extracted to path/version
|
241
|
-
# get the instaled files of files to be written to the readme file
|
242
|
-
versdir = os.path.join(path,version[:version.index('.tar')])
|
243
|
-
installed_files = []
|
244
|
-
wgen = os.walk(versdir)
|
245
|
-
for (dirpath, dirnames, filenames) in wgen:
|
246
|
-
for f in filenames:
|
247
|
-
installed_files.append(os.path.relpath(os.path.join(dirpath,f),versdir))
|
248
|
-
|
249
|
-
# move everything in version up a level to path
|
250
|
-
for f in os.listdir(versdir):
|
251
|
-
srcPath = os.path.join(versdir,f)
|
252
|
-
if os.path.isdir(srcPath):
|
253
|
-
# directories are first copied, then removed
|
254
|
-
# existing directories are reused, existing files are overwritten
|
255
|
-
# things in path that do not exist in srcPath are not changed
|
256
|
-
shutil.copytree(srcPath,os.path.join(path,f),dirs_exist_ok=True)
|
257
|
-
shutil.rmtree(srcPath)
|
258
|
-
else:
|
259
|
-
# assume it's a simple file, these can be moved directly, overwriting anything already there
|
260
|
-
os.rename(srcPath,os.path.join(path,f))
|
261
|
-
|
262
|
-
# safe to remove versdir, it would be a surprise if it's not empty
|
263
|
-
os.rmdir(versdir)
|
264
|
-
# update the readme.txt file
|
265
|
-
with open(readme_path,'w') as fid:
|
266
|
-
fid.write("# casarundata populated by casaconfig.pull_data\nversion : %s\ndate : %s" % (version, datetime.today().strftime('%Y-%m-%d')))
|
267
|
-
fid.write("\n#\n# manifest")
|
268
|
-
for f in installed_files:
|
269
|
-
fid.write("\n%s" % f)
|
270
|
-
|
271
|
-
print_log_messages('casarundata installed %s at %s' % (version, path), logger)
|
193
|
+
do_pull_data(path, version, installed_files, logger)
|
272
194
|
|
273
195
|
# truncate the lock file
|
274
196
|
lock_fd.truncate(0)
|
@@ -281,7 +203,7 @@ def pull_data(path, version=None, force=False, logger=None):
|
|
281
203
|
traceback.print_exc()
|
282
204
|
|
283
205
|
# if the lock file is not closed, do that now to release the lock
|
284
|
-
if lock_fd is not None and not
|
206
|
+
if lock_fd is not None and not lock_fd.closed:
|
285
207
|
lock_fd.close()
|
286
208
|
|
287
209
|
return
|
@@ -3,6 +3,7 @@ MANIFEST.in
|
|
3
3
|
README.md
|
4
4
|
setup.py
|
5
5
|
casaconfig/__init__.py
|
6
|
+
casaconfig/__main__.py
|
6
7
|
casaconfig/config.py
|
7
8
|
casaconfig.egg-info/PKG-INFO
|
8
9
|
casaconfig.egg-info/SOURCES.txt
|
@@ -11,10 +12,12 @@ casaconfig.egg-info/requires.txt
|
|
11
12
|
casaconfig.egg-info/top_level.txt
|
12
13
|
casaconfig/__data__/README.txt
|
13
14
|
casaconfig/private/__init__.py
|
15
|
+
casaconfig/private/casasiteconfig.py
|
14
16
|
casaconfig/private/config_defaults.py
|
15
17
|
casaconfig/private/config_defaults_static.py
|
16
18
|
casaconfig/private/data_available.py
|
17
19
|
casaconfig/private/data_update.py
|
20
|
+
casaconfig/private/do_pull_data.py
|
18
21
|
casaconfig/private/get_argparser.py
|
19
22
|
casaconfig/private/get_config.py
|
20
23
|
casaconfig/private/get_data_lock.py
|
@@ -0,0 +1 @@
|
|
1
|
+
certifi>=2023.5.7
|
@@ -6,7 +6,7 @@ with open('README.md', "r") as fid: #encoding='utf-8'
|
|
6
6
|
|
7
7
|
setup(
|
8
8
|
name='casaconfig',
|
9
|
-
version='0.0.
|
9
|
+
version='0.0.60',
|
10
10
|
description='CASA Operational Configuration Package',
|
11
11
|
long_description=long_description,
|
12
12
|
long_description_content_type="text/markdown",
|
@@ -17,6 +17,5 @@ setup(
|
|
17
17
|
packages=find_packages(),
|
18
18
|
package_data={'casaconfig': ['__data__/*']},
|
19
19
|
include_package_data=True,
|
20
|
-
install_requires=['
|
21
|
-
'certifi>=2023.5.7']
|
20
|
+
install_requires=['certifi>=2023.5.7']
|
22
21
|
)
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# Copyright 2023 AUI, Inc. Washington DC, USA
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
"""
|
15
|
-
this module will be included in the api
|
16
|
-
"""
|
17
|
-
|
18
|
-
def data_update(path, auto_update_rules=False, version=None, force=False, logger=None):
|
19
|
-
"""
|
20
|
-
Retrieve the casarundata from the CASA server and install it in path
|
21
|
-
|
22
|
-
See the External Data section in casadocs for more information about the data retrieved.
|
23
|
-
This retrieves the full set of CASA runtime data, including the measures data available
|
24
|
-
when the requested version of casarundata was produced.
|
25
|
-
|
26
|
-
A text file (readme.txt in top-level directory at path) records the version string
|
27
|
-
and the date when that version was installed in path.
|
28
|
-
|
29
|
-
If the version requested matches the one in that text file then this function does
|
30
|
-
nothing unless force is True.
|
31
|
-
|
32
|
-
If a specific version is not requested (the default) and the date in that text file
|
33
|
-
is today, then this function does nothing unless force is True even if there is a more
|
34
|
-
recent version available from the CASA server.
|
35
|
-
|
36
|
-
A file lock is used to prevent more that one data_update and measures_update from updating
|
37
|
-
any files in path at the same time. When locked, the lock file (datea_update.lock
|
38
|
-
in path) will contain information about the process that has the lock. When a data_update
|
39
|
-
gets the lock it will check the readme.txt file in path to make sure that an update is still
|
40
|
-
necessary (if force is True then an update always happens).
|
41
|
-
|
42
|
-
Some of the tables installed by data_update are only read when casatools starts. Use of
|
43
|
-
data_update should typically be followed by a restart of CASA so that any changes are seen by
|
44
|
-
the tools and task that use this data.
|
45
|
-
|
46
|
-
**Note:** data_update requires that the expected readme.txt file already exists at the top-level
|
47
|
-
directory at path. If the file does not exist or can not be interpreted as expected then
|
48
|
-
data_update will return without updating any data.
|
49
|
-
|
50
|
-
**Note:** if auto_update_rules is True the user must own path (in addition to having read and
|
51
|
-
write permissions there). The version must then also be None and the force option must be False.
|
52
|
-
|
53
|
-
**Note:** the most recent casarundata may not include the most recent measures data. A data_update
|
54
|
-
is typically followed by a measures update.
|
55
|
-
|
56
|
-
Parameters
|
57
|
-
- path (str) - Folder path to update. Must contain a valid readme.txt,
|
58
|
-
- auto_update_rules (bool=False) - If True then the user must be the owner of path, version must be None, and force must be False.
|
59
|
-
- version (str=None) - Version of casarundata to retrieve (usually in the form of casarundata-x.y.z.tar.gz, see data_available()). Default None retrieves the latest.
|
60
|
-
- force (bool=False) - If True, always re-download the casarundata. Default False will not download casarundata if already updated today unless the version parameter is specified and different from what was last downloaded.
|
61
|
-
- logger (casatools.logsink=None) - Instance of the casalogger to use for writing messages. Default None writes messages to the terminal.
|
62
|
-
|
63
|
-
Returns
|
64
|
-
None
|
65
|
-
|
66
|
-
"""
|
67
|
-
|
68
|
-
print("Not yet implemented, nothing has been updated or checked.")
|
69
|
-
return
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|