Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,110 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/base.h>
#include <AzCore/EBus/EBus.h>
#include <AzCore/std/string/string.h>
#include <AzCore/Math/Uuid.h>
namespace AzToolsFramework
{
// use bind if you need additional context.
// Parameters:
// bool - If the archive command was successful or not.
typedef AZStd::function<void(bool)> ArchiveResponseCallback;
// bool - If the archive command was successful or not.
// AZStd::string - The console output from the command.
typedef AZStd::function<void(bool, AZStd::string)> ArchiveResponseOutputCallback;
//! ArchiveCommands
//! This bus handles messages relating to archive commands
//! archive commands are ASYNCHRONOUS
//! archive formats officially supported are .zip
//! do not block the main thread waiting for a response, it is not okay
//! you will not get a message delivered unless you tick the tickbus anyway!
class ArchiveCommands
: public AZ::EBusTraits
{
public:
using Bus = AZ::EBus<ArchiveCommands>;
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
typedef AZStd::recursive_mutex MutexType;
static const bool LocklessDispatch = true;
virtual ~ArchiveCommands() {}
//! Start an async task to extract an archive to the target directory
//! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task.
//! Multiple tasks can be associated with the same handle
virtual void ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback) = 0;
virtual void ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0;
// Maintaining backwards API compatibility - ExtractArchiveBlocking below passes in extractWithRoot as an option
virtual void ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0;
//! Start a sync task to extract an archive to the target directory
//! If you do not want to extract the root folder then set extractWithRootDirectory to false.
virtual bool ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory) = 0;
//! Extract a single file asynchronously from the archive to the destination.
//! Uses cwd if destinationPath empty. overWrite = true for overwrite existing files, false for skipExisting
//! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task.
//! Multiple tasks can be associated with the same handle
virtual void ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0;
//! Extract a single file from the archive to the destination and block until finished.
//! Uses cwd if destinationPath empty. overWrite = true for overwrite existing files, false for skipExisting
virtual bool ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) = 0;
//! Start an async task to create an archive of the target directory (recursively)
//! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task.
//! Multiple tasks can be associated with the same handle.
virtual void CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0;
//! Start a sync task to create an archive of the target directory (recursively)
virtual bool CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive) = 0;
//! Start an async task to retrieve the list of files and their relative paths within an archive (recursively)
//! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task.
//! Multiple tasks can be associated with the same handle.
virtual void ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector<AZStd::string>& fileEntries, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0;
//! Start a sync task to retrieve the list of files and their relative paths within an archive (recursively)
virtual bool ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector<AZStd::string>& fileEntries) = 0;
//! Start an async task to add a file to a preexisting archive.
//! fileToAdd must be a relative path to the file from the working directory. The path to the file from the root of the archive will be the same as the relative path to the file on disk.
//! taskHandles are used to cancel a task at some point in the future and are provided by the caller per task.
//! Multiple tasks can be associated with the same handle.
virtual void AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0;
//! Start a sync task to add a file to a preexisting archive.
//! fileToAdd must be a relative path to the file from the working directory. The path to the file from the root of the archive will be the same as the relative path to the file on disk.
virtual bool AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd) = 0;
//! Start an async task to add files to a archive.
//! File paths inside the list file must either be a relative path from the working directory or an absolute path.
virtual void AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) = 0;
//! Start a sync task to add files to an archive.
//! File paths inside the list file must either be a relative path from the working directory or an absolute path.
virtual bool AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath) = 0;
//! Cancels tasks associtated with the given handle. Blocks until all tasks are cancelled.
virtual void CancelTasks(AZ::Uuid taskHandle) = 0;
};
using ArchiveCommandsBus = AZ::EBus<ArchiveCommands>;
}; // namespace AzToolsFramework
@@ -0,0 +1,464 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "ArchiveComponent.h"
#include <AzCore/Component/TickBus.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <AzToolsFramework/Process/ProcessCommunicator.h>
#include <AzToolsFramework/Process/ProcessWatcher.h>
#include <AzFramework/FileFunc/FileFunc.h>
namespace AzToolsFramework
{
// Forward declare platform specific functions
namespace Platform
{
AZStd::string GetZipExePath();
AZStd::string GetUnzipExePath();
AZStd::string GetCreateArchiveCommand(const AZStd::string& archivePath, const AZStd::string& dirToArchive);
AZStd::string GetExtractArchiveCommand(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool includeRoot);
AZStd::string GetAddFileToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& file);
AZStd::string GetAddFilesToArchiveCommand(const AZStd::string& archivePath, const AZStd::string& listFilePath);
AZStd::string GetExtractFileCommand(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite);
AZStd::string GetListFilesInArchiveCommand(const AZStd::string& archivePath);
void ParseConsoleOutputFromListFilesInArchive(const AZStd::string& consoleOutput, AZStd::vector<AZStd::string>& fileEntries);
}
const char s_traceName[] = "ArchiveComponent";
const unsigned int g_sleepDuration = 1;
// Echoes all results of stdout and stderr to console and never blocks
class ConsoleEchoCommunicator
{
public:
ConsoleEchoCommunicator(AzToolsFramework::ProcessCommunicator* communicator)
: m_communicator(communicator)
{
}
~ConsoleEchoCommunicator()
{
}
// Call this periodically to drain the buffers
void Pump()
{
if (m_communicator->IsValid())
{
AZ::u32 readBufferSize = 0;
AZStd::string readBuffer;
// Don't call readOutput unless there is output or else it will block...
readBufferSize = m_communicator->PeekOutput();
if (readBufferSize)
{
readBuffer.resize_no_construct(readBufferSize + 1);
readBuffer[readBufferSize] = '\0';
m_communicator->ReadOutput(readBuffer.data(), readBufferSize);
EchoBuffer(readBuffer);
}
readBufferSize = m_communicator->PeekError();
if (readBufferSize)
{
readBuffer.resize_no_construct(readBufferSize + 1);
readBuffer[readBufferSize] = '\0';
m_communicator->ReadError(readBuffer.data(), readBufferSize);
EchoBuffer(readBuffer);
}
}
}
private:
void EchoBuffer(const AZStd::string& buffer)
{
size_t startIndex = 0;
size_t endIndex = 0;
const size_t bufferSize = buffer.size();
for (size_t i = 0; i < bufferSize; ++i)
{
if (buffer[i] == '\n' || buffer[i] == '\0')
{
endIndex = i;
bool isEmptyMessage = (endIndex - startIndex == 1) && (buffer[startIndex] == '\r');
if (!isEmptyMessage)
{
AZ_Printf(s_traceName, "%s", buffer.substr(startIndex, endIndex - startIndex).c_str());
}
startIndex = endIndex + 1;
}
}
}
AzToolsFramework::ProcessCommunicator* m_communicator = nullptr;
};
void ArchiveComponent::Activate()
{
m_zipExePath = Platform::GetZipExePath();
m_unzipExePath = Platform::GetUnzipExePath();
ArchiveCommands::Bus::Handler::BusConnect();
}
void ArchiveComponent::Deactivate()
{
ArchiveCommands::Bus::Handler::BusDisconnect();
AZStd::unique_lock<AZStd::mutex> lock(m_threadControlMutex);
for (auto pair : m_threadInfoMap)
{
ThreadInfo& info = pair.second;
info.shouldStop = true;
m_cv.wait(lock, [&info]() {
return info.threads.size() == 0;
});
}
m_threadInfoMap.clear();
}
void ArchiveComponent::Reflect(AZ::ReflectContext * context)
{
if (AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context))
{
serializeContext->Class<ArchiveComponent, AZ::Component>()
->Version(2)
->Attribute(AZ::Edit::Attributes::SystemComponentTags, AZStd::vector<AZ::Crc32>({ AZ_CRC("AssetBuilder", 0xc739c7d7) }))
;
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<ArchiveComponent>(
"Archive", "Handles creation and extraction of zip archives.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Editor")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System", 0xc94d118b))
;
}
}
}
void ArchiveComponent::CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback)
{
AZStd::string commandLineArgs = AZStd::string::format(R"(a -tzip -mx=1 "%s" -r "%s\*")", archivePath.c_str(), dirToArchive.c_str());
LaunchZipExe(m_zipExePath, commandLineArgs, respCallback, taskHandle);
}
bool ArchiveComponent::CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive)
{
bool success = false;
auto createArchiveCallback = [&success](bool result, AZStd::string consoleOutput) {
success = result;
};
AZStd::string commandLineArgs = Platform::GetCreateArchiveCommand(archivePath, dirToArchive);
if (commandLineArgs.empty())
{
// The platform-specific implementation has already thrown its own error, no need to throw another one
return false;
}
LaunchZipExe(m_zipExePath, commandLineArgs, createArchiveCallback, AZ::Uuid::CreateNull(), dirToArchive, false);
return success;
}
void ArchiveComponent::ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback)
{
ArchiveResponseOutputCallback responseHandler = [respCallback](bool result, AZStd::string /*outputStr*/) { respCallback(result); };
ExtractArchiveOutput(archivePath, destinationPath, taskHandle, responseHandler);
}
void ArchiveComponent::ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback)
{
AZStd::string commandLineArgs = Platform::GetExtractArchiveCommand(archivePath, destinationPath, true);
if (commandLineArgs.empty())
{
// The platform-specific implementation has already thrown its own error, no need to throw another one
return;
}
LaunchZipExe(m_unzipExePath, commandLineArgs, respCallback, taskHandle);
}
void ArchiveComponent::ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback)
{
AZStd::string commandLineArgs = Platform::GetExtractArchiveCommand(archivePath, destinationPath, false);
if (commandLineArgs.empty())
{
// The platform-specific implementation has already thrown its own error, no need to throw another one
return;
}
LaunchZipExe(m_unzipExePath, commandLineArgs, respCallback, taskHandle);
}
void ArchiveComponent::ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback)
{
AZStd::string commandLineArgs = AzToolsFramework::Platform::GetExtractFileCommand(archivePath, fileInArchive, destinationPath, overWrite);
if (commandLineArgs.empty())
{
// The platform-specific implementation has already thrown its own error, no need to throw another one
return;
}
LaunchZipExe(m_unzipExePath, commandLineArgs, respCallback, taskHandle);
}
bool ArchiveComponent::ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite)
{
AZStd::string commandLineArgs = AzToolsFramework::Platform::GetExtractFileCommand(archivePath, fileInArchive, destinationPath, overWrite);
if (commandLineArgs.empty())
{
// The platform-specific implementation has already thrown its own error, no need to throw another one
return false;
}
bool success = false;
auto createArchiveCallback = [&success](bool result, AZStd::string consoleOutput) {
success = result;
};
LaunchZipExe(m_unzipExePath, commandLineArgs, createArchiveCallback);
return success;
}
void ArchiveComponent::ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector<AZStd::string>& fileEntries, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback)
{
AZStd::string commandLineArgs = Platform::GetListFilesInArchiveCommand(archivePath);
auto parseOutput = [respCallback, taskHandle, &fileEntries](bool exitCode, AZStd::string consoleOutput)
{
Platform::ParseConsoleOutputFromListFilesInArchive(consoleOutput, fileEntries);
AZ::TickBus::QueueFunction(respCallback, exitCode, AZStd::move(consoleOutput));
};
LaunchZipExe(m_unzipExePath, commandLineArgs, parseOutput, taskHandle, "", true);
}
bool ArchiveComponent::ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector<AZStd::string>& fileEntries)
{
AZStd::string listOutput;
AZStd::string commandLineArgs = Platform::GetListFilesInArchiveCommand(archivePath.c_str());
bool success = false;
auto parseOutput = [&success, &fileEntries](bool result, AZStd::string consoleOutput)
{
Platform::ParseConsoleOutputFromListFilesInArchive(consoleOutput, fileEntries);
success = result;
};
LaunchZipExe(m_unzipExePath, commandLineArgs, parseOutput, AZ::Uuid::CreateNull(), "", true);
return success;
}
void ArchiveComponent::AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback)
{
AZStd::string commandLineArgs = Platform::GetAddFileToArchiveCommand(archivePath, fileToAdd);
if (commandLineArgs.empty())
{
// The platform-specific implementation has already thrown its own error, no need to throw another one
return;
}
LaunchZipExe(m_zipExePath, commandLineArgs, respCallback, taskHandle, workingDirectory);
}
bool ArchiveComponent::AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd)
{
AZStd::string commandLineArgs = Platform::GetAddFileToArchiveCommand(archivePath, fileToAdd);
if (commandLineArgs.empty())
{
// The platform-specific implementation has already thrown its own error, no need to throw another one
return false;
}
bool success = false;
auto addFileToArchiveCallback = [&success](bool result, AZStd::string consoleOutput) {
success = result;
};
LaunchZipExe(m_zipExePath, commandLineArgs, addFileToArchiveCallback, AZ::Uuid::CreateNull(), workingDirectory);
return success;
}
bool ArchiveComponent::AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath)
{
bool success = false;
auto addFileToArchiveCallback = [&success](bool result, AZStd::string consoleOutput) {
success = result;
};
AZStd::string commandLineArgs = Platform::GetAddFilesToArchiveCommand(archivePath.c_str(), listFilePath.c_str());
if (commandLineArgs.empty())
{
// The platform-specific implementation has already thrown its own error, no need to throw another one
return false;
}
LaunchZipExe(m_zipExePath, commandLineArgs, addFileToArchiveCallback, AZ::Uuid::CreateNull(), workingDirectory);
return success;
}
void ArchiveComponent::AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback)
{
AZStd::string commandLineArgs = Platform::GetAddFilesToArchiveCommand(archivePath, listFilePath);
if (commandLineArgs.empty())
{
// The platform-specific implementation has already thrown its own error, no need to throw another one
return;
}
LaunchZipExe(m_zipExePath, commandLineArgs, respCallback, taskHandle, workingDirectory);
}
bool ArchiveComponent::ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory)
{
AZStd::string commandLineArgs = Platform::GetExtractArchiveCommand(archivePath, destinationPath, extractWithRootDirectory);
if (commandLineArgs.empty())
{
// The platform-specific implementation has already thrown its own error, no need to throw another one
return false;
}
bool success = false;
auto extractArchiveCallback = [&success](bool result, AZStd::string consoleOutput) {
success = result;
};
LaunchZipExe(m_unzipExePath, commandLineArgs, extractArchiveCallback);
return success;
}
void ArchiveComponent::CancelTasks(AZ::Uuid taskHandle)
{
AZStd::unique_lock<AZStd::mutex> lock(m_threadControlMutex);
auto it = m_threadInfoMap.find(taskHandle);
if (it == m_threadInfoMap.end())
{
return;
}
ThreadInfo& info = it->second;
info.shouldStop = true;
m_cv.wait(lock, [&info]() {
return info.threads.size() == 0;
});
m_threadInfoMap.erase(it);
}
void ArchiveComponent::LaunchZipExe(const AZStd::string& exePath, const AZStd::string& commandLineArgs, const ArchiveResponseOutputCallback& respCallback, AZ::Uuid taskHandle, const AZStd::string& workingDir, bool captureOutput)
{
auto sevenZJob = [=]()
{
if (!taskHandle.IsNull())
{
AZStd::unique_lock<AZStd::mutex> lock(m_threadControlMutex);
m_threadInfoMap[taskHandle].threads.insert(AZStd::this_thread::get_id());
m_cv.notify_all();
}
ProcessLauncher::ProcessLaunchInfo info;
info.m_commandlineParameters = exePath + " " + commandLineArgs;
info.m_showWindow = false;
if (!workingDir.empty())
{
info.m_workingDirectory = workingDir;
}
AZStd::unique_ptr<ProcessWatcher> watcher(ProcessWatcher::LaunchProcess(info, ProcessCommunicationType::COMMUNICATOR_TYPE_STDINOUT));
AZStd::string consoleOutput;
AZ::u32 exitCode = static_cast<AZ::u32>(SevenZipExitCode::UserStoppedProcess);
if (watcher)
{
// callback requires output captured from 7z
if (captureOutput)
{
AZStd::string consoleBuffer;
while (watcher->IsProcessRunning(&exitCode))
{
if (!taskHandle.IsNull())
{
AZStd::unique_lock<AZStd::mutex> lock(m_threadControlMutex);
if (m_threadInfoMap[taskHandle].shouldStop)
{
watcher->TerminateProcess(static_cast<AZ::u32>(SevenZipExitCode::UserStoppedProcess));
}
}
watcher->WaitForProcessToExit(g_sleepDuration, &exitCode);
AZ::u32 outputSize = watcher->GetCommunicator()->PeekOutput();
if (outputSize)
{
consoleBuffer.resize(outputSize);
watcher->GetCommunicator()->ReadOutput(consoleBuffer.data(), outputSize);
consoleOutput += consoleBuffer;
}
}
}
else
{
ConsoleEchoCommunicator echoCommunicator(watcher->GetCommunicator());
while (watcher->IsProcessRunning(&exitCode))
{
if (!taskHandle.IsNull())
{
AZStd::unique_lock<AZStd::mutex> lock(m_threadControlMutex);
if (m_threadInfoMap[taskHandle].shouldStop)
{
watcher->TerminateProcess(static_cast<AZ::u32>(SevenZipExitCode::UserStoppedProcess));
}
}
watcher->WaitForProcessToExit(g_sleepDuration, &exitCode);
echoCommunicator.Pump();
}
}
}
if (taskHandle.IsNull())
{
respCallback(exitCode == static_cast<AZ::u32>(SevenZipExitCode::NoError), AZStd::move(consoleOutput));
}
else
{
AZ::TickBus::QueueFunction(respCallback, (exitCode == static_cast<AZ::u32>(SevenZipExitCode::NoError)), AZStd::move(consoleOutput));
}
if (!taskHandle.IsNull())
{
AZStd::unique_lock<AZStd::mutex> lock(m_threadControlMutex);
ThreadInfo& tInfo = m_threadInfoMap[taskHandle];
tInfo.threads.erase(AZStd::this_thread::get_id());
m_cv.notify_all();
}
};
if (!taskHandle.IsNull())
{
AZStd::thread processThread(sevenZJob);
AZStd::unique_lock<AZStd::mutex> lock(m_threadControlMutex);
ThreadInfo& info = m_threadInfoMap[taskHandle];
m_cv.wait(lock, [&info, &processThread]() {
return info.threads.find(processThread.get_id()) != info.threads.end();
});
processThread.detach();
}
else
{
sevenZJob();
}
}
} // namespace AzToolsFramework
@@ -0,0 +1,93 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/base.h>
#include <AzCore/Component/Component.h>
#include <AzCore/std/parallel/thread.h>
#include <AzCore/std/parallel/conditional_variable.h>
#include <AzCore/std/containers/set.h>
#include <AzCore/std/containers/unordered_set.h>
#include <AzToolsFramework/Archive/ArchiveAPI.h>
namespace AzToolsFramework
{
enum class SevenZipExitCode : AZ::u32
{
NoError = 0,
Warning = 1,
FatalError = 2,
CommandLineError = 7,
NotEnoughMemory = 8,
UserStoppedProcess = 255
};
// the ArchiveComponent's job is to execute zip commands.
// it parses the status of zip commands and returns results.
class ArchiveComponent
: public AZ::Component
, private ArchiveCommands::Bus::Handler
{
public:
AZ_COMPONENT(ArchiveComponent, "{A19EEA33-3736-447F-ACF7-DAA4B6A179AA}")
ArchiveComponent() = default;
~ArchiveComponent() override = default;
//////////////////////////////////////////////////////////////////////////
// AZ::Component overrides
void Activate() override;
void Deactivate() override;
//////////////////////////////////////////////////////////////////////////
private:
static void Reflect(AZ::ReflectContext* context);
//////////////////////////////////////////////////////////////////////////
// ArchiveCommands::Bus::Handler overrides
void CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
bool CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive) override;
bool ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory) override;
void ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback) override;
void ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
void ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
void ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
bool ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) override;
void ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector<AZStd::string>& fileEntries, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
bool ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector<AZStd::string>& fileEntries) override;
void AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
bool AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& fileToAdd) override;
bool AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath) override;
void AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
void CancelTasks(AZ::Uuid taskHandle) override;
//////////////////////////////////////////////////////////////////////////
// Launches the input zip exe as a background child process in a detached background thread, if the task handle is not null
// otherwise launches input zip exe in the calling thread.
void LaunchZipExe(const AZStd::string& exePath, const AZStd::string& commandLineArgs, const ArchiveResponseOutputCallback& respCallback, AZ::Uuid taskHandle = AZ::Uuid::CreateNull(), const AZStd::string& workingDir = "", bool captureOutput = false);
AZStd::string m_zipExePath;
AZStd::string m_unzipExePath;
// Struct for tracking background threads/tasks
struct ThreadInfo
{
bool shouldStop = false;
AZStd::set<AZStd::thread::id> threads;
};
AZStd::mutex m_threadControlMutex; // Guards m_threadInfoMap
AZStd::condition_variable m_cv;
AZStd::unordered_map<AZ::Uuid, ThreadInfo> m_threadInfoMap;
};
} // namespace AzToolsFramework
@@ -0,0 +1,119 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "NullArchiveComponent.h"
#include <AzCore/Component/TickBus.h>
#include <AzCore/Serialization/SerializeContext.h>
namespace AzToolsFramework
{
void NullArchiveComponent::Activate()
{
ArchiveCommands::Bus::Handler::BusConnect();
}
void NullArchiveComponent::Deactivate()
{
ArchiveCommands::Bus::Handler::BusDisconnect();
}
bool NullArchiveComponent::ExtractArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, bool /*extractWithRootDirectory*/)
{
return false;
}
void NullArchiveComponent::ExtractArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseCallback& respCallback)
{
AZ::TickBus::QueueFunction(respCallback, false);
}
void NullArchiveComponent::ExtractArchiveOutput(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback)
{
AZ::TickBus::QueueFunction(respCallback, false, AZStd::string());
}
void NullArchiveComponent::ExtractArchiveWithoutRoot(const AZStd::string& /*archivePath*/, const AZStd::string& /*destinationPath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback)
{
AZ::TickBus::QueueFunction(respCallback, false, AZStd::string());
}
void NullArchiveComponent::ExtractFile(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileInArchive*/, const AZStd::string& /*destinationPath*/, bool /*overWrite*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback)
{
// Always report we failed to extract
AZ::TickBus::QueueFunction(respCallback, false, AZStd::string());
}
bool NullArchiveComponent::ExtractFileBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileInArchive*/, const AZStd::string& /*destinationPath*/, bool /*overWrite*/)
{
return false;
}
void NullArchiveComponent::ListFilesInArchive(const AZStd::string& /*archivePath*/, AZStd::vector<AZStd::string>& /*consoleOutput*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback)
{
// Always report we failed to extract
AZ::TickBus::QueueFunction(respCallback, false, AZStd::string());
}
bool NullArchiveComponent::ListFilesInArchiveBlocking(const AZStd::string& /*archivePath*/, AZStd::vector<AZStd::string>& /*consoleOutput*/)
{
return false;
}
void NullArchiveComponent::AddFileToArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileToAdd*/, const AZStd::string& /*pathInArchive*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback)
{
// Always report we failed to extract
AZ::TickBus::QueueFunction(respCallback, false, AZStd::string());
}
bool NullArchiveComponent::AddFileToArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*fileToAdd*/, const AZStd::string& /*pathInArchive*/)
{
return false;
}
bool NullArchiveComponent::AddFilesToArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*workingDirectory*/, const AZStd::string& /*listFilePath*/)
{
return false;
}
void NullArchiveComponent::AddFilesToArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*workingDirectory*/, const AZStd::string& /*listFilePath*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback)
{
// Always report we failed to extract
AZ::TickBus::QueueFunction(respCallback, false, AZStd::string());
}
void NullArchiveComponent::CreateArchive(const AZStd::string& /*archivePath*/, const AZStd::string& /*dirToArchive*/, AZ::Uuid /*taskHandle*/, const ArchiveResponseOutputCallback& respCallback)
{
// Always report we failed to extract
AZ::TickBus::QueueFunction(respCallback, false, AZStd::string());
}
bool NullArchiveComponent::CreateArchiveBlocking(const AZStd::string& /*archivePath*/, const AZStd::string& /*dirToArchive*/)
{
return false;
}
void NullArchiveComponent::CancelTasks(AZ::Uuid /*taskHandle*/)
{
}
void NullArchiveComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<NullArchiveComponent, AZ::Component>()
;
}
}
} // namespace AzToolsFramework
@@ -0,0 +1,58 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <AzToolsFramework/Archive/ArchiveAPI.h>
namespace AzToolsFramework
{
class NullArchiveComponent
: public AZ::Component
, private ArchiveCommands::Bus::Handler
{
public:
AZ_COMPONENT(NullArchiveComponent, "{D665B6B1-5FF4-4203-B19F-BBDB82587129}")
NullArchiveComponent() = default;
~NullArchiveComponent() override = default;
//////////////////////////////////////////////////////////////////////////
// AZ::Component overrides
void Activate() override;
void Deactivate() override;
//////////////////////////////////////////////////////////////////////////
private:
static void Reflect(AZ::ReflectContext* context);
//////////////////////////////////////////////////////////////////////////
// ArchiveCommands::Bus::Handler overrides
// ArchiveCommands::Bus::Handler overrides
void CreateArchive(const AZStd::string& archivePath, const AZStd::string& dirToArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
bool CreateArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& dirToArchive) override;
bool ExtractArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& destinationPath, bool extractWithRootDirectory) override;
void ExtractArchive(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseCallback& respCallback) override;
void ExtractArchiveOutput(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
void ExtractArchiveWithoutRoot(const AZStd::string& archivePath, const AZStd::string& destinationPath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
void ExtractFile(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
bool ExtractFileBlocking(const AZStd::string& archivePath, const AZStd::string& fileInArchive, const AZStd::string& destinationPath, bool overWrite) override;
void ListFilesInArchive(const AZStd::string& archivePath, AZStd::vector<AZStd::string>& consoleOutput, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
bool ListFilesInArchiveBlocking(const AZStd::string& archivePath, AZStd::vector<AZStd::string>& consoleOutput) override;
void AddFileToArchive(const AZStd::string& archivePath, const AZStd::string& fileToAdd, const AZStd::string& pathInArchive, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
bool AddFileToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& fileToAdd, const AZStd::string& pathInArchive) override;
bool AddFilesToArchiveBlocking(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath) override;
void AddFilesToArchive(const AZStd::string& archivePath, const AZStd::string& workingDirectory, const AZStd::string& listFilePath, AZ::Uuid taskHandle, const ArchiveResponseOutputCallback& respCallback) override;
void CancelTasks(AZ::Uuid taskHandle) override;
//////////////////////////////////////////////////////////////////////////
};
} // namespace AzToolsFramework