Merge branch 'main' into beta

This commit is contained in:
David Capello 2021-09-29 10:16:02 -03:00
commit f318a42f19
18 changed files with 334 additions and 13 deletions

View File

@ -79,8 +79,14 @@ option(ENABLE_UI "Compile UI (turn off to compile CLI-only version)" o
option(FULLSCREEN_PLATFORM "Enable fullscreen by default" off)
option(ENABLE_CLANG_TIDY "Enable static analysis" off)
option(ENABLE_CCACHE "Use CCache to improve recompilation speed (optional)" on)
option(ENABLE_SENTRY "Use Sentry SDK to report crashes" off)
set(CUSTOM_WEBSITE_URL "" CACHE STRING "Enable custom local webserver to check updates")
if(ENABLE_SENTRY)
set(SENTRY_DIR "" CACHE STRING "Sentry native location")
set(SENTRY_DNS "" CACHE STRING "Sentry DNS URL")
endif()
if(ENABLE_NEWS OR ENABLE_UPDATER)
set(REQUIRE_CURL ON)
else()

View File

@ -735,6 +735,9 @@
<style id="workspace_tabs">
<background color="workspace" />
</style>
<style id="workspace_check_box" extends="check_box" padding="4">
<text color="workspace_text" align="left middle" x="14" />
</style>
<style id="tab">
<background part="tab_normal" align="middle" />
<background part="tab_active" align="middle" state="focus" />

View File

@ -783,11 +783,16 @@ Recover files from crashed sessions or
closed sprite that were not saved in
previous sessions.
END
share_crashdb = Share crash data with Aseprite developers
share_crashdb_tooltip = <<<END
Check to share crash data with Aseprite developers automatically.
This will help to find new bugs and improve the general stability
of Aseprite for all users.
END
recent_files = Recent files:
recent_folders = Recent folders:
news = News:
checking_updates = Checking Updates...
is_up_to_date = {0} is up to date
new_version_available = New {0} v{1} available!
[import_sprite_sheet]

View File

@ -1,5 +1,5 @@
<!-- Aseprite -->
<!-- Copyright (C) 2019 Igara Studio S.A. -->
<!-- Copyright (C) 2019-2021 Igara Studio S.A. -->
<!-- Copyright (C) 2001-2017 David Capello -->
<gui>
<vbox noborders="true" id="home_view" border="4" childspacing="2" expansive="true">
@ -14,6 +14,8 @@
</vbox>
<boxfiller />
<vbox border="4">
<check id="share_crashdb" text="@.share_crashdb"
tooltip="@.share_crashdb_tooltip" style="workspace_check_box" />
<link id="check_update" text="" style="workspace_link" />
</vbox>
</hbox>

View File

@ -68,6 +68,9 @@
text="@.color_bar_entries_separator"
tooltip="@.color_bar_entries_separator"
pref="color_bar.entries_separator" />
<check id="share_crashdb"
text="@home_view.share_crashdb"
tooltip="@home_view.share_crashdb_tooltip" />
<separator horizontal="true" />
<link id="locate_file" text="@.locate_file" />

View File

@ -975,6 +975,31 @@ possible. They may also add themselves to the list below.
*/
```
# [Sentry](https://sentry.io)
```
Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors.
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
# [skia](https://skia.org)
```

View File

@ -410,6 +410,13 @@ if(ENABLE_UI)
endif()
endif()
set(send_crash_files)
if(ENABLE_SENTRY)
set(send_crash_files sentry_wrapper.cpp)
else()
set(send_crash_files send_crash.cpp)
endif()
add_library(app-lib
active_site_handler.cpp
app.cpp
@ -596,7 +603,6 @@ add_library(app-lib
res/resources_loader.cpp
resource_finder.cpp
restore_visible_layers.cpp
send_crash.cpp
shade.cpp
site.cpp
snap_to_grid.cpp
@ -638,6 +644,7 @@ add_library(app-lib
util/wrap_point.cpp
xml_document.cpp
xml_exception.cpp
${send_crash_files}
${ui_app_files}
${app_platform_files}
${data_recovery_files}
@ -698,3 +705,12 @@ if(ENABLE_STEAM)
add_definitions(-DENABLE_STEAM)
target_link_libraries(app-lib steam-lib)
endif()
if(ENABLE_SENTRY)
target_compile_definitions(app-lib PUBLIC
-DENABLE_SENTRY
-DSENTRY_BUILD_STATIC=1
-DSENTRY_DNS="${SENTRY_DNS}")
add_subdirectory(${SENTRY_DIR} sentry)
target_link_libraries(app-lib sentry)
endif()

View File

@ -418,8 +418,10 @@ void App::run()
checkUpdate.launch();
#endif
#if !ENABLE_SENTRY
app::SendCrash sendCrash;
sendCrash.search();
#endif
// Keep the console alive the whole program execute (just in case
// we've to print errors).

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2020-2021 Igara Studio S.A.
// Copyright (C) 2001-2017 David Capello
//
// This program is distributed under the terms of
@ -21,6 +21,10 @@
#include "base/version.h"
#include "ver/info.h"
#if ENABLE_SENTRY
#include "app/sentry_wrapper.h"
#endif
#include <ctime>
#include <sstream>
@ -113,6 +117,14 @@ CheckUpdateThreadLauncher::~CheckUpdateThreadLauncher()
void CheckUpdateThreadLauncher::launch()
{
if (m_uuid.empty())
m_uuid = m_preferences.updater.uuid();
#if ENABLE_SENTRY
if (!m_uuid.empty())
Sentry::setUserID(m_uuid);
#endif
// In this case we are in the "wait days" period, so we don't check
// for updates.
if (!m_doCheck) {
@ -120,9 +132,6 @@ void CheckUpdateThreadLauncher::launch()
return;
}
if (m_uuid.empty())
m_uuid = m_preferences.updater.uuid();
m_delegate->onCheckingUpdates();
m_bgJob.reset(new CheckUpdateBackgroundJob);
@ -168,6 +177,11 @@ void CheckUpdateThreadLauncher::onMonitoringTick()
if (!m_response.getUuid().empty()) {
m_uuid = m_response.getUuid();
m_preferences.updater.uuid(m_uuid);
#if ENABLE_SENTRY
if (!m_uuid.empty())
Sentry::setUserID(m_uuid);
#endif
}
// Set the date of the last "check for updates" and the "WaitDays" parameter.

View File

@ -27,6 +27,7 @@
#include "app/resource_finder.h"
#include "app/tx.h"
#include "app/ui/color_button.h"
#include "app/ui/main_window.h"
#include "app/ui/pref_widget.h"
#include "app/ui/rgbmap_algorithm_selector.h"
#include "app/ui/separator_in_view.h"
@ -43,6 +44,10 @@
#include "render/render.h"
#include "ui/ui.h"
#if ENABLE_SENTRY
#include "app/sentry_wrapper.h"
#endif
#include "options.xml.h"
namespace app {
@ -543,6 +548,13 @@ public:
else
locateCrashFolder()->setVisible(false);
// Share crashdb
#if ENABLE_SENTRY
shareCrashdb()->setSelected(Sentry::consentGiven());
#else
shareCrashdb()->setVisible(false);
#endif
// Undo preferences
limitUndo()->Click.connect([this]{ onLimitUndoCheck(); });
limitUndo()->setSelected(m_pref.undo.sizeLimit() != 0);
@ -594,6 +606,15 @@ public:
sendMessage(&msg);
}
// Share crashdb
#if ENABLE_SENTRY
if (shareCrashdb()->isSelected())
Sentry::giveConsent();
else
Sentry::revokeConsent();
App::instance()->mainWindow()->updateConsentCheckbox();
#endif
// Update language
Strings::instance()->setCurrentLanguage(
language()->getItemText(language()->getSelectedItemIndex()));

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2020 Igara Studio S.A.
// Copyright (C) 2020-2021 Igara Studio S.A.
// Copyright (C) 2001-2018 David Capello
//
// This program is distributed under the terms of
@ -16,6 +16,8 @@
namespace app {
#if !ENABLE_SENTRY
class SendCrash
#ifdef ENABLE_UI
: public INotificationDelegate
@ -43,6 +45,8 @@ namespace app {
std::string m_dumpFilename;
};
#endif // !ENABLE_SENTRY
} // namespace app
#endif // APP_SEND_CRASH_H_INCLUDED

113
src/app/sentry_wrapper.cpp Normal file
View File

@ -0,0 +1,113 @@
// Aseprite
// Copyright (C) 2021 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "app/sentry_wrapper.h"
#include "app/resource_finder.h"
#include "base/fs.h"
#include "base/string.h"
#include "ver/info.h"
#include "sentry.h"
namespace app {
// Directory where Sentry database is saved.
std::string Sentry::m_dbdir;
void Sentry::init()
{
sentry_options_t* options = sentry_options_new();
sentry_options_set_dsn(options, SENTRY_DNS);
std::string release = "aseprite@";
release += get_app_version();
sentry_options_set_release(options, release.c_str());
#if _DEBUG
sentry_options_set_debug(options, 1);
#endif
setupDirs(options);
// We require the user consent to upload files.
sentry_options_set_require_user_consent(options, 1);
if (sentry_init(options) == 0)
m_init = true;
}
Sentry::~Sentry()
{
if (m_init)
sentry_close();
}
// static
void Sentry::setUserID(const std::string& uuid)
{
sentry_value_t user = sentry_value_new_object();
sentry_value_set_by_key(user, "id", sentry_value_new_string(uuid.c_str()));
sentry_set_user(user);
}
// static
bool Sentry::requireConsent()
{
return (sentry_user_consent_get() != SENTRY_USER_CONSENT_GIVEN);
}
// static
bool Sentry::consentGiven()
{
return (sentry_user_consent_get() == SENTRY_USER_CONSENT_GIVEN);
}
// static
void Sentry::giveConsent()
{
sentry_user_consent_give();
}
// static
void Sentry::revokeConsent()
{
sentry_user_consent_revoke();
}
// static
bool Sentry::areThereCrashesToReport()
{
if (m_dbdir.empty())
return false;
for (auto f : base::list_files(base::join_path(m_dbdir, "completed"))) {
if (base::get_file_extension(f) == "dmp")
return true; // At least one .dmp file in the completed/ directory
}
return false;
}
void Sentry::setupDirs(sentry_options_t* options)
{
ResourceFinder rf;
rf.includeUserDir("crashdb");
const std::string dir = rf.getFirstOrCreateDefault();
#if SENTRY_PLATFORM_WINDOWS
sentry_options_set_database_pathw(options, base::from_utf8(dir).c_str());
#else
sentry_options_set_database_path(options, dir.c_str());
#endif
m_dbdir = dir;
}
} // namespace app

45
src/app/sentry_wrapper.h Normal file
View File

@ -0,0 +1,45 @@
// Aseprite
// Copyright (C) 2021 Igara Studio S.A.
//
// This program is distributed under the terms of
// the End-User License Agreement for Aseprite.
#ifndef APP_SENTRY_WRAPPER_H
#define APP_SENTRY_WRAPPER_H
#if !ENABLE_SENTRY
#error ENABLE_SENTRY must be defined
#endif
#include "sentry.h"
#include <string>
namespace app {
class Sentry {
public:
void init();
~Sentry();
static void setUserID(const std::string& uuid);
static bool requireConsent();
static bool consentGiven();
static void giveConsent();
static void revokeConsent();
// Returns true if there are some crash to report. Used to display
// the "give consent" check box for first time.
static bool areThereCrashesToReport();
private:
void setupDirs(sentry_options_t* options);
bool m_init = false;
static std::string m_dbdir;
};
} // namespace app
#endif // APP_SENTRY_WRAPPER_H

View File

@ -38,6 +38,10 @@
#include "app/ui/news_listbox.h"
#endif
#if ENABLE_SENTRY
#include "app/sentry_wrapper.h"
#endif
namespace app {
using namespace ui;
@ -66,6 +70,23 @@ HomeView::HomeView()
#endif
checkUpdate()->setVisible(false);
shareCrashdb()->setVisible(false);
#if ENABLE_SENTRY
// Show this option in home tab only when we require consent for the
// first time and there is crash data available to report
if (Sentry::requireConsent() &&
Sentry::areThereCrashesToReport()) {
shareCrashdb()->setVisible(true);
shareCrashdb()->Click.connect(
[this]{
if (shareCrashdb()->isSelected())
Sentry::giveConsent();
else
Sentry::revokeConsent();
});
}
#endif
InitTheme.connect(
[this]{
@ -101,6 +122,21 @@ void HomeView::dataRecoverySessionsAreReady()
#endif
}
#if ENABLE_SENTRY
void HomeView::updateConsentCheckbox()
{
if (Sentry::requireConsent()) {
shareCrashdb()->setVisible(true);
shareCrashdb()->setSelected(false);
}
else if (Sentry::consentGiven()) {
shareCrashdb()->setVisible(false);
shareCrashdb()->setSelected(true);
}
layout();
}
#endif
std::string HomeView::getTabText()
{
return Strings::home_view_title();
@ -181,9 +217,7 @@ void HomeView::onCheckingUpdates()
void HomeView::onUpToDate()
{
checkUpdate()->setText(
fmt::format(Strings::home_view_is_up_to_date(), get_app_name()));
checkUpdate()->setVisible(true);
checkUpdate()->setVisible(false);
layout();
}

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (C) 2019 Igara Studio S.A.
// Copyright (C) 2019-2021 Igara Studio S.A.
// Copyright (C) 2001-2016 David Capello
//
// This program is distributed under the terms of
@ -46,6 +46,10 @@ namespace app {
// function is called.
void dataRecoverySessionsAreReady();
#if ENABLE_SENTRY
void updateConsentCheckbox();
#endif
// TabView implementation
std::string getTabText() override;
TabIcon getTabIcon() override;

View File

@ -222,6 +222,13 @@ CheckUpdateDelegate* MainWindow::getCheckUpdateDelegate()
}
#endif
#if ENABLE_SENTRY
void MainWindow::updateConsentCheckbox()
{
getHomeView()->updateConsentCheckbox();
}
#endif
void MainWindow::showNotification(INotificationDelegate* del)
{
m_notifications->addLink(del);

View File

@ -66,6 +66,9 @@ namespace app {
#ifdef ENABLE_UPDATER
CheckUpdateDelegate* getCheckUpdateDelegate();
#endif
#if ENABLE_SENTRY
void updateConsentCheckbox();
#endif
void start();
void showNotification(INotificationDelegate* del);

View File

@ -16,10 +16,16 @@
#include "app/send_crash.h"
#include "base/exception.h"
#include "base/memory.h"
#include "base/memory_dump.h"
#include "base/system_console.h"
#include "os/error.h"
#include "os/system.h"
#include "ver/info.h"
#if ENABLE_SENTRY
#include "app/sentry_wrapper.h"
#else
#include "base/memory_dump.h"
#endif
#include <clocale>
#include <cstdlib>
@ -78,13 +84,20 @@ int app_main(int argc, char* argv[])
#endif
try {
#if ENABLE_SENTRY
app::Sentry sentry;
#else
base::MemoryDump memoryDump;
#endif
MemLeak memleak;
base::SystemConsole systemConsole;
app::AppOptions options(argc, const_cast<const char**>(argv));
os::SystemRef system(os::make_system());
app::App app;
#if ENABLE_SENTRY
sentry.init();
#else
// Change the memory dump filename to save on disk (.dmp
// file). Note: Only useful on Windows.
{
@ -92,6 +105,7 @@ int app_main(int argc, char* argv[])
if (!fn.empty())
memoryDump.setFileName(fn);
}
#endif
const int code = app.initialize(options);