Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/WolfireGames/overgrowth.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Ogda/manifest.cpp')
-rw-r--r--Source/Ogda/manifest.cpp456
1 files changed, 456 insertions, 0 deletions
diff --git a/Source/Ogda/manifest.cpp b/Source/Ogda/manifest.cpp
new file mode 100644
index 00000000..bc5ebb87
--- /dev/null
+++ b/Source/Ogda/manifest.cpp
@@ -0,0 +1,456 @@
+//-----------------------------------------------------------------------------
+// Name: manifest.cpp
+// Developer: Wolfire Games LLC
+// Description:
+// License: Read below
+//-----------------------------------------------------------------------------
+//
+// Copyright 2022 Wolfire Games LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+//-----------------------------------------------------------------------------
+#include "manifest.h"
+
+#include <tinyxml.h>
+#include <XML/xml_helper.h>
+
+#include <Utility/commonregex.h>
+#include <Logging/logdata.h>
+#include <Internal/filesystem.h>
+#include <XML/Parsers/jobxmlparser.h>
+#include <Version/version.h>
+
+#include "jobhandler.h"
+#include "manifestthreadpool.h"
+
+Manifest::Manifest(int thread): thread(thread)
+{
+}
+
+bool Manifest::Load(const std::string& manifest)
+{
+ results.clear();
+ CommonRegex cr;
+ TiXmlDocument doc( manifest.c_str() );
+ doc.LoadFile();
+
+ if( !doc.Error() )
+ {
+ TiXmlElement* pRoot = doc.RootElement();
+
+ if( pRoot )
+ {
+ TiXmlHandle hRoot(pRoot);
+
+ TiXmlNode* nResult = hRoot.FirstChild().ToNode();
+
+ while( nResult )
+ {
+ TiXmlElement* eResult = nResult->ToElement();
+
+ if( eResult )
+ {
+ if( strcmp(eResult->Value(), "Result") == 0 //Result is a backwards compatible name, never generated.
+ || strcmp(eResult->Value(), "BuilderResult") == 0 )
+ {
+
+ const char* dest = eResult->Attribute("dest");
+ const char* dest_hash = eResult->Attribute("dest_hash");
+ const char* builder = eResult->Attribute("builder");
+ const char* builder_version = eResult->Attribute("builder_version");
+ const char* type = eResult->Attribute("type");
+ bool success = cr.saysTrue(eResult->Attribute("success"));
+
+ std::string dest_s;
+ if( dest )
+ dest_s = std::string( dest );
+ std::string dest_hash_s;
+ if( dest_hash )
+ dest_hash_s = std::string( dest_hash );
+ std::string builder_s;
+ if( builder )
+ builder_s = std::string( builder );
+ std::string builder_version_s;
+ if( builder_version )
+ builder_version_s = std::string(builder_version);
+ std::string type_s;
+ if( type )
+ type_s = std::string(type);
+
+ std::vector<Item> items;
+
+ TiXmlElement* eItem = nResult->FirstChild("Item")->ToElement();
+
+ while( eItem )
+ {
+ const char* item_path = eItem->Attribute("path");
+ const char* item_type = eItem->Attribute("type");
+ const char* item_hash = eItem->Attribute("hash");
+
+ std::string item_path_s;
+ if( item_path )
+ item_path_s = std::string( item_path );
+ std::string item_type_s;
+ if( item_type )
+ item_type_s = std::string( item_type );
+ std::string item_hash_s;
+ if( item_hash )
+ item_hash_s = std::string( item_hash );
+
+ items.push_back(Item("", item_path_s, item_type_s, item_hash_s, JobXMLParser::Item()));
+
+ eItem = eItem->NextSiblingElement("Item");
+ }
+
+ results.push_back( ManifestResult( dest_hash_s, items, dest_s, success, builder_s, builder_version_s, ManifestResult::BUILT, type_s ) );
+ }
+ else if( strcmp(eResult->Value(), "DatabaseResult") == 0 )
+ {
+
+ const char* dest = eResult->Attribute("dest");
+ const char* dest_hash = eResult->Attribute("dest_hash");
+ const char* builder = eResult->Attribute("builder");
+ const char* builder_version = eResult->Attribute("builder_version");
+ const char* type = eResult->Attribute("type");
+
+ std::string dest_s;
+ if( dest )
+ dest_s = std::string( dest );
+ std::string dest_hash_s;
+ if( dest_hash )
+ dest_hash_s = std::string( dest_hash );
+ std::string builder_s;
+ if( builder )
+ builder_s = std::string( builder );
+ std::string builder_version_s;
+ if( builder_version )
+ builder_version_s = std::string(builder_version);
+ std::string type_s;
+ if( type )
+ type_s = std::string(type);
+
+ std::vector<Item> items;
+
+ TiXmlElement* eItem = nResult->FirstChild("Item")->ToElement();
+
+ while( eItem )
+ {
+ const char* item_path = eItem->Attribute("path");
+ const char* item_type = eItem->Attribute("type");
+ const char* item_hash = eItem->Attribute("hash");
+
+ std::string item_path_s;
+ if( item_path )
+ item_path_s = std::string( item_path );
+ std::string item_type_s;
+ if( item_type )
+ item_type_s = std::string( item_type );
+ std::string item_hash_s;
+ if( item_hash )
+ item_hash_s = std::string( item_hash );
+
+ items.push_back(Item("", item_path_s, item_type_s, item_hash_s, JobXMLParser::Item()));
+
+ eItem = eItem->NextSiblingElement("Item");
+ }
+
+ results.push_back( ManifestResult( dest_hash_s, items, dest_s, true, builder_s, builder_version_s, ManifestResult::DATABASE, type_s ) );
+ }
+ else if(strcmp(eResult->Value(), "GeneratorResult") == 0 )
+ {
+ const char* dest = eResult->Attribute("dest");
+ const char* dest_hash = eResult->Attribute("dest_hash");
+ const char* generator = eResult->Attribute("generator");
+ const char* generator_version = eResult->Attribute("generator_version");
+ const char* type = eResult->Attribute("type");
+ bool success = cr.saysTrue(eResult->Attribute("success"));
+
+ std::string dest_s;
+ if( dest )
+ dest_s = std::string( dest );
+ std::string dest_hash_s;
+ if( dest_hash )
+ dest_hash_s = std::string( dest_hash );
+ std::string generator_s;
+ if( generator )
+ generator_s = std::string( generator );
+ std::string generator_version_s;
+ if( generator_version )
+ generator_version_s = std::string(generator_version);
+ std::string type_s;
+ if( type )
+ type_s = std::string(type);
+
+ results.push_back( ManifestResult( dest_hash_s, dest_s, success, generator_s, generator_version_s, ManifestResult::GENERATED, type_s ) );
+
+ }
+ else
+ {
+ LOGE << "Unknown element name: " << eResult->Value() << std::endl;
+ }
+ }
+ else
+ {
+ LOGE << "Malformed element in manifest" << std::endl;
+ }
+
+ nResult = nResult->NextSibling();
+ }
+ }
+ else
+ {
+ LOGE << "Problem loading manifest file" << manifest << std::endl;
+ return false;
+ }
+ }
+ else
+ {
+ LOGE << "Error parsing manifest file: \"" << doc.ErrorDesc() << "\"" << std::endl;
+ return false;
+ }
+
+ std::vector<ManifestResult>::const_iterator mrit;
+ for( mrit = results.begin(); mrit != results.end(); mrit++ )
+ {
+ std::vector<Item>::const_iterator itemit;
+ for( itemit = mrit->items.begin(); itemit != mrit->items.end(); itemit++ )
+ {
+ hash_set.insert(itemit->GetSubHash());
+ }
+ }
+
+ return true;
+}
+
+bool Manifest::Save(const std::string& manifest)
+{
+ TiXmlDocument doc;
+ TiXmlDeclaration * decl = new TiXmlDeclaration( "2.0", "", "" );
+ TiXmlElement * root = new TiXmlElement( "Manifest" );
+
+ TiXmlElement* builder_info = new TiXmlElement( "ProgramInfo" );
+ builder_info->SetAttribute("name", "Ogda");
+ builder_info->SetAttribute("build_version", GetBuildVersion());
+ builder_info->SetAttribute("build_date", GetBuildTimestamp());
+ builder_info->SetAttribute("platform", GetPlatform());
+ builder_info->SetAttribute("arch", GetArch());
+ root->LinkEndChild(builder_info);
+
+ TiXmlElement* execution_info = new TiXmlElement( "ExecutionInfo" );
+ //Add timestamp when it was run in here.
+ //Add how long it took here.
+ root->LinkEndChild(execution_info);
+
+ std::vector<ManifestResult>::const_iterator mrit;
+
+ for( mrit = results.begin(); mrit != results.end(); mrit++ )
+ {
+ if( mrit->mr_type == ManifestResult::BUILT )
+ {
+ TiXmlElement* eResult = new TiXmlElement( "BuilderResult" );
+
+ std::vector<Item>::const_iterator itemit;
+
+ for( itemit = mrit->items.begin(); itemit != mrit->items.end(); itemit++ )
+ {
+ TiXmlElement* eItem = new TiXmlElement( "Item" );
+
+ eItem->SetAttribute( "path", itemit->GetPath().c_str() );
+ eItem->SetAttribute( "type", itemit->type.c_str() );
+ eItem->SetAttribute( "hash", itemit->hash.c_str() );
+
+ eResult->LinkEndChild( eItem );
+ }
+
+ eResult->SetAttribute( "dest", mrit->dest.c_str() );
+ eResult->SetAttribute( "dest_hash", mrit->dest_hash.c_str() );
+ eResult->SetAttribute( "builder", mrit->name.c_str() );
+ eResult->SetAttribute( "builder_version", mrit->version.c_str() );
+ eResult->SetAttribute( "type", mrit->type.c_str() );
+ eResult->SetAttribute( "success", mrit->success ? "true" : "false" );
+ eResult->SetAttribute( "fresh_built", mrit->fresh_built ? "true" : "false" );
+
+ root->LinkEndChild( eResult );
+ }
+ else if( mrit->mr_type == ManifestResult::DATABASE )
+ {
+ TiXmlElement* eResult = new TiXmlElement( "DatabaseResult" );
+
+ std::vector<Item>::const_iterator itemit;
+
+ for( itemit = mrit->items.begin(); itemit != mrit->items.end(); itemit++ )
+ {
+ TiXmlElement* eItem = new TiXmlElement( "Item" );
+
+ eItem->SetAttribute( "path", itemit->GetPath().c_str() );
+ eItem->SetAttribute( "type", itemit->type.c_str() );
+ eItem->SetAttribute( "hash", itemit->hash.c_str() );
+
+ eResult->LinkEndChild( eItem );
+ }
+
+ eResult->SetAttribute( "dest", mrit->dest.c_str() );
+ eResult->SetAttribute( "dest_hash", mrit->dest_hash.c_str() );
+ eResult->SetAttribute( "builder", mrit->name.c_str() );
+ eResult->SetAttribute( "builder_version", mrit->version.c_str() );
+ eResult->SetAttribute( "type", mrit->type.c_str() );
+
+ root->LinkEndChild( eResult );
+ }
+ else if( mrit->mr_type == ManifestResult::GENERATED )
+ {
+ TiXmlElement* eResult = new TiXmlElement( "GeneratorResult" );
+
+ eResult->SetAttribute( "dest", mrit->dest.c_str() );
+ eResult->SetAttribute( "dest_hash", mrit->dest_hash.c_str() );
+ eResult->SetAttribute( "generator", mrit->name.c_str() );
+ eResult->SetAttribute( "generator_version", mrit->version.c_str() );
+ eResult->SetAttribute( "typ", mrit->type.c_str() );
+ eResult->SetAttribute( "success", mrit->success ? "true" : "false" );
+ eResult->SetAttribute( "fresh_built", mrit->fresh_built ? "true" : "false" );
+
+ root->LinkEndChild( eResult );
+ }
+ else
+ {
+ LOGE << "Unknown ManifestResult type" << std::endl;
+ }
+ }
+
+ doc.LinkEndChild( decl );
+ doc.LinkEndChild( root );
+ doc.SaveFile( manifest.c_str() );
+
+ return !doc.Error();
+}
+
+void Manifest::AddResult( const ManifestResult& a ) {
+ results.push_back(a);
+ std::vector<Item>::const_iterator itemit;
+ for( itemit = a.items.begin(); itemit != a.items.end(); itemit++ ) {
+ hash_set.insert(itemit->GetSubHash());
+ }
+}
+
+bool Manifest::HasError()
+{
+ std::vector<ManifestResult>::const_iterator mrit;
+ for( mrit = results.begin(); mrit != results.end(); mrit++ )
+ {
+ if( mrit->success == false )
+ return true;
+ }
+ return false;
+}
+
+std::vector<std::string> Manifest::GetDestinationFiles()
+{
+ std::vector<std::string> values;
+
+ std::vector<ManifestResult>::const_iterator mrit;
+ for( mrit = results.begin(); mrit != results.end(); mrit++ )
+ {
+ values.push_back( mrit->dest );
+ }
+
+ return values;
+}
+
+bool Manifest::IsUpToDate( JobHandler& jh, const Item& item, const Builder& builder )
+{
+ std::vector<ManifestResult>::iterator mrit;
+ if( hash_set.find(item.GetSubHash()) != hash_set.end() )
+ {
+ for( mrit = results.begin(); mrit != results.end(); mrit++ )
+ {
+ if( mrit->items.size() == 1 )
+ {
+ //First, check that it's the same item.
+ //This "magically" includes the hash as item contains the hash value
+ if( mrit->items[0] == item )
+ {
+ //Check that it's the same builder, one builder, one type of possible output file
+ if( mrit->name == builder.GetBuilderName() )
+ {
+ //Check the builder version, to verify that the expected output wouldn't change.
+ if( mrit->version == builder.GetBuilderVersion() )
+ {
+ //Check if the claimed destination file from the manifest differs from the file on disk according to hash
+ //and that the hash isn't invalid
+ if( mrit->GetCurrentDestHash(jh.output_folder) == mrit->dest_hash && mrit->dest_hash != std::string("") )
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ else if( mrit->items.size() > 1 )
+ {
+ LOGW << "System is not currently built to handle matching ManifestResults with more than one item" << std::endl;
+ }
+ }
+ }
+ return false;
+}
+
+ManifestResult Manifest::GetPreviouslyBuiltResult(const Item& item, const Builder& builder)
+{
+ std::vector<ManifestResult>::const_iterator mrit;
+ for( mrit = results.begin(); mrit != results.end(); mrit++ )
+ {
+ if( mrit->items.size() == 1 )
+ {
+ //First, check that it's the same item.
+ //This "magically" includes the hash as item contains the hash value
+ if( mrit->items[0] == item )
+ {
+ //Check that it's the same builder, one builder, one type of possible output file
+ if( mrit->name == builder.GetBuilderName() )
+ {
+ //This is mostly for sanity, but should never really evaluate to false as we already found the right builder and there is only one per name.
+ //If this was false, that would mean we have changed the version of the builder and the asset we're looking for is actually outdated.
+ //Meaning that previous checks and evalutation should have lead us to the conclusion to rebuild this item.
+ if( mrit->version == builder.GetBuilderVersion() )
+ {
+ return *mrit;
+ }
+ }
+ }
+ }
+ else if( mrit->items.size() > 1 )
+ {
+ LOGW << "System is not currently built to handle matching ManifestResults with more than one item" << std::endl;
+ }
+ }
+ throw "Big error";
+}
+
+
+void Manifest::PrecalculateCurrentDestinationHashes( const std::string& dest_path )
+{
+ ManifestThreadPool mtp(thread);
+
+ mtp.RunHashCalculation(dest_path, results);
+}
+
+std::vector<ManifestResult>::const_iterator Manifest::ResultsBegin() const
+{
+ return results.begin();
+}
+
+std::vector<ManifestResult>::const_iterator Manifest::ResultsEnd() const
+{
+ return results.end();
+}