From 7d10e2377b01ac3e38b412f6bc2fa2e384804057 Mon Sep 17 00:00:00 2001 From: gramanas Date: Sun, 18 Nov 2018 20:58:35 +0200 Subject: Update edit and add edit test --- ck.1 | 44 +++++++++++--- res/test-ck | 3 +- src/actions.h | 14 ++++- src/clparser.h | 2 +- src/edit.c | 181 +++++++++++++++++++++++++++++++++++++++++++++------------ src/restore.c | 1 - test/06_edit | 83 ++++++++++++++++++++++++++ 7 files changed, 278 insertions(+), 50 deletions(-) create mode 100644 test/06_edit diff --git a/ck.1 b/ck.1 index a1c3d5e..205270e 100644 --- a/ck.1 +++ b/ck.1 @@ -68,6 +68,9 @@ ck \- manage configuration across the system .B edit .I PROGRAM_NAME .RI [ CONFIG_BASENAME ] +.OP \-\-editor EDITOR +.OP \-\-command COMMAND +.OP \-s .YS \" Search .SY ck @@ -125,12 +128,12 @@ it is moved to the appropriate directory, and then symbolically linked back to it's original place (\fIln -s\fR). .P In a later time you can sync the -.I VERSION_CONRTOL_DIR +.I VERSION_CONTROL_DIR and .IR SECRET_DIR . You can also .B restore -the links given these two directories and the correspondig rc file and database. +the links given these two directories and the corresponding rc file and database. .SH CONFIGURATION .B ck uses @@ -153,7 +156,7 @@ environment variable. If it is set it will use the .I ckrc and .I ckdb -inside this directory. Else it wil use +inside this directory. Else it will use .I $XDG_CONFIG_HOME/ck and if that is not set as well it will fall back to .IR $HOME/.ck . @@ -175,7 +178,7 @@ section for more details. .SH OPTIONS Change .B ck -behaviour using the following options. They must be present before any +behavior using the following options. They must be present before any .B action. .TP .B \-\-verbose\fR, \fB\-v @@ -190,7 +193,7 @@ residing in .IR DIR . .TP .B \-\-version\fR, \fBversion -Print version and licence information, and quit. +Print version and license information, and quit. .SH ACTIONS Each .B action @@ -473,7 +476,7 @@ to print it like a python array or to print it like a lisp list. .TP 21 .B \-a -Show attributes to the listing (when aplicable). +Show attributes to the listing (when applicable). These are .B [s] for @@ -530,6 +533,9 @@ will be shown. .B edit .I PROGRAM_NAME .RI [ CONFIG_BASENAME ] +.OP \-\-editor EDITOR +.OP \-\-command COMMAND +.OP \-s .YS .RE .TP 2 @@ -563,10 +569,34 @@ other than the one. .RE .TP 2 +.B FLAGS +.ns +.RS 2 +.TP 21 +.BI \-\-editor \ EDITOR +Use +.I EDITOR +to edit the config. +.TP 21 +.BI \-\-command \ COMMAND +The +.I COMMAND +string will be used instead of an editor. +.TP 21 +.B \-\-s +Prepend the whole command with sudo, should you want to edit a +.B config +belonging to root. +.RE +.TP 2 .B EXAMPLES .EX $ ck edit emacs +$ ck edit emacs --command cat +$ ck edit emacs --command "emacsclient -a \"\" -t" $ ck e tmux .tmux.conf +$ ck e tmux .tmux.conf --editor vi +$ ck e ssh -s .EE .SS "SEARCH CONFIGS" Grep through the configs. This @@ -659,7 +689,7 @@ the user as the owner instead of the root. checks that the .B configs exist and that the location for the link -is avaliable before making any links. However, in the even that +is available before making any links. However, in the even that .B symlink fails for some other reason, the process will stop as is. The user will have to take care of the already created links, if that's the case. diff --git a/res/test-ck b/res/test-ck index 35837fa..5e33bb9 100755 --- a/res/test-ck +++ b/res/test-ck @@ -26,7 +26,7 @@ function init { function add_config { echo -e "test $2\n$3" > $2 - exec $BIN/ck -c $BIN -a $1 $2 > /dev/null & + exec $BIN/ck -c $BIN -a $1 $2 $4 > /dev/null & wait $! if [ $? -ne 0 ]; then @@ -118,6 +118,7 @@ do ;; -f | --filter) FILTER=$2; + UNIT=0; shift shift ;; diff --git a/src/actions.h b/src/actions.h index 881fe9d..60b9645 100644 --- a/src/actions.h +++ b/src/actions.h @@ -31,7 +31,6 @@ enum AddOptErrors { }; typedef enum AddOptErrors AddOptErr; -typedef struct AddOptions AddOpt; struct AddOptions { char *progName; char confPath[STR_L]; @@ -39,6 +38,7 @@ struct AddOptions { int prime; AddOptErr err; }; +typedef struct AddOptions AddOpt; enum ListTypes { LT_PATH, @@ -56,7 +56,6 @@ enum ListShowTypes { }; typedef enum ListShowTypes ListShowType; -typedef struct ListOptions ListOpt; struct ListOptions { ListType _lt; ListShowType _lst; @@ -65,6 +64,17 @@ struct ListOptions { int bName; int err; }; +typedef struct ListOptions ListOpt; + +struct EditOptions { + char *pName; + char *cBasename; + char *editor; + char *cmd; + int sudo; + int err; +}; +typedef struct EditOptions EditOpt; /**************/ /* PRINT HELP */ diff --git a/src/clparser.h b/src/clparser.h index f6818fa..4208a91 100644 --- a/src/clparser.h +++ b/src/clparser.h @@ -25,7 +25,7 @@ X(INIT, 2 , 2) \ X(ADD, 2, 4) \ X(DEL, 1, 2) \ - X(EDIT, 1, 2) \ + X(EDIT, 1, 5) \ X(LIST, 1, 6) \ X(SEARCH, 1, 1) \ X(RESTORE, 1, 2) \ diff --git a/src/edit.c b/src/edit.c index 5179a54..b41f748 100644 --- a/src/edit.c +++ b/src/edit.c @@ -81,7 +81,6 @@ static int edit_get_config(DB *db, const char *pName, char *ret, const char *cNa } } free(tmp); - break; } else { /* Since we are here, it means there is only 1 config for the selected program */ @@ -100,78 +99,184 @@ static int edit_get_config(DB *db, const char *pName, char *ret, const char *cNa return -1; } +static EditOpt edit_make_options(cklist *args) { + list_rewind(args); + + EditOpt editOpt = { + .pName = NULL, + .cBasename = NULL, + .editor = NULL, + .cmd = NULL, + .sudo = 0, + .err = 0 + }; + + if (list_size(args)) { + editOpt.pName = list_get(args); + } + else { + editOpt.err = 1; + sERR("Please specify the program to edit.") + goto done; + } + + if (list_next(args)) { + /* if the next argument doesn't start with `-` treat it as + a config basename */ + if (strncmp("-", list_get(args), strlen("-")) != 0) { + editOpt.cBasename = list_get(args); + if (!list_next(args)) { + goto done; + } + } + do { + if (strcmp(list_get(args), "-s") == 0) { + editOpt.sudo = 1; + } + else if (strcmp(list_get(args), "--editor") == 0) { + if (editOpt.cmd) { + sERR("Use only one of --command and --editor"); + editOpt.err = 1; + break; + } + if (!list_next(args)) { + sERR("Specify the editor to use.") + editOpt.err = 1; + break; + } + editOpt.editor = list_get(args); + } + else if (strcmp(list_get(args), "--command") == 0) { + if (editOpt.editor) { + sERR("Use only one of --command and --editor"); + editOpt.err = 1; + break; + } + if (!list_next(args)) { + sERR("Specify the command to use.") + editOpt.err = 1; + break; + } + editOpt.cmd = list_get(args); + } + else { + editOpt.err = 1; + ERR("Unknown argument %s", list_get(args)); + break; + } + } while(list_next(args)); + } + done: + list_rewind(args); + return editOpt; +} + +static char * form_edit_command(char *ret, const EditOpt *editOpt, const char *confPath) { + char command[STR_L] = ""; + + if (editOpt->editor) { + char tmp[STR_L] = "which "; + strcat(tmp, editOpt->editor); + strcat(tmp, " > /dev/null 2>&1"); + if (system(tmp) != 0) { + ERR("Editor %s not found.", editOpt->editor); + HELP("If you want to run the command either way use --command instead of --editor.") + return NULL; + } + else { + strcpy(command, editOpt->editor); + } + } + else if (editOpt->cmd) { + strcpy(command, editOpt->cmd); + } + else { + char *editor = getenv("EDITOR"); + if (str_is_empty(editor)) { + if (system("which emacs > /dev/null 2>&1") != 0) { + ERR("No editor avaliable."); + HELP("Emacs not found. Please set $EDITOR to your desired editor,"); + HELP("or use the --editor flag.") + return NULL; + } + strcpy(command, "nano"); + } + else { + strcpy(command, editor); + } + } + + strcat(command, " "); + strcat(command, confPath); + + if (editOpt->sudo) { + char tmp[STR_L] = "sudo "; + strcat(tmp, command); + return strcpy(ret, tmp); + } + + return strcpy(ret, command); +} + int run_EDIT(UserOpt *opt, Conf *conf) { + char confPath[STR_L] = ""; + char confName[STR_M] = ""; + int secret = 0; DB db; if (open_DB(&db, opt)) { return -1; } - list_rewind(opt->args); - char confPath[STR_L] = ""; - char confName[STR_M] = ""; - int secret = 0; - /* Since we are here, args have to be 1 or 2 */ - char *pName = list_get(opt->args); - if (!program_exists(&db, pName)) { - ERR("Program %s doesn't exist in the database.", pName); + EditOpt editOpt = edit_make_options(opt->args); + if (editOpt.err) { + goto error; + } + + if (!program_exists(&db, editOpt.pName)) { + ERR("Program %s doesn't exist in the database.", editOpt.pName); goto error; } - /* If there is no next argument */ - if (!list_next(opt->args)) { + /* If there is no config basename */ + if (!editOpt.cBasename) { /* If there is no primary config*/ - if (edit_get_prime_config_from_program(&db, pName, confName, &secret) == -1) { + if (edit_get_prime_config_from_program(&db, editOpt.pName, confName, &secret) == -1) { /* If the program has only one config */ - if (get_config_number(&db, pName) == 1) { - if (edit_get_config(&db, pName, confName, NULL, &secret)) { - ERR("Coudln't find config file for %s", pName); + if (get_config_number(&db, editOpt.pName) == 1) { + if (edit_get_config(&db, editOpt.pName, confName, NULL, &secret)) { + ERR("Coudln't find config file for %s", editOpt.pName); goto error; } } /* If the program has many configs */ else { HELP("Ambiguous config. Please type the config name after the program."); - print_suggested_configs(&db, pName); + print_suggested_configs(&db, editOpt.pName); goto error; } } } /* If there are more arguments */ else { - char *cName = list_get(opt->args); - if (edit_get_config(&db, pName, confName, cName, &secret)) { - ERR("Program %s doesn't have a config named %s", pName, cName); - print_suggested_configs(&db, pName); + if (edit_get_config(&db, editOpt.pName, confName, editOpt.cBasename, &secret)) { + ERR("Program %s doesn't have a config named %s", editOpt.pName, editOpt.cBasename); + print_suggested_configs(&db, editOpt.pName); goto error; } } close_DB(&db); str_join_dirname_with_basename(confPath, secret ? conf->scrt_dir : conf->vc_dir, confName); - char *editor = getenv("EDITOR"); char command[STR_L] = ""; - if (str_is_empty(editor)) { - if (system("which nano > /dev/null 2>&1") != 0) { - ERR("Nano not found. Please set $EDITOR to your desired editor."); - return -1; - } - strcpy(command, "nano"); - } else { - strcpy(command, editor); + if (form_edit_command(command, &editOpt, confPath)) { + hLOG("Running: %s", command); + return system(command); } - - - strcat(command, " "); - strcat(command, confPath); - - HELP("editing...\n%s", command); - system(command); - return 0; error: close_DB(&db); return -1; } void print_EDIT_help() { - HELP("ck edit PROGRAM_NAME [CONFIG_BASENAME]"); + HELP("ck edit PROGRAM_NAME [CONFIG_BASENAME] [--editor EDITOR] [--command COMMAND] [-s]"); } diff --git a/src/restore.c b/src/restore.c index a02f6f3..3aff790 100644 --- a/src/restore.c +++ b/src/restore.c @@ -22,7 +22,6 @@ static int restore_make_links(cklist *from, cklist *to) { && list_size(to) > 0 && list_size(from) == list_size(to)) { do { - HELP("If %d OR %d then file exists.", util_file_exists(list_get(to), NULL), !util_is_file_link(list_get(to))); if (util_file_exists(list_get(to), NULL) || !util_is_file_link(list_get(to))) { ERR("File %s already exists.", list_get(to)); diff --git a/test/06_edit b/test/06_edit new file mode 100644 index 0000000..65419b1 --- /dev/null +++ b/test/06_edit @@ -0,0 +1,83 @@ +#!/bin/bash + +init edit + +# add configs to ck +path1=$BIN/test1.conf +path2=$BIN/test2.conf +path3=$BIN/test3.conf +path4=$BIN/test4.conf +path5=$BIN/test5.conf + +add_config prog1 $path1 "" -p +add_config prog1 $path2 + +add_config prog2 $path3 +add_config prog2 $path4 + +add_config prog3 $path5 + +# edit primary +exec $BIN/ck -c $BIN e prog1 --command ":" > __test_file & +wait $! + +TEST_STR=$(cat __test_file) +EXPECTED_STR="Running: : $(realpath $path1)" + +echo "Expected: $EXPECTED_STR" >&${V} +echo " Actual: $TEST_STR" >&${V} + +if [[ "$TEST_STR" != "$EXPECTED_STR" ]]; then + err "Worng edit." + exit 1; +fi + +# edit specific +exec $BIN/ck -c $BIN e prog1 test2.conf --command ":" > __test_file & +wait $! + +echo "Expected: $EXPECTED_STR" >&${V} +echo " Actual: $TEST_STR" >&${V} + +TEST_STR=$(cat __test_file) +EXPECTED_STR="Running: : $(realpath $path2)" + +if [[ "$TEST_STR" != "$EXPECTED_STR" ]]; then + err "Worng edit." + exit 1; +fi + +# Ambiguous config +exec $BIN/ck -c $BIN e prog2 --command ":" > __test_file & +wait $! + +echo "Expected: $EXPECTED_STR" >&${V} +echo " Actual: $TEST_STR" >&${V} + +TEST_STR=$(head -1 __test_file) +EXPECTED_STR="Ambiguous config. Please type the config name after the program." + +if [[ "$TEST_STR" != "$EXPECTED_STR" ]]; then + err "Worng edit." + exit 1; +fi + +# solo program +exec $BIN/ck -c $BIN e prog3 --command ":" > __test_file & +wait $! + +echo "Expected: $EXPECTED_STR" >&${V} +echo " Actual: $TEST_STR" >&${V} + +TEST_STR=$(cat __test_file) +EXPECTED_STR="Running: : $(realpath $path5)" + +if [[ "$TEST_STR" != "$EXPECTED_STR" ]]; then + err "Worng edit." + exit 1; +fi + +rm __test_file + +clear_tests +echo -e $PASS -- cgit v1.2.3