From cc0cec20d1f5fe683b79cb1cf9475cda1e17a410 Mon Sep 17 00:00:00 2001 From: Pablo P Varela Date: Sat, 7 Dec 2024 17:10:44 +0100 Subject: [PATCH 1/4] remember the last profile --- README.md | 2 +- dot.lua | 73 +++++++++++++++++++++++++++++++++++++++++++---- spec/dot_spec.lua | 42 +++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 898e85c..3d28381 100644 --- a/README.md +++ b/README.md @@ -372,4 +372,4 @@ return { - [x] Ignore on linux - [x] Add cog images to the header so it's easier to tell that it's not only about plaintext dotfiles - [ ] Support an `os` field. i.e `os = { "mac" }` will be ignored on Linux. -- [ ] After using a profile, like `dot profile1`, it should remember it and all calls to `dot` should be done with this profile unless another profile is explicitely invoked, like `dot profile2`, which will replace it for the next invokations. +- [x] After using a profile, like `dot profile1`, it should remember it and all calls to `dot` should be done with this profile unless another profile is explicitely invoked, like `dot profile2`, which will replace it for the next invokations. diff --git a/dot.lua b/dot.lua index e2fa73c..7bf15ca 100755 --- a/dot.lua +++ b/dot.lua @@ -17,6 +17,7 @@ local function parse_args() local mock_defaults = false local defaults_export = false local defaults_import = false + local remove_profile = false local args = {} local i = 1 @@ -42,6 +43,8 @@ local function parse_args() defaults_import = true elseif arg[i] == "--hooks" then hooks_mode = true + elseif arg[i] == "--remove-profile" then + remove_profile = true elseif arg[i] == "-h" then print [[ Usage: dot [options] [module/profile] @@ -57,6 +60,7 @@ Options: --defaults-export Save app preferences to a plist file --defaults-import Import app preferences from a plist file --hooks Run hooks even if dependencies haven't changed + --remove-profile Remove the last used profile -h Display this help message ]] os.exit(0) @@ -76,6 +80,7 @@ Options: defaults_export = defaults_export, defaults_import = defaults_import, hooks_mode = hooks_mode, + remove_profile = remove_profile, args = args, } end @@ -91,6 +96,10 @@ local colors = { magenta = "\27[35m", } +local function print_section(message) + print(colors.bold .. colors.blue .. "[" .. message .. "]" .. colors.reset) +end + -- Unified print function local function print_message(message_type, message) local color, symbol @@ -225,7 +234,7 @@ local function get_installed_brew_packages() installed_brew_packages[package] = true end else - print(colors.red .. "Warning: Failed to get list of installed brew packages" .. colors.reset) + print_message("error", "Failed to get list of installed brew packages") end end add_packages "brew list --formula" @@ -683,7 +692,7 @@ local function process_defaults(config, module_dir, options) local move_cmd = string.format('mv "%s" "%s"', tmp_file, resolved_plist) local exit_code, move_output = execute(move_cmd) if exit_code == 0 then - print_message("success", "defaults → exported current preferences for `" .. app .. "` to dotfiles as `" .. resolved_plist .. "` did not exist") + print_message("success", "defaults �� exported current preferences for `" .. app .. "` to dotfiles as `" .. resolved_plist .. "` did not exist") else print_message("error", "defaults → failed to export preferences: " .. move_output) end @@ -735,7 +744,7 @@ end -- Process each module by installing/uninstalling dependencies and managing symlinks local function process_module(module_name, options) - print(colors.bold .. colors.blue .. "[" .. module_name .. "]" .. colors.reset) + print_section(module_name) local module_dir = "modules/" .. module_name local init_file = module_dir .. "/init.lua" @@ -798,13 +807,13 @@ local function process_tool(tool_name, options) -- Load and process the profile local profile_func, load_err = loadfile(profile_path) if not profile_func then - print(colors.red .. "Error loading profile: " .. load_err .. colors.reset) + print_message("error", "Error loading profile: " .. load_err) return end local success, profile = pcall(profile_func) if not success or not profile or not profile.modules then - print(colors.red .. "Error executing profile or invalid profile structure" .. colors.reset) + print_message("error", "Error executing profile or invalid profile structure") return end @@ -835,11 +844,45 @@ local function process_tool(tool_name, options) if is_file(module_path) then process_module(tool_name, options) else - print(colors.red .. "Module not found: " .. tool_name .. colors.reset) + print_message("error", "Module not found: " .. tool_name) end end end +local function save_last_profile(profile_name) + local file_path = ".git/dot" + if not is_dir(".git") then + file_path = ".dot" + end + local file = io.open(file_path, "w") + if file then + file:write(profile_name) + file:close() + end +end + +local function get_last_profile() + local file_path = ".git/dot" + if not is_dir(".git") then + file_path = ".dot" + end + local file = io.open(file_path, "r") + if file then + local profile_name = file:read("*a") + file:close() + return profile_name:match("^%s*(.-)%s*$") -- Trim whitespace + end + return nil +end + +local function remove_last_profile() + local file_path = ".git/dot" + if not is_dir(".git") then + file_path = ".dot" + end + os.remove(file_path) +end + -- Main function local function main() local options = parse_args() @@ -858,7 +901,25 @@ local function main() get_installed_brew_packages() + if options.remove_profile then + remove_last_profile() + print_message("info", "Profile removed.") + return + end + local tool_name = options.args[1] + + if not tool_name then + tool_name = get_last_profile() + if tool_name then + print_section("using profile " .. tool_name) + print_message("log", "dot # use another profile") + print_message("log", "dot --remove-profile # remove the current profile") + end + else + save_last_profile(tool_name) + end + if tool_name then process_tool(tool_name, options) else diff --git a/spec/dot_spec.lua b/spec/dot_spec.lua index f346734..6d24c85 100644 --- a/spec/dot_spec.lua +++ b/spec/dot_spec.lua @@ -544,4 +544,46 @@ return { -- Check if the import was successful (mocked, so no actual change) -- This is mainly to ensure no errors occur during the import process end) + + it("should save the last used profile", function() + -- Set up 'neovim' module + setup_module( + "neovim", + [[ +return { + brew = { "neovim" }, + config = { + source = "./config", + output = "~/.config/nvim", + } +} +]] + ) + + -- Create config directories and files for 'neovim' + pl_dir.makepath(pl_path.join(modules_dir, "neovim", "config")) + pl_file.write(pl_path.join(modules_dir, "neovim", "config", "init.vim"), "set number") + + -- Set up a dummy profile + setup_profile( + "test_profile", + [[ +return { + modules = { + "neovim" + } +} +]] + ) + + -- Run dot.lua with the 'test_profile' profile + assert.is_true(run_dot "test_profile") + + -- Check if the .dot file contains the correct profile name + local dot_file_path = pl_path.join(dotfiles_dir, ".dot") + assert.is_true(pl_path.isfile(dot_file_path), ".dot file not found") + + local content = pl_file.read(dot_file_path) + assert.are.equal("test_profile", content:match("^%s*(.-)%s*$"), "Profile name in .dot file is incorrect") + end) end) From c50bba6d15c5d1d22fec5e4faad3f9969362b773 Mon Sep 17 00:00:00 2001 From: Pablo P Varela Date: Sat, 7 Dec 2024 17:14:41 +0100 Subject: [PATCH 2/4] docs --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 3d28381..a4f25b6 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,24 @@ return { > [!NOTE] > If your profile is named just like a module (e.g., `profiles/neovim` and `modules/neovim`), running `dot neovim` will default to the profile. +#### Profiles are persistent + +When you run `dot `, it will remember it, so next time you only need to run `dot` to use the same profile. + +```bash +$ dot work +...installing work profile... + +$ dot +...installing work profile again... +``` + +To get rid of the last profile used, select any other profile or run: + +```bash +$ dot --remove-profile +``` + ### Force Mode `-f` By default, `dot` won't touch your existing dotfiles if the destination already exists. If you still want to replace them, you can use the `-f` flag: From 50c8995fbf134fe738bcd3934c968e965b2473dd Mon Sep 17 00:00:00 2001 From: Pablo P Varela Date: Sat, 7 Dec 2024 17:19:53 +0100 Subject: [PATCH 3/4] dont save modules as profiles --- dot.lua | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/dot.lua b/dot.lua index 7bf15ca..ca2dd47 100755 --- a/dot.lua +++ b/dot.lua @@ -917,7 +917,10 @@ local function main() print_message("log", "dot --remove-profile # remove the current profile") end else - save_last_profile(tool_name) + local profile_path = os.getenv "PWD" .. "/profiles/" .. tool_name .. ".lua" + if is_file(profile_path) then + save_last_profile(tool_name) + end end if tool_name then From aba015b5873a7edbd0e3d4e103459113c9f36547 Mon Sep 17 00:00:00 2001 From: Pablo P Varela Date: Sat, 7 Dec 2024 17:21:17 +0100 Subject: [PATCH 4/4] don't remove if it does not exist Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- dot.lua | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dot.lua b/dot.lua index ca2dd47..ff6caee 100755 --- a/dot.lua +++ b/dot.lua @@ -880,7 +880,15 @@ local function remove_last_profile() if not is_dir(".git") then file_path = ".dot" end - os.remove(file_path) + if is_file(file_path) then + local success, err = os.remove(file_path) + if not success then + print_message("error", "Failed to remove profile: " .. err) + return false + end + return true + end + return true end -- Main function