Ver Fonte

Additional remote project fixes

Signed-off-by: AMZN-Phil <[email protected]>
AMZN-Phil há 2 anos atrás
pai
commit
d2bdb7f30a

+ 1 - 0
Code/Tools/ProjectManager/Resources/ProjectManager.qrc

@@ -47,5 +47,6 @@
         <file>SpinningGears.webp</file>
         <file>Cloud.svg</file>
         <file>Cloud_Hover.svg</file>
+        <file>error.svg</file>
     </qresource>
 </RCC>

+ 9 - 0
Code/Tools/ProjectManager/Resources/error.svg

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <title>Icons / Notification / Error - black</title>
+    <g id="Icons-/-Notification-/-Error---black" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <rect id="Icon-Background" x="0" y="0" width="24" height="24"></rect>
+        <circle id="Oval" fill="#222222" cx="12" cy="12" r="10"></circle>
+        <path d="M12,22 C6.4771525,22 2,17.5228475 2,12 C2,6.4771525 6.4771525,2 12,2 C17.5228475,2 22,6.4771525 22,12 C22,17.5228475 17.5228475,22 12,22 Z M10.7544302,11.9140192 L6.01969457,16.6545313 L7.12818919,17.7643783 L11.8629248,13.0238662 L16.6415483,17.8083198 L17.750043,16.6984728 L12.9714194,11.9140192 L17.7697375,7.10984701 L16.6612429,6 L11.8629248,10.8041722 L7.10849462,6.04394146 L6,7.15378847 L10.7544302,11.9140192 L10.7544302,11.9140192 Z" id="Shape" fill="#E25243"></path>
+    </g>
+</svg>

+ 7 - 2
Code/Tools/ProjectManager/Source/AddRemoteProjectDialog.cpp

@@ -48,6 +48,7 @@ namespace O3DE::ProjectManager
 
         m_repoPath = new FormLineEditWidget(tr("Remote URL"), "", this);
         m_repoPath->setMinimumSize(QSize(600, 0));
+        m_repoPath->setErrorLabelText(tr("Not a valid remote source."));
         vLayout->addWidget(m_repoPath);
 
         vLayout->addSpacing(10);
@@ -171,7 +172,7 @@ namespace O3DE::ProjectManager
             {
                 // wait for a second before attempting to validate so we're less likely to do it per keypress
                 m_inputTimer->start(1000);
-                
+                m_repoPath->SetValidationState(FormLineEditWidget::ValidationState::Validating);
             });
 
         SetDialogReady(false);
@@ -200,6 +201,10 @@ namespace O3DE::ProjectManager
             }
         }
 
+        m_repoPath->SetValidationState(
+            (validRepository && containsProjects) ? FormLineEditWidget::ValidationState::ValidationSuccess
+                                                  : FormLineEditWidget::ValidationState::ValidationFailed);
+        m_repoPath->setErrorLabelVisible(!(validRepository && containsProjects));
         SetDialogReady(validRepository && containsProjects);
     }
 
@@ -211,7 +216,7 @@ namespace O3DE::ProjectManager
         if (addGemRepoResult.IsSuccess())
         {
             // Send download to project screen to initiate download
-            emit StartObjectDownload(m_currentProject.m_projectName);
+            emit StartObjectDownload(m_currentProject.m_projectName, ShouldBuild());
             emit QDialog::accept();
         }
         else

+ 1 - 1
Code/Tools/ProjectManager/Source/AddRemoteProjectDialog.h

@@ -43,7 +43,7 @@ namespace O3DE::ProjectManager
         void SetDialogReady(bool isReady);
 
     signals:
-        void StartObjectDownload(const QString& objectName);
+        void StartObjectDownload(const QString& objectName, bool queueBuild);
 
     private slots:
         void ValidateURI();

+ 50 - 0
Code/Tools/ProjectManager/Source/FormLineEditWidget.cpp

@@ -13,6 +13,7 @@
 #include <QHBoxLayout>
 #include <QLineEdit>
 #include <QLabel>
+#include <QMovie>
 #include <QFrame>
 #include <QValidator>
 #include <QStyle>
@@ -54,6 +55,23 @@ namespace O3DE::ProjectManager
 
                 QWidget* emptyWidget = new QWidget(this);
                 m_frameLayout->addWidget(emptyWidget);
+
+                m_processingSpinnerMovie = new QMovie(":/in_progress.gif");
+                m_processingSpinner = new QLabel(this);
+                m_processingSpinner->setScaledContents(true);
+                m_processingSpinner->setMaximumSize(32, 32);
+                m_processingSpinner->setMovie(m_processingSpinnerMovie);
+                m_frameLayout->addWidget(m_processingSpinner);
+
+                m_validationErrorIcon = new QLabel(this);
+                m_validationErrorIcon->setPixmap(QIcon(":/error.svg").pixmap(32, 32));
+                m_frameLayout->addWidget(m_validationErrorIcon);
+
+                m_validationSuccessIcon = new QLabel(this);
+                m_validationSuccessIcon->setPixmap(QIcon(":/checkmark.svg").pixmap(32, 32));
+                m_frameLayout->addWidget(m_validationSuccessIcon);
+
+                SetValidationState(ValidationState::NotValidating);
             }
 
             m_frame->setLayout(m_frameLayout);
@@ -130,6 +148,38 @@ namespace O3DE::ProjectManager
         m_lineEdit->setText(text);
     }
 
+    void FormLineEditWidget::SetValidationState(ValidationState validationState)
+    {
+        switch (validationState)
+        {
+        case ValidationState::Validating:
+            m_processingSpinnerMovie->start();
+            m_processingSpinner->setVisible(true);
+            m_validationErrorIcon->setVisible(false);
+            m_validationSuccessIcon->setVisible(false);
+            break;
+        case ValidationState::ValidationSuccess:
+            m_processingSpinnerMovie->stop();
+            m_processingSpinner->setVisible(false);
+            m_validationErrorIcon->setVisible(false);
+            m_validationSuccessIcon->setVisible(true);
+            break;
+        case ValidationState::ValidationFailed:
+            m_processingSpinnerMovie->stop();
+            m_processingSpinner->setVisible(false);
+            m_validationErrorIcon->setVisible(true);
+            m_validationSuccessIcon->setVisible(false);
+            break;
+        case ValidationState::NotValidating:
+        default:
+            m_processingSpinnerMovie->stop();
+            m_processingSpinner->setVisible(false);
+            m_validationErrorIcon->setVisible(false);
+            m_validationSuccessIcon->setVisible(false);
+            break;
+        }
+    }
+
     void FormLineEditWidget::mousePressEvent([[maybe_unused]] QMouseEvent* event)
     {
         m_lineEdit->setFocus();

+ 19 - 0
Code/Tools/ProjectManager/Source/FormLineEditWidget.h

@@ -15,6 +15,7 @@
 QT_FORWARD_DECLARE_CLASS(QLineEdit)
 QT_FORWARD_DECLARE_CLASS(QLabel)
 QT_FORWARD_DECLARE_CLASS(QFrame)
+QT_FORWARD_DECLARE_CLASS(QMovie)
 QT_FORWARD_DECLARE_CLASS(QHBoxLayout)
 QT_FORWARD_DECLARE_CLASS(QMouseEvent)
 
@@ -31,6 +32,15 @@ namespace O3DE::ProjectManager
         Q_OBJECT
 
     public:
+
+        enum class ValidationState
+        {
+            NotValidating,
+            Validating,
+            ValidationFailed,
+            ValidationSuccess
+        };
+
         explicit FormLineEditWidget(const QString& labelText, const QString& valueText = "", QWidget* parent = nullptr);
         ~FormLineEditWidget() = default;
 
@@ -43,12 +53,21 @@ namespace O3DE::ProjectManager
 
         virtual void setText(const QString& text);
 
+        void SetValidationState(ValidationState validationState);
+
     protected:
         QLabel* m_errorLabel = nullptr;
         QFrame* m_frame = nullptr;
         QHBoxLayout* m_frameLayout = nullptr;
         AzQtComponents::StyledLineEdit* m_lineEdit = nullptr;
 
+        //Validation icons
+        QMovie* m_processingSpinnerMovie = nullptr;
+        QLabel* m_processingSpinner = nullptr;
+        QLabel* m_validationErrorIcon = nullptr;
+        QLabel* m_validationSuccessIcon = nullptr;
+        ValidationState m_validationState;
+
     private slots:
         void flavorChanged();
         void onFocus();

+ 1 - 0
Code/Tools/ProjectManager/Source/ProjectButtonWidget.cpp

@@ -445,6 +445,7 @@ namespace O3DE::ProjectManager
         case ProjectButtonState::NotDownloaded:
             ShowNotDownloadedState();
             break;
+        case ProjectButtonState::DownloadingBuildQueued:
         case ProjectButtonState::Downloading:
             ShowDownloadingState();
             break;

+ 5 - 0
Code/Tools/ProjectManager/Source/ProjectButtonWidget.h

@@ -98,6 +98,7 @@ namespace O3DE::ProjectManager
         BuildFailed,
         NotDownloaded,
         Downloading,
+        DownloadingBuildQueued,
         DownloadFailed
     };
 
@@ -115,6 +116,10 @@ namespace O3DE::ProjectManager
         void SetEngine(const EngineInfo& engine);
         void SetProject(const ProjectInfo& project);
         void SetState(enum ProjectButtonState state);
+        const ProjectButtonState& GetState() const
+        {
+            return m_currentState;
+         }
 
         void SetProjectButtonAction(const QString& text, AZStd::function<void()> lambda);
         void SetBuildLogsLink(const QUrl& logUrl);

+ 45 - 4
Code/Tools/ProjectManager/Source/ProjectsScreen.cpp

@@ -670,7 +670,7 @@ namespace O3DE::ProjectManager
         ResetProjectsContent();
     }
 
-    void ProjectsScreen::StartProjectDownload(const QString& projectName)
+    void ProjectsScreen::StartProjectDownload(const QString& projectName, bool queueBuild)
     {
         m_downloadController->AddObjectDownload(projectName, DownloadController::DownloadObjectType::Project);
 
@@ -682,13 +682,54 @@ namespace O3DE::ProjectManager
 
         if (foundButton != m_projectButtons.end())
         {
-            (*foundButton).second->SetState(ProjectButtonState::Downloading);
+            (*foundButton).second->SetState(queueBuild ? ProjectButtonState::DownloadingBuildQueued : ProjectButtonState::Downloading);
         }
     }
 
-    void ProjectsScreen::HandleDownloadResult(const QString& /*projectName*/, bool /*succeeded*/)
+    void ProjectsScreen::HandleDownloadResult(const QString& projectName, bool succeeded)
     {
-        ResetProjectsContent();
+        auto foundButton = AZStd::ranges::find_if(
+            m_projectButtons,
+            [&projectName](const AZStd::unordered_map<AZ::IO::Path, ProjectButton*>::value_type& value)
+            {
+                return (value.second->GetProjectInfo().m_projectName == projectName);
+            });
+
+        if (foundButton != m_projectButtons.end())
+        {
+            if (succeeded)
+            {
+                // Find the project info since it should now be local
+                auto projectsResult = PythonBindingsInterface::Get()->GetProjects();
+                if (projectsResult.IsSuccess() && !projectsResult.GetValue().isEmpty())
+                {
+                    for (const ProjectInfo& projectInfo : projectsResult.GetValue())
+                    {
+                        if (projectInfo.m_projectName == projectName)
+                        {
+                            (*foundButton).second->SetProject(projectInfo);
+
+                            if ((*foundButton).second->GetState() == ProjectButtonState::DownloadingBuildQueued)
+                            {
+                                QueueBuildProject(projectInfo);
+                            }
+                            else
+                            {
+                                (*foundButton).second->SetState(ProjectButtonState::NeedsToBuild);
+                            }
+                        }
+                    }
+                }
+            }
+            else
+            {
+                (*foundButton).second->SetState(ProjectButtonState::NotDownloaded);
+            }
+        }
+        else
+        {
+            ResetProjectsContent();
+        }
     }
 
     void ProjectsScreen::HandleDownloadProgress(const QString& projectName, DownloadController::DownloadObjectType objectType, int bytesDownloaded, int totalBytes)

+ 1 - 1
Code/Tools/ProjectManager/Source/ProjectsScreen.h

@@ -63,7 +63,7 @@ namespace O3DE::ProjectManager
         void QueueBuildProject(const ProjectInfo& projectInfo);
         void UnqueueBuildProject(const ProjectInfo& projectInfo);
 
-        void StartProjectDownload(const QString& projectName);
+        void StartProjectDownload(const QString& projectName, bool queueBuild);
         void HandleDownloadProgress(const QString& projectName, DownloadController::DownloadObjectType objectType, int bytesDownloaded, int totalBytes);
         void HandleDownloadResult(const QString& projectName, bool succeeded);
 

+ 10 - 4
scripts/o3de/o3de/github_utils.py

@@ -30,10 +30,16 @@ class GitHubProvider(gitproviderinterface.GitProviderInterface):
         filepath = '/'.join(components[2:len(components)])
         api_url = f'http://api.github.com/repos/{user}/{repository}/contents/{filepath}'
 
-        with urllib.request.urlopen(api_url) as url:
-            json_data = json.loads(url.read().decode())
-            download_url = json_data['download_url']
-            parsed_uri = urllib.parse.urlparse(download_url)
+        try:
+            with urllib.request.urlopen(api_url) as url:
+                json_data = json.loads(url.read().decode())
+                download_url = json_data['download_url']
+                parsed_uri = urllib.parse.urlparse(download_url)
+        except urllib.error.HTTPError as e:
+            logger.error(f'HTTP Error {e.code} opening {api_url.geturl()}')
+        except urllib.error.URLError as e:
+            logger.error(f'URL Error {e.reason} opening {api_url.geturl()}')
+
         return parsed_uri
 
     def clone_from_git(uri, download_path: pathlib.Path) -> int:

+ 4 - 10
scripts/o3de/o3de/repo.py

@@ -254,20 +254,15 @@ def get_template_json_paths_from_all_cached_repos() -> set:
     return template_set
 
 def refresh_repo(repo_uri: str,
-                 cache_folder: str = None,
                  repo_set: set = None) -> int:
-    if not cache_folder:
-        cache_folder = manifest.get_o3de_cache_folder()
     if not repo_set:
         repo_set = set()
 
     repo_uri = f'{repo_uri}/repo.json'
-    cache_file, parsed_uri = get_cache_file_uri(repo_uri)
-
-    download_file_result = utils.download_file(parsed_uri, cache_file, True)
-    if download_file_result != 0:
+    cache_file = download_repo_manifest(repo_uri)
+    if not cache_file:
         logger.error(f'Repo json {repo_uri} could not download.')
-        return download_file_result
+        return 1
 
     if not validation.valid_o3de_repo_json(cache_file):
         logger.error(f'Repo json {repo_uri} is not valid.')
@@ -278,7 +273,6 @@ def refresh_repo(repo_uri: str,
 
 def refresh_repos() -> int:
     json_data = manifest.load_o3de_manifest()
-    cache_folder = manifest.get_o3de_cache_folder()
     result = 0
 
     # set will stop circular references
@@ -288,7 +282,7 @@ def refresh_repos() -> int:
         if repo_uri not in repo_set:
             repo_set.add(repo_uri)
 
-            last_failure = refresh_repo(repo_uri, cache_folder, repo_set)
+            last_failure = refresh_repo(repo_uri, repo_set)
             if last_failure:
                 result = last_failure