head	1.1;
access;
symbols
	branch:1.1.0.2;
locks; strict;
comment	@# @;


1.1
date	2000.06.14.16.35.03;	author pearson;	state Exp;
branches
	1.1.2.1;
next	;

1.1.2.1
date	2000.06.14.16.35.27;	author pearson;	state Exp;
branches;
next	1.1.2.2;

1.1.2.2
date	2000.06.14.16.35.34;	author pearson;	state Exp;
branches;
next	;


desc
@@


1.1
log
@*** empty log message ***
@
text
@/*****************************************************************************
 *
 * $HPCopyright: Copyright (C) 1999 Hewlett-Packard Company.$
 * All rights reserved.
 *
 * 11311 Chinden Blvd.
 * Boise, Idaho 83714
 * 
 *****************************************************************************/


#include <hpfedpack.h>
#include "fpmanager.h"
#include "bundles.h"
#include <fcntl.h>



FPMSelectorPrivate::FPMSelectorPrivate()
	: installed(FALSE),
	  selected(FALSE),
	  available(TRUE)			// filter this one by platform
{
}




FPMSelector::FPMSelector()
{
	ASSERT(isValidObject());

	m_private = new FPMSelectorPrivate();
	Initialize();
}


FPMSelector::~FPMSelector()
{
	ASSERT(isValidObject());

	if( m_private ISNT NULL )
	{
		DELETE_AND_NULL(m_private);
	}
}


void FPMSelector::Initialize()
{
	ASSERT(isValidObject());

	FPMDatabase db;

	m_private->installed.RemoveAll();
	m_private->installed.AddHeaderSet(db);
	m_private->selected.RemoveAll();
	m_private->available.RemoveAll();
}


FPMResult FPMSelector::AddAvailableFile(LPCTSTR filename)
{
	CTStringList fileList;
//	FPMBundleManager bundleManager;
	FPMResult rc, ret = FPM_ERR_OK;

	ASSERT(isValidObject());

	if( filename == NULL ) {
		ASSERT(FALSE);
		return FPM_ERR_ARGUMENT;
	}

	fileList.AddTail(filename);

//  	// expand bundles
//  	rc = bundleManager.OpenBundles(fileList);
//  	if( rc != FPM_ERR_OK ) {
//  		ASSERT(FALSE);
//  		ret = rc;
//  	}

	for(int i=0; i < fileList.Length(); i++) {
		rc = m_private->available.AddFile(fileList.Get(i));
		if( rc != FPM_ERR_OK && rc != FPM_ERR_PLATFORM ) { // ignore if wrong platform
			ASSERT(FALSE);
			ret = rc;
		}
	}
	
	return ret;
}


FPMResult FPMSelector::AddAvailableFileIndex(LPCTSTR indexFilename)
{
	gzFile gzfd;
	FPMResult rc;
	FPMHeaderSet set;

	ASSERT(isValidObject());

	// check argument
	if( indexFilename == NULL ) {
		ASSERT(FALSE);
		return FPM_ERR_ARGUMENT;
	}

	// open the file for reading
	gzfd = gzopen((LPCSTR)CCString(indexFilename),"rb");
	if( gzfd == NULL ) {
		ASSERT(FALSE);
		return FPM_ERR_IO;
	}

	// read the header set out of the file
	rc = set.ReadXML(gzfd);
	gzclose(gzfd);
	if( rc != FPM_ERR_OK ) {
		ASSERT(FALSE);
		return rc;
	}

	// merge the set into the list of available files; okay if some of
	// the files are not for this platform
	rc = m_private->available.AddHeaderSet(set);
	if( rc != FPM_ERR_OK && rc != FPM_ERR_PLATFORM ) {
		ASSERT(FALSE);
		return rc;
	}

	return FPM_ERR_OK;
}


FPMResult FPMSelector::PruneAvailableByMissingDependencies()
{
	BOOL bRemovedSomething;
	FPMHeader header;
	FPMResult rc, ret = FPM_ERR_OK;
	FPMResultList resultList;

	FPMLog0(TEXT("PruneAvailableByMissingDependencies()...\n"));

	// ok, here's how we do this:
	// Iterate over available packages
	// Check each package's dependencies against available and installed sets.
	// Remove the package from the available list if it has unsatisfied dependencies.
	// Repeat until no packages are removed.

	// repeat as long as we're removing something each time
	do {
		bRemovedSomething = FALSE;

		// iterate over the available packages
		FPMHeaderSetIterator iter(m_private->available);
		while( iter.NextHeader(header) ) {
			resultList.RemoveAll();
			// check this package's dependencies
			rc = m_private->available.CheckDependencies(header,resultList,
														&(m_private->installed));
			if( rc == FPM_ERR_OK ) {
				// a-ok; keep going
				continue;
			}
			else if( rc == FPM_ERR_DEPENDENCY ) {
				// missing dependencies, so remove this package
				LTRACE4(TRACE_JAMES,
						TEXT("Pruning package %s %s due to dependency on %s %s\n"),
						header.GetName(), header.GetVersion(),
						(LPCTSTR)(resultList.Get(0)->m_packageName),
						(LPCTSTR)(resultList.Get(0)->m_packageVersion));
				rc = m_private->available.RemoveHeader(header);
				if( rc != FPM_ERR_OK ) {
					ASSERT(FALSE);
					ret = rc;
					continue;
				}
				bRemovedSomething = TRUE; // remember that we need to go around again
			}
			else {
				ASSERT(FALSE);
				ret = rc;
			}
		}

	} while( bRemovedSomething );

	FPMLog1(TEXT("PruneAvailableByMissingDependencies() Done %d...\n"),ret);

	return ret;
}


FPMResult FPMSelector::SelectPackage(LPCTSTR packageName, LPCTSTR version,
									 BOOL forceOverInstall)
{
	FPMHeader selectedHeader, installedHeader, previousHeader;
	FPMResult rc;

	ASSERT(isValidObject());

	// check arguments
	if( packageName == NULL ) {
		ASSERT(FALSE);
		return FPM_ERR_ARGUMENT;
	}

	// get the header of the package to install
	rc = m_private->available.GetByName(packageName,version,selectedHeader);
	if( rc != FPM_ERR_OK ) {
		return rc;
	}

	// check to see if the package is already installed
	rc = m_private->installed.GetByName(packageName,installedHeader);
	if( rc == FPM_ERR_OK ) {
		// if it is, check the version
		int cmp = FPManager::CompareVersions(selectedHeader.GetVersion(),
											 installedHeader.GetVersion());
		if( cmp < 0 ) {
			// older version selected
			return FPM_ERR_DOWNGRADE;
		}
		if( cmp == 0 ) {
			// same version selected
			if( ! forceOverInstall ) {
				return FPM_ERR_ALREADYINSTALLED;
			}
			// drop thru as though this one were newer if forceOverInstall
		}

		// drop thru if newer version selected
	}

	// check for a previously-selected header
	rc = m_private->selected.GetHeader(packageName,previousHeader);
	if( rc == FPM_ERR_OK ) {
		// if there is one, check the version
		int cmp = FPManager::CompareVersions(selectedHeader.GetVersion(),
											 previousHeader.GetVersion());
		if( cmp < 0 ) {
			// older version selected
			return FPM_ERR_DOWNGRADE;
		}
		if( cmp == 0 ) {
			// same version selected
			return FPM_ERR_OK;
		}

		// we've selected a newer version, so remove the old one
		rc = m_private->selected.RemoveHeader(packageName);
		if( rc != FPM_ERR_OK ) {
			ASSERT(FALSE);
			return rc;
		}
	}

	// add the new one to the selected list
	rc = m_private->selected.AddHeader(selectedHeader);
	if( rc != FPM_ERR_OK ) {
		ASSERT(FALSE);
		return rc;
	}
			
	return FPM_ERR_OK;
}



FPMResult FPMSelector::SelectDeviceSupport(const CTStringList &devices,
										   FPMResultList &resultList)
{
	int i;
	FPMResult rc, ret = FPM_ERR_OK;
	FPMHeader header;

	ASSERT(isValidObject());
	ASSERT(resultList.isValidObject());

	FPMLog0(TEXT("SelectDeviceSupport()...\n"));

	// for each specified device
	for(i=0; i < devices.Length(); i++) {
		LPCTSTR device = devices.Get(i);
		
		// check if available
		rc = m_private->available.GetByDevice(device,header);
		if( rc == FPM_ERR_OK ) {
			// support is available; try to select
			rc = SelectPackage(header.GetName(),header.GetVersion());
			if( rc != FPM_ERR_OK && rc != FPM_ERR_ALREADYINSTALLED ) {
				resultList.AddTail(FPMResultData(rc,
												 header.GetName(),
												 header.GetVersion(),
												 device,
												 header.GetDescription(),0));
				ret = rc;
			}
		}
		else {
			// support not available; check if already installed
			rc = m_private->installed.GetByDevice(device,header);
			if( rc == FPM_ERR_OK ) {
				resultList.AddTail(FPMResultData(FPM_ERR_ALREADYINSTALLED,
												 header.GetName(),
												 header.GetVersion(),
												 device,
												 header.GetDescription(),0));
				ret = FPM_ERR_ALREADYINSTALLED;
			}
			else {
				resultList.AddTail(FPMResultData(FPM_ERR_NODEVICE,
												 NULL,NULL,device,NULL,0));
			}
		}

	}

	// now, select dependencies
	rc = SelectDependencies(resultList);
	if( rc != FPM_ERR_OK ) {
		ret = rc;
	}

	FPMLog1(TEXT("SelectDeviceSupport() Done %d\n"),ret);

	return ret;
}


// select packages to support the specified language list
FPMResult FPMSelector::SelectLanguageSupport(const CTStringList &languages,
											 FPMResultList &resultList)
{
	FPMResult rc;

	ASSERT(isValidObject());
	ASSERT(resultList.isValidObject());

	FPMLog0(TEXT("SelectLanguageSupport()...\n"));

	BOOL bSelectedDependencies;
	BOOL bMissingLanguage = FALSE;
	do {
		FPMHeaderSetIndex target;

		// simulate the final installation
		rc = _simulateInstall(target);
		if( rc != FPM_ERR_OK ) {
			ASSERT(FALSE);
			return rc;
		}

		// for each localizable package
		FPMHeaderSetIndexIterator headerIter(target);
		FPMHeader packageHeader;
		while( headerIter.NextHeader(packageHeader) ) {
			LTRACE1(TRACE_JAMES,TEXT("Header: %s\n"),
					packageHeader.GetName());

			if( ! packageHeader.IsLocalizable() ) {
				continue;
			}

			LTRACE1(TRACE_JAMES,TEXT("Localizable header: %s\n"),
					packageHeader.GetName());

			// for each language
			for(int i=0; i < languages.Length(); i++) {
				FPMHeader tempHeader;
				LPCTSTR language = languages.Get(i);

				LTRACE1(TRACE_JAMES,TEXT("Checking language: %s\n"),language);

				// check to see if support for the language is installed
				rc = target.GetByLanguageSupport(packageHeader.GetName(),
												 packageHeader.GetVersion(),
												 language, tempHeader);
				if( rc == FPM_ERR_OK ) {
					LTRACE0(TRACE_JAMES,TEXT("  already installed\n"));
					continue; // language support already installed
				}
				if( rc != FPM_ERR_NOTFOUND ) {
					LTRACE0(TRACE_JAMES,TEXT("  ERROR!\n"));
					ASSERT(FALSE); // unexpected error encountered
					return rc;
				}
				
				// try to find support in the available list
				rc = m_private->available.GetByLanguageSupport(
					packageHeader.GetName(),
					packageHeader.GetVersion(),
					language, tempHeader);
				if( rc != FPM_ERR_OK ) {
					// no support available; return NOLANGUAGE
					LTRACE0(TRACE_JAMES,TEXT("  none available\n"));
					resultList.AddTail(FPMResultData(FPM_ERR_NOLANGUAGE,
													 packageHeader.GetName(),
													 packageHeader.GetVersion(),
													 language,
													 packageHeader.GetDescription(),0));
					bMissingLanguage = TRUE;
					continue;
				}
															   
				// we found support; select for install
				LTRACE2(TRACE_JAMES,TEXT("  selecting %s %s...\n"),
					    tempHeader.GetName(),tempHeader.GetVersion());
				rc = SelectPackage(tempHeader.GetName(),tempHeader.GetVersion());
				if( rc != FPM_ERR_OK ) {
					LTRACE1(TRACE_JAMES,TEXT("  ERROR: %d\n"),(int)rc);
					// can't select for some reason; return NOLANGUAGE
					resultList.AddTail(FPMResultData(FPM_ERR_NOLANGUAGE,
													 packageHeader.GetName(),
													 packageHeader.GetVersion(),
													 language,
													 packageHeader.GetDescription(),0));
					bMissingLanguage = TRUE;
					continue;
				}					

				LTRACE0(TRACE_JAMES,TEXT("    success\n"));

			}
		}

		LTRACE0(TRACE_JAMES,TEXT("Selecting dependencies...\n"));

		// select dependencies, just in case an installed package has deps
		rc = SelectDependencies(resultList,&bSelectedDependencies);
		if( rc != FPM_ERR_OK ) {
			return rc;
		}

		LTRACE1(TRACE_JAMES,TEXT("  Done: %d...\n"),bSelectedDependencies);

	} while( bSelectedDependencies );
		
	if( bMissingLanguage ) {
		FPMLog0(TEXT("SelectLanguageSupport() Done NOLANGUAGE\n"));
		return FPM_ERR_NOLANGUAGE;
	}

	FPMLog0(TEXT("SelectLanguageSupport() Done OK\n"));

	return FPM_ERR_OK;
}


// select new <Selectable> packages available for install
FPMResult FPMSelector::SelectNew(FPMResultList &resultList)
{
	FPMResult rc, ret = FPM_ERR_OK;

	ASSERT(isValidObject());
	ASSERT(resultList.isValidObject());

	FPMLog0(TEXT("SelectNew()...\n"));

	// for each available package
	FPMHeaderSetIterator iter(m_private->available);
	FPMHeader availableHeader;
	while( iter.NextHeader(availableHeader) ) {
		FPMHeader testHeader;

		// check to see if the package is selectable
		if( ! availableHeader.IsSelectable() ) {
			continue;			// if not, skip it
		}

		// check to see if the package is the newest one available
		// we could call SelectPackage() on all of these, but it copies
		// a bunch of memory, so it should be more efficient to filter
		// these out here.  GetByName() returns the newest version if none
		// is specified, so we can compare to see if the header we have is
		// the newest one
		rc = m_private->available.GetByName(availableHeader.GetName(),testHeader);
		if( FPManager::CompareVersions(availableHeader.GetVersion(),
									   testHeader.GetVersion()) != 0 ) {
			continue;			// not the newest
		}

		// we have the newest version of a selectable package; try to select it
		rc = SelectPackage(availableHeader.GetName(),availableHeader.GetVersion());
		switch(rc) {
		case FPM_ERR_OK:		// ok; selected
		case FPM_ERR_ALREADYINSTALLED: // ok; not selected
		case FPM_ERR_DOWNGRADE:	// ok; not selected
			break;				// all okay
		default:
			ASSERT(FALSE);
			ret = rc;			// something unexpected
		}

	}

	// now, select dependencies
	rc = SelectDependencies(resultList);
	if( rc != FPM_ERR_OK ) {
		ret = rc;
	}

	FPMLog1(TEXT("SelectNew() Done %d\n"),ret);

	return ret;
}


// select upgrades available for currently-installed packages
FPMResult FPMSelector::SelectUpgrades(FPMResultList &resultList)
{
	FPMResult rc, ret = FPM_ERR_OK;

	ASSERT(isValidObject());
	ASSERT(resultList.isValidObject());

	FPMLog0(TEXT("SelectUpgrades()...\n"));

	// for each package currently installed
	FPMHeaderSetIterator iter(m_private->installed);
	FPMHeader installedHeader;
	while( iter.NextHeader(installedHeader) ) {
		FPMHeader availableHeader;

		// get the newest one in the repository
		rc = m_private->available.GetByName(installedHeader.GetName(),availableHeader);
		if( rc == FPM_ERR_NOTFOUND ) {
			continue;			// no version available
		}
		if( rc != FPM_ERR_OK ) {
			ASSERT(FALSE);
			return rc;			// some other error
		}

		// check the version to see if it is newer than the one we have
		if( FPManager::CompareVersions(availableHeader.GetVersion(),
									   installedHeader.GetVersion()) > 0 ) {
			// it's newer; select it for install
			rc = SelectPackage(installedHeader.GetName(),NULL);
			if( rc != FPM_ERR_OK ) {
				ASSERT(FALSE);
				return rc;
			}
		}
	}

	// now, select dependencies
	rc = SelectDependencies(resultList);
	if( rc != FPM_ERR_OK ) {
		ret = rc;
	}

	FPMLog1(TEXT("SelectUpgrades() Done %d\n"),ret);

	return ret;
}


// select packages to satisfy dependencies
// first, merge 
FPMResult FPMSelector::SelectDependencies(FPMResultList &resultList,
										  BOOL *bSelectedSomething)
{
	FPMResult rc;

	ASSERT(isValidObject());
	ASSERT(resultList.isValidObject());

	FPMLog0(TEXT("SelectDependencies()...\n"));

	// clear the flag (if provided)
	if( bSelectedSomething != NULL ) {
		*bSelectedSomething = FALSE;
	}

	// loop until all dependencies satisfied, or we have dependencies that
	// can't be satisfied
	BOOL bDone = FALSE, bFailedDependency = FALSE;
	do {
		FPMHeaderSetIndex target;
		FPMResultList depList(1);

		// simulate the final installation
		rc = _simulateInstall(target);
		if( rc != FPM_ERR_OK ) {
			ASSERT(FALSE);
			return rc;
		}

		// check dependencies in the target
		rc = target.CheckDependencies(depList);
		switch(rc) {
		case FPM_ERR_DEPENDENCY:
			break;				// ok; we have work to do
		case FPM_ERR_OK:
			bDone = TRUE;		// all dependencies satisfied; we're done
			continue;
		default:
			ASSERT(FALSE);		// unexpected error
			return rc;
		}

		// try to satisfy each dependency
		FPMResultListIterator iter(depList);
		const FPMResultData *data;
		while( (data = iter.nextElement()) != NULL ) {

			// first, make sure this is a dependency error
			if( data->m_result != FPM_ERR_DEPENDENCY ) {
				ASSERT(FALSE);
				return rc;
			}

			// now, try to satisfy it
//  			LTRACE2(TRACE_JAMES,TEXT("Selecting dependency: %s %s\n"),
//  					(LPCTSTR)data->m_packageName, (LPCTSTR)data->m_packageVersion);
			rc = SelectPackage(data->m_packageName,data->m_packageVersion);
			if( rc != FPM_ERR_OK ) {
				resultList.AddTail(*data); // log the failed dependency
				bFailedDependency = TRUE;
				break;
			}
			if( rc == FPM_ERR_OK && bSelectedSomething != NULL ) {
				*bSelectedSomething = TRUE;
			}

		}

	} while( !bDone && !bFailedDependency );
		
	FPMLog0(TEXT("SelectDependencies() Done.\n"));

	if( bFailedDependency ) {
		return FPM_ERR_DEPENDENCY;
	}

	return FPM_ERR_OK;
}



FPMResult FPMSelector::GetSelection(FPMResultList &resultList, BOOL bSelectableOnly)
{
	FPMHeader header;
	FPMHeaderSetIndexIterator iter(m_private->selected);

	ASSERT(isValidObject());

	while( iter.NextHeader(header) ) {
		FPMResult tag = FPM_ERR_OK;
		FPMHeader dummyHeader;

		// check to see if a version of the package is already installed
		if( m_private->installed.GetByName(header.GetName(),dummyHeader) == FPM_ERR_OK ) {
			// this had better be an upgrade
			ASSERT(FPManager::CompareVersions(header.GetVersion(),
											  dummyHeader.GetVersion()) >= 0);
			// mark this one as an upgrade
			tag = FPM_ERR_UPGRADE;
		}

		// add this package to the list if:
		//   1.  The caller hasn't specified filtering with bSelectableOnly, OR
		//   2.  The header is selectable, OR
		//   3.  The package is an upgrade
		if( ! bSelectableOnly ||
			header.IsSelectable() ||
			tag == FPM_ERR_UPGRADE ) {

			// make the entry
			resultList.AddTail(FPMResultData(tag,
											 header.GetName(),
											 header.GetVersion(),
											 header.GetFilename(),
											 header.GetDescription(),
											 header.GetFileSize()));
		}
	}

	return FPM_ERR_OK;
	
}


FPMResult FPMSelector::GetPotentialLanguageSet(CTStringList &outList)
{
	CTStringHashTable langHash;

	ASSERT(isValidObject());
	ASSERT(outList.isValidObject());

	FPMHeader header;
	FPMLanguageList langList;

	// get language entries for installed packages
	FPMHeaderSetIterator installedIter(m_private->installed);
	while( installedIter.NextHeader(header) ) {
		header.GetLanguageList(langList);
	}

	// and for available packages
	FPMHeaderSetIterator availableIter(m_private->available);
	while( availableIter.NextHeader(header) ) {
		header.GetLanguageList(langList);
	}

	// now, process the list, building a set of unique languages
	for( int i=0; i < langList.Length(); i++ ) {
		const FPMLanguage *lang = langList.Get(i);
		if( lang == NULL ) continue;

		// set it into the hash (ignore collisions)
		langHash.Add(lang->language,lang->language);
	}
	
	// now, iterate the unique language codes into the output list
	CTStringHashTableIterator hashIter(langHash);
	LPCTSTR langCode;
	while( (langCode = hashIter.nextValue()) != NULL ) {
		outList.AddInOrder(langCode);
	}

	return FPM_ERR_OK;
}


FPMResult FPMSelector::CheckInstall(const CTStringList &fileList,
									FPMResultList &resultList)
{
	FPMResult rc, ret = FPM_ERR_OK;
	int i;

	ASSERT(isValidObject());
	ASSERT(fileList.isValidObject());
	ASSERT(resultList.isValidObject());

	FPMLog0(TEXT("CheckInstall()...\n"));

	// add each file as available
	for(i=0; i < fileList.Length(); i++) {
		LPCTSTR filename = fileList.Get(i);
		ASSERT(filename != NULL);

		// we call available.AddFile instead of AddAvailableFile here
		// because we don't want to ignore FPM_ERR_PLATFORM
		rc = m_private->available.AddFile(filename);
		if( rc != FPM_ERR_OK ) {
			ret = rc;
			resultList.AddTail(FPMResultData(rc,NULL,NULL,filename,NULL,0));
		}
	}

	// abort if there were errors
	if( ret != FPM_ERR_OK ) {
		FPMLog1(TEXT("CheckInstall() Done %d\n"),ret);
		return ret;
	}

	// now, select them all for install
	for(i=0; i < fileList.Length(); i++) {
		LPCTSTR filename = fileList.Get(i);
		ASSERT(filename != NULL);

		FPMHeader header(filename);
		if( ! header.isValidState() ) {
			ret = header.GetState();
			resultList.AddTail(FPMResultData(header.GetState(),NULL,NULL,filename,NULL,0));
		}

		// TODO: verify package before forcing overinstall
		rc = SelectPackage(header.GetName(),header.GetVersion(),TRUE);
		if( rc != FPM_ERR_OK ) {
			resultList.AddTail(FPMResultData(rc,header.GetName(),header.GetVersion(),
											 filename,header.GetDescription(),0));
			// don't return an error code for downgrade (put it in the list only)
			if( rc != FPM_ERR_DOWNGRADE ) {
				ret = rc;
			}
		}
	}

	// abort if any errors
	if( ret != FPM_ERR_OK ) {
		FPMLog1(TEXT("CheckInstall() Done %d\n"),ret);
		return ret;
	}
		
	// now, select dependencies to make sure they are all satisfied
	rc = SelectDependencies(resultList);
	if( rc != FPM_ERR_OK ) {
		ret = rc;
	}

	FPMLog1(TEXT("CheckInstall() Done %d\n"),ret);

	return ret;
}


FPMResult FPMSelector::TestSetInstalled(LPCTSTR filename)
{
	int fd;
	FPMResult rc;

	ASSERT(isValidObject());

	// check argument
	if( filename == NULL ) {
		ASSERT(FALSE);
		return FPM_ERR_ARGUMENT;
	}

	// open the file for reading
	fd = _topen(filename,O_RDONLY|O_BINARY);
	//LTRACE1(TRACE_JAMES,TEXT("File Descriptor: %d\n"),fd);
	if( fd < 0 ) {
		ASSERT(FALSE);
		return FPM_ERR_IO;
	}

	// read the header set out of the file
	rc = m_private->installed.ReadXML(fd);
	close(fd);
	if( rc != FPM_ERR_OK ) {
		ASSERT(FALSE);
		return rc;
	}

	return FPM_ERR_OK;
}



FPMResult FPMSelector::TestGetPlatform(CTString &platform)
{
	ASSERT(isValidObject());

	platform = FPM_platform.GetPlatformString();
	if( platform.GetPointer() == NULL ) {
		FPMLog0(TEXT("FPM_ERR_INTERNAL\n"));
		return FPM_ERR_INTERNAL;
	}

	return FPM_ERR_OK;
}


BOOL FPMSelector::TestMatchPlatform(LPCTSTR platformIn)
{
	ASSERT(isValidObject());

	return FPM_platform.MatchPlatformString(platformIn);
}


FPMResult FPMSelector::_simulateInstall(FPMHeaderSetIndex &target)
{
	FPMResult rc, rc2;

	ASSERT(isValidObject());
	ASSERT(target.isValidObject());

	// start with an empty set
	rc = target.RemoveAll();
	if( rc != FPM_ERR_OK ) {
		ASSERT(FALSE);
		return rc;
	}

	// put the selected packages in the target
	rc = target.AddHeaderSetIndex(m_private->selected);
	if( rc != FPM_ERR_OK ) {
		ASSERT(FALSE);
		return rc;
	}

	// loop through the installed packages, adding only ones that aren't
	// being replaced by selected packages
	FPMHeaderSetIterator iter(m_private->installed);
	FPMHeader header, dummy;
	while( iter.NextHeader(header) ) {
		rc = target.GetHeader(header.GetName(),dummy);
		switch(rc) {
		case FPM_ERR_OK:
			// it's already there; skip this one
			break;
		case FPM_ERR_NOTFOUND:
			// it's not there; add it
			rc2 = target.AddHeader(header);
			if( rc2 != FPM_ERR_OK ) {
				ASSERT(FALSE);
				return rc2;
			}
			break;
		default:
			// some other error
			ASSERT(FALSE)
			return rc;
		}
	}

	return FPM_ERR_OK;
}




@


1.1.2.1
log
@*** empty log message ***
@
text
@a21 1
	  obsolete(FALSE),
a57 1
	m_private->obsolete.RemoveAll();
d199 1
a199 1
	FPMHeader selectedHeader, installedHeader, previousHeader, obsoleteHeader;
a265 55

	// if the package was obsolete, remove it from the obsolete list
	rc = m_private->obsolete.GetHeader(selectedHeader.GetName(),obsoleteHeader);
	if( rc == FPM_ERR_OK ) {
		// we really shouldn't be selecting an obsolete package, so I want
		// to know when we do
		ASSERT(FALSE);
		m_private->obsolete.RemoveHeader(selectedHeader.GetName());
	}
			
	return FPM_ERR_OK;
}



FPMResult FPMSelector::ObsoletePackage(LPCTSTR packageName)
{
	FPMHeader header;
	FPMResult rc;

	ASSERT(isValidObject());

	// check arguments
	if( packageName == NULL ) {
		ASSERT(FALSE);
		return FPM_ERR_ARGUMENT;
	}

	// if the package is already obsolete, return OK
	rc = m_private->obsolete.GetHeader(packageName,header);
	if( rc == FPM_ERR_OK ) {
		return FPM_ERR_OK;
	}

	// if the package is selected for install, don't make it obsolete
	rc = m_private->selected.GetHeader(packageName,header);
	if( rc == FPM_ERR_OK ) {
		// we really shouldn't be obsoleting a selected package, so I want
		// to know when we do
		ASSERT(FALSE);
		return FPM_ERR_OK;
	}

	// get the header of the installed package
	rc = m_private->installed.GetByName(packageName,header);
	if( rc != FPM_ERR_OK ) {
		return rc;
	}

	// add it to the obsolete list
	rc = m_private->obsolete.AddHeader(header);
	if( rc != FPM_ERR_OK ) {
		ASSERT(FALSE);
		return rc;
	}
a560 35
// find obsolete packages and mark them as such
// there are two ways a package could be considered obsolete:
//   1.  Another package selected for install obsoletes it
//   2.  It provides languages for a package no longer on the system
FPMResult FPMSelector::SelectObsolete(FPMResultList &resultList)
{
	FPMResult rc;

	rc = _markObsoletePackages(resultList);
	if (rc != FPM_ERR_OK)
	{
		return rc;
	}

	rc = _markObsoleteLanguagePacks(resultList);
	if (rc != FPM_ERR_OK)
	{
		return rc;
	}

	return FPM_ERR_OK;
}


FPMResult FPMSelector::_markObsoletePackages(FPMResultList &resultList)
{
	return FPM_ERR_OK;
}


FPMResult FPMSelector::_markObsoleteLanguagePacks(FPMResultList &resultList)
{
	return FPM_ERR_OK;
}

a650 1
	// packages to be installed
a681 11
	// packages to be removed
	FPMHeaderSetIndexIterator obsoleteIter(m_private->obsolete);
	while( obsoleteIter.NextHeader(header) ) {
		resultList.AddTail(FPMResultData(FPM_ERR_OBSOLETE,
										 header.GetName(),
										 header.GetVersion(),
										 header.GetFilename(),
										 header.GetDescription(),
										 header.GetFileSize()));
	}

a883 16

		// don't add obsolete packages
		rc = m_private->obsolete.GetHeader(header.GetName(),dummy);
		switch(rc) {
		case FPM_ERR_OK:
			// it's obsolete, so skip this one
			continue;
		case FPM_ERR_NOTFOUND:
			// not obsolete; continue
			break;
		default:
			// some other error
			ASSERT(FALSE);
			return rc;
		}
			
@


1.1.2.2
log
@*** empty log message ***
@
text
@a202 1
	BOOL previouslySelected = FALSE;
a211 7
	// check first to see if the package has been obsoleted
	rc = m_private->obsolete.GetHeader(packageName,obsoleteHeader);
	if( rc == FPM_ERR_OK ) {
		// selecting a package that has been obsoleted is a dependency conflict
		return FPM_ERR_CONFLICT;
	}

d218 21
a241 2
		previouslySelected = TRUE;

a261 24
	// if not previousln selected, check to see if the package is already installed
	if( !previouslySelected )
	{
		rc = m_private->installed.GetByName(packageName,installedHeader);
		if( rc == FPM_ERR_OK ) {
			// if it is, check the version
			int cmp = FPManager::CompareVersions(selectedHeader.GetVersion(),
												 installedHeader.GetVersion());
			if( cmp < 0 ) {
				// older version selected
				return FPM_ERR_DOWNGRADE;
			}
			if( cmp == 0 ) {
				// same version selected
				if( ! forceOverInstall ) {
					return FPM_ERR_ALREADYINSTALLED;
				}
				// drop thru as though this one were newer if forceOverInstall
			}
			
			// drop thru if newer version selected
		}
	}

d269 9
a282 4
// To obsolete a package:
//   1.  If it is selected for install, deselect it.
//   2.  If it is currently installed, put it on the obsolete list
//
d302 1
a302 1
	// if the package is selected for install, deselect it
d305 4
a308 6
		rc = m_private->selected.RemoveHeader(packageName);
		if( rc != FPM_ERR_OK )
		{
			ASSERT(FALSE);
			return rc;
		}
d313 2
a314 4
	if( rc == FPM_ERR_NOTFOUND )
	{
		// also look in the available list
		rc = m_private->available.GetByName(packageName,header);
d316 6
a321 8
	if( rc == FPM_ERR_OK )
	{
		// add it to the obsolete list
		rc = m_private->obsolete.AddHeader(header);
		if( rc != FPM_ERR_OK ) {
			ASSERT(FALSE);
			return rc;
		}
d497 1
a497 1

d621 2
a622 3
//   2.  It provides one or more languages for one or more packages no
//       longer on the system
FPMResult FPMSelector::_selectObsolete()
d626 1
a626 1
	rc = _selectObsoletePredecessors();
a628 1

d632 1
a632 1
	rc = _selectObsoleteLanguagePacks();
d642 1
a642 3
// check for obsolete predecessors that will be on the system after the
// install and make sure they are either deselected or marked to be removed
FPMResult FPMSelector::_selectObsoletePredecessors()
d644 1
a644 53
	ASSERT(isValidObject());

	FPMResult ret = FPM_ERR_OK, rc;
	FPMHeaderSetIndex target;

	// simulate the final installation
	rc = _simulateInstall(target);
	if( rc != FPM_ERR_OK ) {
		ASSERT(FALSE);
		return rc;
	}
	
	// for each package in the final installation
	FPMHeaderSetIndexIterator iter(target);
	FPMHeader header;
	CTStringList predecessors;
	int i;
	while( iter.NextHeader(header) )
	{
		// get a list of predecessors
		predecessors.RemoveAll();
		rc = header.GetPredecessorList(predecessors);
		if( rc != FPM_ERR_OK )
		{
			ASSERT(FALSE);
			ret = rc;
			continue;
		}

		// mark them as obsolete
		for( i=0; i < predecessors.Length(); i++ )
		{
			LPCTSTR pred = predecessors.Get(i);
			if( pred == NULL )
			{
				ASSERT(FALSE);
				continue;
			}

			FPMLog3(TEXT("Package %s obsolete (predecessor of %s %s)\n"),
					pred,
					header.GetName(), header.GetVersion());
			rc = ObsoletePackage(pred);
			if( rc != FPM_ERR_OK )
			{
				ASSERT(FALSE);
				ret = rc;
				continue;
			}
		}
	}

	return ret;
d648 1
a648 1
FPMResult FPMSelector::_selectObsoleteLanguagePacks()
d650 1
a650 86
	ASSERT(isValidObject());

	FPMResult ret = FPM_ERR_OK, rc;
	FPMHeaderSetIndex target;

	// simulate the final installation
	rc = _simulateInstall(target);
	if( rc != FPM_ERR_OK ) {
		ASSERT(FALSE);
		return rc;
	}
	
	// for each package in the final installation
	FPMHeaderSetIndexIterator iter(target);
	FPMHeader header;    // header being examined; contains language tags
	FPMHeader refHeader; // header referenced by language tags
	FPMLanguageList languages;
	int i;
	while( iter.NextHeader(header) )
	{
		// get a list of languages provided
		languages.RemoveAll();
		rc = header.GetLanguageList(languages);
		if( rc != FPM_ERR_OK )
		{
			ASSERT(FALSE);
			ret = rc;
			continue;
		}

		// for each language tag
		BOOL pkgIsObsolete = FALSE;
		for( i=0; i < languages.Length(); i++ )
		{
			const FPMLanguage *lang = languages.Get(i);
			if( lang == NULL )
			{
				ASSERT(FALSE);
				continue;
			}

			// check to see if the referenced package will be on the system
			rc = target.GetHeader(lang->packageName,refHeader);
			if( rc == FPM_ERR_NOTFOUND )
			{
				pkgIsObsolete = TRUE;
				FPMLog4(TEXT("Language pack %s obsolete (%s for %s %s)\n"),
						header.GetName(),
						(LPCTSTR)(lang->language), 
						(LPCTSTR)(lang->packageName),
						(LPCTSTR)(lang->version));
			}
			if( rc != FPM_ERR_OK )
			{
				ASSERT(FALSE);
				ret = rc;
				continue;
			}

			// found the target; check the version
			if( FPManager::CompareVersions(lang->version,refHeader.GetVersion()) != 0 )
			{
				// versions don't match
				pkgIsObsolete = TRUE;
				FPMLog4(TEXT("Language pack %s obsolete (%s for %s %s)\n"),
						header.GetName(),
						(LPCTSTR)(lang->language),
						(LPCTSTR)(lang->packageName),
						(LPCTSTR)(lang->version));
			}

		}

		if( pkgIsObsolete )
		{
			rc = ObsoletePackage(header.GetName());
			if( rc != FPM_ERR_OK )
			{
				ASSERT(FALSE);
				ret = rc;
				continue;
			}
		}
	}

	return ret;
d658 1
a658 1
	FPMResult rc, ret = FPM_ERR_OK;
a676 9
		// first, obsolete any unnecessary packages
		rc = _selectObsolete();
		if( rc != FPM_ERR_OK )
		{
			ASSERT(FALSE);
			ret = rc;
			break;				// stop if an error occurs
		}

d709 2
d713 1
a713 17
				// report dependency conflicts
				if( rc == FPM_ERR_CONFLICT )
				{
					resultList.AddTail(FPMResultData(FPM_ERR_CONFLICT,
													 data->m_packageName,
													 data->m_packageVersion,
													 data->m_filename,
													 data->m_packageDescription,
													 data->m_fileSize));
					ret = FPM_ERR_CONFLICT;
				}
				else
				{
					// otherwise, just use the original data
					resultList.AddTail(*data); // log the failed dependency
					ret = data->m_result;
				}
d727 5
a731 1
	return ret;
d738 2
a739 1
	FPMHeader header, dummyHeader;
d743 1
a743 2
	// for each selected package
	FPMHeaderSetIndexIterator iter(m_private->selected);
d778 6
a783 10
		// only report ones that are currently installed
		if( m_private->installed.GetByName(header.GetName(),dummyHeader) == FPM_ERR_OK )
		{
			resultList.AddTail(FPMResultData(FPM_ERR_OBSOLETE,
											 header.GetName(),
											 header.GetVersion(),
											 header.GetFilename(),
											 header.GetDescription(),
											 header.GetFileSize()));
		}
@


