1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
|
#!/usr/bin/env python
# -*- Mode: python -*-
#
# Copyright (C) 2000-2002 The ViewCVS Group. All Rights Reserved.
#
# By using this file, you agree to the terms and conditions set forth in
# the LICENSE.html file which can be found at the top level of the ViewCVS
# distribution or at http://viewcvs.sourceforge.net/license-1.html.
#
# Contact information:
# Greg Stein, PO Box 760, Palo Alto, CA, 94302
# gstein@lyra.org, http://viewcvs.sourceforge.net/
#
# -----------------------------------------------------------------------
#
# install script for viewcvs -- temporary?
#
# ### this will eventually be replaced by autoconf plus tools. an
# ### interactive front-end to ./configure may be provided.
#
# -----------------------------------------------------------------------
#
import os
import sys
import string
import re
import traceback
import py_compile
import StringIO
# get access to our library modules
sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), 'lib'))
import compat
import viewcvs
import ndiff
version = viewcvs.__version__
## installer text
INFO_TEXT = """\
This is the ViewCVS %s installer.
It will allow you to choose the install path for ViewCVS. You will
now be asked some installation questions.
Defaults are given in square brackets. Just hit [Enter] if a default
is okay.
""" % version
## installer defaults
if sys.platform == "win32":
pf = os.getenv("ProgramFiles", "C:\\Program Files")
ROOT_DIR = os.path.join(pf, "viewcvs-" + version)
else:
ROOT_DIR = "/usr/local/viewcvs-" + version
## list of files for installation
## tuple (source path, destination path, install mode, true/false flag for
## search-and-replace, flag or text for prompt before replace,
## compile_it)
##
FILE_INFO_LIST = [
("www/cgi/viewcvs.cgi", "www/cgi/viewcvs.cgi", 0755, 1, 0, 0),
("www/cgi/query.cgi", "www/cgi/query.cgi", 0755, 1, 0, 0),
("www/mod_python/viewcvs.py", "www/mod_python/viewcvs.py", 0755, 1, 0, 0),
("www/mod_python/query.py", "www/mod_python/query.py", 0755, 1, 0, 0),
("www/mod_python/.htaccess", "www/mod_python/.htaccess", 0755, 1, 0, 0),
("standalone.py", "standalone.py", 0755, 1, 0, 0),
("viewcvs.conf.dist", "viewcvs.conf", 0644, 1,
"""Note: If you are upgrading from viewcvs-0.7 or earlier:
The section [text] has been removed from viewcvs.conf. The functionality
went into the new files in subdirectory templates.""", 0),
("cvsgraph.conf.dist", "cvsgraph.conf", 0644, 0, 1, 0),
("tools/loginfo-handler", "loginfo-handler", 0755, 1, 0, 0),
("tools/cvsdbadmin", "cvsdbadmin", 0755, 1, 0, 0),
("tools/svndbadmin", "svndbadmin", 0755, 1, 0, 0),
("tools/make-database", "make-database", 0755, 1, 0, 0),
]
if sys.platform == "win32":
FILE_INFO_LIST.extend([
("www/asp/viewcvs.asp", "www/asp/viewcvs.asp", 0755, 1, 0, 0),
("www/asp/query.asp", "www/asp/query.asp", 0755, 1, 0, 0),
])
TREE_LIST = [
("lib", "lib", 0),
("website", "doc", 0),
("templates", "templates", 1),
]
# used to escape substitution strings passed to re.sub(). re.escape() is no
# good because it blindly puts backslashes in front of anything that is not
# a number or letter regardless of whether the resulting sequence will be
# interpreted.
def ReEscape(str):
return string.replace(str, "\\", "\\\\")
# Used to escape backslashes and quotes in apache options
def ApacheEscape(str):
return re.sub(_re_apache, r"\\\g<0>", str)
_re_apache = re.compile("[\\\\\"]")
def Error(text, etype=None, evalue=None):
print
print "[ERROR] %s" % text
if etype:
print '[ERROR] ',
traceback.print_exception(etype, evalue, None, file=sys.stdout)
sys.exit(1)
def MkDir(path):
try:
compat.makedirs(path)
except os.error, e:
if e[0] == 17:
# EEXIST: file exists
return
if e[0] == 13:
# EACCES: permission denied
Error("You do not have permission to create directory %s" % path)
Error("Unknown error creating directory %s" % path, OSError, e)
def SetOnePath(contents, var, value):
pattern = re.compile('^' + var + r'\s*=\s*.*$', re.MULTILINE)
repl = '%s = r"%s"' % (var, os.path.join(ROOT_DIR, value))
return re.sub(pattern, ReEscape(repl), contents)
def SetPythonPaths(contents):
if contents[:2] == '#!':
shbang = '#!' + sys.executable
contents = re.sub('^#![^\n]*', ReEscape(shbang), contents)
contents = re.sub("<VIEWCVS_INSTALL_DIRECTORY>", ReEscape(ROOT_DIR), contents)
apacheDir = ApacheEscape(os.path.join(ROOT_DIR, 'lib'))
contents = re.sub("<VIEWCVS_APACHE_LIBRARY_DIRECTORY>", ReEscape(apacheDir), contents)
contents = SetOnePath(contents, 'LIBRARY_DIR', 'lib')
contents = SetOnePath(contents, 'CONF_PATHNAME', 'viewcvs.conf')
return contents
def InstallFile(src_path, dest_path, mode, set_python_paths, prompt_replace,
compile_it):
dest_path = os.path.join(ROOT_DIR, dest_path)
if prompt_replace and os.path.exists(dest_path):
# Collect ndiff output from ndiff
sys.stdout = StringIO.StringIO()
ndiff.main([dest_path,src_path])
ndiff_output = sys.stdout.getvalue()
# Return everything to normal
sys.stdout = sys.__stdout__
# Collect the '+ ' and '- ' lines
# total collects the difference lines to be printed later
total = ""
# I use flag to throw out match lines.
flag = 1
for line in string.split(ndiff_output,'\n'):
# Print line if it is a difference line
if line[:2] == "+ " or line[:2] == "- " or line[:2] == "? ":
total = total + line + "\n"
flag = 1
else:
# Compress lines that are the same to print one blank line
if flag:
total = total + "\n"
flag = 0
if total == "\n":
print " File %s exists,\n but there is no difference between target and source files.\n" % (dest_path)
return
if type(prompt_replace) == type(""):
print prompt_replace
while 1:
temp = raw_input("\n File %s\n exists and is different from source file.\n DO YOU WANT TO,\n overwrite [o]\n do not overwrite [d]\n view differences [v]: " % (dest_path))
print
temp = string.lower(temp[0])
if temp == "d":
return
if temp == "v":
print total
print "\nLEGEND\n A leading '- ' indicates line to remove from installed file\n A leading '+ ' indicates line to add to installed file\n A leading '? ' shows intraline differences."
if temp == "o":
ReplaceFile(src_path, dest_path, mode, set_python_paths, prompt_replace, compile_it)
return
else:
ReplaceFile(src_path, dest_path, mode, set_python_paths, prompt_replace, compile_it)
return
def ReplaceFile(src_path, dest_path, mode, set_python_paths, prompt_replace, compile_it):
try:
contents = open(src_path, "rb").read()
except IOError, e:
Error(str(e))
if set_python_paths:
contents = SetPythonPaths(contents)
## write the file to the destination location
path, basename = os.path.split(dest_path)
MkDir(path)
try:
open(dest_path, "wb").write(contents)
except IOError, e:
if e[0] == 13:
# EACCES: permission denied
Error("You do not have permission to write file %s" % dest_path)
Error("Unknown error writing file %s" % dest_path, IOError, e)
os.chmod(dest_path, mode)
if compile_it:
py_compile.compile(dest_path)
return
def install_tree(src_path, dst_path, prompt_replace):
files = os.listdir(src_path)
files.sort()
for fname in files:
# eliminate some items which appear in a development area
if fname == 'CVS' or fname[-4:] == '.pyc' or fname[-5:] == '.orig' \
or fname[-4:] == '.rej' or fname[0] == '.' or fname[-1] == '~':
continue
src = os.path.join(src_path, fname)
dst = os.path.join(dst_path, fname)
if os.path.isdir(src):
install_tree(src, dst, prompt_replace)
else:
print " ", src
compile_it = fname[-3:] == '.py'
# set the paths in all Python files -- it doesn't hurt to do a
# search/replace on these files even if they don't have the
# special symbols.
set_paths = compile_it
InstallFile(src, dst, 0644, set_paths, prompt_replace, compile_it)
# prompt to delete all .py and .pyc files that don't belong in installation
full_dst_path = os.path.join(ROOT_DIR, dst_path)
for fname in os.listdir(full_dst_path):
if not os.path.isfile(os.path.join(full_dst_path, fname)) or \
not ((fname[-3:] == '.py' and fname not in files) or
(fname[-4:] == '.pyc' and fname[:-1] not in files)):
continue
while 1:
temp = raw_input("\n File %s does not belong in ViewCVS %s.\n DO YOU WANT TO,\n delete [d]\n leave as is [l]: " % (os.path.join(dst_path, fname), version))
print
temp = string.lower(temp[0])
if temp == "l":
break
if temp == "d":
os.unlink(os.path.join(full_dst_path, fname))
break
## MAIN
if __name__ == "__main__":
print INFO_TEXT
## get the install path
temp = raw_input("Installation Path [%s]: " % ROOT_DIR)
temp = string.strip(temp)
if len(temp):
ROOT_DIR = temp
## install the files
print
print "Installing ViewCVS to:", ROOT_DIR
for args in FILE_INFO_LIST:
print " ", args[0]
apply(InstallFile, args)
for args in TREE_LIST:
apply(install_tree, args)
print """
ViewCVS File Installation Complete
Consult INSTALL for detailed information to finish the installation
and configure ViewCVS for your system.
Overview of remaining steps:
1) Edit the %s file.
2) Configure an existing web server to run (or copy to cgi-bin)
%s.
OR
Run the web server that comes with ViewCVS at
%s.
""" % (
os.path.join(ROOT_DIR, 'viewcvs.conf'),
os.path.join(ROOT_DIR, 'www', 'cgi', 'viewcvs.cgi'),
os.path.join(ROOT_DIR, 'standalone.py'))
|