diff --git a/CHANGELOG.md b/CHANGELOG.md index ac4ad60..ccd70d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] +### Added + +- `:Conan create [args...]` now forwards arbitrary additional arguments directly to Conan after + the configured recipe, profiles, and optional build policy. + ### Fixed - Reconfiguration now preserves the existing configuration when the wizard is cancelled or writing fails. diff --git a/README.md b/README.md index d2986bd..1fc74d5 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,16 @@ offers a free-form optional input for the value following `--build=` (for exampl `missing:zlib/*`). Leaving it empty preserves Conan's default behavior; when configured, the value is stored as `build_policy` and commands append it as `--build=`. +Package the configured recipe with optional additional Conan arguments: + +```vim +:Conan create [args...] +:Conan create --version=1.2.3 +``` + +All arguments following `create` are passed directly to Conan, in their original order, after the +configured recipe, profiles, and optional build policy. + ------- # 📋 Requirements diff --git a/doc/nvim-conan.txt b/doc/nvim-conan.txt index 5de4d3a..b492a5d 100644 --- a/doc/nvim-conan.txt +++ b/doc/nvim-conan.txt @@ -71,8 +71,12 @@ Available subcommands: `lock` Run `conan lock create` for the configured recipe. -`create` - Run `conan create`. +`:Conan create [args...]` + Run `conan create` for the configured recipe. Remaining arguments are + passed directly to Conan, after the configured profiles and optional build + policy. For example: > + :Conan create --version=1.2.3 +< `export [user] [channel]` Run `conan export` for the configured recipe. diff --git a/lua/commands.lua b/lua/commands.lua index f968ea5..811194c 100644 --- a/lua/commands.lua +++ b/lua/commands.lua @@ -92,7 +92,7 @@ end -- Conan commands (terminal) -- ------------------------- ---- Runs `conan install` using config from `.nvim-conan.json`. +--- Runs `conan install` using config file. --- Opens a floating terminal and shows statusline spinner until the command finishes. function M.install() local config = read_config() @@ -105,7 +105,7 @@ function M.install() run_terminal_with_status("📦 Conan: install", argv, "📦 Conan Install", true) end ---- Runs `conan build` using config from `.nvim-conan.json`. +--- Runs `conan build` using config file. --- Also attempts to symlink `compile_commands.json` into project root if it can be located. function M.build() local config = read_config() @@ -127,7 +127,7 @@ function M.build() end) end ---- Runs `conan lock create` using config from `.nvim-conan.json`. +--- Runs `conan lock create` using config file. function M.lock() local config = read_config() if config == nil then @@ -139,15 +139,16 @@ function M.lock() run_terminal_with_status("🔒 Conan: lock", argv, "🔒 Conan Lock", true) end ---- Runs `conan create` using config from `.nvim-conan.json`. -function M.create() +--- Runs `conan create` using config file. +---@param args string[]|nil Additional arguments passed directly to `conan create`. +function M.create(args) local config = read_config() if config == nil then vim.notify("Couldn't read config", vim.log.levels.ERROR) return end - local argv = command_builder.create(config) + local argv = command_builder.create(config, args) run_terminal_with_status("📦 Conan: create", argv, "📦 Conan Create", true) end diff --git a/lua/conan/command_builder.lua b/lua/conan/command_builder.lua index 4d14d8b..1f9dbef 100644 --- a/lua/conan/command_builder.lua +++ b/lua/conan/command_builder.lua @@ -70,11 +70,13 @@ function M.lock(config) return { "conan", "lock", "create", config.recipe or "." } end -function M.create(config) - local argv = { "conan", "create" } +function M.create(config, additional_args) + local argv = { "conan", "create", config.recipe or "." } append_profiles(argv, config) append_build_policy(argv, config) - append(argv, config.recipe or ".") + for _, argument in ipairs(additional_args or {}) do + append(argv, argument) + end return argv end diff --git a/lua/conan_status.lua b/lua/conan_status.lua index b8fbf2d..904473c 100644 --- a/lua/conan_status.lua +++ b/lua/conan_status.lua @@ -14,7 +14,8 @@ local function in_conan_project() local cwd = vim.fn.getcwd() return exists(cwd .. "/conanfile.py") or exists(cwd .. "/conanfile.txt") - or exists(cwd .. "/.nvim-conan.json") + or exists(cwd .. "/conan-config.json") + or exists(cwd .. "/.vscode/conan-config.json") or exists(cwd .. "/conan.lock") end diff --git a/tests/test_command_builder.lua b/tests/test_command_builder.lua index 4a295e4..172505c 100644 --- a/tests/test_command_builder.lua +++ b/tests/test_command_builder.lua @@ -144,33 +144,102 @@ test_set["lock uses the configured recipe"] = function() }) end -test_set["create preserves profile and recipe ordering"] = function() +test_set["create without additional arguments preserves existing configured arguments"] = function() expect.equality(command_builder.create(config), { "conan", "create", + "recipes/conanfile.py", "-pr:b", "build-profile", "-pr:h", "host-profile", "--build=missing", - "recipes/conanfile.py", }) end -test_set["create omits a blank build policy without changing argument ordering"] = function() - local create_config = vim.tbl_extend("force", config, { build_policy = " \t" }) - - expect.equality(command_builder.create(create_config), { +test_set["create forwards a version argument after configured arguments"] = function() + expect.equality(command_builder.create(config, { "--version=1.0.0" }), { "conan", "create", + "recipes/conanfile.py", "-pr:b", "build-profile", "-pr:h", "host-profile", - "recipes/conanfile.py", + "--build=missing", + "--version=1.0.0", }) end +test_set["create preserves multiple additional arguments in their original order"] = function() + expect.equality( + command_builder.create(config, { + "--version=1.2.3", + "--user=alice", + "--channel=testing", + }), + { + "conan", + "create", + "recipes/conanfile.py", + "-pr:b", + "build-profile", + "-pr:h", + "host-profile", + "--build=missing", + "--version=1.2.3", + "--user=alice", + "--channel=testing", + } + ) +end + +test_set["create preserves spaces and shell metacharacters as literal arguments"] = function() + expect.equality( + command_builder.create(config, { + "value with spaces", + "$(touch unsafe);&|*", + }), + { + "conan", + "create", + "recipes/conanfile.py", + "-pr:b", + "build-profile", + "-pr:h", + "host-profile", + "--build=missing", + "value with spaces", + "$(touch unsafe);&|*", + } + ) +end + +test_set["create omits missing, empty, and blank build policies"] = function() + local configs = { + { + recipe = config.recipe, + profile_build = config.profile_build, + profile_host = config.profile_host, + }, + vim.tbl_extend("force", config, { build_policy = "" }), + vim.tbl_extend("force", config, { build_policy = " \t" }), + } + + for _, create_config in ipairs(configs) do + expect.equality(command_builder.create(create_config, { "--version=1.0.0" }), { + "conan", + "create", + "recipes/conanfile.py", + "-pr:b", + "build-profile", + "-pr:h", + "host-profile", + "--version=1.0.0", + }) + end +end + test_set["export includes user and channel before the recipe"] = function() expect.equality(command_builder.export(config, "alice", "stable"), { "conan", diff --git a/tests/test_create_command.lua b/tests/test_create_command.lua new file mode 100644 index 0000000..dbea72a --- /dev/null +++ b/tests/test_create_command.lua @@ -0,0 +1,76 @@ +local test_set = MiniTest.new_set() +local expect = MiniTest.expect + +test_set["Conan create propagates dispatcher arguments through the handler"] = function() + local utils = require("utils") + local conan_status = require("conan_status") + local plugin_root = vim.fn.getcwd() + local original = { + cwd = vim.fn.getcwd(), + create_user_command = vim.api.nvim_create_user_command, + open_floating_terminal = utils.open_floating_terminal, + status_start = conan_status.start, + status_stop = conan_status.stop, + } + local project_dir = vim.fn.tempname() + local captured_argv + local dispatcher + + vim.fn.mkdir(project_dir, "p") + local config_file = assert(io.open(project_dir .. "/conan-config.json", "w")) + assert(config_file:write(vim.json.encode({ + recipe = "recipes/conanfile.py", + profile_build = "build-profile", + profile_host = "host-profile", + build_policy = "missing", + }))) + assert(config_file:close()) + + local ok, err = xpcall(function() + vim.api.nvim_create_user_command = function(name, callback) + if name == "Conan" then + dispatcher = callback + end + end + dofile(plugin_root .. "/lua/conan.lua") + vim.api.nvim_create_user_command = original.create_user_command + + vim.fn.chdir(project_dir) + conan_status.start = function() end + conan_status.stop = function() end + utils.open_floating_terminal = function(argv) + captured_argv = argv + end + + dispatcher({ + fargs = { "create", "--version=1.2.3", "--user=alice", "--channel=testing" }, + }) + + expect.equality(captured_argv, { + "conan", + "create", + "recipes/conanfile.py", + "-pr:b", + "build-profile", + "-pr:h", + "host-profile", + "--build=missing", + "--version=1.2.3", + "--user=alice", + "--channel=testing", + }) + end, debug.traceback) + + vim.api.nvim_create_user_command = original.create_user_command + utils.open_floating_terminal = original.open_floating_terminal + conan_status.start = original.status_start + conan_status.stop = original.status_stop + vim.fn.chdir(original.cwd) + vim.fn.delete(project_dir, "rf") + + if not ok then + error(err) + end +end + +return test_set