lsst.daf.persistence  14.0-11-g0362164+2
fmtPosixRepositoryCfg.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2017 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 
23 import copy
24 import errno
25 import yaml
26 import os
27 import urllib
28 from . import PosixStorage, RepositoryCfg, safeFileIo, ParentsMismatch
29 
30 
31 __all__ = []
32 
33 
34 def _write(butlerLocation, cfg):
35  """Serialize a RepositoryCfg to a location.
36 
37  When the location is the same as cfg.root, the RepositoryCfg is to be written at the root location of
38  the repository. In that case, root is not written in the serialized cfg; it is implicit in the
39  location of the cfg. This allows the cfg to move from machine to machine without modification.
40 
41  Parameters
42  ----------
43  butlerLocation : ButlerLocation
44  The location to write the RepositoryCfg.
45  cfg : RepositoryCfg instance
46  The RepositoryCfg to be serialized.
47  """
48  def setRoot(cfg, loc):
49  loc = os.path.split(loc)[0] # remove the `repoistoryCfg.yaml` file name
50  if loc is None or cfg.root == loc:
51  cfg = copy.copy(cfg)
52  cfg.root = None
53  return cfg
54 
55  # This class supports schema 'file' and also treats no schema as 'file'.
56  # Split the URI and take only the path; remove the schema from loc if it's there.
57  loc = butlerLocation.storage.root
58  parseRes = urllib.parse.urlparse(loc if loc is not None else cfg.root)
59  loc = os.path.join(parseRes.path, butlerLocation.getLocations()[0])
60  try:
61  with safeFileIo.SafeLockedFileForRead(loc) as f:
62  existingCfg = _doRead(f, parseRes.path)
63  if existingCfg == cfg:
64  cfg.dirty = False
65  return
66  except IOError as e:
67  if e.errno != errno.ENOENT: # ENOENT is 'No such file or directory'
68  raise
69  with safeFileIo.SafeLockedFileForWrite(loc) as f:
70  existingCfg = _doRead(f, parseRes.path)
71  if existingCfg is None:
72  cfgToWrite = setRoot(cfg, loc)
73  else:
74  if existingCfg == cfg:
75  cfg.dirty = False
76  return
77  try:
78  existingCfg.extend(cfg)
79  cfgToWrite = setRoot(existingCfg, loc)
80  except ParentsMismatch as e:
81  raise RuntimeError("Can not extend existing repository cfg because: {}".format(e))
82  yaml.dump(cfgToWrite, f)
83  cfg.dirty = False
84 
85 
86 def _doRead(fileObject, uri):
87  """Get a persisted RepositoryCfg from an open file object.
88 
89  Parameters
90  ----------
91  fileObject : an open file object
92  the file that contains the RepositoryCfg.
93  uri : string
94  path to the repositoryCfg
95 
96  Returns
97  -------
98  A RepositoryCfg instance or None
99  """
100  repositoryCfg = yaml.load(fileObject)
101  if repositoryCfg is not None:
102  if repositoryCfg.root is None:
103  repositoryCfg.root = uri
104  return repositoryCfg
105 
106 
107 def _read(butlerLocation):
108  """Deserialize a RepositoryCfg from a location.
109 
110  Parameters
111  ----------
112  butlerLocation : ButlerLocation
113  The lcoation from which to read the RepositoryCfg.
114 
115  Returns
116  -------
117  RepositoryCfg
118  The deserialized RepoistoryCfg.
119 
120  Raises
121  ------
122  IOError
123  Raised if no repositoryCfg exists at the location.
124  """
125  repositoryCfg = None
126  loc = butlerLocation.storage.root
127  fileLoc = os.path.join(loc, butlerLocation.getLocations()[0])
128  try:
129  with safeFileIo.SafeLockedFileForRead(fileLoc) as f:
130  repositoryCfg = _doRead(f, loc)
131  except IOError as e:
132  if e.errno != errno.ENOENT: # ENOENT is 'No such file or directory'
133  raise
134  return repositoryCfg
135 
136 
137 PosixStorage.registerFormatters(RepositoryCfg, _read, _write)