diff --git a/src/app/app.cpp b/src/app/app.cpp index c7d85fc9a..0f952a121 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -215,7 +215,7 @@ App::App(AppMod* mod) m_instance = this; } -void App::initialize(const AppOptions& options) +int App::initialize(const AppOptions& options) { #ifdef ENABLE_UI m_isGui = options.startUI() && !options.previewCLI(); @@ -319,10 +319,13 @@ void App::initialize(const AppOptions& options) delegate.reset(new DefaultCliDelegate); CliProcessor cli(delegate.get(), options); - cli.process(&m_modules->m_context); + int code = cli.process(&m_modules->m_context); + if (code != 0) + return code; } os::instance()->finishLaunching(); + return 0; } void App::run() diff --git a/src/app/app.h b/src/app/app.h index b7ea917f1..ea4dce1fa 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -84,7 +84,7 @@ namespace app { // Runs the Aseprite application. In GUI mode it's the top-level // window, in console/scripting it just runs the specified // scripts. - void initialize(const AppOptions& options); + int initialize(const AppOptions& options); void run(); AppMod* mod() const { return m_mod; } diff --git a/src/app/cli/cli_delegate.h b/src/app/cli/cli_delegate.h index 3bf752a1a..c4f38cd43 100644 --- a/src/app/cli/cli_delegate.h +++ b/src/app/cli/cli_delegate.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018 Igara Studio S.A. +// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2016-2018 David Capello // // This program is distributed under the terms of @@ -33,8 +33,10 @@ namespace app { virtual void loadPalette(Context* ctx, const CliOpenFile& cof, const std::string& filename) { } virtual void exportFiles(Context* ctx, DocExporter& exporter) { } #ifdef ENABLE_SCRIPTING - virtual void execScript(const std::string& filename, - const Params& params) { } + virtual int execScript(const std::string& filename, + const Params& params) { + return 0; + } #endif // ENABLE_SCRIPTING }; diff --git a/src/app/cli/cli_processor.cpp b/src/app/cli/cli_processor.cpp index 9ac1b938e..2c6de13bd 100644 --- a/src/app/cli/cli_processor.cpp +++ b/src/app/cli/cli_processor.cpp @@ -178,7 +178,7 @@ CliProcessor::CliProcessor(CliDelegate* delegate, m_exporter.reset(new DocExporter); } -void CliProcessor::process(Context* ctx) +int CliProcessor::process(Context* ctx) { // --help if (m_options.showHelp()) { @@ -529,7 +529,9 @@ void CliProcessor::process(Context* ctx) // --script else if (opt == &m_options.script()) { std::string filename = value.value(); - m_delegate->execScript(filename, scriptParams); + int code = m_delegate->execScript(filename, scriptParams); + if (code != 0) + return code; } // --script-param else if (opt == &m_options.scriptParam()) { @@ -598,6 +600,7 @@ void CliProcessor::process(Context* ctx) else { m_delegate->batchMode(); } + return 0; } bool CliProcessor::openFile(Context* ctx, CliOpenFile& cof) diff --git a/src/app/cli/cli_processor.h b/src/app/cli/cli_processor.h index 62eac8d12..70668fa39 100644 --- a/src/app/cli/cli_processor.h +++ b/src/app/cli/cli_processor.h @@ -32,7 +32,7 @@ namespace app { public: CliProcessor(CliDelegate* delegate, const AppOptions& options); - void process(Context* ctx); + int process(Context* ctx); // Public so it can be tested static void FilterLayers(const doc::Sprite* sprite, diff --git a/src/app/cli/cli_tests.cpp b/src/app/cli/cli_tests.cpp index f19885fa2..f6b3f0617 100644 --- a/src/app/cli/cli_tests.cpp +++ b/src/app/cli/cli_tests.cpp @@ -35,8 +35,10 @@ public: void saveFile(Context* ctx, const CliOpenFile& cof) override { } void exportFiles(Context* ctx, DocExporter& exporter) override { } #ifdef ENABLE_SCRIPTING - void execScript(const std::string& filename, - const Params& params) override { } + int execScript(const std::string& filename, + const Params& params) override { + return 0; + } #endif bool helpWasShown() const { return m_helpWasShown; } diff --git a/src/app/cli/default_cli_delegate.cpp b/src/app/cli/default_cli_delegate.cpp index 4bb31c41a..527a4eceb 100644 --- a/src/app/cli/default_cli_delegate.cpp +++ b/src/app/cli/default_cli_delegate.cpp @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018 Igara Studio S.A. +// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2016-2018 David Capello // // This program is distributed under the terms of @@ -131,11 +131,13 @@ void DefaultCliDelegate::exportFiles(Context* ctx, DocExporter& exporter) } #ifdef ENABLE_SCRIPTING -void DefaultCliDelegate::execScript(const std::string& filename, - const Params& params) +int DefaultCliDelegate::execScript(const std::string& filename, + const Params& params) { - if (!App::instance()->scriptEngine()->evalFile(filename, params)) - throw std::runtime_error("Error executing script"); + auto engine = App::instance()->scriptEngine(); + if (!engine->evalFile(filename, params)) + throw base::Exception("Error executing script %s", filename.c_str()); + return engine->returnCode(); } #endif // ENABLE_SCRIPTING diff --git a/src/app/cli/default_cli_delegate.h b/src/app/cli/default_cli_delegate.h index e71b52f04..6e85305bc 100644 --- a/src/app/cli/default_cli_delegate.h +++ b/src/app/cli/default_cli_delegate.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018 Igara Studio S.A. +// Copyright (C) 2018-2019 Igara Studio S.A. // Copyright (C) 2016-2018 David Capello // // This program is distributed under the terms of @@ -22,8 +22,8 @@ namespace app { void loadPalette(Context* ctx, const CliOpenFile& cof, const std::string& filename) override; void exportFiles(Context* ctx, DocExporter& exporter) override; #ifdef ENABLE_SCRIPTING - void execScript(const std::string& filename, - const Params& params) override; + int execScript(const std::string& filename, + const Params& params) override; #endif }; diff --git a/src/app/cli/preview_cli_delegate.cpp b/src/app/cli/preview_cli_delegate.cpp index ec501b916..0098ccdfb 100644 --- a/src/app/cli/preview_cli_delegate.cpp +++ b/src/app/cli/preview_cli_delegate.cpp @@ -214,8 +214,8 @@ void PreviewCliDelegate::exportFiles(Context* ctx, DocExporter& exporter) } #ifdef ENABLE_SCRIPTING -void PreviewCliDelegate::execScript(const std::string& filename, - const Params& params) +int PreviewCliDelegate::execScript(const std::string& filename, + const Params& params) { std::cout << "- Run script: '" << filename << "'\n"; if (!params.empty()) { @@ -224,6 +224,7 @@ void PreviewCliDelegate::execScript(const std::string& filename, std::cout << " " << kv.first << "=\"" << kv.second << "\",\n"; std::cout << " }\n"; } + return 0; } #endif // ENABLE_SCRIPTING diff --git a/src/app/cli/preview_cli_delegate.h b/src/app/cli/preview_cli_delegate.h index 1077bb3e8..e8d40b50a 100644 --- a/src/app/cli/preview_cli_delegate.h +++ b/src/app/cli/preview_cli_delegate.h @@ -34,8 +34,8 @@ namespace app { const std::string& filename) override; void exportFiles(Context* ctx, DocExporter& exporter) override; #ifdef ENABLE_SCRIPTING - void execScript(const std::string& filename, - const Params& params) override; + int execScript(const std::string& filename, + const Params& params) override; #endif // ENABLE_SCRIPTING private: diff --git a/src/app/script/engine.cpp b/src/app/script/engine.cpp index e1ab91d87..ad5f9f5ab 100644 --- a/src/app/script/engine.cpp +++ b/src/app/script/engine.cpp @@ -391,8 +391,15 @@ bool Engine::evalCode(const std::string& code, if (s) onConsolePrint(s); ok = false; + m_returnCode = -1; } else { + // Return code + if (lua_isinteger(L, -1)) + m_returnCode = lua_tointeger(L, -1); + else + m_returnCode = 0; + // Code was executed correctly if (m_printLastResult) { if (!lua_isnone(L, -1)) { @@ -407,6 +414,7 @@ bool Engine::evalCode(const std::string& code, catch (const std::exception& ex) { onConsolePrint(ex.what()); ok = false; + m_returnCode = -1; } // Collect script garbage. @@ -420,6 +428,9 @@ bool Engine::evalFile(const std::string& filename, std::stringstream buf; { std::ifstream s(FSTREAM_PATH(filename)); + // Returns false if we cannot open the file + if (!s) + return false; buf << s.rdbuf(); } std::string absFilename = base::get_absolute_path(filename); diff --git a/src/app/script/engine.h b/src/app/script/engine.h index 8b2b7c6bb..dfec00fb0 100644 --- a/src/app/script/engine.h +++ b/src/app/script/engine.h @@ -89,12 +89,17 @@ namespace app { onConsolePrint(text); } + int returnCode() const { + return m_returnCode; + } + private: void onConsolePrint(const char* text); lua_State* L; EngineDelegate* m_delegate; bool m_printLastResult; + int m_returnCode; }; class ScopedEngineDelegate { diff --git a/src/main/main.cpp b/src/main/main.cpp index 06d1e626f..2a3f88945 100644 --- a/src/main/main.cpp +++ b/src/main/main.cpp @@ -1,4 +1,5 @@ // Aseprite +// Copyright (C) 2019 Igara Studio S.A. // Copyright (C) 2001-2016 David Capello // // This program is distributed under the terms of @@ -71,12 +72,14 @@ int app_main(int argc, char* argv[]) // Change the name of the memory dump file { - std::string filename = app::memory_dump_filename(); + const std::string filename = app::memory_dump_filename(); if (!filename.empty()) memoryDump.setFileName(filename); } - app.initialize(options); + const int code = app.initialize(options); + if (code != 0) + return code; if (options.startShell()) systemConsole.prepareShell();