// GetRemotePath //------------------------------------------------------------------------------ void ToolManifest::GetRemotePath( AString & path ) const { VERIFY( FileIO::GetTempDir( path ) ); AStackString<> subDir; #if defined( __WINDOWS__ ) subDir.Format( ".fbuild.tmp\\worker\\toolchain.%016llx\\", m_ToolId ); #else subDir.Format( "_fbuild.tmp/worker/toolchain.%016llx/", m_ToolId ); #endif path += subDir; }
// Lock //------------------------------------------------------------------------------ bool SystemMutex::TryLock() { #if defined( __WINDOWS__ ) void * handle = (void *)CreateMutex( nullptr, TRUE, m_Name.Get() ); if ( GetLastError() == ERROR_ALREADY_EXISTS ) { if ( ( handle != INVALID_HANDLE_VALUE ) && ( handle != 0 ) ) { CloseHandle( handle ); } return false; } m_Handle = handle; return true; #elif defined( __LINUX__ ) || defined( __APPLE__ ) AStackString<> tempFileName; tempFileName.Format( "/var/run/%s.lock", m_Name.Get() ); m_Handle = open( tempFileName.Get(), O_CREAT | O_RDWR, 0666 ); int rc = flock( m_Handle, LOCK_EX | LOCK_NB ); if ( rc ) { if ( errno == EWOULDBLOCK ) { return false; // locked by another process } } return true; // we own it now #else #error Unknown platform #endif }
// DoToggleSection //------------------------------------------------------------------------------ void Report::DoToggleSection( size_t numMore ) { static int tableId = 0; ++tableId; AStackString<> tableIdStr; tableIdStr.Format( "table%u", tableId ); DoTableStop(); AStackString<> more; if ( numMore ) { more.Format( "%u ", (uint32_t)numMore ); } Write( "<a href='javascript:toggleTable(\"%s\");'>%sMore...</a>\n", tableIdStr.Get(), more.Get() ); DoTableStart( DEFAULT_TABLE_WIDTH, tableIdStr.Get(), true ); // hide table }
int LaunchSubProcess( const AString & args ) { // try to make a copy of our exe AStackString<> exeName; Env::GetExePath( exeName ); AStackString<> exeNameCopy( exeName ); exeNameCopy += ".copy"; Timer t; while ( FileIO::FileCopy( exeName.Get(), exeNameCopy.Get() ) == false ) { if ( t.GetElapsed() > 5.0f ) { AStackString<> msg; msg.Format( "Failed to make sub-process copy - error: %u (0x%x)\n\nSrc: %s\nDst: %s\n", Env::GetLastErr(), Env::GetLastErr(), exeName.Get(), exeNameCopy.Get() ); ShowMsgBox( msg.Get() ); return -2; } Thread::Sleep( 100 ); } AStackString<> argsCopy( args ); argsCopy += " -subprocess"; // allow subprocess to access the mutex g_OneProcessMutex.Unlock(); Process p; #if defined( __WINDOWS__ ) p.DisableHandleRedirection(); // TODO:MAC TODO:LINUX is this needed? #endif p.Spawn( exeNameCopy.Get(), argsCopy.Get(), nullptr, nullptr ); p.Detach(); return 0; }
// Load //------------------------------------------------------------------------------ /*static*/ Object * ReflectionInfo::Load( const char * scopedName ) { AStackString<> fullPath; fullPath.Format( "Reflection\\%s.obj", scopedName ); FileStream fs; if ( fs.Open( fullPath.Get(), FileStream::READ_ONLY ) == false ) { return nullptr; } const size_t fileSize = (size_t)fs.GetFileSize(); AutoPtr< char > mem( (char *)Alloc( fileSize + 1 ) ); if ( fs.Read( mem.Get(), fileSize ) != fileSize ) { return nullptr; } mem.Get()[ fileSize ] = 0; ConstMemoryStream ms( mem.Get(), fileSize + 1 ); TextReader tr( ms ); RefObject * refObject = tr.Read(); ASSERT( !refObject || DynamicCast< Object >( refObject ) ); return (Object *)refObject; }
PRAGMA_DISABLE_POP_MSVC // warning C6262: Function uses '262212' bytes of stack // DoPieChart //------------------------------------------------------------------------------ void Report::DoPieChart( const Array< PieItem > & items, const char * units ) { AStackString<> buffer; uint32_t height = Math::Max< uint32_t >( 140, 40 + 25 * (uint32_t)items.GetSize() ); m_NumPieCharts++; Write( "<section>\n" ); Write( "<div>\n" ); Write( "<canvas id=\"canvas%u\" width=\"500\" height=\"%u\">\n", m_NumPieCharts, height ); Write( "HTML5 Canvas support required.\n" ); Write( "</canvas>\n" ); Write( "</div>\n" ); Write( "<script type=\"text/javascript\">\n" ); Write( " var myData = [" ); for ( size_t i=0; i<items.GetSize(); ++i ) { if ( i > 0 ) { Write( "," ); } buffer.Format( "%2.3f", items[ i ].value ); Write( buffer.Get() ); } Write( "];\n" ); Write( " var myLabels = [" ); for ( size_t i=0; i<items.GetSize(); ++i ) { if ( i > 0 ) { Write( "," ); } Write( "\"%s\"", items[ i ].label ); } Write( "];\n" ); Write( " var myColors = [" ); for ( size_t i=0; i<items.GetSize(); ++i ) { if ( i > 0 ) { Write( "," ); } Write( "\"#%x\"", items[ i ].color ); } Write( "];\n" ); Write( " plotData(\"canvas%u\",myData,myLabels,myColors,\"%s\");\n", m_NumPieCharts, units ); Write( "</script>\n" ); Write( "</section>\n" ); }
// GenerateTempFileName //------------------------------------------------------------------------------ void TestFileIO::GenerateTempFileName( AString & tmpFileName ) const { // get system temp folder VERIFY( FileIO::GetTempDir( tmpFileName ) ); // add process unique identifier AStackString<> buffer; buffer.Format( "TestFileIO.%u.%u", Process::GetCurrentId(), m_Random.GetRand() ); tmpFileName += buffer; }
// UpdateUI //------------------------------------------------------------------------------ void Worker::UpdateUI() { // throttle UI updates if ( m_UIUpdateTimer.GetElapsed() < 0.25f ) { return; } // title bar size_t numConnections = m_ConnectionPool->GetNumConnections(); AStackString<> status; status.Format( "%u Connections", (uint32_t)numConnections ); if ( m_RestartNeeded ) { status += " (Restart Pending)"; } #if defined( __WINDOWS__ ) if ( m_LastDiskSpaceResult == 0 ) { status += " (Low Disk Space)"; } #endif m_MainWindow->SetStatus( status.Get() ); // thread output JobQueueRemote & jqr = JobQueueRemote::Get(); const size_t numWorkers = jqr.GetNumWorkers(); for ( size_t i=0; i<numWorkers; ++i ) { // get status of worker AStackString<> workerStatus; AStackString<> hostName; bool isIdle; jqr.GetWorkerStatus( i, hostName, workerStatus, isIdle ); // are we syncing tools? if ( isIdle ) { AStackString<> statusStr; if ( m_ConnectionPool->IsSynchingTool( statusStr ) ) { // show status of synchronization workerStatus = statusStr; } } // reflect in UI m_MainWindow->SetWorkerState( i, hostName, workerStatus ); } m_UIUpdateTimer.Start(); }
// Format //------------------------------------------------------------------------------ void TestAString::Format() const { // Create a really long input string AStackString<> longInput; const size_t longStringLen( 1024 * 1024 ); for ( size_t i=0; i<longStringLen; ++i ) { longInput += 'A'; } // Make sure we correctly handle formatting large strings AStackString<> buffer; buffer.Format( "%s", longInput.Get() ); TEST_ASSERT( buffer.GetLength() == longStringLen ); TEST_ASSERT( AString::StrLen( buffer.Get() ) == longStringLen ); }
// DoTableStart //------------------------------------------------------------------------------ void Report::DoTableStart( int width, const char * id, bool hidden ) { AStackString<> output; output.Format( "<table width=%u", width ); if ( id ) { output += " id=\""; output += id; output += "\""; } if ( hidden ) { output += " style=\"display:none;\""; } output += ">\n"; Write( output.Get() ); }
// InitTmpDir //------------------------------------------------------------------------------ /*static*/ void WorkerThread::InitTmpDir( bool remote ) { VERIFY( FileIO::GetTempDir( s_TmpRoot ) ); #if defined( __WINDOWS__ ) s_TmpRoot += ".fbuild.tmp\\"; #else s_TmpRoot += "_fbuild.tmp/"; #endif // use the working dir hash to uniquify the path AStackString<> buffer; const uint32_t workingDirHash = remote ? 0 : FBuild::Get().GetOptions().GetWorkingDirHash(); buffer.Format( "0x%08x", workingDirHash ); s_TmpRoot += buffer; s_TmpRoot += NATIVE_SLASH; VERIFY( FileIO::EnsurePathExists( s_TmpRoot ) ); }
// FixupAllowedFileExtensions //------------------------------------------------------------------------------ /*static*/ void ProjectGeneratorBase::FixupAllowedFileExtensions( Array< AString > & extensions ) { // For backwards compatibility, we support explicit extensions ".ext" and wildcards "*.ext" // To normalize run-time behaviour, we convert everything to wildcard format // convert any that are not wildcards patterns for ( auto & ext : extensions ) { if ( ext.Find('*') || ext.Find('?') ) { continue; // already a pattern, leave as is } // convert ".ext" to "*.ext" AStackString<> tmp; tmp.Format("*%s", ext.Get()); ext = tmp; } }
// Monitor //------------------------------------------------------------------------------ /*static*/ void FLog::Monitor( const char * formatString, ... ) { // Is monitoring enabled? if ( g_MonitorFileStream == nullptr ) { return; // No - nothing to do } PROFILE_SECTION( "FLog::Monitor" ) AStackString< 1024 > buffer; va_list args; va_start( args, formatString ); buffer.VFormat( formatString, args ); va_end( args ); AStackString< 1024 > finalBuffer; finalBuffer.Format( "%llu %s", Time::GetCurrentFileTime(), buffer.Get() ); MutexHolder lock( g_MonitorMutex ); g_MonitorFileStream->WriteBuffer( finalBuffer.Get(), finalBuffer.GetLength() ); }
// EmitCompilationMessage //------------------------------------------------------------------------------ void ExecNode::EmitCompilationMessage( const AString & args ) const { // basic info AStackString< 2048 > output; output += "Run: "; output += GetName(); output += '\n'; // verbose mode if ( FLog::ShowInfo() || FBuild::Get().GetOptions().m_ShowCommandLines ) { AStackString< 1024 > verboseOutput; verboseOutput.Format( "%s %s\nWorkingDir: %s\nExpectedReturnCode: %i\n", m_Executable->GetName().Get(), args.Get(), m_WorkingDir.Get(), m_ExpectedReturnCode ); output += verboseOutput; } // output all at once for contiguousness FLOG_BUILD_DIRECT( output.Get() ); }
/*static*/ bool ReflectionInfo::WriteDefinitions() { uint32_t numProblems = 0; const ReflectionInfo * ri = s_FirstReflectionInfo; for ( ; ri != nullptr; ri = ri->m_Next ) { // ignore abstract classes if ( ri->IsAbstract() ) { continue; } // Serialize a default instance to a MemoryStream MemoryStream ms; { // Create and serialize default instance if ( ri->IsObject() ) { RefObject * object = ri->CreateObject(); { TextWriter tw( ms ); tw.Write( object ); } FDELETE( object ); } else { ASSERT( ri->IsStruct() ) Struct * str = ri->CreateStruct(); { TextWriter tw( ms ); tw.Write( str, ri ); } FDELETE( str ); } } AStackString<> fileName; fileName.Format( "..\\Data\\Reflection\\.Definitions\\%s.definition", ri->GetTypeName() ); // avoid writing file if not changed // Try to open existing file FileStream f; if ( f.Open( fileName.Get(), FileStream::READ_ONLY ) ) { // read content const uint64_t fileSize = f.GetFileSize(); if ( fileSize == ms.GetSize() ) { AutoPtr< char > mem( (char *)Alloc( (size_t)fileSize ) ); if ( f.Read( mem.Get(), (size_t)fileSize ) == fileSize ) { if ( memcmp( mem.Get(), ms.GetData(), (size_t)fileSize ) == 0 ) { continue; // definition has not changed } } } f.Close(); } // Definition changed - try to save it int result = 0; AutoPtr< char > memOut; AutoPtr< char > memErr; uint32_t memOutSize; uint32_t memErrSize; // existing definition? if ( FileIO::FileExists( fileName.Get() ) ) { // existing - need to open for edit? if ( FileIO::GetReadOnly( fileName ) ) { AStackString<> args( "edit " ); args += fileName; Process p; if ( p.Spawn( "p4", args.Get(), nullptr, nullptr ) ) { p.ReadAllData( memOut, &memOutSize, memErr, &memErrSize ); result = p.WaitForExit(); } } } else { // new - open for add AStackString<> args( "add " ); args += fileName; Process p; if ( p.Spawn( "p4", args.Get(), nullptr, nullptr ) ) { p.ReadAllData( memOut, &memOutSize, memErr, &memErrSize ); result = p.WaitForExit(); } } if ( result == 0 ) { if ( f.Open( fileName.Get(), FileStream::WRITE_ONLY ) ) { if ( f.Write( ms.GetData(), ms.GetSize() ) == ms.GetSize() ) { continue; // all ok! } } } // PROBLEM! OUTPUT( "Error writing definition '%s'\n", fileName.Get() ); if ( result != 0 ) { OUTPUT( "Perforce error: %s\n", memErr.Get() ); } ++numProblems; } if ( numProblems > 0 ) { FATALERROR( "Problem writing %u definition(s).\n", numProblems ); } return ( numProblems == 0 ); }
// WriteProjectListings //------------------------------------------------------------------------------ void SLNGenerator::WriteProjectListings( const AString& solutionBasePath, const AString& solutionBuildProject, const Array< VCXProjectNode * > & projects, const Array< SLNSolutionFolder > & folders, const Array< SLNDependency > & slnDeps, AString & solutionBuildProjectGuid, Array< AString > & projectGuids, Array< AString > & solutionProjectsToFolder ) { // Project Listings VCXProjectNode ** const projectsEnd = projects.End(); for( VCXProjectNode ** it = projects.Begin() ; it != projectsEnd ; ++it ) { // check if this project is the master project const bool projectIsActive = ( solutionBuildProject.CompareI( (*it)->GetName() ) == 0 ); AStackString<> projectPath( (*it)->GetName() ); // get project base name only const char * lastSlash = projectPath.FindLast( NATIVE_SLASH ); const char * lastPeriod = projectPath.FindLast( '.' ); AStackString<> projectName( lastSlash ? lastSlash + 1 : projectPath.Get(), lastPeriod ? lastPeriod : projectPath.GetEnd() ); // retrieve projectGuid AStackString<> projectGuid; if ( (*it)->GetProjectGuid().GetLength() == 0 ) { // For backward compatibility, keep the preceding slash and .vcxproj extension for GUID generation AStackString<> projectNameForGuid( lastSlash ? lastSlash : projectPath.Get() ); VSProjectGenerator::FormatDeterministicProjectGUID( projectGuid, projectNameForGuid ); } else { projectGuid = (*it)->GetProjectGuid(); } // make project path relative projectPath.Replace( solutionBasePath.Get(), "" ); // projectGuid must be uppercase (visual does that, it changes the .sln otherwise) projectGuid.ToUpper(); if ( projectIsActive ) { ASSERT( solutionBuildProjectGuid.GetLength() == 0 ); solutionBuildProjectGuid = projectGuid; } Write( "Project(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"%s\", \"%s\", \"%s\"\r\n", projectName.Get(), projectPath.Get(), projectGuid.Get() ); // Manage dependencies Array< AString > dependencyGUIDs( 64, true ); const AString & fullProjectPath = (*it)->GetName(); for ( const SLNDependency & deps : slnDeps ) { // is the set of deps relevant to this project? if ( deps.m_Projects.Find( fullProjectPath ) ) { // get all the projects this project depends on for ( const AString & dependency : deps.m_Dependencies ) { // For backward compatibility, keep the preceding slash and .vcxproj extension for GUID generation const char * projNameFromSlash = dependency.FindLast( NATIVE_SLASH ); AStackString<> projectNameForGuid( projNameFromSlash ? projNameFromSlash : dependency.Get() ); AStackString<> newGUID; VSProjectGenerator::FormatDeterministicProjectGUID( newGUID, projectNameForGuid ); dependencyGUIDs.Append( newGUID ); } } } if ( !dependencyGUIDs.IsEmpty() ) { Write( "\tProjectSection(ProjectDependencies) = postProject\r\n" ); for ( const AString & guid : dependencyGUIDs ) { Write( "\t\t%s = %s\r\n", guid.Get(), guid.Get() ); } Write( "\tEndProjectSection\r\n" ); } Write( "EndProject\r\n" ); projectGuids.Append( projectGuid ); // check if this project is in a solution folder const SLNSolutionFolder * const foldersEnd = folders.End(); for ( const SLNSolutionFolder * it2 = folders.Begin() ; it2 != foldersEnd ; ++it2 ) { // this has to be done here to have the same order of declaration (like visual) if ( it2->m_ProjectNames.Find( (*it)->GetName() ) ) { // generate a guid for the solution folder AStackString<> solutionFolderGuid; VSProjectGenerator::FormatDeterministicProjectGUID( solutionFolderGuid, it2->m_Path ); solutionFolderGuid.ToUpper(); AStackString<> projectToFolder; projectToFolder.Format( "\t\t%s = %s\r\n", projectGuid.Get(), solutionFolderGuid.Get() ); solutionProjectsToFolder.Append( projectToFolder ); } } } }
// Commit //------------------------------------------------------------------------------ /*virtual*/ bool FunctionSLN::Commit( const BFFIterator & funcStartIter ) const { AStackString<> solutionOutput; Array< AString > solutionProjects( 8, true ); if ( !GetString( funcStartIter, solutionOutput, ".SolutionOutput", true ) || !GetStrings( funcStartIter, solutionProjects, ".SolutionProjects", false ) ) { return false; } // optional inputs AString solutionBuildProject; AString solutionVisualStudioVersion; AString solutionMinimumVisualStudioVersion; if ( !GetString( funcStartIter, solutionBuildProject, ".SolutionBuildProject", false ) || !GetString( funcStartIter, solutionVisualStudioVersion, ".SolutionVisualStudioVersion", false ) || !GetString( funcStartIter, solutionMinimumVisualStudioVersion, ".SolutionMinimumVisualStudioVersion", false ) ) { return false; } // base config VSProjectConfig baseConfig; // create configs Array< VSProjectConfig > configs( 16, true ); const BFFVariable * solutionConfigs = BFFStackFrame::GetVar( ".SolutionConfigs" ); if ( solutionConfigs ) { if ( solutionConfigs->IsArrayOfStructs() == false ) { Error::Error_1050_PropertyMustBeOfType( funcStartIter, this, ".SolutionConfigs", solutionConfigs->GetType(), BFFVariable::VAR_ARRAY_OF_STRUCTS ); return false; } const Array< const BFFVariable * > & structs = solutionConfigs->GetArrayOfStructs(); const BFFVariable * const * end = structs.End(); for ( const BFFVariable ** it = structs.Begin(); it != end; ++it ) { const BFFVariable * s = *it; // start with the base configuration VSProjectConfig newConfig( baseConfig ); // .Platform must be provided if ( !GetStringFromStruct( s, ".Platform", newConfig.m_Platform ) ) { // TODO:B custom error Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".Platform" ) ); return false; } // .Config must be provided if ( !GetStringFromStruct( s, ".Config", newConfig.m_Config ) ) { // TODO:B custom error Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".Config" ) ); return false; } configs.Append( newConfig ); } } else { // no user specified configs, make some defaults // start from the default VSProjectConfig config( baseConfig ); // make the configs config.m_Platform = "Win32"; config.m_Config = "Debug"; configs.Append( config ); config.m_Config = "Release"; configs.Append( config ); config.m_Platform = "x64"; configs.Append( config ); config.m_Config = "Debug"; configs.Append( config ); } // sort project configs by config and by platform (like visual) configs.Sort( VSProjectConfigComp() ); // create solution folders Array< SLNSolutionFolder > folders( 16, true ); const BFFVariable * solutionFolders = BFFStackFrame::GetVar( ".SolutionFolders" ); if ( solutionFolders ) { if ( solutionFolders->IsArrayOfStructs() == false ) { Error::Error_1050_PropertyMustBeOfType( funcStartIter, this, ".SolutionFolders", solutionFolders->GetType(), BFFVariable::VAR_ARRAY_OF_STRUCTS ); return false; } const Array< const BFFVariable * > & structs = solutionFolders->GetArrayOfStructs(); const BFFVariable * const * end = structs.End(); for ( const BFFVariable ** it = structs.Begin(); it != end; ++it ) { const BFFVariable * s = *it; // start with the base configuration SLNSolutionFolder newFolder; // .Path must be provided if ( !GetStringFromStruct( s, ".Path", newFolder.m_Path ) ) { // TODO:B custom error Error::Error_1101_MissingProperty( funcStartIter, this, AStackString<>( ".Path" ) ); return false; } newFolder.m_Path.Replace( OTHER_SLASH, NATIVE_SLASH ); // check if this path was already defined { const SLNSolutionFolder * const end2 = folders.End(); for ( const SLNSolutionFolder * it2 = folders.Begin() ; it2 != end2 ; ++it2 ) { if ( it2->m_Path == newFolder.m_Path ) { // TODO:B custom error Error::Error_1100_AlreadyDefined( funcStartIter, this, it2->m_Path ); return false; } } } // .Projects must be provided if ( !GetStringOrArrayOfStringsFromStruct( funcStartIter, s, ".Projects", newFolder.m_ProjectNames ) ) { return false; // GetStringOrArrayOfStringsFromStruct has emitted an error } // check if this project is included in the solution for ( const AString & projectName : newFolder.m_ProjectNames ) { if ( solutionProjects.Find( projectName ) == nullptr ) { solutionProjects.Append( projectName ); } } folders.Append( newFolder ); } } NodeGraph & ng = FBuild::Get().GetDependencyGraph(); // Check for existing node if ( ng.FindNode( solutionOutput ) ) { Error::Error_1100_AlreadyDefined( funcStartIter, this, solutionOutput ); return false; } // resolves VCXProject nodes associated to solutionProjects Array< VCXProjectNode * > projects( solutionProjects.GetSize(), false ); { const AString * const end = solutionProjects.End(); for ( const AString * it = solutionProjects.Begin(); it != end; ++it ) { VCXProjectNode * project = ResolveVCXProject( funcStartIter, *it ); if ( project == nullptr ) { return false; // ResolveVCXProject will have emitted error } // check that this project contains all .SolutionConfigs const Array< VSProjectConfig > & projectConfigs = project->GetConfigs(); const size_t configsSize = configs.GetSize(); for ( size_t i = 0 ; i < configsSize ; ++i ) { bool containsConfig = false; const VSProjectConfig * const config = &configs[i]; const VSProjectConfig * const end2 = projectConfigs.End(); for ( const VSProjectConfig * it2 = projectConfigs.Begin(); it2 != end2; ++it2 ) { if ( it2->m_Platform == config->m_Platform && it2->m_Config == config->m_Config ) { containsConfig = true; break; } } if ( containsConfig == false ) { // TODO: specific error message "ProjectConfigNotFound" AStackString<> configName; configName.Format( "%s|%s", config->m_Platform.Get(), config->m_Config.Get() ); Error::Error_1104_TargetNotDefined( funcStartIter, this, configName.Get(), project->GetName() ); return false; } } // append vcxproject node to solution projects.Append( project ); } } // sort projects by name (like visual) projects.Sort( VCXProjectNodeComp() ); // resolves VCXProject nodes associated to solutionFolders { SLNSolutionFolder * const end = folders.End(); for ( SLNSolutionFolder * it = folders.Begin(); it != end; ++it ) { // retrieves full path of contained vcxprojects AString * const end2 = it->m_ProjectNames.End(); for ( AString * it2 = it->m_ProjectNames.Begin(); it2 != end2; ++it2 ) { // Get associate project file VCXProjectNode * project = ResolveVCXProject( funcStartIter, *it2 ); if ( project == nullptr ) { return false; // ResolveVCXProjectRecurse will have emitted error } ASSERT( projects.Find( project ) ); // Sanity check in global list // fixup name to be to final project *it2 = project->GetName(); } } } // resolves VCXProject node referenced by solutionBuildProject if ( solutionBuildProject.GetLength() > 0 ) { // Get associate project file const VCXProjectNode * project = ResolveVCXProject( funcStartIter, solutionBuildProject ); if ( project == nullptr ) { return false; // ResolveVCXProject will have emitted error } if ( projects.Find( project ) == nullptr ) { // project referenced in .SolutionBuildProject is not referenced in .SolutionProjects Error::Error_1104_TargetNotDefined( funcStartIter, this, ".SolutionBuildProject", project->GetName() ); return false; } solutionBuildProject = project->GetName(); } // Project Dependencies Array< SLNDependency > slnDeps( 0, true ); const BFFVariable * projectDepsVar = BFFStackFrame::GetVar( ".SolutionDependencies" ); if ( projectDepsVar ) { if ( projectDepsVar->IsArrayOfStructs() == false ) { Error::Error_1050_PropertyMustBeOfType( funcStartIter, this, ".SolutionDependencies", projectDepsVar->GetType(), BFFVariable::VAR_ARRAY_OF_STRUCTS ); return false; } slnDeps.SetCapacity( projectDepsVar->GetArrayOfStructs().GetSize() ); for ( const BFFVariable * s : projectDepsVar->GetArrayOfStructs() ) { // .Projects must be provided // .Dependencies must be provided SLNDependency deps; if ( !GetStringOrArrayOfStringsFromStruct( funcStartIter, s, ".Projects", deps.m_Projects ) || !GetStringOrArrayOfStringsFromStruct( funcStartIter, s, ".Dependencies", deps.m_Dependencies ) ) { return false; // GetStringOrArrayOfStringsFromStruct has emitted an error } // fixup for ( AString & projectName : deps.m_Projects ) { // Get associated project file const VCXProjectNode * project = ResolveVCXProject( funcStartIter, projectName ); if ( project == nullptr ) { return false; // ResolveVCXProject will have emitted error } projectName = project->GetName(); } for ( AString & projectName : deps.m_Dependencies ) { // Get associated project file const VCXProjectNode * project = ResolveVCXProject( funcStartIter, projectName ); if ( project == nullptr ) { return false; // ResolveVCXProject will have emitted error } projectName = project->GetName(); } slnDeps.Append( deps ); } } SLNNode * sln = ng.CreateSLNNode( solutionOutput, solutionBuildProject, solutionVisualStudioVersion, solutionMinimumVisualStudioVersion, configs, projects, slnDeps, folders ); ASSERT( sln ); return ProcessAlias( funcStartIter, sln ); }
// Deserialize //------------------------------------------------------------------------------ void ToolManifest::Deserialize( IOStream & ms ) { ms.Read( m_ToolId ); ASSERT( m_Files.IsEmpty() ); uint32_t numFiles( 0 ); ms.Read( numFiles ); m_Files.SetCapacity( numFiles ); for ( size_t i=0; i<(size_t)numFiles; ++i ) { AStackString<> name; uint64_t timeStamp( 0 ); uint32_t hash( 0 ); uint32_t contentSize( 0 ); ms.Read( name ); ms.Read( timeStamp ); ms.Read( hash ); ms.Read( contentSize ); m_Files.Append( File( name, timeStamp, hash, nullptr, contentSize ) ); } // determine if any files are remaining from a previous run size_t numFilesAlreadySynchronized = 0; for ( size_t i=0; i<(size_t)numFiles; ++i ) { AStackString<> localFile; GetRemoteFilePath( (uint32_t)i, localFile ); // is this file already present? AutoPtr< FileStream > fileStream( FNEW( FileStream ) ); FileStream & f = *( fileStream.Get() ); if ( f.Open( localFile.Get() ) == false ) { continue; // file not found } if ( f.GetFileSize() != m_Files[ i ].m_ContentSize ) { continue; // file is not complete } AutoPtr< char > mem( (char *)ALLOC( (size_t)f.GetFileSize() ) ); if ( f.Read( mem.Get(), (size_t)f.GetFileSize() ) != f.GetFileSize() ) { continue; // problem reading file } if( Murmur3::Calc32( mem.Get(), (size_t)f.GetFileSize() ) != m_Files[ i ].m_Hash ) { continue; // file contents unexpected } // file present and ok m_Files[ i ].m_FileLock = fileStream.Release(); // NOTE: keep file open to prevent deletions m_Files[ i ].m_SyncState = File::SYNCHRONIZED; numFilesAlreadySynchronized++; } // Generate Environment ASSERT( m_RemoteEnvironmentString == nullptr ); // PATH= AStackString<> basePath; GetRemotePath( basePath ); AStackString<> paths; paths.Format( "PATH=%s", basePath.Get() ); // TMP= AStackString<> normalTmp; Env::GetEnvVariable( "TMP", normalTmp ); AStackString<> tmp; tmp.Format( "TMP=%s", normalTmp.Get() ); // SystemRoot= AStackString<> sysRoot( "SystemRoot=C:\\Windows" ); char * mem = (char *)ALLOC( paths.GetLength() + 1 + tmp.GetLength() + 1 + sysRoot.GetLength() + 1 + 1 ); m_RemoteEnvironmentString = mem; AString::Copy( paths.Get(), mem, paths.GetLength() + 1 ); // including null mem += ( paths.GetLength() + 1 ); // including null AString::Copy( tmp.Get(), mem, tmp.GetLength() + 1 ); // including null mem += ( tmp.GetLength() + 1 ); // including null AString::Copy( sysRoot.Get(), mem, sysRoot.GetLength() + 1 ); // including null mem += ( sysRoot.GetLength() + 1 ); // including null *mem = 0; ++mem; // double null // are all files already present? if ( numFilesAlreadySynchronized == m_Files.GetSize() ) { m_Synchronized = true; } }