Coverage for python/lsst/daf/persistence/fmtPosixRepositoryCfg.py: 15%

62 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-08-27 02:38 -0700

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 

23import copy 

24import errno 

25import yaml 

26import os 

27import urllib 

28from . import PosixStorage, RepositoryCfg, safeFileIo, ParentsMismatch 

29 

30 

31__all__ = [] 

32 

33try: 

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 

38except AttributeError: 

39 Loader = yaml.Loader 

40 

41 

42def _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 

94def _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 

115def _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 

145PosixStorage.registerFormatters(RepositoryCfg, _read, _write)