From ef70cebe5583048f72918fd9170585ebba1bc1f3 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Sun, 12 Mar 2023 18:34:59 +0200 Subject: [PATCH 1/7] [FIX] use stderrPassThrough for lodoo.databaseList command. This is needed to avoid 'execute' putting warnings from stderr to output param of result --- subpackages/lib/source/odood/lib/odoo/lodoo.d | 39 +++++++++-- subpackages/lib/source/odood/lib/venv.d | 66 +++++++++++-------- 2 files changed, 73 insertions(+), 32 deletions(-) diff --git a/subpackages/lib/source/odood/lib/odoo/lodoo.d b/subpackages/lib/source/odood/lib/odoo/lodoo.d index b01b85ab..b8fe1746 100644 --- a/subpackages/lib/source/odood/lib/odoo/lodoo.d +++ b/subpackages/lib/source/odood/lib/odoo/lodoo.d @@ -3,6 +3,9 @@ module odood.lib.odoo.lodoo; private import std.logger; private import std.exception: enforce; private import std.format: format; +private import std.typecons: Nullable; +private static import std.process; + private import thepath: Path; private import odood.lib.project: Project; @@ -27,19 +30,39 @@ const struct LOdoo { /** Run lodoo with provided args **/ - auto run(in string[] args...) { + auto run( + in string[] args, + std.process.Config config) { tracef("Running LOdoo with args %s", args); return _project.venv.run( - ["lodoo", "--conf", _odoo_conf.toString] ~ args); + ["lodoo", "--conf", _odoo_conf.toString] ~ args, + Nullable!Path.init, // workdir + null, // env + config); + } + + /// ditto + auto run(in string[] args...) { + return run(args, std.process.Config.none); } /** Run lodoo with provided args, raising error * in case of non-zero exit status. **/ - auto runE(in string[] args...) { + auto runE( + in string[] args, + std.process.Config config) { tracef("Running LOdoo with args %s", args); return _project.venv.runE( - ["lodoo", "--conf", _odoo_conf.toString] ~ args); + ["lodoo", "--conf", _odoo_conf.toString] ~ args, + Nullable!Path.init, // workdir + null, // env + config); + } + + /// ditto + auto runE(in string[] args...) { + return runE(args, std.process.Config.none); } public: @@ -55,7 +78,8 @@ const struct LOdoo { string[] databaseList() { import std.array: split, array; import std.algorithm.iteration: filter; - auto res = runE("db-list"); + import std.process: Config; + auto res = runE(["db-list"], Config.stderrPassThrough); return res.output.split("\n").filter!(db => db && db != "").array; } @@ -95,9 +119,12 @@ const struct LOdoo { return runE("db-drop", name); } - /** Check if database eixsts + /** Check if database exists **/ bool databaseExists(in string name) { + // TODO: replace with project's db wrapper to check if database exists + // This could simplify performance by avoiding call to python + // interpreter auto res = run("db-exists", name); return res.status == 0; } diff --git a/subpackages/lib/source/odood/lib/venv.d b/subpackages/lib/source/odood/lib/venv.d index cba37176..2fdb5822 100644 --- a/subpackages/lib/source/odood/lib/venv.d +++ b/subpackages/lib/source/odood/lib/venv.d @@ -5,6 +5,7 @@ private import std.format: format; private import std.typecons: Nullable; private import std.exception: enforce; private import std.conv: to; +private static import std.process; private import thepath: Path; private static import dyaml; @@ -98,56 +99,69 @@ const struct VirtualEnv { /** Run command in virtual environment **/ - auto run(in string[] args, - in Nullable!Path workDir=Nullable!Path.init, - in string[string] env=null) { + auto run( + in string[] args, + in Nullable!Path workDir=Nullable!Path.init, + in string[string] env=null, + std.process.Config config = std.process.Config.none) { tracef( "Running command in virtualenv: cmd=%s, work dir=%s, env=%s", args, workDir, env); - return _path.join("bin", "run-in-venv").runCmd(args, workDir, env); + return _path.join("bin", "run-in-venv").runCmd(args, workDir, env, config); } /// ditto - auto run(in string[] args, - in Path workDir, - in string[string] env=null) { - return run(args, Nullable!Path(workDir), env); + auto run( + in string[] args, + in Path workDir, + in string[string] env=null, + std.process.Config config = std.process.Config.none) { + return run(args, Nullable!Path(workDir), env, config); } /// ditto - auto run(in Path path, - in string[] args, - in Path workDir, - in string[string] env=null) { - return run([path.toString] ~ args, workDir, env); + auto run( + in Path path, + in string[] args, + in Path workDir, + in string[string] env=null, + std.process.Config config = std.process.Config.none) { + return run([path.toString] ~ args, workDir, env, config); } /** Run command in virtual environment. * Raise error on non-zero return code. **/ - auto runE(in string[] args, - in Nullable!Path workDir=Nullable!Path.init, - in string[string] env=null) { + auto runE( + in string[] args, + in Nullable!Path workDir=Nullable!Path.init, + in string[string] env=null, + std.process.Config config = std.process.Config.none) { tracef( "Running command in virtualenv (with exit-code check): " ~ "cmd=%s, work dir=%s, env=%s", args, workDir, env); - return _path.join("bin", "run-in-venv").runCmdE(args, workDir, env); + return _path.join("bin", "run-in-venv").runCmdE( + args, workDir, env, config); } /// ditto - auto runE(in string[] args, - in Path workDir, - in string[string] env=null) { - return runE(args, Nullable!Path(workDir), env); + auto runE( + in string[] args, + in Path workDir, + in string[string] env=null, + std.process.Config config = std.process.Config.none) { + return runE(args, Nullable!Path(workDir), env, config); } /// ditto - auto runE(in Path path, - in string[] args, - in Path workDir, - in string[string] env=null) { - return runE([path.toString] ~ args, workDir, env); + auto runE( + in Path path, + in string[] args, + in Path workDir, + in string[string] env=null, + std.process.Config config = std.process.Config.none) { + return runE([path.toString] ~ args, workDir, env, config); } From f2b74653453658f657d1604a94cab376a2498fd8 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Sun, 12 Mar 2023 18:36:23 +0200 Subject: [PATCH 2/7] Change version to 0.0.4-dev --- subpackages/lib/source/odood/lib/package.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subpackages/lib/source/odood/lib/package.d b/subpackages/lib/source/odood/lib/package.d index 07663a9b..aa67a72e 100644 --- a/subpackages/lib/source/odood/lib/package.d +++ b/subpackages/lib/source/odood/lib/package.d @@ -1,6 +1,6 @@ module odood.lib; -public immutable string _version = "0.0.3"; +public immutable string _version = "0.0.4-dev"; public import odood.lib.project; From 06e89174121a16cab04b8368ed8c7c7778517f45 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Tue, 14 Mar 2023 23:44:24 +0200 Subject: [PATCH 3/7] Added basic support for migration testing --- .../cli/source/odood/cli/commands/test.d | 18 +++ .../lib/source/odood/lib/addons/manager.d | 4 +- .../lib/source/odood/lib/addons/repository.d | 36 ++++- subpackages/lib/source/odood/lib/odoo/test.d | 135 +++++++++++++++++- subpackages/lib/source/odood/lib/utils.d | 25 +++- 5 files changed, 209 insertions(+), 9 deletions(-) diff --git a/subpackages/cli/source/odood/cli/commands/test.d b/subpackages/cli/source/odood/cli/commands/test.d index 926b86a9..658f7c0e 100644 --- a/subpackages/cli/source/odood/cli/commands/test.d +++ b/subpackages/cli/source/odood/cli/commands/test.d @@ -49,6 +49,8 @@ class CommandTest: OdoodCommand { "t", "temp-db", "Create temporary database for tests.")); this.add(new Flag( null, "isw", "Ignore warnings that are considered safe.")); + this.add(new Flag( + null, "migration", "Run migration against stable branch.")); this.add(new Flag( null, "coverage", "Calculate code coverage.")); this.add(new Flag( @@ -64,6 +66,12 @@ class CommandTest: OdoodCommand { this.add(new Option( null, "dir-r", "Directory to recursively search for addons to test").repeating); + this.add(new Option( + null, "migration-start-ref", + "git reference (branch/commit/tag) to start migration from")); + this.add(new Option( + null, "migration-repo", + "run migration tests for repo specified by path")); this.add(new Argument( "addon", "Name of addon to run tests for.").optional.repeating); } @@ -114,6 +122,16 @@ class CommandTest: OdoodCommand { testRunner.setCoverage(coverage); + if (args.flag("migration")) + testRunner.enableMigrationTest(); + if (!args.option("migration-repo").empty) + testRunner.setMigrationRepo(Path(args.option("migration-repo"))); + if (!args.option("migration-start-ref").empty) + testRunner.setMigrationStartRef(args.option("migration-start-ref")); + + if (testRunner.test_migration && !testRunner.migration_repo) + testRunner.setMigrationRepo(Path.current); + auto res = testRunner.run(); if (coverage) diff --git a/subpackages/lib/source/odood/lib/addons/manager.d b/subpackages/lib/source/odood/lib/addons/manager.d index 7211b16c..3074e0da 100644 --- a/subpackages/lib/source/odood/lib/addons/manager.d +++ b/subpackages/lib/source/odood/lib/addons/manager.d @@ -371,7 +371,7 @@ struct AddonManager { gitClone(git_url, dest, branch); // TODO: Do we need to create instance of repo here? - auto repo = AddonRepository(_project, dest); + auto repo = new AddonRepository(_project, dest); link(repo.path, true); // If there is odoo_requirements.txt file present, then we have to @@ -391,6 +391,6 @@ struct AddonManager { enforce!OdoodException( path.join(".git").exists, "Is not a git root directory."); - return AddonRepository(_project, path); + return new AddonRepository(_project, path); } } diff --git a/subpackages/lib/source/odood/lib/addons/repository.d b/subpackages/lib/source/odood/lib/addons/repository.d index 669a84fc..a1302d46 100644 --- a/subpackages/lib/source/odood/lib/addons/repository.d +++ b/subpackages/lib/source/odood/lib/addons/repository.d @@ -4,6 +4,7 @@ private import std.regex; private import std.exception: enforce; private import std.format: format; private import std.logger; +private static import std.process; private import thepath: Path; @@ -14,11 +15,11 @@ private import odood.lib.git: parseGitURL, gitClone; // TODO: Do we need this struct? -struct AddonRepository { +class AddonRepository { private const Project _project; private const Path _path; - @disable this(); + //@disable this(); this(in Project project, in Path path) { _project = project; @@ -47,4 +48,35 @@ struct AddonRepository { } } + /** Find the name of current git branch for this repo + **/ + string getCurrBranch() { + import std.string: chompPrefix, strip; + string git_ref = runCmdE( + ["git", "symbolic-ref", "-q", "HEAD"], + _path, + null, + std.process.Config.stderrPassThrough, + ).output; + + return git_ref.strip().chompPrefix("refs/heads/"); + } + + /** Fetch remote 'origin' + **/ + void fetchOrigin() { + runCmdE(["git", "fetch", "origin"], _path); + } + + /// ditto + void fetchOrigin(in string branch) { + runCmdE(["git", "fetch", "origin", branch], _path); + } + + /** Switch repo to specified branch + **/ + void switchBranchTo(in string branch_name) { + runCmdE(["git", "checkout", branch_name], _path); + + } } diff --git a/subpackages/lib/source/odood/lib/odoo/test.d b/subpackages/lib/source/odood/lib/odoo/test.d index e34b6413..166ca3c3 100644 --- a/subpackages/lib/source/odood/lib/odoo/test.d +++ b/subpackages/lib/source/odood/lib/odoo/test.d @@ -18,6 +18,7 @@ private import odood.lib.odoo.lodoo: LOdoo; private import odood.lib.odoo.log: OdooLogRecord; private import odood.lib.addons.addon: OdooAddon; private import odood.lib.addons.manager: AddonManager; +private import odood.lib.addons.repository: AddonRepository; private import odood.lib.server: OdooServer, CoverageOptions; private import odood.lib.exception: OdoodException; private import odood.lib.utils: generateRandomString; @@ -156,6 +157,12 @@ struct OdooTestRunner { // Optionaly we can ignore non important warnings private bool _ignore_safe_warnings; + // Migration tests settings + private bool _test_migration=false; + private string _test_migration_start_ref=null; + private AddonRepository _test_migration_repo; + + this(in Project project) { _project = project; _lodoo = LOdoo(_project, _project.odoo.testconfigfile); @@ -166,6 +173,12 @@ struct OdooTestRunner { _temporary_db = false; } + @property auto test_migration() const { return _test_migration; } + @property auto migration_repo() const { return _test_migration_repo; } + @property auto migration_start_ref() const { + return _test_migration_start_ref; + } + private void getOrCreateTestDb() { if (!_test_db_name) setDatabaseName( @@ -205,6 +218,29 @@ struct OdooTestRunner { _project.odoo.serie.major, generateRandomString(8))); } + /** Enable migration testing + **/ + auto ref enableMigrationTest() { + _test_migration = true; + return this; + } + + /** Set start git ref (branch, commit, test) for migration test + **/ + auto ref setMigrationStartRef(in string git_ref) { + _test_migration_start_ref = git_ref; + _test_migration = true; + return this; + } + + /** Set git repo path for migration test + **/ + auto ref setMigrationRepo(in Path path) { + _test_migration_repo = _project.addons.getRepo(path); + _test_migration = true; + return this; + } + /** Enable Coverage **/ auto ref setCoverage(in bool coverage) { @@ -212,6 +248,8 @@ struct OdooTestRunner { return this; } + /** Return CoverageOptions to run server with + **/ auto getCoverageOptions() { CoverageOptions res = CoverageOptions(_coverage); foreach(addon; _addons) @@ -289,16 +327,58 @@ struct OdooTestRunner { enforce!OdoodException( _addons.length > 0, "No addons specified for test"); + enforce!OdoodException( + !(_test_migration && _test_migration_repo is null), + "Migration test requested, but migration repo is not specified!"); + + // Configure test database (create if needed) getOrCreateTestDb(); + // Set up signal handlers + signal.initSigIntHandling(); + scope(exit) signal.deinitSigIntHandling(); + OdooTestResult result; + // Precompute option for http port + // (different on different odoo versions) auto opt_http_port = _project.odoo.serie > OdooSerie(10) ? "--http-port=%s".format(ODOO_TEST_HTTP_PORT) : "--xmlrpc-port=%s".format(ODOO_TEST_HTTP_PORT); - signal.initSigIntHandling(); - scope(exit) signal.deinitSigIntHandling(); + // Switch branch to migration start ref + string current_branch; + if (_test_migration) { + current_branch = _test_migration_repo.getCurrBranch(); + if (_test_migration_start_ref) { + infof( + "Switching to %s branch before running migration tests...", + _test_migration_start_ref); + _test_migration_repo.fetchOrigin(); + _test_migration_repo.switchBranchTo(_test_migration_start_ref); + } else { + infof( + "Switching to origin/%s branch before running migration tests...", + _project.odoo.serie); + _test_migration_repo.fetchOrigin(_project.odoo.serie.toString); + _test_migration_repo.switchBranchTo( + "origin/" ~ _project.odoo.serie.toString); + } + + // Link module from migration start ref + _project.addons.link( + _test_migration_repo.path, + false, // No recursive + true, // Force + ); + } + scope(exit) { + // Ensure that on exit repo will be returned in it's correct state + if (_test_migration && _test_migration_repo.getCurrBranch() != current_branch) { + infof("Switching back to %s ...", current_branch); + _test_migration_repo.switchBranchTo(current_branch); + } + } infof("Installing modules before test..."); auto init_res =_server.pipeServerLog( @@ -338,6 +418,57 @@ struct OdooTestRunner { return result; } + if (_test_migration) { + infof("Switching back to %s ...", current_branch); + _test_migration_repo.switchBranchTo(current_branch); + + // TODO: clean -fdx ? + + // Link module from current branch + _project.addons.link( + _test_migration_repo.path, + false, // No recursive + true, // Force + ); + _project.lodoo.updateAddonsList(_test_db_name); + + infof("Updating modules to run migrations before running tests..."); + auto update_res =_server.pipeServerLog( + getCoverageOptions(), + [ + "--update=%s".format(getModuleList), + "--log-level=info", + "--stop-after-init", + "--workers=0", + "--database=%s".format(_test_db_name), + ]); + foreach(ref log_record; update_res) { + logToFile(log_record); + + if (!filterLogRecord(log_record)) + continue; + + if (_log_handler) + _log_handler(log_record); + + result.addLogRecord(log_record); + + if (signal.interrupted) { + warningf("Canceling test because of Keyboard Interrupt"); + result.setCancelled("Keyboard interrupt"); + cleanUp(); + update_res.kill(); + return result; + } + } + + if (update_res.wait != 0) { + result.setFailed(); + cleanUp(); + return result; + } + } + infof("Running tests for modules: %s", getModuleList); auto update_res =_server.pipeServerLog( getCoverageOptions(), diff --git a/subpackages/lib/source/odood/lib/utils.d b/subpackages/lib/source/odood/lib/utils.d index 1a394939..41575a70 100644 --- a/subpackages/lib/source/odood/lib/utils.d +++ b/subpackages/lib/source/odood/lib/utils.d @@ -26,7 +26,17 @@ private import odood.lib.exception: OdoodException; } /// ditto -auto runCmd( +@safe auto runCmd( + in string[] args, + in Path workDir, + in string[string] env = null, + in Config config = Config.none, + in size_t maxOutput = size_t.max) { + return runCmd(args, workDir.toString, env, config, maxOutput); +} + +/// ditto +@safe auto runCmd( in Path path, in string[] args = [], in Nullable!Path workDir = Nullable!Path.init, @@ -52,7 +62,7 @@ auto runCmd( /// Run command raising exception for non-zero return code -auto runCmdE( +@safe auto runCmdE( scope const(char[])[] args, scope const(char)[] workDir = null, const string[string] env = null, @@ -63,10 +73,19 @@ auto runCmdE( enforce!OdoodException( result.status == 0, "Command %s returned non-zero error code!\nOutput: %s".format( - args, result.output)); + args.dup, result.output)); return result; } +/// ditto +@safe auto runCmdE( + in string[] args, + in Path workDir, + in string[string] env = null, + in Config config = Config.none, + in size_t maxOutput = size_t.max) { + return runCmdE(args, workDir.toString, env, config, maxOutput); +} /// ditto auto runCmdE( From 0e50bf8af771da990fe238ecfd59ff82620e26a5 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Wed, 15 Mar 2023 18:12:13 +0200 Subject: [PATCH 4/7] Added opt '--no-drop-db' to 'test' cmd --- subpackages/cli/source/odood/cli/commands/test.d | 6 ++++++ subpackages/lib/source/odood/lib/odoo/test.d | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/subpackages/cli/source/odood/cli/commands/test.d b/subpackages/cli/source/odood/cli/commands/test.d index 658f7c0e..6621ff0f 100644 --- a/subpackages/cli/source/odood/cli/commands/test.d +++ b/subpackages/cli/source/odood/cli/commands/test.d @@ -47,6 +47,9 @@ class CommandTest: OdoodCommand { super("test", "Run tests for mudles."); this.add(new Flag( "t", "temp-db", "Create temporary database for tests.")); + this.add(new Flag( + null, "no-drop-db", + "Do not drop temporary database after test completed.")); this.add(new Flag( null, "isw", "Ignore warnings that are considered safe.")); this.add(new Flag( @@ -132,6 +135,9 @@ class CommandTest: OdoodCommand { if (testRunner.test_migration && !testRunner.migration_repo) testRunner.setMigrationRepo(Path.current); + if (args.flag("no-drop-db")) + testRunner.setNoDropDatabase(); + auto res = testRunner.run(); if (coverage) diff --git a/subpackages/lib/source/odood/lib/odoo/test.d b/subpackages/lib/source/odood/lib/odoo/test.d index 166ca3c3..38082c23 100644 --- a/subpackages/lib/source/odood/lib/odoo/test.d +++ b/subpackages/lib/source/odood/lib/odoo/test.d @@ -146,8 +146,12 @@ struct OdooTestRunner { // TODO: Create separate struct to handle AddonsLists private const(OdooAddon)[] _addons; // Addons to run tests for + // Database configuration private string _test_db_name; private bool _temporary_db; + private bool _db_no_drop; + + // Logging config private Path _log_file; private void delegate(in ref OdooLogRecord rec) _log_handler; @@ -241,6 +245,13 @@ struct OdooTestRunner { return this; } + /** Do not drop database after test completed + **/ + auto ref setNoDropDatabase() { + _db_no_drop = true; + return this; + } + /** Enable Coverage **/ auto ref setCoverage(in bool coverage) { @@ -302,7 +313,9 @@ struct OdooTestRunner { /** Take clean up actions before test finished **/ void cleanUp() { - if (_temporary_db && _lodoo.databaseExists(_test_db_name)) { + if (_temporary_db && + _db_no_drop == false && + _lodoo.databaseExists(_test_db_name)) { _lodoo.databaseDrop(_test_db_name); } } From 5ca603fce233550920e421132a832a2c2cd466ab Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Wed, 15 Mar 2023 18:40:34 +0200 Subject: [PATCH 5/7] In case of migration tests, first switch branch and then create database --- subpackages/lib/source/odood/lib/odoo/test.d | 30 ++++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/subpackages/lib/source/odood/lib/odoo/test.d b/subpackages/lib/source/odood/lib/odoo/test.d index 38082c23..22dc87a3 100644 --- a/subpackages/lib/source/odood/lib/odoo/test.d +++ b/subpackages/lib/source/odood/lib/odoo/test.d @@ -344,21 +344,6 @@ struct OdooTestRunner { !(_test_migration && _test_migration_repo is null), "Migration test requested, but migration repo is not specified!"); - // Configure test database (create if needed) - getOrCreateTestDb(); - - // Set up signal handlers - signal.initSigIntHandling(); - scope(exit) signal.deinitSigIntHandling(); - - OdooTestResult result; - - // Precompute option for http port - // (different on different odoo versions) - auto opt_http_port = _project.odoo.serie > OdooSerie(10) ? - "--http-port=%s".format(ODOO_TEST_HTTP_PORT) : - "--xmlrpc-port=%s".format(ODOO_TEST_HTTP_PORT); - // Switch branch to migration start ref string current_branch; if (_test_migration) { @@ -393,6 +378,21 @@ struct OdooTestRunner { } } + // Configure test database (create if needed) + getOrCreateTestDb(); + + // Set up signal handlers + signal.initSigIntHandling(); + scope(exit) signal.deinitSigIntHandling(); + + OdooTestResult result; + + // Precompute option for http port + // (different on different odoo versions) + auto opt_http_port = _project.odoo.serie > OdooSerie(10) ? + "--http-port=%s".format(ODOO_TEST_HTTP_PORT) : + "--xmlrpc-port=%s".format(ODOO_TEST_HTTP_PORT); + infof("Installing modules before test..."); auto init_res =_server.pipeServerLog( getCoverageOptions(), From 9e31d4a78160335d827309a116f69eb84f230473 Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Mon, 20 Mar 2023 22:52:43 +0200 Subject: [PATCH 6/7] Added psql command --- source/odood/package.d | 3 ++ subpackages/cli/source/odood/cli/app.d | 2 + .../cli/source/odood/cli/commands/psql.d | 54 +++++++++++++++++++ 3 files changed, 59 insertions(+) create mode 100644 subpackages/cli/source/odood/cli/commands/psql.d diff --git a/source/odood/package.d b/source/odood/package.d index 4c4367b4..fc446940 100644 --- a/source/odood/package.d +++ b/source/odood/package.d @@ -1 +1,4 @@ module odood; + +public import odood.cli; +public import odood.lib; diff --git a/subpackages/cli/source/odood/cli/app.d b/subpackages/cli/source/odood/cli/app.d index 7d807268..495c73d1 100644 --- a/subpackages/cli/source/odood/cli/app.d +++ b/subpackages/cli/source/odood/cli/app.d @@ -25,6 +25,7 @@ private import odood.cli.commands.venv: CommandVenv; private import odood.cli.commands.discover: CommandDiscover; private import odood.cli.commands.log: CommandLogView; private import odood.cli.commands.script: CommandScript; +private import odood.cli.commands.psql: CommandPSQL; /** Class that represents main OdoodProgram @@ -48,6 +49,7 @@ class App: OdoodProgram { this.add(new CommandDiscover()); this.add(new CommandLogView()); this.add(new CommandScript()); + this.add(new CommandPSQL()); // shortcuts this.add(new CommandServerStart()); diff --git a/subpackages/cli/source/odood/cli/commands/psql.d b/subpackages/cli/source/odood/cli/commands/psql.d new file mode 100644 index 00000000..7969ce2e --- /dev/null +++ b/subpackages/cli/source/odood/cli/commands/psql.d @@ -0,0 +1,54 @@ +module odood.cli.commands.psql; + +private import std.logger; +private import std.format: format; +private import std.conv: to, ConvException; + +private import commandr: Argument, Option, Flag, ProgramArgs; + +private import odood.cli.core: OdoodCommand; +private import odood.lib.project: Project; + + +class CommandPSQL: OdoodCommand { + this() { + super("psql", "Run psql for specified database"); + this.add(new Option( + "d", "db", "Name of database to connect to.").required); + } + + public override void execute(ProgramArgs args) { + import std.process; + import std.algorithm; + import std.array; + auto project = Project.loadProject; + + string[string] env = environment.toAA; + + auto odoo_conf = project.getOdooConfig(); + + env["PGDATABASE"] = args.option("db"); + + if (odoo_conf["options"].hasKey("db_host")) + env["PGHOST"] = odoo_conf["options"].getKey("db_host"); + if (odoo_conf["options"].hasKey("db_port")) { + auto db_port = odoo_conf["options"].getKey("db_port"); + try { + env["PGPORT"] = db_port.to!(int).to!string; + } catch (ConvException) { + warningf("Unparsable value for db port: %s", db_port); + } + } + + env["PGUSER"] = odoo_conf["options"].hasKey("db_user") ? + odoo_conf["options"].getKey("db_user") : "odoo"; + env["PGPASSWORD"] = odoo_conf["options"].hasKey("db_password") ? + odoo_conf["options"].getKey("db_password") : "odoo"; + + execvpe( + "psql", ["psql"], + env.byKeyValue.map!( + (i) => "%s=%s".format(i.key, i.value)).array); + } +} + From 642b048b15423f95b90ddd36aa10583d51a1117e Mon Sep 17 00:00:00 2001 From: Dmytro Katyukha Date: Thu, 23 Mar 2023 13:47:03 +0200 Subject: [PATCH 7/7] Added option --recreate to 'odood db create' cmd --- .../cli/source/odood/cli/commands/database.d | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/subpackages/cli/source/odood/cli/commands/database.d b/subpackages/cli/source/odood/cli/commands/database.d index a4254eb1..158db37d 100644 --- a/subpackages/cli/source/odood/cli/commands/database.d +++ b/subpackages/cli/source/odood/cli/commands/database.d @@ -42,6 +42,8 @@ class CommandDatabaseCreate: OdoodCommand { this() { super("create", "Create new odoo database."); this.add(new Flag("d", "demo", "Load demo data for this db")); + this.add(new Flag( + null, "recreate", "Recreate database if it already exists.")); this.add(new Option( "l", "lang", "Language of database, specified as ISO code of language." @@ -63,6 +65,17 @@ class CommandDatabaseCreate: OdoodCommand { auto project = Project.loadProject; string dbname = args.arg("name"); + if (project.lodoo.databaseExists(dbname)) { + if (args.flag("recreate")) { + warningf( + "Dropting database %s before recreating it " ~ + "(because --recreate option specified).", dbname); + project.lodoo.databaseDrop(dbname); + } else { + throw new OdoodException( + "Database %s already exists!".format(dbname)); + } + } project.lodoo.databaseCreate( dbname, args.flag("demo"),