#!/usr/bin/env python
#
#   Pacman is a package manager.
#
#   See http://physics.bu.edu/~youssef/pacman/index.html
#
#      Saul Youssef, Boston University
#
from unix_base          import *
from Package            import *
from Package_getter     import *
from package_processor  import *
from Platform           import *
from Caches             import *
from PackageName        import *
from Converter          import *
from SystemEnviros      import *
import os,urllib,py_compile,pickle,unix_base,time
import pac_symbols
import Platform

def pacman_update(pdb):
	pdb_save(pdb)
	pgt = Package_getter(pdb)
	html_save(pdb,caches,pgt)

import pac_html
def html_save(pdb,caches,pg):
	if verbose: print 'Updating documentation in ./doc/index.html'
	if not os.path.exists('doc'): os.system('mkdir doc')
	f = open('doc/xxxtmp','w')
	pac_html.pac_html_write(f,pdb,caches,pg)
	f.close()
	os.system('mv doc/xxxtmp doc/index.html')
	if os.path.exists('infomirror'):
		dm = open('infomirror','r')
		dmd = dm.readline()[:-1]
		
		os.system('scp doc/index.html '+dmd)
		
#		if os.path.exists(dmd):
#			if verbose: print 'Updating documentation mirror at ['+dmd+']...'
#			os.system('cp -f doc/index.html '+fncat(dmd,'pacman_infomirror/index.html'))
#		else:
#			print "Document mirror ["+dmd+"] can't be found. Document mirror not updated..."
		dm.close()

enviro_save = {}
for k in os.environ.keys():
	enviro_save[k] = os.environ[k]
	
def pdb_save(pdb):
	if verbose: print 'Updating data base...'
	f = open('xxxpacman.db','w')
	pickle.dump(pdb,f)
	f.close()
	os.system('rm -f Pacman.db')
	os.system('mv xxxpacman.db Pacman.db')

def pacman_use():
	print 'Use:    pacman {Options} <package1> <package2> ... '
	print 'Options: '
	print '    -help                  To get this message.'
	print '    -version               Print version number.'
	print '    -info                  Launch a browser showing the local installation.'
	print '    -doc                   Launch a browser pointing to the local Pacman '
	print '                           documentation (use -mozilla, -netscape or -lynx'
	print '                           to force a browser choice).'
	print '    -infomirror            Sets up and maintains a mirror of the installation web page.'
	print '                           documentation at directory dir.'
	print ' '
	print '    -get                   Fetch and install packages from the caches.'
	print '    -fetch                 Fetch packages from the caches.'
	print '    -install               Install the named packages.'
#	print '    -uninstall             Uninstall the named packages.'
	print '    -remove                Remove the named packages.'
	print '    -update                Check if there are updates or update a particular package.'
	print '    -updateall             Update all packages which have an update.'
	print '    -removeall             Remove all packages in the installation.'
#	print '    -wipe                  Remove all packages in the installation.'
#	print ' '
	print '    -cache:cachename       Use cache "cachename" to search for packages.'
	print '    -rel:dir               Installs relative to an installation in directory dir.'
	print ' '
#	print '    -no-recursive          To prevent recursive removals and uninstalls.'
	print '    -recursive (-r)        Recursively removes or uninstalls packages.'
	print '    -rpmcheck              To check the rpm signature.'
	print '    -force-rpm             To automatically replace rpms without asking.'
	print '    -no-native             To never accept non-Pacman local installations.'
	print '    -savedownload          To save downloaded file even after installation.'
	print ' '
	print '    -http_proxy:URL        To set and remember an http_proxy.'
	print '    -system-setenv:EV      To set system wide environment variable "EV"'
	print '                             pointing to the current installation.'
	print '    -system-unsetenv:EV    To unset a system wide environment variable "EV".'
	print ' '
	print '    -ask                   Ask before executing build commands.'
	print '    -v                     Verbose messages.'
#	print '    -very_verbose          Even more verbose messages.'
	print '    -registry              Display the available symbolic cache names.'
	print '    -trust-registered-caches '
	print '                           Automatically trust all registered caches (use at your own risk).'
	print '    -trust-all-caches '
	print '                           Automatically trust *all* caches (use at your own risk).'
#	print '    -platforms             Display available platform types.'
	print '    -convert               To convert an old Pacman 1 installation.'
#	print '    -dump                  To get an ascii dump of the local installation.'
	sys.exit()
	
for sw in switches:
	if not ( string.count(sw,':')>0 or \
			 sw == '-registry' or \
			 sw == '-help' or \
			 sw == '--help' or \
			 sw == '-h' or \
			 sw == '-local' or \
			 sw == '-info' or \
			 sw == '-doc'  or \
			 sw == '-get'  or \
			 sw == '-fetch' or \
			 sw == '-install' or \
#			 sw == '-uninstall' or \
			 sw == '-updateall' or \
			 sw == '-remove' or \
			 sw == '-update' or \
			 sw == '-removeall' or \
			 sw == '-wipe' or \
			 sw == '-no-recursive' or \
			 sw == '-recursive' or \
			 sw == '-r' or \
			 sw == '-no-rpmcheck' or \
			 sw == '-force-rpm' or \
			 sw == '-ask' or \
			 sw == '-v' or \
			 sw == '-verbose' or \
			 sw == '-very_verbose' or \
			 sw == '-dump' or \
			 sw == '-no-native' or \
			 sw == '-version' or \
			 sw == '-mozilla' or \
			 sw == '-netscape' or \
			 sw == '-lynx'     or \
			 sw == '-platforms' or \
			 sw == '-trust-all-caches' or \
			 sw == '-trust-registered-caches' or \
			 sw == '-infomirror' or \
			 sw == '-debug' or \
			 sw == '-savedownload' or \
			 sw == '-convert' or \
			 sw == '-swapcache' or \
			 sw == '-tar_xvf'): 
		print 'Unknown command line switch ['+sw+'].'
		pacman_use()	
	
#
#	check python version
#
pver = sys.version
#if sys.version[:3]=='2.2':
#	print "** You are using Python 2.2 **"
#	print "** Pacman only works up to Python 2.1 at the moment. **"
#	print "** This will be fixed soon... **"
#	sys.exit()
if verbose: print pver
if int(pver[0:1])>= 1:
	if int(pver[0:1])>1:
		ok = 1
	else:
		if int(pver[2:3])>=5:
			if int(pver[2:3])>5:
				ok = 1
			else:
				if pver[4:5]=='2' or \
				   pver[4:5]=='3' or \
				   pver[4:5]=='4' or \
				   pver[4:5]=='5' or \
				   pver[4:5]=='6' or \
				   pver[4:5]=='7' or \
				   pver[4:5]=='8' or \
				   pver[4:5]=='9': ok = 1
				else:
					ok = 0
		else:
			ok = 0
else:
	ok = 0

if switch('local') or switch('info'):
	if os.path.exists('Pacman.db'):
		if os.path.exists('doc/index.html'):
			launchbrowser(fncat(os.getcwd(),'doc/index.html'))
		else:
			print 'Local documentation in ./doc is missing.'
	else:
		print 'cd to an installation directory before doing [% pacman -info].'
	sys.exit()

if not ok: 
	print '** You need Python version 1.5.2 or greater from http://www.python.org/'
	sys.exit()
#
#   setup the PACMAN environment variable for the duration of the session.
#
os.environ['PACMAN'] = os.path.dirname(os.path.abspath(sys.argv[0]))

if switch('swapcache'):
	print '-swapcache lets you swap caches for installed software.'
	fromCache = raw_input('Full URL of cache that you want to replace:')
	toCache   = raw_input('Full URL of the replacement cache:')
	
	if os.path.exists('Pacman.db'):
		pdbf = open('Pacman.db','r')
		pdb  = pickle.load(pdbf)
		pdbf.close()
		
		for pac in pdb.keys():
			p = pdb[pac]
			if p.cache == fromCache: 
				print 'Replacing cache for installed package ['+p.name+'].'
				p.cache = toCache
		pacman_update(pdb)
	else:
		print "Can't find Pacman.db."
		sys.exit(1)
	
	if os.path.exists('caches'):
		f = open('caches','r')
		file = f.readlines()
		f.close()
		file2 = []
		for line in file:
			if not line[0]=='#': 
				if count(line,fromCache)>0:
					string.replace(line,fromCache,toCache)
					print 'Replacing ['+fromCache+'] with ['+toCache+'] in caches file.'
			file2.append(line)
			
		f = open('zzzcaches','w')
		for line in file2: f.write(line)
		f.close()
	else:
		print "Can't find caches file."
		sys.exit(1)
#
#	create the cache registry
#
#creg = Registry()
if switch('registry') or switch('very_verbose'):
	creg.table()
	if switch('registry'): sys.exit()

if switch('platforms'):
	print ' -- List of platforms coming soon... -- '
	sys.exit()
	
#
#	check that the PACMAN environment variable is set
#
if os.environ.has_key('PACMAN'):
	if not os.path.exists(envFile('PACMAN','caches_starter')):
		print '** caches file is missing in $PACMAN area'
		sys.exit()
		
if switch('doc'):
	if os.environ.has_key('PACMAN'): 
		if verbose: print 'netscape file:'+fncat(os.environ['PACMAN'],'doc/index.html &')
		launchbrowser(fncat(os.environ['PACMAN'],'doc/index.html'))
#		os.system('netscape file:'+fncat(os.environ['PACMAN'],'doc/index.html &'))
	else:
		print '** Error: $PACMAN not defined.'
	sys.exit()
	
if switch('infomirror'):
	print 'The Pacman -infomirror switch sets up a mirror of the documentation for your local installation.'
	infomirrordir = raw_input('Enter the full path of an existing directory in the local file system or an existing remote directory as you would in an scp command: ')
	os.system('rm -f infomirror')
	f = open('infomirror','w')
	f.write(infomirrordir+'\n')
	f.close()
	print ' '
	print 'All updates of this installation will be mirrored to ['+infomirrordir+'] without any further intervention on your part.'
	print 'If you want to change the mirror location, edit the file [infomirror] in the current directory.'
	print 'If your mirror is on a remove machine, you can avoid being asked for your password every time setting up an authentication method. See the ssh man pages.'
	
qdm,infomirrordir = switchpar('infomirror')
if qdm:
	print '-infomirror:dir is obsolete, use just -infomirror'
	print 'Try again...'
	sys.exit()
	if os.path.exists(os.path.expanduser(infomirrordir)):
		if os.path.exists(fncat(os.path.expanduser(infomirrordir),'pacman_infomirror')):
			print 'A mirror has already been set up for this Pacman installation.'
			sys.exit()
		os.system('rm -f infomirror')
		f = open('infomirror','w')
		f.write(os.path.expanduser(infomirrordir)+'\n')
		f.close()
		ask_to_execute('mkdir '+fncat(os.path.expanduser(infomirrordir),'pacman_infomirror'))
		print 'Pacman will mirror installation documentation for the current installation here ['+os.path.expanduser(infomirrordir)+'].'
	else:
		print 'Mirror location ['+infomirrordir+'] does not exist.'
		sys.exit()
#
#   remembers a proxy so the user doesn't have to keep setting it.
#
qproxy,proxy = switchpar('http_proxy')
if qproxy:
	print 'Using ['+proxy+'] as an http proxy.  This is saved in a local file called "proxy" which can be edited in the future.'
	f = open('proxy','w')
	f.write(proxy+'\n')
	f.close()
		
#
#	set an http proxy if necessary
#
if os.path.exists('proxy'):
	f = open('proxy','r')
	proxy = f.readline()[:-1]
	if verbose: print 'Setting http_proxy to ['+proxy+'].'
	os.environ['http_proxy'] = proxy
	f.close()
	
if os.path.exists('caches_starter') and os.path.exists('src') and os.path.exists('README'):
	print '** cd out of the pacman home area before running pacman.'
	sys.exit()

if switch('help') or switch('h') or switch('-help'): pacman_use()

if verbose or switch('version'): 
	print 'Pacman Version:  '+version
	print 'Platform:       ', findPlatform()[0]
	if switch('version'):
		print 'Python Version: ',sys.version
		sys.exit()

#
#	ask before making a new installation
#
if not os.path.exists('Pacman.db'):
	if not yesno('Do you want to start a new Pacman installation here: ['+os.getcwd()+']?'): sys.exit(1)
	
#
#	set an environment variable pointing to the root of the current Pacman installation.
#
os.environ['PACMAN_INSTALLATION'] = os.getcwd()

#
#	create the package db object
#
if switch('convert') and os.path.exists('pacman.db'):
	if yesno('This directory contains an old pacman installation.  Do you want to convert it to version 2 of pacman?'):
		pdbtf_old = open('pacman.db','r')
		pdbt_old  = pickle.load(pdbtf_old)
		pdbtf_old.close()
		
		print 'Converting old data base in [pacman.db] to a Pacman 2 data base in [Pacman.db]...'
		newdatabase = {}
		for oldpac in pdbt_old.keys():
			newp = convertOld2New(pdbt_old[oldpac])
			newdatabase[oldpac] = newp

		if os.path.exists('Pacman.db'): ask_to_execute('rm -r -f Pacman.db')
		fnew = open('xxxpacman.db','w')
		pickle.dump(newdatabase,fnew)
		fnew.close()
		os.system('mv pacman.db pacman.db.old')
		os.system('mv xxxpacman.db Pacman.db')

	pdbf = open('Pacman.db','rw')
	pdb  = pickle.load(pdbf)
	pdbf.close()
	sys.exit()
elif os.path.exists('Pacman.db'):
	pdbf = open('Pacman.db','rw')
	pdb  = pickle.load(pdbf)
	pdbf.close()
else:
	pdb  = {}
	pdb_save(pdb)
	
if switch('setup'):
	pac_symbols.make_symbols(pdb,enviro_save)
	sys.exit()
	
#
#	if it's an existing installation, make sure that the platform agrees with 
#	the platform which is executing this command.
#
if os.path.exists('platform'):
	fp = open('platform','r')
	for line in fp.readlines():
		if not (line == Platform.findPlatform()[0]+"\n"):
			print "This Pacman installation was made on a ["+line+"] system."
			print "You are currently running on a ["+Platform.findPlatform()[0]+"] system."
			sys.exit()
else:
	fp2 = open('platform','w')
	fp2.write(Platform.findPlatform()[0]+'\n')
	fp2.close()

#
#	create the list of caches
#
#caches = []
if not os.path.exists('caches'): 
	if verbose: print 'Copying starting caches file to local directory.'
	os.system('cp $PACMAN/caches_starter caches')
	
#	caches.append(creg.url(cache))
#	cachetruster(cache,caches)

f = open('caches','r')
file = f.readlines()
for line in file:
	if not ( line[:1] == '#' or len(line)<=1 ): caches.append(creg.url(line[0:len(line)-1]))

qcache,cache = switchpar('cache')
qcache2,cache2 = switchpar('relative')
qcache3,cache3 = switchpar('rel')
if qcache:
	cachetruster(cache)
elif qcache2:
	cachetruster(cache2)
elif qcache3:
	cachetruster(cache3)

if switch('dump'):
	import pac_displays
	
	print ' '
	if 1:
		pbkeys = pdb.keys()
		if len(pbkeys)==0: print 'No packages in local database.'
		for key in pbkeys:
			p = pdb[key]
			p.display()
			print ' '
	else:
		pac_displays.display(pdb)	
	print ' '
	
	print '-- Caches --'
	print ' '
	for cache in caches: print '      ',cache
	print ' '
	sys.exit()
#		
#if switch('caches'):
#	print "-caches isn't written yet..."
#	

qsystem_enviro,enviro = switchpar('system-setenv')
if qsystem_enviro:
	print "** "
	print "** You are about to set the environment variable ["+enviro+"] to the \n** value ["+os.getcwd()+"] for all users on this system."
	print "** "
	if yesno("** Do you want to proceed?"):
		sys_set = SystemEnviros()
		sys_set.insert(enviro)
		sys_set.place()
	else:
		print "No system environment variables set."
	sys.exit(1)
		
qsystem_enviro_unsetenv,enviro = switchpar('system-unsetenv')
if qsystem_enviro_unsetenv:
	print "** "
	print "** You are about to remove the environment variable ["+enviro+"] for all users on this system."
	if yesno("** Do you want to proceed?"):
		sys_set = SystemEnviros()
		sys_set.remove(enviro)
		sys_set.place()
	else:
		print "No system environment variables removed."
	sys.exit(1)

if verbose:
	print 'Caches in use:'
	for cache in caches:
		print '  ',cache
try:
	if switch('removeall'):
		for pac in pdb.keys():
#			if pdb.has_key(pn(pac).name) and not pn(pac).name[:6]=='Pacman': 
			if pdb.has_key(pn(pac).name): 
				pdb = pdb[pn(pac).name].remove(pdb)
		
	if switch('wipe'):
		for pac in pdb.keys():
			if pdb.has_key(pn(pac).name): pdb = pdb[pn(pac).name].remove(pdb)
	
	if switch('remove'):
		for pac in params: 
			if pdb.has_key(pn(pac).name): pdb = pdb[pn(pac).name].remove(pdb)
			else: print "Can't remove ["+pn(pac).name+"].  It hasn't been fetched."
	
	if switch('uninstall'):
		for pac in params:
			if pdb.has_key(pn(pac).name): pdb = pdb[pn(pac).name].uninstall(pdb)
			else: print "Can't uninstall ["+pn(pac).name+"].  It hasn't been fetched."
	
	if switch('fetch') or switch('get'):
		for pac in params:
			pg = Package_getter(pdb)
#			p = pg.get(pac)
			p = pg.get(pac)
			pdb = p.fetch(pdb,pg)
	
	if switch('install') or switch ('get'):
		for pac in params:
			if pdb.has_key(pn(pac).name): pdb = pdb[pn(pac).name].install(pdb)
			else: print "Can't install ["+pn(pac).name+"].  It hasn't been fetched."	
			
	if switch('updateall'):
		updateList = []
		for pac in pdb.keys():
			pg = Package_getter(pdb)
			got_it,pcache = pg.get_cache2(pdb[pac].name,pdb[pac].cache)
			instld = pdb[pac].installed
			if got_it:
				if pdb[pac].equiv(pcache):
					print "Package ["+pac+"] has not been changed..."
				else:
					if pdb[pac].location==os.getcwd():
						print "Updating ["+pac+"]..."
						pdb = pdb[pac].removeSelf(pdb)
						updateList.append(pac)
						
#						p = pg.get(pac)
#						pdb = p.fetch(pdb,pg)
#						if instld: pdb = p.install(pdb)
					else:
						print "Package ["+pac+"] has an update but it is relatively installed at ["+p.location+\
								"]. Update at that location..."
			else:
				print "Cache ["+pdb[pac].cache+"] is unreachable."
				
		for pac in updateList:
			p = pg.get(pac)
			pdb = p.fetch(pdb,pg)
			p.install(pdb)
#			
#	if switch('updateall'):
#		for pac in pdb.keys():
#			pg = Package_getter(pdb)
#			got_it,pcache = pg.get_cache2(pdb[pac].name,pdb[pac].cache)
#			instld = pdb[pac].installed
#			if got_it:
#				if pdb[pac].equiv(pcache):
#					print "Package ["+pac+"] has not been changed..."
#				else:
#					if pdb[pac].location==os.getcwd():
#						print "Updating ["+pac+"]..."
#						pdb = pdb[pac].removeSelf(pdb)
#						p = pg.get(pac)
#						pdb = p.fetch(pdb,pg)
#						if instld: pdb = p.install(pdb)
#					else:
#						print "Package ["+pac+"] has an update but it is relatively installed at ["+p.location+\
#								"]. Update at that location..."
#			else:
#				print "Cache ["+pdb[pac].cache+"] is unreachable."
		
	if switch('update'):
		for pac in params:
			pg = Package_getter(pdb)
			if not pdb.has_key(pac):
				print "Can't update ["+pac+"]. It hasn't been installed."
				sys.exit(1)
			got_it,pcache = pg.get_cache2(pdb[pac].name,pdb[pac].cache)
			instld = pdb[pac].installed
			
			if got_it:
				if pdb[pac].equiv(pcache):
					print "Package ["+pac+"] has not been changed..."
				else:
					if pdb[pac].location==os.getcwd():
						print "Updating ["+pac+"]..."
						pdb = pdb[pac].removeSelf(pdb)
						p = pg.get(pac)
						pdb = p.fetch(pdb,pg)
						if instld: pdb = p.install(pdb)
					else:
						print "Package ["+pac+"] has an update but it is relatively installed at ["+p.location+ \
							"]. Update at that location..."
			else:
				print "Cache ["+pdb[pac].cache+"] is unreachable."
		
#			if pdb.has_key(pac):
#				if pdb[pac].installed:
#					pg = Package_getter(pdb)
#					pdb = pdb[pac].remove(pdb)
#					p = pg.get(pac)
#					pdb = p.fetch(pdb,pg)
#					pdb = p.install(pdb,pg)
#				else:
#					print "Can't update ["+pac+"].  It's not installed..."
#			else:
#				print "Can't update ["+pac+"].  It's not fetched..."
				
#		for pac in params: 
#			if pdb.has_key(pac): pdb = pdb[pac].remove(pdb)
#			else: print "Can't remove ["+pac+"].  It hasn't been fetched."
#		for pac in params:
#			pg = Package_getter(pdb)
#			p = pg.get_pn(pn(pac))
#			pdb = p.fetch(pdb,pg)
#		for pac in params:
#			if pdb.has_key(pac): pdb = pdb[pac].install(pdb)
#			else: print "Can't install ["+pac+"].  It hasn't been fetched."	
except:
	print "Pacman is exiting. Saving work so far..."
	pacman_update(pdb)
	if switch('debug') or verbose: 
		print "Error:",sys.exc_info()[0]
		raise
	else: sys.exit(1)
else:	
#
#pdb_save(pdb)
#pgt = Package_getter(pdb,caches)
#html_save(pdb,caches,pgt)
#
	pacman_update(pdb)
	print 'Done.'
#
# keep the pacman_setup.sh file updated accordingly
#
	pac_symbols.make_symbols(pdb,enviro_save)
	
#	if switch('local') or switch('info'):
#		if os.path.exists('Pacman.db'):
#			if os.path.exists('doc/index.html'):
#				launchbrowser(fncat(os.getcwd(),'doc/index.html'))
#				sys.exit()
		
#	if switch('local') or switch('info'):
#		if os.path.exists('Pacman.db'):
#			if os.path.exists('doc/index.html'):
#				if switch('lynx'):
#					tt = 'lynx '+fncat(os.getcwd(),'doc/index.html')
#				else:
#					tt = 'netscape file:'+fncat(os.getcwd(),'doc/index.html &') 
#				os.system(tt)
#			else:
#				print "Can't find [./doc/index.html] documentation."
#		elif len(params)>0:
#			if os.path.exists(fncat(params[0],'doc/index.html')):
#				if switch('lynx'):
#					tt = 'lynx '+fncat(params[0],'doc/index.html')
#				else:
#					tt = 'netscape file:'+fncat(params[0],'doc/index.html &')
#				os.system(tt)
#			else:
#				print "Can't find [doc/index.html] documentation."
#		else:
#			print '** cd to an existing installation directory before doing "% pacman -local".'
#			print '** or use % pacman -local <one_of_your_installations>.'
	
