| 1 |
|
|---|
| 2 |
|
|---|
| 3 |
|
|---|
| 4 |
|
|---|
| 5 |
|
|---|
| 6 |
|
|---|
| 7 |
|
|---|
| 8 |
|
|---|
| 9 |
import os, sys, shutil, compiler |
|---|
| 10 |
from optparse import OptionParser |
|---|
| 11 |
|
|---|
| 12 |
DefaultBinDir = '/usr/local/sbin' |
|---|
| 13 |
DefaultDataDir = '/usr/share/mobiled' |
|---|
| 14 |
DefaultEtcDir = '/etc/mobiled' |
|---|
| 15 |
DefaultLogDir = '/var/log/mobiled' |
|---|
| 16 |
DefaultLibDir = '/usr/lib/mobiled' |
|---|
| 17 |
DefaultVarLibDir = '/var/lib/mobiled' |
|---|
| 18 |
|
|---|
| 19 |
class InstallError(Exception): |
|---|
| 20 |
""" Simple generic installation error exception """ |
|---|
| 21 |
|
|---|
| 22 |
def doMenu(DirBin, DirData, DirEtc, DirLog, DirLib, DirVarLib): |
|---|
| 23 |
|
|---|
| 24 |
def getInput(DefaultValue=''): |
|---|
| 25 |
line = raw_input('>>').strip() |
|---|
| 26 |
if len(line) > 0: |
|---|
| 27 |
return line |
|---|
| 28 |
else: |
|---|
| 29 |
return DefaultValue |
|---|
| 30 |
|
|---|
| 31 |
print '\n+--------------------+\n|MobilEd installation|\n+--------------------+\n\n' |
|---|
| 32 |
|
|---|
| 33 |
questions = (('Directory to place main executable in [%s]:' % DirBin, DirBin), |
|---|
| 34 |
('Directory to install program data files [%s]:' % DirData, DirData), |
|---|
| 35 |
('Directory for configuration files [%s]:' % DirEtc, DirEtc), |
|---|
| 36 |
('Directory for plugin files [%s]:' % DirLib, DirLib), |
|---|
| 37 |
('Directory for log files [%s]:' % DirLog, DirLog), |
|---|
| 38 |
('Directory for dynamic application data [%s]:' % DirVarLib, DirVarLib)) |
|---|
| 39 |
|
|---|
| 40 |
done = False |
|---|
| 41 |
while not done: |
|---|
| 42 |
print questions[0][0] |
|---|
| 43 |
_binDir = getInput(questions[0][1]) |
|---|
| 44 |
print questions[1][0] |
|---|
| 45 |
_dataDir = getInput(questions[1][1]) |
|---|
| 46 |
print questions[2][0] |
|---|
| 47 |
_etcDir = getInput(questions[2][1]) |
|---|
| 48 |
print questions[3][0] |
|---|
| 49 |
_libDir = getInput(questions[3][1]) |
|---|
| 50 |
print questions[4][0] |
|---|
| 51 |
_logDir = getInput(questions[4][1]) |
|---|
| 52 |
print questions[5][0] |
|---|
| 53 |
_varLibDir = getInput(questions[4][1]) |
|---|
| 54 |
|
|---|
| 55 |
print '\nSummary\n-------' |
|---|
| 56 |
print 'Install program executable to:', _binDir |
|---|
| 57 |
print 'Install program data files to:', _dataDir |
|---|
| 58 |
print 'Install configuration files to:', _etcDir |
|---|
| 59 |
print 'Directory to place plugins in:', _libDir |
|---|
| 60 |
print 'Directory to place log files in:', _logDir |
|---|
| 61 |
print 'Directory to use for application-generated data files:', _varLibDir |
|---|
| 62 |
print '\nIs this OK? (y/n) [n]' |
|---|
| 63 |
if getInput('n').lower() == 'y': |
|---|
| 64 |
done = True |
|---|
| 65 |
print |
|---|
| 66 |
|
|---|
| 67 |
return (_binDir, _dataDir, _etcDir, _libDir, _logDir, _varLibDir) |
|---|
| 68 |
|
|---|
| 69 |
def createDirs(DirList): |
|---|
| 70 |
""" Makes sure all directories in <DirList> exist; creates them if they don't |
|---|
| 71 |
|
|---|
| 72 |
Raises InstallError: if directory does not exist, and could not be created |
|---|
| 73 |
""" |
|---|
| 74 |
for directory in DirList: |
|---|
| 75 |
try: |
|---|
| 76 |
os.makedirs(directory) |
|---|
| 77 |
except OSError, (errno, msg): |
|---|
| 78 |
if errno == 13: |
|---|
| 79 |
raise InstallError, 'You do not have permissions to create directory: '+logDir |
|---|
| 80 |
elif errno != 17: |
|---|
| 81 |
raise |
|---|
| 82 |
|
|---|
| 83 |
def getRelPath(Target, LocalDir): |
|---|
| 84 |
commonPrefix = os.path.commonprefix((LocalDir, Target)) |
|---|
| 85 |
commonRelDepth = len(commonPrefix.split('/'))-1 |
|---|
| 86 |
relDepth = len(LocalDir.split('/'))-commonRelDepth |
|---|
| 87 |
return relDepth*'../'+Target[len(commonPrefix):] |
|---|
| 88 |
|
|---|
| 89 |
def configure(DirBin, DirData, DirEtc, DirPlugins, DirLog, DirVarLib, SettingsFilename='./mobiled/settings.py', BinFilename='./bin/mobiled'): |
|---|
| 90 |
""" Modifies the settings.py file in the mobiled root to point to the |
|---|
| 91 |
specified dirs, and compiles it to bytecode. |
|---|
| 92 |
|
|---|
| 93 |
Raises InstallError: if any step could not be accomplished |
|---|
| 94 |
""" |
|---|
| 95 |
|
|---|
| 96 |
|
|---|
| 97 |
|
|---|
| 98 |
|
|---|
| 99 |
|
|---|
| 100 |
try: |
|---|
| 101 |
if not os.path.exists(SettingsFilename+'.orig'): |
|---|
| 102 |
shutil.copy2(SettingsFilename, SettingsFilename+'.orig') |
|---|
| 103 |
f = open(SettingsFilename+'.orig', 'r') |
|---|
| 104 |
buff = f.read() |
|---|
| 105 |
f.close() |
|---|
| 106 |
except: |
|---|
| 107 |
raise InstallError, 'Could not open MobilEd settings file for reading: '+SettingsFilename |
|---|
| 108 |
buff = buff.replace("DIR_HOME = os.path.abspath(sys.path[0])+'/cache'", "DIR_HOME = '%s'" % DirVarLib) |
|---|
| 109 |
buff = buff.replace("DIR_CONFIG = '/../../'.join((DIR_HOME,'etc'))", "DIR_CONFIG = '%s'" % DirEtc) |
|---|
| 110 |
buff = buff.replace("DIR_LOG = DIR_HOME", "DIR_LOG = '%s'" % DirLog) |
|---|
| 111 |
buff = buff.replace("DIR_PLUGINS = os.path.abspath(sys.path[0])", "DIR_PLUGINS = '%s'" % DirPlugins) |
|---|
| 112 |
try: |
|---|
| 113 |
f = open(SettingsFilename, 'w') |
|---|
| 114 |
f.write(buff) |
|---|
| 115 |
f.close() |
|---|
| 116 |
except: |
|---|
| 117 |
raise InstallError, 'Could not write to MobilEd settings file: '+SettingsFilename |
|---|
| 118 |
try: |
|---|
| 119 |
compiler.compileFile(SettingsFilename) |
|---|
| 120 |
except: |
|---|
| 121 |
raise InstallError, 'Could not compile MobilEd settings file: '+SettingsFilename |
|---|
| 122 |
|
|---|
| 123 |
try: |
|---|
| 124 |
if not os.path.exists(BinFilename+'.orig'): |
|---|
| 125 |
shutil.copy2(BinFilename, BinFilename+'.orig') |
|---|
| 126 |
f = open(BinFilename+'.orig', 'r') |
|---|
| 127 |
buff = f.read() |
|---|
| 128 |
f.close() |
|---|
| 129 |
except: |
|---|
| 130 |
raise InstallError, 'Could not open MobilEd executable file for reading: '+BinFilename |
|---|
| 131 |
buff = buff.replace("sys.path.insert(0, '../mobiled')", "sys.path.insert(0, '%s')" % DirData) |
|---|
| 132 |
try: |
|---|
| 133 |
f = open(BinFilename, 'w') |
|---|
| 134 |
f.write(buff) |
|---|
| 135 |
f.close() |
|---|
| 136 |
except: |
|---|
| 137 |
raise InstallError, 'Could not write to MobilEd executable file: '+BinFilename |
|---|
| 138 |
try: |
|---|
| 139 |
compiler.compileFile(BinFilename) |
|---|
| 140 |
except: |
|---|
| 141 |
raise InstallError, 'Could not compile MobilEd executable: '+BinFilename |
|---|
| 142 |
|
|---|
| 143 |
|
|---|
| 144 |
def cpPythonFile(Src, Dest): |
|---|
| 145 |
for ext in ('.py', '.pyc', '.pyo'): |
|---|
| 146 |
try: |
|---|
| 147 |
shutil.copy2(Src+ext, Dest) |
|---|
| 148 |
print 'copying:',Src+ext |
|---|
| 149 |
except IOError, (errno, msg): |
|---|
| 150 |
if errno != 2: |
|---|
| 151 |
raise |
|---|
| 152 |
|
|---|
| 153 |
def copyFiles(DirBin, DirData, DirEtc, DirLib, SrcDir='./mobiled', SrcExec='./bin/mobiled', SrcEtc='./etc'): |
|---|
| 154 |
|
|---|
| 155 |
for filename in ('/mobiled', '/settings'): |
|---|
| 156 |
cpPythonFile(SrcDir+filename, DirData) |
|---|
| 157 |
for dataSubDir in ('/lib',): |
|---|
| 158 |
shutil.copytree(SrcDir+dataSubDir, DirData+dataSubDir, symlinks=True) |
|---|
| 159 |
|
|---|
| 160 |
|
|---|
| 161 |
for filename in os.listdir(SrcEtc): |
|---|
| 162 |
|
|---|
| 163 |
if filename == '.svn': |
|---|
| 164 |
continue |
|---|
| 165 |
filename = SrcEtc+'/'+filename |
|---|
| 166 |
if os.path.isfile(filename): |
|---|
| 167 |
print 'copying:',filename |
|---|
| 168 |
shutil.copy2(filename, DirEtc) |
|---|
| 169 |
else: |
|---|
| 170 |
print 'copying tree:',filename |
|---|
| 171 |
shutil.copytree(filename, DirEtc+'/'+os.path.basename(filename), symlinks=True) |
|---|
| 172 |
|
|---|
| 173 |
|
|---|
| 174 |
for pluginDir in ('/channels', '/datasources', '/requestinputs'): |
|---|
| 175 |
print 'copying tree:',SrcDir+pluginDir |
|---|
| 176 |
shutil.copytree(SrcDir+pluginDir, DirLib+pluginDir, symlinks=True) |
|---|
| 177 |
|
|---|
| 178 |
|
|---|
| 179 |
print 'copying:', SrcExec |
|---|
| 180 |
shutil.copy2(SrcExec, DirBin) |
|---|
| 181 |
|
|---|
| 182 |
|
|---|
| 183 |
|
|---|
| 184 |
def doInstall(DirBin, DirData, DirEtc, DirLib, DirLog, DirVarLib, CopyPrefix=''): |
|---|
| 185 |
""" Wrapper 'make install'-type function """ |
|---|
| 186 |
try: |
|---|
| 187 |
print 'Configuring...' |
|---|
| 188 |
configure(DirBin, DirData, DirEtc, DirLib, DirLog, DirVarLib) |
|---|
| 189 |
print 'Creating directories...' |
|---|
| 190 |
createDirs((CopyPrefix+DirBin, CopyPrefix+DirData, CopyPrefix+DirEtc, CopyPrefix+DirLib, CopyPrefix+DirLog, CopyPrefix+DirVarLib)) |
|---|
| 191 |
print 'Copying files...' |
|---|
| 192 |
copyFiles(CopyPrefix+DirBin, CopyPrefix+DirData, CopyPrefix+DirEtc, CopyPrefix+DirLib) |
|---|
| 193 |
except InstallError, msg: |
|---|
| 194 |
print 'Error:',msg |
|---|
| 195 |
print 'Installation aborted.' |
|---|
| 196 |
sys.exit(1) |
|---|
| 197 |
print 'Done!' |
|---|
| 198 |
|
|---|
| 199 |
|
|---|
| 200 |
if __name__ == '__main__': |
|---|
| 201 |
parser = OptionParser() |
|---|
| 202 |
parser.add_option('-a', action="store_true", dest='autoInstall', help='automatic install; do not ask questions') |
|---|
| 203 |
parser.add_option('--no-destdir-config', action='store_true', dest='noDestdirConfig', help='use DESTDIR prefix (if given) for file copying only, not for configuration (useful for packaging)') |
|---|
| 204 |
parser.add_option('--DESTDIR', dest='rootDir', help='specify a root directory prefix; defaults to /') |
|---|
| 205 |
parser.add_option('--BINDIR', dest='binDir', help='directory to place main executable program in; defaults to %s' % DefaultBinDir) |
|---|
| 206 |
parser.add_option('--DATADIR', dest='dataDir', help='directory to install program data files; defaults to %s' % DefaultDataDir) |
|---|
| 207 |
parser.add_option('--LOGDIR', dest='logDir', help='directory for log files; defaults to %s' % DefaultLogDir) |
|---|
| 208 |
parser.add_option('--CONFDIR', dest='etcDir', help='directory for configuration files; defaults to %s' % DefaultEtcDir) |
|---|
| 209 |
parser.add_option('--PLUGINDIR', dest='libDir', help='directory for plugins; defaults to %s' % DefaultLibDir) |
|---|
| 210 |
parser.add_option('--VARLIBDIR', dest='varLibDir', help='directory for dynamic application-generated data files; defaults to %s' % DefaultVarLibDir) |
|---|
| 211 |
parser.parse_args() |
|---|
| 212 |
|
|---|
| 213 |
if parser.values.rootDir == None: |
|---|
| 214 |
parser.values.rootDir = '' |
|---|
| 215 |
if parser.values.binDir == None: |
|---|
| 216 |
parser.values.binDir = DefaultBinDir |
|---|
| 217 |
if parser.values.dataDir == None: |
|---|
| 218 |
parser.values.dataDir = DefaultDataDir |
|---|
| 219 |
if parser.values.etcDir == None: |
|---|
| 220 |
parser.values.etcDir = DefaultEtcDir |
|---|
| 221 |
if parser.values.logDir == None: |
|---|
| 222 |
parser.values.logDir = DefaultLogDir |
|---|
| 223 |
if parser.values.libDir == None: |
|---|
| 224 |
parser.values.libDir = DefaultLibDir |
|---|
| 225 |
if parser.values.varLibDir == None: |
|---|
| 226 |
parser.values.varLibDir = DefaultVarLibDir |
|---|
| 227 |
|
|---|
| 228 |
if not parser.values.noDestdirConfig: |
|---|
| 229 |
binDir = parser.values.rootDir+parser.values.binDir |
|---|
| 230 |
dataDir = parser.values.rootDir+parser.values.dataDir |
|---|
| 231 |
etcDir = parser.values.rootDir+parser.values.etcDir |
|---|
| 232 |
logDir = parser.values.rootDir+parser.values.logDir |
|---|
| 233 |
libDir = parser.values.rootDir+parser.values.libDir |
|---|
| 234 |
varLibDir = parser.values.rootDir+parser.values.varLibDir |
|---|
| 235 |
cpPrefix = '' |
|---|
| 236 |
else: |
|---|
| 237 |
binDir = parser.values.binDir |
|---|
| 238 |
dataDir = parser.values.dataDir |
|---|
| 239 |
etcDir = parser.values.etcDir |
|---|
| 240 |
logDir = parser.values.logDir |
|---|
| 241 |
libDir = parser.values.libDir |
|---|
| 242 |
varLibDir = parser.values.varLibDir |
|---|
| 243 |
cpPrefix = parser.values.rootDir |
|---|
| 244 |
|
|---|
| 245 |
try: |
|---|
| 246 |
if not parser.values.autoInstall: |
|---|
| 247 |
binDir, dataDir, etcDir, libDir, logDir, varLibDir = doMenu(binDir, dataDir, etcDir, logDir, libDir, varLibDir) |
|---|
| 248 |
|
|---|
| 249 |
doInstall(binDir, dataDir, etcDir, libDir, logDir, varLibDir, cpPrefix) |
|---|
| 250 |
except KeyboardInterrupt: |
|---|
| 251 |
print '\nUser cancelled, aborting installation...' |
|---|
| 252 |
else: |
|---|
| 253 |
print 'This install script should be called directly.' |
|---|
| 254 |
sys.exit(1) |
|---|
| 255 |
|
|---|