Skip to content

Commit

Permalink
cmd/flux-kvs: add ls subcommand
Browse files Browse the repository at this point in the history
Add new subcommand:
   flux kvs ls [-R] [-d] [-w COLS] [-1] [key]

This is supposed to be similar to ls(1) as discussed
in flux-framework#1158.
  • Loading branch information
garlick committed Aug 28, 2017
1 parent 1c99b02 commit 5d837fb
Showing 1 changed file with 162 additions and 0 deletions.
162 changes: 162 additions & 0 deletions src/cmd/flux-kvs.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/ioctl.h>
#include <flux/core.h>
#include <flux/optparse.h>
#include <unistd.h>
Expand All @@ -48,6 +49,7 @@ int cmd_dropcache (optparse_t *p, int argc, char **argv);
int cmd_copy (optparse_t *p, int argc, char **argv);
int cmd_move (optparse_t *p, int argc, char **argv);
int cmd_dir (optparse_t *p, int argc, char **argv);
int cmd_ls (optparse_t *p, int argc, char **argv);

static void dump_kvs_dir (kvsdir_t *dir, bool Ropt, bool dopt);

Expand All @@ -61,6 +63,25 @@ static struct optparse_option dir_opts[] = {
OPTPARSE_TABLE_END
};

static struct optparse_option ls_opts[] = {
{ .name = "recursive", .key = 'R', .has_arg = 0,
.usage = "List directory recursively",
},
{ .name = "directory", .key = 'd', .has_arg = 0,
.usage = "List directory instead of contents",
},
{ .name = "width", .key = 'w', .has_arg = 1,
.usage = "Set output width to COLS. 0 width means no limit",
},
{ .name = "1", .key = '1', .has_arg = 0,
.usage = "Force one entry per line",
},
{ .name = "classify", .key = 'F', .has_arg = 0,
.usage = "Append indicator (one of .@) to entries",
},
OPTPARSE_TABLE_END
};

static struct optparse_option watch_opts[] = {
{ .name = "recursive", .key = 'R', .has_arg = 0,
.usage = "Recursively display keys under subdirectories",
Expand Down Expand Up @@ -116,6 +137,13 @@ static struct optparse_subcommand subcommands[] = {
0,
dir_opts
},
{ "ls",
"[-R] [-d] [-w COLS] [-1] [-W] [key]",
"List directory",
cmd_ls,
0,
ls_opts
},
{ "unlink",
"key [key...]",
"Remove key",
Expand Down Expand Up @@ -816,6 +844,140 @@ int cmd_dir (optparse_t *p, int argc, char **argv)
return (0);
}

static int get_dir_maxname (kvsdir_t *dir)
{
kvsitr_t *itr;
const char *name;
int max = 0;

if (!(itr = kvsitr_create (dir)))
log_err_exit ("kvsitr_create");
while ((name = kvsitr_next (itr)))
if (max < strlen (name))
max = strlen (name);
kvsitr_destroy (itr);
return max;
}

static int get_win_cols (void)
{
struct winsize w;

if (ioctl (STDIN_FILENO, TIOCGWINSZ, &w) < 0)
log_err_exit ("ioctl TIOCGSIZE");
return w.ws_col;
}

static const char *get_decorator (kvsdir_t *dir, const char *name)
{
if (kvsdir_isdir (dir, name))
return ".";
else if (kvsdir_issymlink (dir, name))
return "@";
else
return "";
}

static void list_kvs_dir_single (kvsdir_t *dir, int wincols, optparse_t *p)
{
kvsitr_t *itr;
const char *name;
int tabstop = get_dir_maxname (dir) + 4;
int col = 0;
char *namebuf;

if (!(namebuf = malloc (tabstop + 2)))
log_err_exit ("malloc");
if (!(itr = kvsitr_create (dir)))
log_err_exit ("kvsitr_create");
while ((name = kvsitr_next (itr))) {
if (wincols != 0 && col + tabstop > wincols && col > 0) {
printf ("\n");
col = 0;
}
strcpy (namebuf, name);
if (optparse_hasopt (p, "classify"))
strcat (namebuf, get_decorator (dir, name));
printf ("%-*s", tabstop, namebuf);
col += tabstop;
}
printf ("\n");
kvsitr_destroy (itr);
free (namebuf);
}

static void list_kvs_dir (flux_t *h, const char *key, optparse_t *p,
int wincols, int level)
{
flux_future_t *f;
kvsdir_t *dir;
kvsitr_t *itr;
const char *name, *json_str;

if (!(f = flux_kvs_lookup (h, FLUX_KVS_READDIR, key))
|| flux_kvs_lookup_get (f, &json_str) < 0) {
log_err ("%s", key);
goto done;
}
if (optparse_hasopt (p, "directory")) {
printf ("%s\n", key);
goto done;
}

/* List the directory
*/
if (optparse_hasopt (p, "recursive"))
printf ("%s%s:\n", level > 0 ? "\n" : "", key);
if (!(dir = kvsdir_create (h, NULL, key, json_str)))
log_err_exit ("kvsdir_create");
list_kvs_dir_single (dir, wincols, p);

/* List subdirectories
*/
if (optparse_hasopt (p, "recursive")) {
if (!(itr = kvsitr_create (dir)))
log_err_exit ("kvsitr_create");
while ((name = kvsitr_next (itr))) {
if (kvsdir_isdir (dir, name)) {
char *nkey;
if (!(nkey = kvsdir_key_at (dir, name))) {
log_err ("%s: kvsdir_key_at failed", name);
continue;
}
list_kvs_dir (h, nkey, p, wincols, level + 1);
free (nkey);
}
}
kvsdir_destroy (dir);
}
done:
flux_future_destroy (f);
}

int cmd_ls (optparse_t *p, int argc, char **argv)
{
flux_t *h = (flux_t *)optparse_get_data (p, "flux_handle");
int optindex = optparse_option_index (p);
const char *key = ".";
int wincols;

/* 'wincols' is the number of columns available in the current window,
* with 0 meaning "unlimited". 1 effectively forces single column output.
*/
wincols = optparse_get_int (p, "width", get_win_cols ());
if (wincols < 0 || optparse_hasopt (p, "1"))
wincols = 1;

if (optindex < argc)
key = argv[optindex++];
if (optindex < argc)
log_msg_exit ("dir: specify zero or one directory");

list_kvs_dir (h, key, p, wincols, 0);

return (0);
}

int cmd_copy (optparse_t *p, int argc, char **argv)
{
flux_t *h = (flux_t *)optparse_get_data (p, "flux_handle");
Expand Down

0 comments on commit 5d837fb

Please sign in to comment.