1############################################################################### 2# 3# checkmData.py - database management utilities 4# 5############################################################################### 6# # 7# This program is free software: you can redistribute it and/or modify # 8# it under the terms of the GNU General Public License as published by # 9# the Free Software Foundation, either version 3 of the License, or # 10# (at your option) any later version. # 11# # 12# This program is distributed in the hope that it will be useful, # 13# but WITHOUT ANY WARRANTY; without even the implied warranty of # 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # 15# GNU General Public License for more details. # 16# # 17# You should have received a copy of the GNU General Public License # 18# along with this program. If not, see <http://www.gnu.org/licenses/>. # 19# # 20############################################################################### 21 22import os 23import sys 24import logging 25from pkg_resources import resource_filename 26import json 27 28import checkm.manifestManager as mm 29 30 31class DBConfig(object): 32 """CheckM uses packageutils to distribute a file called "DATA_CONFIG" which is placed with 33 the other files during installation. This file stores information about where data is 34 stored locally and where to look for remote updates. This class essentially exposes 35 the DATA_CONFIG file as an object. 36 """ 37 def __init__(self): 38 self.logger = logging.getLogger('timestamp') 39 self.configFile = os.path.abspath(resource_filename('checkm', 'DATA_CONFIG')) 40 self.values = self.getConfig() 41 42#----------------------------------------------------------------------------- 43# Read and write local config file 44 45 def getConfig(self): 46 """Get a listing of the versions of files in the local data config""" 47 try: 48 with open(self.configFile, 'r') as local_config: 49 # config is a one line file 50 for line in local_config: 51 return json.loads(line) 52 53 except Exception: 54 self.logger.error("There seems to be a problem with loading the CheckM config file") 55 self.logger.error("Please check the permissions / existence / contents of:") 56 self.logger.error(self.configFile) 57 raise 58 59 return {} 60 61 def setConfig(self): 62 """Update the local config to reflect and changes made""" 63 if self.checkPermissions(): 64 with open(self.configFile, 'w') as config_fh: 65 config_fh.write(json.dumps(self.values)) 66 67#----------------------------------------------------------------------------- 68# Display config 69 70 def displayConfig(self): 71 """Print out the contents of the CheckM config file""" 72 self.logger.info("Contents of the config located at:\n\n\t%s\n" % (self.configFile)) 73 self.logger.info("-------------------------------------------------------------------------------") 74 self.logger.info("Data root: %s" % self.values["dataRoot"]) 75 self.logger.info("Local manifest name: %s" % self.values["remoteManifestURL"]) 76 self.logger.info("Manifest type: %s" % self.values["remoteManifestName"]) 77 self.logger.info("Remote URL: %s" % self.values["localManifestName"]) 78 self.logger.info("Remote manifest name: %s" % self.values["manifestType"]) 79 self.logger.info("-------------------------------------------------------------------------------") 80 81#----------------------------------------------------------------------------- 82# Housekeeping 83 84 def checkPermissions(self): 85 """Work out if we have permission to write to the CheckM config before attempting to make changes""" 86 try: 87 open(self.configFile, 'a') 88 except IOError, e: 89 print "You do not seem to have permission to edit the checkm config file" 90 print "located at %s" % self.configFile 91 print "Please try again with updated privileges. Error was:\n" 92 print e 93 return False 94 return True 95 96 97class DBManager(mm.ManifestManager): 98 99 """Manage all aspects of data location and version control.""" 100 def __init__(self, set_path=None): 101 mm.ManifestManager.__init__(self, timeout=15) 102 self.logger = logging.getLogger('timestamp') 103 self.config = DBConfig() # load inbuilt configuration 104 self.type = self.config.values["manifestType"] 105 106 if set_path: 107 self.setRoot(set_path) 108 109 # check that the data root is legit 110 manifestFile = os.path.join(self.config.values["dataRoot"], mm.__MANIFEST__) 111 if not os.path.exists(self.config.values["dataRoot"]) or not os.path.exists(manifestFile): 112 self.config.values["dataRoot"] = "" 113 114 if self.config.values["dataRoot"] == "": 115 # no data folder set. 116 print ("It seems that the CheckM data folder has not been set yet or has been removed. Please run 'checkm data setRoot'.") 117 if not self.setRoot(): 118 print("Sorry, CheckM cannot run without a valid data folder.") 119 120 def runAction(self, action): 121 """Main entry point for the updating code""" 122 123 if action[0] == "setRoot": 124 if len(action) > 1: 125 path = self.setRoot(path=action[1]) 126 else: 127 path = self.setRoot() 128 129 if path is None: 130 self.logger.info("Data location not changed") 131 else: 132 self.logger.info("Data location successfully changed to: %s" % path) 133 else: 134 self.logger.error("Unknown action: %s" % action[0]) 135 136 def setRoot(self, path=None): 137 """Set the data folder""" 138 # check to see we have permission to update the data root 139 if not self.config.checkPermissions(): 140 return None 141 142 # validate the supplied path or prompt for a new one 143 path = self.confirmPath(path=path) 144 if path is None: 145 # The user is not interested 146 return None 147 148 # path should be set, exist and be writable 149 self.config.values["dataRoot"] = path 150 151 # save the new path 152 self.config.setConfig() 153 154 return path 155 156 def confirmPath(self, path=None): 157 """Ask the user to supply a path""" 158 path_set = False 159 minimal = False 160 while not path_set: 161 if not path: 162 path = os.path.join(os.path.expanduser("~"), ".checkm") 163 164 if path.upper() == "ABORT": 165 # user has given up 166 return None 167 else: 168 path = os.path.abspath(os.path.expanduser(path)) 169 170 print "" 171 if os.path.exists(path): 172 # path exists 173 if os.access(path, os.W_OK): 174 # path is writable 175 path_set = True 176 print "Path [%s] exists and you have permission to write to this folder." % path 177 else: 178 print "Path [%s] exists but you do not have permission to write to this folder." % path 179 else: 180 # path does not exist, try to make it 181 "Path [%s] does not exist so I will attempt to create it" % path 182 try: 183 self.makeSurePathExists(path) 184 print "Path [%s] has been created and you have permission to write to this folder." % path 185 path_set = True 186 except Exception: 187 print "Unable to make the folder, Error was: %s" % sys.exc_info()[0] 188 minimal = True 189 190 # (re)make the manifest file 191 print "(re) creating manifest file (please be patient)." 192 self.createManifest(path, self.config.values["localManifestName"]) 193 194 return path 195 196 def checkPermissions(self): 197 """See if the user has permission to write to the data directory""" 198 if not os.access(self.config.values["dataRoot"], os.W_OK): 199 print "You do not seem to have permission to edit the CheckM data folder" 200 print "located at %s" % self.config.values["dataRoot"] 201 return False 202 203 return True 204