Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

240 lines
7.7 KiB

//====== Copyright © 1996-2005, Valve Corporation, All rights reserved. =======
//
// Purpose:
//
//=============================================================================
#include "vpc.h"
#include "p4lib/ip4.h"
// fix filenames that have double backslashes at the start
// (Perforce will return this if the root of a clientspec is e.g. "D:\")
static const char* FixPerforceFilename( const char *filename )
{
if ( filename && Q_strlen( filename ) > 2 && !Q_strnicmp( filename + 1, ":\\\\", 3 ) )
{
// strip out the first backslash
static char newFilename[MAX_PATH];
Q_snprintf( newFilename, sizeof(newFilename), "%c:%s",
filename[0],
&filename[3]
);
return newFilename;
}
return filename;
}
static void GetChangelistFilenames( CUtlVector<int> &changelists, CUtlVector<CUtlString> &changelistFilenames )
{
// P4 interface didn't initalize in main - abort
if ( !p4 )
{
g_pVPC->VPCWarning( "P4SLN: Perforce interface not available. Unable to generate solution from the given Perforce changelist." );
return;
}
CUtlVector<P4File_t> fileList;
int changeListIndex = 0;
if ( changelists.Count() )
{
changeListIndex = changelists[0];
}
if ( changeListIndex == -1 )
{
p4->GetOpenedFileList( fileList, false );
}
else if ( changeListIndex == 0 )
{
p4->GetOpenedFileList( fileList, true );
}
else
{
CUtlVector<P4File_t> partialFileList;
FOR_EACH_VEC( changelists, i )
{
p4->GetFileListInChangelist( changelists[i], partialFileList );
FOR_EACH_VEC( partialFileList, j )
{
fileList.AddToTail( partialFileList[j] );
}
}
}
// If -1 is in the changelist index, then include all.
bool bIncludeAllChangelists = ( changelists.Find( -1 ) != changelists.InvalidIndex() );
for ( int i=0; i < fileList.Count(); i++ )
{
if ( bIncludeAllChangelists || changelists.Find( fileList[i].m_iChangelist ) != changelists.InvalidIndex() )
{
const char *pFilename = p4->String( fileList[i].m_sLocalFile );
const char *pNewFilename = FixPerforceFilename( pFilename );
changelistFilenames.AddToTail( pNewFilename );
}
}
}
static void AddAdditionalDependencies( CUtlVector<CDependency_Project*> &projects, CUtlVector<CDependency_Project*> &allProjects )
{
for ( int nProject=0; nProject < projects.Count(); nProject++ )
{
CDependency_Project *pCurProject = projects[nProject];
// Look at all the $AdditionalProjectDependencies projects for this one.
for ( int nDependency=0; nDependency < pCurProject->m_AdditionalProjectDependencies.Count(); nDependency++ )
{
const char *pLookingFor = pCurProject->m_AdditionalProjectDependencies[nDependency].String();
// Search for a match in allProjects.
int nFound = CDependency_Project::FindByProjectName( allProjects, pLookingFor );
if ( nFound == -1 )
{
g_pVPC->VPCError( "P4SLN: Project %s lists '%s' in its $AdditionalProjectDependencies, but there is no project by that name.", pCurProject->GetName(), pLookingFor );
}
else
{
// Got a match.
CDependency_Project *pFound = allProjects[nFound];
int nTest = projects.Find( pFound );
if ( nTest == projects.InvalidIndex() )
{
projects.AddToTail( pFound );
}
}
}
}
}
static void GetProjectsDependingOnFiles( CProjectDependencyGraph &dependencyGraph, CUtlVector<CUtlString> &filenames, CUtlVector<CDependency_Project*> &projects )
{
// Now figure out the projects that depend on each of these files.
for ( int iFile=0; iFile < filenames.Count(); iFile++ )
{
CDependency *pFile = dependencyGraph.FindDependency( filenames[iFile].String() );
if ( !pFile )
{
char szRelative[MAX_PATH];
if ( !V_MakeRelativePath( filenames[iFile].String(), g_pVPC->GetSourcePath(), szRelative, sizeof( szRelative ) ) )
{
V_strncpy( szRelative, filenames[iFile].String(), sizeof( szRelative ) );
}
// This probably means their build commands on the command line didn't include
// any projects that included this file.
g_pVPC->VPCWarning( "%s is not found in the projects searched.", szRelative );
continue;
}
// Now see which projects depend on this file.
for ( int iProject=0; iProject < dependencyGraph.m_Projects.Count(); iProject++ )
{
CDependency_Project *pProject = dependencyGraph.m_Projects[iProject];
if ( pProject->DependsOn( pFile, k_EDependsOnFlagCheckNormalDependencies | k_EDependsOnFlagRecurse | k_EDependsOnFlagTraversePastLibs | k_EDependsOnFlagCheckAdditionalDependencies ) )
{
if ( projects.Find( pProject ) == -1 )
projects.AddToTail( pProject );
}
}
}
//
// Make sure that each of the dependent projects are members of the "everything" group
//
// Find the everything group
groupTagIndex_t everythingIndex = VPC_Group_FindOrCreateGroupTag( "everything", false );
if ( everythingIndex != INVALID_INDEX )
{
CUtlVector<int> doomedProjectIndices;
CUtlVector<int> everythingProjectsIndices;
FOR_EACH_VEC( g_pVPC->m_GroupTags[everythingIndex].groups, m )
{
FOR_EACH_VEC( g_pVPC->m_Groups[g_pVPC->m_GroupTags[everythingIndex].groups[m]].projects, n )
{
everythingProjectsIndices.AddToTail( g_pVPC->m_Groups[g_pVPC->m_GroupTags[everythingIndex].groups[m]].projects[n] );
}
}
// Search for each dependency project in the everything group
FOR_EACH_VEC( projects, j )
{
// If it wasn't in the everything group then mark it for removal
if ( everythingProjectsIndices.InvalidIndex() == everythingProjectsIndices.Find( projects[j]->m_iProjectIndex ) )
{
doomedProjectIndices.AddToHead( j );
}
}
// Remove the projects that aren't in the everything solution
FOR_EACH_VEC( doomedProjectIndices, p )
{
projects.Remove( doomedProjectIndices[p] );
}
}
}
static void UpdateProjects( CUtlVector<CDependency_Project*> &projects )
{
for ( int iProject=0; iProject < projects.Count(); iProject++ )
{
Log_Msg( LOG_VPC, "\n" );
CDependency_Project *pDependency = projects[iProject];
pDependency->ExportProjectParameters();
if ( g_pVPC->IsForceGenerate() || !g_pVPC->IsProjectCurrent( g_pVPC->GetOutputFilename() ) )
{
project_t *pProject = &g_pVPC->m_Projects[ pDependency->m_iProjectIndex ];
g_pVPC->SetProjectName( pProject->name.String() );
g_pVPC->SetLoadAddressName( pProject->name.String() );
g_pVPC->ParseProjectScript( pDependency->m_szStoredScriptName, 0, false, true );
}
}
}
void GenerateSolutionForPerforceChangelist( CProjectDependencyGraph &dependencyGraph, CUtlVector<int> &changelists, IBaseSolutionGenerator *pGenerator, const char *pSolutionFilename )
{
// We want to check against ALL projects in projects.vgc.
int nDepFlags = BUILDPROJDEPS_FULL_DEPENDENCY_SET | BUILDPROJDEPS_CHECK_ALL_PROJECTS;
dependencyGraph.BuildProjectDependencies( nDepFlags );
// Get the list of files from Perforce.
CUtlVector<CUtlString> filenames;
GetChangelistFilenames( changelists, filenames );
// Get the list of projects that depend on these files.
CUtlVector<CDependency_Project*> projects;
GetProjectsDependingOnFiles( dependencyGraph, filenames, projects );
// Add g_targetProjects, which will include any other projects that they added on the command line with +tier0 *engine syntax.
CUtlVector<CDependency_Project*> commandLineProjects;
dependencyGraph.TranslateProjectIndicesToDependencyProjects( g_pVPC->m_TargetProjects, commandLineProjects );
for ( int i=0; i < commandLineProjects.Count(); i++ )
{
if ( projects.Find( commandLineProjects[i] ) == projects.InvalidIndex() )
projects.AddToTail( commandLineProjects[i] );
}
// Make sure the latest .vcproj files are generated.
UpdateProjects( projects );
// List the projects.
Msg( "Dependent projects: \n\n" );
for ( int i=0; i < projects.Count(); i++ )
Msg( "%s\n", projects[i]->GetName() );
// Write the solution file.
pGenerator->GenerateSolutionFile( pSolutionFilename, projects );
}