LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
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 try:
34  # PyYAML >=5.1 prefers a different loader
35  # We need to use Unsafe because obs packages do not register
36  # constructors but rely on python object syntax.
37  Loader = yaml.UnsafeLoader
38 except AttributeError:
39  Loader = yaml.Loader
40 
41 
42 def _write(butlerLocation, cfg):
43  """Serialize a RepositoryCfg to a location.
44 
45  When the location is the same as cfg.root, the RepositoryCfg is to be written at the root location of
46  the repository. In that case, root is not written in the serialized cfg; it is implicit in the
47  location of the cfg. This allows the cfg to move from machine to machine without modification.
48 
49  Parameters
50  ----------
51  butlerLocation : ButlerLocation
52  The location to write the RepositoryCfg.
53  cfg : RepositoryCfg instance
54  The RepositoryCfg to be serialized.
55  """
56  def setRoot(cfg, loc):
57  loc = os.path.split(loc)[0] # remove the `repoistoryCfg.yaml` file name
58  if loc is None or cfg.root == loc:
59  cfg = copy.copy(cfg)
60  cfg.root = None
61  return cfg
62 
63  # This class supports schema 'file' and also treats no schema as 'file'.
64  # Split the URI and take only the path; remove the schema from loc if it's there.
65  loc = butlerLocation.storage.root
66  parseRes = urllib.parse.urlparse(loc if loc is not None else cfg.root)
67  loc = os.path.join(parseRes.path, butlerLocation.getLocations()[0])
68  try:
69  with safeFileIo.SafeLockedFileForRead(loc) as f:
70  existingCfg = _doRead(f, parseRes.path)
71  if existingCfg == cfg:
72  cfg.dirty = False
73  return
74  except IOError as e:
75  if e.errno != errno.ENOENT: # ENOENT is 'No such file or directory'
76  raise
77  with safeFileIo.SafeLockedFileForWrite(loc) as f:
78  existingCfg = _doRead(f, parseRes.path)
79  if existingCfg is None:
80  cfgToWrite = setRoot(cfg, loc)
81  else:
82  if existingCfg == cfg:
83  cfg.dirty = False
84  return
85  try:
86  existingCfg.extend(cfg)
87  cfgToWrite = setRoot(existingCfg, loc)
88  except ParentsMismatch as e:
89  raise RuntimeError("Can not extend existing repository cfg because: {}".format(e))
90  yaml.dump(cfgToWrite, f)
91  cfg.dirty = False
92 
93 
94 def _doRead(fileObject, uri):
95  """Get a persisted RepositoryCfg from an open file object.
96 
97  Parameters
98  ----------
99  fileObject : an open file object
100  the file that contains the RepositoryCfg.
101  uri : string
102  path to the repositoryCfg
103 
104  Returns
105  -------
106  A RepositoryCfg instance or None
107  """
108  repositoryCfg = yaml.load(fileObject, Loader=Loader)
109  if repositoryCfg is not None:
110  if repositoryCfg.root is None:
111  repositoryCfg.root = uri
112  return repositoryCfg
113 
114 
115 def _read(butlerLocation):
116  """Deserialize a RepositoryCfg from a location.
117 
118  Parameters
119  ----------
120  butlerLocation : ButlerLocation
121  The lcoation from which to read the RepositoryCfg.
122 
123  Returns
124  -------
125  RepositoryCfg
126  The deserialized RepoistoryCfg.
127 
128  Raises
129  ------
130  IOError
131  Raised if no repositoryCfg exists at the location.
132  """
133  repositoryCfg = None
134  loc = butlerLocation.storage.root
135  fileLoc = os.path.join(loc, butlerLocation.getLocations()[0])
136  try:
137  with safeFileIo.SafeLockedFileForRead(fileLoc) as f:
138  repositoryCfg = _doRead(f, loc)
139  except IOError as e:
140  if e.errno != errno.ENOENT: # ENOENT is 'No such file or directory'
141  raise
142  return repositoryCfg
143 
144 
145 PosixStorage.registerFormatters(RepositoryCfg, _read, _write)
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174