From 6a43f7bfdfdb693e877943490abd5839a630ad9d Mon Sep 17 00:00:00 2001 From: gramanas Date: Tue, 13 Nov 2018 13:22:53 +0200 Subject: Fixed homedir with restore and updated delete --- ck.1 | 32 +++++------- src/actionhelper.c | 144 ++++++----------------------------------------------- src/actionhelper.h | 5 -- src/actions.c | 48 +++++++++++------- src/actions.h | 14 ------ src/ckutil.c | 12 +++++ src/ckutil.h | 3 ++ src/dblayer.c | 62 +++++++++++++++++++---- src/dblayer.h | 2 +- test/01_add | 4 +- test/03_delete | 4 +- 11 files changed, 128 insertions(+), 202 deletions(-) diff --git a/ck.1 b/ck.1 index 9c5599e..d120757 100644 --- a/ck.1 +++ b/ck.1 @@ -25,12 +25,9 @@ ck \- manage configuration across the system .YS \" Delete .SY ck -.BI delete \ PROGRAM_NAME -.YS -.ns -.SY ck -.B delete \-c -.I CONFIG_PATH +.B delete +.I PROGRAM_NAME +.RI [ CONFIG_BASENAME ] .YS \" List .SY ck @@ -342,12 +339,9 @@ to handle it. .ns .RS 2 .SY ck -.BI delete \ PROGRAM_NAME -.YS -.ns -.SY ck -.B delete \-c -.I CONFIG_PATH +.B delete +.I PROGRAM_NAME +.RI [ CONFIG_BASENAME ] .YS .RE .TP 2 @@ -364,17 +358,17 @@ Delete the and all it's .BR configs . .TP 21 -.BI \-c \ CONFIG_PATH -Delete the -.BR config . -This has to be the full path of the link as shown by the -.B list action\fR. +.I CONFIG_BASENAME +The basename of the +.B config +file to be deleted. It has to follow the +.IR PROGRAM_NAME . .RE .TP 2 .B EXAMPLES .EX $ ck delete emacs -$ ck del -c /home/ckuser/.emacs.d/init.el +$ ck del emacs init.el .EE .SS "LIST VALUES" List programs, configs and ck configuration values. @@ -554,7 +548,7 @@ one, no further action is required. The basename of the .B config to be edited. This has to follow the -.B program +.I PROGRAM_NAME name. It is only needed when editing a .B config other than the diff --git a/src/actionhelper.c b/src/actionhelper.c index c0dff0f..93b3107 100644 --- a/src/actionhelper.c +++ b/src/actionhelper.c @@ -85,33 +85,6 @@ AddOpt add_make_options(cklist *args) { return addOpt; } -DelOpt del_make_options(cklist *args) { - list_rewind(args); - DelOpt delOpt = { - .arg = NULL, - .isConf = 0, - .err = DEL_NO_ERR - }; - - if (strcmp(list_get(args), "-c") == 0) { - delOpt.isConf = 1; - if (!list_next(args)) { - delOpt.err = DEL_ERR_WRONG_ARGS; - return delOpt; - } - delOpt.arg = list_get(args); - } else { - delOpt.arg = list_get(args); - if (list_next(args)) { - delOpt.err = DEL_ERR_WRONG_ARGS; - return delOpt; - } - } - - list_rewind(args); - return delOpt; -} - void add_print_opts(AddOpt *opt) { printf("Program:\t%s\nConfig:\t\t%s\n", opt->progName, opt->confPath); if (opt->prime && opt->secret) { @@ -353,135 +326,48 @@ void print_RESTORE_result(int err) { } void print_INIT_help() { - ckhelp("Initialize the database and create the file that holds"); - ckhelp("the paths where configurations will be stored."); - ckhelp("Namely the version control and the secret directories.\n"); - ckhelp("It takes two arguments:"); - ckhelp(" `version_control_dir`: the path to the version control directory"); - ckhelp(" `secret_dir`: the path to the secret directory"); - report_help(); + HELP("ck init VERSION_CONTROL_DIR SECRET_DIR"); } void print_ADD_help() { - ckhelp("Add a config for ck to keep track of.\n"); - ckhelp("The file will be stored to the desired directory and will"); - ckhelp("be linked back to it's original position.\n"); - ckhelp("It takes the following arguments:"); - ckhelp(" `program_name`: the name of the config's program"); - ckhelp(" `path`: path to the configuration (can be relative)\n"); - ckhelp("It also takes the flags:"); - ckhelp(" `-p`: to mark a configuration as primary (so it will open with edit by default)"); - ckhelp(" `-s`: to mark a configuration as secret (to end up in the secret dir)\n"); - ckhelp("Note:\nThere can be only one primary config per program."); - ckhelp("It is advised to use your distribution's package name for the program_name."); - ckhelp("The arguments have to be in the order shown here (name -> path -> flags)"); - report_help(); + HELP("ck add PROGRAM_NAME CONFIG_PATH [-p] [-s]"); } void print_DEL_help() { - ckhelp("Delete a program/config from ck.\n"); - ckhelp("This will not interfere with any files or links, it will"); - ckhelp("just remove the program/config from the ck database.\n"); - ckhelp("To completely remove a program/config you have to manually"); - ckhelp("erase it from the folder it is stored. You can do it either before"); - ckhelp("or after running this command.\n"); - ckhelp("It takes one or two arguments:"); - ckhelp(" `program_name`: will delete all configs under that program."); - ckhelp(" `-c path`: will delete the config specified by the path.\n"); - ckhelp("Note:\nThe path that follows the -c option has to be the path shown"); - ckhelp("when you list the configurations of a program. (ck help list for more)"); - report_help(); + HELP("ck delete PROGRAM_NAME [CONFIG_BASENAME]"); } void print_EDIT_help() { - ckhelp("Edit a config tracked by ck.\n"); - ckhelp("It takes one or two arguments:"); - ckhelp(" `program_name`: will open the primary config of that program (if set)"); - ckhelp(" `config_name`: will open the specified config\n"); - ckhelp("Note:\nIf a program has only one config, edit will open it even if it's not the primary."); - ckhelp("Edit will use the $EDITOR and if it's not set it falls back to nano."); - ckhelp("If there is ambiguity ck will list the available config names"); - ckhelp("for the program specified."); - report_help(); + HELP("ck edit PROGRAM_NAME [CONFIG_BASENAME]"); } void print_LIST_help() { - ckhelp("List various stuff ck knows about.\n"); - ckhelp("List can work in a few different ways:"); - ckhelp(" `tree`: list all the programs and paths in a tree like structure."); - ckhelp(" `paths`: list all the configs ck keeps track."); - ckhelp(" `programs`: list all the programs ck keeps track."); - ckhelp(" `-p program_name`: list only the configs of the specified program."); - ckhelp(" `ckconf`: list the ck configuration values.\n"); - ckhelp("There are also some flags:"); - ckhelp(" `-a`: add the attributes next to the config paths (secret,primary,root)"); - ckhelp(" `-b`: print the config basenames instead of the full path"); - ckhelp(" `-t`: change the list type. (does not work with tree or ckconf)"); - ckhelp(" `plain`: default plain listing"); - ckhelp(" `python`: enclose the list in [ , ]"); - ckhelp(" `lisp`: enclose the list in ( , )"); + ckhelp("ck list tree [-a] [-b]"); + ckhelp("ck list -p PROGRAM_NAME [-t list-type] [-a] [-b]"); + ckhelp("ck list programs [-t list-type] [-a] [-b]"); + ckhelp("ck list paths [-t list-type] [-a] [-b]"); + ckhelp("ck list ckconf"); report_help(); } void print_SEARCH_help() { - ckhelp("Search through the configs ck keeps track of.\n"); - ckhelp("Search performs a grep with the supplied term to each"); - ckhelp("file ck keeps track and prints the results.\n"); - ckhelp("The exact grep command used is `grep -H -n`\n"); - ckhelp("It takes one argument:"); - ckhelp(" `search_term`\n"); - ckhelp("Note:\nIf you want to search for a phrase enclose it in \'\' or \"\""); - report_help(); + HELP("ck search SEARCH_TERM"); } void print_HELP_help() { - ckhelp("Get help for ck actions.\n"); - ckhelp("It takes one argument:"); - ckhelp(" `action`\n"); - ckhelp("Note:\nRunning ck without arguments will print all the available actions."); - report_help(); + HELP("ck help action"); } void print_RESTORE_help() { - ckhelp("Restore links.\n"); - ckhelp("Given a working ck instance (ckdb + ckrc + directories in ckrc with configs)"); - ckhelp("restore shall recreate the links from the config directories in ckrc"); - ckhelp("back to their corresponding position when added in ck.\n"); - ckhelp("It is useful for copying your configs to a new linux installation"); - ckhelp("or restoring deleted links.\n"); - ckhelp("It can either restore a specific program or all of them:"); - ckhelp(" `-p progName`: restores progName."); - ckhelp(" `all`: restores everything.\n"); - ckhelp("Note:\nIf ck tracks configs that are owned by root, simply running"); - ckhelp("`ck restore ...` will fail due to permissions. To remedy this, ck will alter the"); - ckhelp("owner and group of a link to match the one in the ckrc directories."); - ckhelp("Thus, running `sudo ck -c /home/myuser/.ck restore ..` will restore"); - ckhelp("the root user's links as it should and the user links will have"); - ckhelp("the user as the owner instead of the root.\n"); - ckhelp("ck checks that the configs exist and that the location for the link"); - ckhelp("is avaliable before making any links. However, in the even that symlink"); - ckhelp("fails for some other reason, the process will stop as is. Make sure you"); - ckhelp("take care of the already created links, if that's the case."); + ckhelp("ck restore -p PROGRAM_NAME"); + ckhelp("ck restore all"); report_help(); } void print_conf_help(void) { - ckhelp("Set a different ck configuration directory.\n"); - ckhelp("This has to be passed before any action or action argument"); - ckhelp("and after verbose (if set).\n"); - ckhelp("Usage:"); - ckhelp(" ck -c /path/to/conf ..."); - ckhelp(" ck config /path/to/conf ...\n"); - ckhelp("ck will use the database and config file in the path supplied"); - ckhelp("to perform any actions.\n"); - ckhelp("Tip:\nYou can alias `ck -c /path/to/conf` and use the new alias"); - ckhelp("to organise a different set of configurations, or some custom scrpits."); - report_help(); + HELP("ck [-v|--verbose] [-c|--config DIR] action [...]"); } void print_verbose_help(void) { - ckhelp("WIP\n"); - ckhelp("Currently passing the verbose flag, prints a log of what ck is doing"); - ckhelp("during excecution of an action."); - report_help(); + HELP("ck [-v|--verbose] [-c|--config DIR] action [...]"); } diff --git a/src/actionhelper.h b/src/actionhelper.h index 4265691..3f16ce3 100644 --- a/src/actionhelper.h +++ b/src/actionhelper.h @@ -38,11 +38,6 @@ extern AddOpt add_make_options(cklist *args); extern void add_print_opts(AddOpt *opt); extern void add_make_link(const AddOpt *opt, const Conf *conf); -/*******/ -/* DEL */ -/*******/ -extern DelOpt del_make_options(cklist *args); - /********/ /* EDIT */ /********/ diff --git a/src/actions.c b/src/actions.c index 990b371..5a3befe 100644 --- a/src/actions.c +++ b/src/actions.c @@ -74,27 +74,38 @@ int run_ADD(UserOpt * opt, Conf *conf) { int run_DEL(UserOpt * opt, Conf *conf) { UNUSED(conf); DB db; + db = open_DB(opt); + if (db.ptr == NULL) { + if (db.error == SQL_ERR_NO_TABLES) { + ERR("The database file is currupted. Run ck init anew."); + } + return -1; + } - DelOpt delOpt = del_make_options(opt->args); - switch(delOpt.err) { - case DEL_NO_ERR: - db = open_DB(opt); - if (db.ptr == NULL) { - if (db.error == SQL_ERR_NO_TABLES) { - ERR("The database file is currupted. Run ck init anew."); - } - return -1; + int rc = -1; + /* 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); + goto error; + } + + /* If there is no next argument */ + if (!list_next(opt->args)) { + rc = del_transaction_try(&db, pName, NULL); + } + /* If there are more arguments */ + else { + char *cName = list_get(opt->args); + rc = del_transaction_try(&db, pName, cName); + if (rc) { + HELP("Program %s doesn't have a config named %s", pName, cName); + edit_print_suggested_configs(&db, pName); } - int rc = del_transaction_try(&db, delOpt.arg, delOpt.isConf); - close_DB(&db); - return rc; - case DEL_ERR_WRONG_ARGS: - ERR("Wrong delete arguments."); - break; - case DEL_ERR_WRONG_PATH: - ERR("Path %s doesnt exist.", delOpt.arg); } - return -1; + error: + close_DB(&db); + return rc; } int run_EDIT(UserOpt *opt, Conf *conf) { @@ -309,7 +320,6 @@ int run_HELP(UserOpt *opt, Conf *conf) { } int run_RESTORE(UserOpt *opt, Conf *conf) { - UNUSED(conf); DB db = open_DB(opt); if (db.ptr == NULL) { if (db.error == SQL_ERR_NO_TABLES) { diff --git a/src/actions.h b/src/actions.h index e6fe336..4bd0c9e 100644 --- a/src/actions.h +++ b/src/actions.h @@ -41,20 +41,6 @@ struct AddOptions { AddOptErr err; }; -enum DelErrors { - DEL_NO_ERR = 0, - DEL_ERR_WRONG_PATH, - DEL_ERR_WRONG_ARGS -}; -typedef enum DelErrors DelErr; - -typedef struct DelOptions DelOpt; -struct DelOptions { - char *arg; - int isConf; - DelErr err; -}; - enum ListTypes { LT_PATH, LT_PROGRAM, diff --git a/src/ckutil.c b/src/ckutil.c index 8ae7e41..fde5e24 100644 --- a/src/ckutil.c +++ b/src/ckutil.c @@ -216,3 +216,15 @@ int util_is_link_owned_by_root(const char *link) { } return 0; } + +int y_or_n_prompt() { + char c; + + printf("[y/n] > "); + c = (char)getchar(); + + if (c == 'y') { + return 1; + } + return 0; +} diff --git a/src/ckutil.h b/src/ckutil.h index 1a8c162..3003a45 100644 --- a/src/ckutil.h +++ b/src/ckutil.h @@ -96,4 +96,7 @@ extern int util_symlink_file(const char *path, const char* dest); extern int util_own_grp_copy(const char *new, const char* old); extern int util_is_link_owned_by_root(const char *link); + +/* yes is 1, no is 0 */ +extern int y_or_n_prompt(); #endif // CKUTIL_H diff --git a/src/dblayer.c b/src/dblayer.c index f263b86..0e2ba5b 100644 --- a/src/dblayer.c +++ b/src/dblayer.c @@ -862,29 +862,64 @@ int remove_all_configs(DB *db, int pid) { return 0; } -int del_transaction_try(DB *db, char *arg, int conf) { +int get_cid_from_pname_and_basename(DB *db, const char *pName, const char *cBaseName) { + sqlite3_stmt *stmt; + int rc; + + char sql[STR_L] = ""; + char selection[STR_M] = TBL_CONFIG; + strcat(selection, "."); + strcat(selection, COL_CONFIG_ID); + strcat(selection, ", "); + strcat(selection, COL_CONFIG_PATH); + + char condition[STR_M] = TBL_PROGRAM; + strcat(condition, "."); + strcat(condition, COL_PROGRAM_NAME); + + dbh_form_query_select_from_joined_eq(sql, selection, condition); + rc = sqlite3_prepare_v2(db->ptr, sql, -1, &stmt, 0); + if (rc != SQLITE_OK) { + ERR("while preparing get_cid_from_pname_and_basename"); + db->error = SQL_ERR_SQLITE; + return -1; + } + + sqlite3_bind_text(stmt, 1, pName, -1, 0); + int _cid = -1; + while (sqlite3_step(stmt) == SQLITE_ROW) { + if (strcmp(cBaseName, basename((char *)sqlite3_column_text(stmt, 1))) == 0) { + _cid = sqlite3_column_int(stmt, 0); + break; + } + } + sqlite3_finalize(stmt); + return _cid; +} + +int del_transaction_try(DB *db, const char *pName, const char *cBaseName) { __BEGIN_TRANSACTION__ int pid = -1; - if (conf) { + if (cBaseName) { // del conf - int cid = get_config_id(db, arg); + int cid = get_cid_from_pname_and_basename(db, pName, cBaseName); if (cid < 0) { - ERR("Config %s doesn't exist in the database.", arg); + ERR("Config %s doesn't exist in the database.", cBaseName); return -1; } if (delete_conf(db, cid)) { - ERR("Could not delete config from db."); + ERR("Could not delete config %s from db.", cBaseName); return -1; } // handle relations pid = remove_conf_rel(db, cid); - HELP("Deleted config: %s", arg); + HELP("Deleted %s config: %s", pName, cBaseName); if (get_program_relations(db, pid) > 0) { goto end; } } else { - pid = get_program_id(db, arg); + pid = get_program_id(db, pName); } if (pid < 0) { ERR("Program not found in the db."); @@ -892,14 +927,14 @@ int del_transaction_try(DB *db, char *arg, int conf) { } /* If we are deleting a program we should delete everything that * refferences it (configs and relationships) */ - if (!conf) { + if (!cBaseName) { remove_all_configs(db, pid); } if(delete_prog(db, pid)) { - ERR("Could not delete program from db."); + ERR("Could not delete program %s from db.", pName); return -1; } - HELP("Deleted program %s", conf ? "" : arg); + HELP("Deleted program %s", pName); end: __END_TRANSACTION__ return 0; @@ -983,9 +1018,14 @@ int restore_configs_exists(DB *db, Conf *conf, const char *pName, cklist *from, if (!util_is_file_rw(filePath)) { sERR("%s does not exist or is not accessible.", filePath); err_flag = 1; + break; } list_add(from, filePath); - list_add(to, /*path*/ (char *)sqlite3_column_text(stmt, 0)); + char tpath[STR_L] = ""; + if (!swap_tilde_with_home(tpath, (char *)sqlite3_column_text(stmt, 0), conf->home_dir)) { + strcpy(tpath, (char *)sqlite3_column_text(stmt, 0)); + } + list_add(to, tpath); } sqlite3_finalize(stmt); return !err_flag; diff --git a/src/dblayer.h b/src/dblayer.h index b826327..199471a 100644 --- a/src/dblayer.h +++ b/src/dblayer.h @@ -80,7 +80,7 @@ extern int list_get_path_program_tree(DB *db, cklist *ckl, int bName, int attr, /* del */ /*******/ -extern int del_transaction_try(DB *db, char *arg, int conf); +extern int del_transaction_try(DB *db, const char *pName, const char *cBaseName); /***********/ /* restore */ diff --git a/test/01_add b/test/01_add index 1de64bf..5f156da 100644 --- a/test/01_add +++ b/test/01_add @@ -20,8 +20,8 @@ function run_add { if [ "$(sqlite3 $BIN/ckdb "select name from program where name = '$1'")" != "$1" ]; then err "$1 is not in the db." fi - - if [ "$(sqlite3 $BIN/ckdb "select path from config where path = '$BIN/$2'")" != "$BIN/$2" ]; then + + if [ "$($BIN/ck -c $BIN ls -p $1)" != "$BIN/$2" ]; then err "$2 is not in the db." fi diff --git a/test/03_delete b/test/03_delete index 1668576..e4663bd 100644 --- a/test/03_delete +++ b/test/03_delete @@ -15,7 +15,7 @@ add_config prog2 $path3 add_config prog2 $path4 # delete path1 -exec $BIN/ck -c $BIN del -c $path1 > /dev/null & +exec $BIN/ck -c $BIN del prog1 `basename $path1` > /dev/null & wait $! for i in $($BIN/ck -c $BIN list paths); do @@ -26,7 +26,7 @@ for i in $($BIN/ck -c $BIN list paths); do done # delete path2 (also prog1) -exec $BIN/ck -c $BIN del -c $path2 > /dev/null & +exec $BIN/ck -c $BIN del prog1 `basename $path2` > /dev/null & wait $! for i in $($BIN/ck -c $BIN list programs); do -- cgit v1.2.3