// Commit //------------------------------------------------------------------------------ /*virtual*/ bool FunctionCopy::Commit( NodeGraph & nodeGraph, const BFFIterator & funcStartIter ) const { // make sure all required variables are defined Array< AString > sources( 16, true ); const BFFVariable * dstFileV; if ( !GetStrings( funcStartIter, sources, ".Source", true ) || !GetString( funcStartIter, dstFileV, ".Dest", true ) ) { return false; // GetString will have emitted errors } // Optional AStackString<> sourceBasePath; if ( !GetString( funcStartIter, sourceBasePath, ".SourceBasePath", false ) ) { return false; // GetString will have emitted errors } // Canonicalize the SourceBasePath if ( !sourceBasePath.IsEmpty() ) { AStackString<> cleanValue; NodeGraph::CleanPath( sourceBasePath, cleanValue ); PathUtils::EnsureTrailingSlash( cleanValue ); sourceBasePath = cleanValue; } // check sources are not paths { const AString * const end = sources.End(); for ( const AString * it = sources.Begin(); it != end; ++it ) { const AString & srcFile( *it ); // source must be a file, not a path if ( PathUtils::IsFolderPath( srcFile ) ) { Error::Error_1105_PathNotAllowed( funcStartIter, this, ".Source", srcFile ); return false; } } } // Pre-build dependencies Dependencies preBuildDependencies; if ( !GetNodeList( nodeGraph, funcStartIter, ".PreBuildDependencies", preBuildDependencies, false ) ) { return false; // GetNodeList will have emitted an error } Array< AString > preBuildDependencyNames( preBuildDependencies.GetSize(), false ); for ( const auto & dep : preBuildDependencies ) { preBuildDependencyNames.Append( dep.GetNode()->GetName() ); } // get source node Array< Node * > srcNodes; { const AString * const end = sources.End(); for ( const AString * it = sources.Begin(); it != end; ++it ) { Node * srcNode = nodeGraph.FindNode( *it ); if ( srcNode ) { if ( GetSourceNodes( funcStartIter, srcNode, srcNodes ) == false ) { return false; } } else { // source file not defined by use - assume an external file srcNodes.Append( nodeGraph.CreateFileNode( *it ) ); } } } AStackString<> dstFile; NodeGraph::CleanPath( dstFileV->GetString(), dstFile ); const bool dstIsFolderPath = PathUtils::IsFolderPath( dstFile ); // make all the nodes for copies Dependencies copyNodes( srcNodes.GetSize(), false ); for ( const Node * srcNode : srcNodes ) { AStackString<> dst( dstFile ); // dest can be a file OR a path. If it's a path, use the source filename part if ( dstIsFolderPath ) { // find filename part of source const AString & srcName = srcNode->GetName(); // If the sourceBasePath is specified (and valid) use the name relative to that if ( !sourceBasePath.IsEmpty() && PathUtils::PathBeginsWith( srcName, sourceBasePath ) ) { // Use everything relative to the SourceBasePath dst += srcName.Get() + sourceBasePath.GetLength(); } else { // Use just the file name const char * lastSlash = srcName.FindLast( NATIVE_SLASH ); dst += lastSlash ? ( lastSlash + 1 ) // append filename part if found : srcName.Get(); // otherwise append whole thing } } // check node doesn't already exist if ( nodeGraph.FindNode( dst ) ) { // TODO:C could have a specific error for multiple sources with only 1 output // to differentiate from two rules creating the same dst target Error::Error_1100_AlreadyDefined( funcStartIter, this, dst ); return false; } // create our node CopyFileNode * copyFileNode = nodeGraph.CreateCopyFileNode( dst ); copyFileNode->m_Source = srcNode->GetName(); copyFileNode->m_PreBuildDependencyNames = preBuildDependencyNames; if ( !copyFileNode->Initialize( nodeGraph, funcStartIter, this ) ) { return false; // Initialize will have emitted an error } copyNodes.Append( Dependency( copyFileNode ) ); } // handle alias creation return ProcessAlias( nodeGraph, funcStartIter, copyNodes ); }
// DoDynamicDependencies //------------------------------------------------------------------------------ /*virtual*/ bool CopyDirNode::DoDynamicDependencies( NodeGraph & nodeGraph, bool forceClean ) { (void)forceClean; // dynamic deps are always re-added here, so this is meaningless ASSERT( !m_StaticDependencies.IsEmpty() ); Array< AString > preBuildDependencyNames( m_PreBuildDependencies.GetSize(), false ); for ( const auto & dep : m_PreBuildDependencies ) { preBuildDependencyNames.Append( dep.GetNode()->GetName() ); } // Iterate all the DirectoryListNodes const Dependency * const depEnd = m_StaticDependencies.End(); for ( const Dependency * dep = m_StaticDependencies.Begin(); dep != depEnd; ++dep ) { // Grab the files DirectoryListNode * dln = dep->GetNode()->CastTo< DirectoryListNode >(); const Array< FileIO::FileInfo > & files = dln->GetFiles(); const FileIO::FileInfo * const fEnd = files.End(); for ( const FileIO::FileInfo * fIt = files.Begin(); fIt != fEnd; ++fIt ) { // Create a CopyFileNode for each dynamically discovered file // source file (full path) const AString & srcFile = fIt->m_Name; // source file (relative to base path) const AStackString<> srcFileRel( srcFile.Get() + dln->GetPath().GetLength() ); // source file (as a node) Node * srcFileNode = nodeGraph.FindNode( srcFile ); if ( srcFileNode == nullptr ) { srcFileNode = nodeGraph.CreateFileNode( srcFile ); } else if ( srcFileNode->IsAFile() == false ) { FLOG_ERROR( "CopyDir() Node '%s' is not a FileNode (type: %s)", srcFile.Get(), srcFileNode->GetTypeName() ); return false; } // generate dest file name const AStackString<> dstFile( m_DestPath ); (AString &)dstFile += (AString &)srcFileRel; // make sure dest doesn't already exist Node * n = nodeGraph.FindNode( dstFile ); if ( n == nullptr ) { CopyFileNode * copyFileNode = nodeGraph.CreateCopyFileNode( dstFile ); copyFileNode->m_Source = srcFileNode->GetName(); copyFileNode->m_PreBuildDependencyNames = preBuildDependencyNames; // inherit PreBuildDependencies BFFIterator iter; if ( !copyFileNode->Initialize( nodeGraph, iter, nullptr ) ) { return false; // Initialize will have emitted an error } n = copyFileNode; } else if ( n->GetType() != Node::COPY_FILE_NODE ) { FLOG_ERROR( "Node '%s' is not a CopyFileNode (type: %s)", n->GetName().Get(), n->GetTypeName() ); return false; } else { CopyFileNode * cn = n->CastTo< CopyFileNode >(); if ( srcFileNode != cn->GetSourceNode() ) { FLOG_ERROR( "Conflicting objects found during CopyDir:\n" " File A: %s\n" " File B: %s\n" " Both copy to: %s\n", srcFile.Get(), cn->GetSourceNode()->GetName().Get(), dstFile.Get() ); return false; } } m_DynamicDependencies.Append( Dependency( n ) ); } } return true; }