Пример #1
0
// 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;
}
Пример #2
0
// 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
}
Пример #3
0
// 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
}
Пример #4
0
	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;
	}
Пример #5
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;
}
Пример #6
0
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" );
}
Пример #7
0
// 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;
}
Пример #8
0
// 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();
}
Пример #9
0
// 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 );
}
Пример #10
0
// 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() );
}
Пример #11
0
// 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 ) );
}
Пример #12
0
// 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;
    }
}
Пример #13
0
// 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() );
}
Пример #14
0
// 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() );
}
Пример #15
0
	/*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 );
	}
Пример #16
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 );
            }
        }
    }
}
Пример #17
0
// 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 );
}
Пример #18
0
// 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;		
	}
}