mirror of
http://github.com/valkey-io/valkey
synced 2024-11-22 00:52:38 +00:00
Merge branch 'master' into brpoplpush
This commit is contained in:
commit
bc8ffafeb9
3
Makefile
3
Makefile
@ -16,4 +16,7 @@ clean:
|
||||
$(TARGETS):
|
||||
cd src && $(MAKE) $@
|
||||
|
||||
src/help.h:
|
||||
@./utils/generate-command-help.rb > $@
|
||||
|
||||
dummy:
|
||||
|
9
deps/linenoise/example.c
vendored
9
deps/linenoise/example.c
vendored
@ -2,9 +2,18 @@
|
||||
#include <stdlib.h>
|
||||
#include "linenoise.h"
|
||||
|
||||
|
||||
void completion(const char *buf, linenoiseCompletions *lc) {
|
||||
if (buf[0] == 'h') {
|
||||
linenoiseAddCompletion(lc,"hello");
|
||||
linenoiseAddCompletion(lc,"hello there");
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
char *line;
|
||||
|
||||
linenoiseSetCompletionCallback(completion);
|
||||
linenoiseHistoryLoad("history.txt"); /* Load the history at startup */
|
||||
while((line = linenoise("hello> ")) != NULL) {
|
||||
if (line[0] != '\0') {
|
||||
|
115
deps/linenoise/linenoise.c
vendored
115
deps/linenoise/linenoise.c
vendored
@ -9,6 +9,8 @@
|
||||
* the 2010 UNIX computers around.
|
||||
*
|
||||
* Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -66,6 +68,17 @@
|
||||
* CUF (CUrsor Forward)
|
||||
* Sequence: ESC [ n C
|
||||
* Effect: moves cursor forward of n chars
|
||||
*
|
||||
* The following are used to clear the screen: ESC [ H ESC [ 2 J
|
||||
* This is actually composed of two sequences:
|
||||
*
|
||||
* cursorhome
|
||||
* Sequence: ESC [ H
|
||||
* Effect: moves the cursor to upper left corner
|
||||
*
|
||||
* ED2 (Clear entire screen)
|
||||
* Sequence: ESC [ 2 J
|
||||
* Effect: clear the whole screen
|
||||
*
|
||||
*/
|
||||
|
||||
@ -79,10 +92,12 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include "linenoise.h"
|
||||
|
||||
#define LINENOISE_DEFAULT_HISTORY_MAX_LEN 100
|
||||
#define LINENOISE_MAX_LINE 4096
|
||||
static char *unsupported_term[] = {"dumb","cons25",NULL};
|
||||
static linenoiseCompletionCallback *completionCallback = NULL;
|
||||
|
||||
static struct termios orig_termios; /* in order to restore at exit */
|
||||
static int rawmode = 0; /* for atexit() function to check if restore is needed*/
|
||||
@ -195,6 +210,78 @@ static void refreshLine(int fd, const char *prompt, char *buf, size_t len, size_
|
||||
if (write(fd,seq,strlen(seq)) == -1) return;
|
||||
}
|
||||
|
||||
static void beep() {
|
||||
fprintf(stderr, "\x7");
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
static void freeCompletions(linenoiseCompletions *lc) {
|
||||
size_t i;
|
||||
for (i = 0; i < lc->len; i++)
|
||||
free(lc->cvec[i]);
|
||||
if (lc->cvec != NULL)
|
||||
free(lc->cvec);
|
||||
}
|
||||
|
||||
static int completeLine(int fd, const char *prompt, char *buf, size_t buflen, size_t *len, size_t *pos, size_t cols) {
|
||||
linenoiseCompletions lc = { 0, NULL };
|
||||
int nread, nwritten;
|
||||
char c = 0;
|
||||
|
||||
completionCallback(buf,&lc);
|
||||
if (lc.len == 0) {
|
||||
beep();
|
||||
} else {
|
||||
size_t stop = 0, i = 0;
|
||||
size_t clen;
|
||||
|
||||
while(!stop) {
|
||||
/* Show completion or original buffer */
|
||||
if (i < lc.len) {
|
||||
clen = strlen(lc.cvec[i]);
|
||||
refreshLine(fd,prompt,lc.cvec[i],clen,clen,cols);
|
||||
} else {
|
||||
refreshLine(fd,prompt,buf,*len,*pos,cols);
|
||||
}
|
||||
|
||||
nread = read(fd,&c,1);
|
||||
if (nread <= 0) {
|
||||
freeCompletions(&lc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(c) {
|
||||
case 9: /* tab */
|
||||
i = (i+1) % (lc.len+1);
|
||||
if (i == lc.len) beep();
|
||||
break;
|
||||
case 27: /* escape */
|
||||
/* Re-show original buffer */
|
||||
if (i < lc.len) {
|
||||
refreshLine(fd,prompt,buf,*len,*pos,cols);
|
||||
}
|
||||
stop = 1;
|
||||
break;
|
||||
default:
|
||||
/* Update buffer and return */
|
||||
if (i < lc.len) {
|
||||
nwritten = snprintf(buf,buflen,"%s",lc.cvec[i]);
|
||||
*len = *pos = nwritten;
|
||||
}
|
||||
stop = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
freeCompletions(&lc);
|
||||
return c; /* Return last read character */
|
||||
}
|
||||
|
||||
void linenoiseClearScreen(void) {
|
||||
write(STDIN_FILENO,"\x1b[H\x1b[2J",7);
|
||||
}
|
||||
|
||||
static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt) {
|
||||
size_t plen = strlen(prompt);
|
||||
size_t pos = 0;
|
||||
@ -217,6 +304,18 @@ static int linenoisePrompt(int fd, char *buf, size_t buflen, const char *prompt)
|
||||
|
||||
nread = read(fd,&c,1);
|
||||
if (nread <= 0) return len;
|
||||
|
||||
/* Only autocomplete when the callback is set. It returns < 0 when
|
||||
* there was an error reading from fd. Otherwise it will return the
|
||||
* character that should be handled next. */
|
||||
if (c == 9 && completionCallback != NULL) {
|
||||
c = completeLine(fd,prompt,buf,buflen,&len,&pos,cols);
|
||||
/* Return on errors */
|
||||
if (c < 0) return len;
|
||||
/* Read next character when 0 */
|
||||
if (c == 0) continue;
|
||||
}
|
||||
|
||||
switch(c) {
|
||||
case 13: /* enter */
|
||||
case 4: /* ctrl-d */
|
||||
@ -350,6 +449,9 @@ up_down_arrow:
|
||||
pos = len;
|
||||
refreshLine(fd,prompt,buf,len,pos,cols);
|
||||
break;
|
||||
case 12: /* ctrl+l, clear screen */
|
||||
linenoiseClearScreen();
|
||||
refreshLine(fd,prompt,buf,len,pos,cols);
|
||||
}
|
||||
}
|
||||
return len;
|
||||
@ -402,6 +504,19 @@ char *linenoise(const char *prompt) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Register a callback function to be called for tab-completion. */
|
||||
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *fn) {
|
||||
completionCallback = fn;
|
||||
}
|
||||
|
||||
void linenoiseAddCompletion(linenoiseCompletions *lc, char *str) {
|
||||
size_t len = strlen(str);
|
||||
char *copy = malloc(len+1);
|
||||
memcpy(copy,str,len+1);
|
||||
lc->cvec = realloc(lc->cvec,sizeof(char*)*(lc->len+1));
|
||||
lc->cvec[lc->len++] = copy;
|
||||
}
|
||||
|
||||
/* Using a circular buffer is smarter, but a bit more complex to handle. */
|
||||
int linenoiseHistoryAdd(const char *line) {
|
||||
char *linecopy;
|
||||
|
12
deps/linenoise/linenoise.h
vendored
12
deps/linenoise/linenoise.h
vendored
@ -4,6 +4,8 @@
|
||||
* See linenoise.c for more information.
|
||||
*
|
||||
* Copyright (c) 2010, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||
* Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -34,10 +36,20 @@
|
||||
#ifndef __LINENOISE_H
|
||||
#define __LINENOISE_H
|
||||
|
||||
typedef struct linenoiseCompletions {
|
||||
size_t len;
|
||||
char **cvec;
|
||||
} linenoiseCompletions;
|
||||
|
||||
typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *);
|
||||
void linenoiseSetCompletionCallback(linenoiseCompletionCallback *);
|
||||
void linenoiseAddCompletion(linenoiseCompletions *, char *);
|
||||
|
||||
char *linenoise(const char *prompt);
|
||||
int linenoiseHistoryAdd(const char *line);
|
||||
int linenoiseHistorySetMaxLen(int len);
|
||||
int linenoiseHistorySave(char *filename);
|
||||
int linenoiseHistoryLoad(char *filename);
|
||||
void linenoiseClearScreen(void);
|
||||
|
||||
#endif /* __LINENOISE_H */
|
||||
|
608
src/help.h
Normal file
608
src/help.h
Normal file
@ -0,0 +1,608 @@
|
||||
/* Automatically generated by utils/generate-command-help.rb, do not edit. */
|
||||
|
||||
#ifndef __REDIS_HELP_H
|
||||
#define __REDIS_HELP_H
|
||||
|
||||
static char *commandGroups[] = {
|
||||
"generic",
|
||||
"string",
|
||||
"list",
|
||||
"set",
|
||||
"sorted_set",
|
||||
"hash",
|
||||
"pubsub",
|
||||
"transactions",
|
||||
"connection",
|
||||
"server"
|
||||
};
|
||||
|
||||
struct commandHelp {
|
||||
char *name;
|
||||
char *params;
|
||||
char *summary;
|
||||
int group;
|
||||
char *since;
|
||||
} commandHelp[] = {
|
||||
{ "APPEND",
|
||||
"key value",
|
||||
"Append a value to a key",
|
||||
1,
|
||||
"1.3.3" },
|
||||
{ "AUTH",
|
||||
"password",
|
||||
"Authenticate to the server",
|
||||
8,
|
||||
"0.08" },
|
||||
{ "BGREWRITEAOF",
|
||||
"-",
|
||||
"Asynchronously rewrite the append-only file",
|
||||
9,
|
||||
"1.07" },
|
||||
{ "BGSAVE",
|
||||
"-",
|
||||
"Asynchronously save the dataset to disk",
|
||||
9,
|
||||
"0.07" },
|
||||
{ "BLPOP",
|
||||
"key [key ...] timeout",
|
||||
"Remove and get the first element in a list, or block until one is available",
|
||||
2,
|
||||
"1.3.1" },
|
||||
{ "BRPOP",
|
||||
"key [key ...] timeout",
|
||||
"Remove and get the last element in a list, or block until one is available",
|
||||
2,
|
||||
"1.3.1" },
|
||||
{ "CONFIG GET",
|
||||
"parameter",
|
||||
"Get the value of a configuration parameter",
|
||||
9,
|
||||
"2.0" },
|
||||
{ "CONFIG SET",
|
||||
"parameter value",
|
||||
"Set a configuration parameter to the given value",
|
||||
9,
|
||||
"2.0" },
|
||||
{ "DBSIZE",
|
||||
"-",
|
||||
"Return the number of keys in the selected database",
|
||||
9,
|
||||
"0.07" },
|
||||
{ "DEBUG OBJECT",
|
||||
"key",
|
||||
"Get debugging information about a key",
|
||||
9,
|
||||
"0.101" },
|
||||
{ "DEBUG SEGFAULT",
|
||||
"-",
|
||||
"Make the server crash",
|
||||
9,
|
||||
"0.101" },
|
||||
{ "DECR",
|
||||
"key decrement",
|
||||
"Decrement the integer value of a key by one",
|
||||
1,
|
||||
"0.07" },
|
||||
{ "DECRBY",
|
||||
"key decrement",
|
||||
"Decrement the integer value of a key by the given number",
|
||||
1,
|
||||
"0.07" },
|
||||
{ "DEL",
|
||||
"key [key ...]",
|
||||
"Delete a key",
|
||||
0,
|
||||
"0.07" },
|
||||
{ "DISCARD",
|
||||
"-",
|
||||
"Discard all commands issued after MULTI",
|
||||
7,
|
||||
"1.3.3" },
|
||||
{ "ECHO",
|
||||
"message",
|
||||
"Echo the given string",
|
||||
8,
|
||||
"0.07" },
|
||||
{ "EXEC",
|
||||
"-",
|
||||
"Execute all commands issued after MULTI",
|
||||
7,
|
||||
"1.1.95" },
|
||||
{ "EXISTS",
|
||||
"key",
|
||||
"Determine if a key exists",
|
||||
9,
|
||||
"0.07" },
|
||||
{ "EXPIRE",
|
||||
"key seconds",
|
||||
"Set a key's time to live in seconds",
|
||||
0,
|
||||
"0.09" },
|
||||
{ "EXPIREAT",
|
||||
"key timestamp",
|
||||
"Set the expiration for a key as a UNIX timestamp",
|
||||
0,
|
||||
"1.1" },
|
||||
{ "FLUSHALL",
|
||||
"-",
|
||||
"Remove all keys from all databases",
|
||||
9,
|
||||
"0.07" },
|
||||
{ "FLUSHDB",
|
||||
"-",
|
||||
"Remove all keys from the current database",
|
||||
9,
|
||||
"0.07" },
|
||||
{ "GET",
|
||||
"key",
|
||||
"Get the value of a key",
|
||||
1,
|
||||
"0.07" },
|
||||
{ "GETSET",
|
||||
"key value",
|
||||
"Set the string value of a key and return its old value",
|
||||
1,
|
||||
"0.091" },
|
||||
{ "HDEL",
|
||||
"key field",
|
||||
"Delete a hash field",
|
||||
5,
|
||||
"1.3.10" },
|
||||
{ "HEXISTS",
|
||||
"key field",
|
||||
"Determine if a hash field exists",
|
||||
5,
|
||||
"1.3.10" },
|
||||
{ "HGET",
|
||||
"key field",
|
||||
"Get the value of a hash field",
|
||||
5,
|
||||
"1.3.10" },
|
||||
{ "HGETALL",
|
||||
"key",
|
||||
"Get all the fields and values in a hash",
|
||||
5,
|
||||
"1.3.10" },
|
||||
{ "HINCRBY",
|
||||
"key field increment",
|
||||
"Increment the integer value of a hash field by the given number",
|
||||
5,
|
||||
"1.3.10" },
|
||||
{ "HKEYS",
|
||||
"key",
|
||||
"Get all the fields in a hash",
|
||||
5,
|
||||
"1.3.10" },
|
||||
{ "HLEN",
|
||||
"key",
|
||||
"Get the number of fields in a hash",
|
||||
5,
|
||||
"1.3.10" },
|
||||
{ "HMGET",
|
||||
"key field [field ...]",
|
||||
"Get the values of all the given hash fields",
|
||||
5,
|
||||
"1.3.10" },
|
||||
{ "HMSET",
|
||||
"key field value [field value ...]",
|
||||
"Set multiple hash fields to multiple values",
|
||||
5,
|
||||
"1.3.8" },
|
||||
{ "HSET",
|
||||
"key field value",
|
||||
"Set the string value of a hash field",
|
||||
5,
|
||||
"1.3.10" },
|
||||
{ "HSETNX",
|
||||
"key field value",
|
||||
"Set the value of a hash field, only if the field does not exist",
|
||||
5,
|
||||
"1.3.8" },
|
||||
{ "HVALS",
|
||||
"key",
|
||||
"Get all the values in a hash",
|
||||
5,
|
||||
"1.3.10" },
|
||||
{ "INCR",
|
||||
"key",
|
||||
"Increment the integer value of a key by one",
|
||||
1,
|
||||
"0.07" },
|
||||
{ "INCRBY",
|
||||
"key increment",
|
||||
"Increment the integer value of a key by the given number",
|
||||
1,
|
||||
"0.07" },
|
||||
{ "INFO",
|
||||
"-",
|
||||
"Get information and statistics about the server",
|
||||
9,
|
||||
"0.07" },
|
||||
{ "KEYS",
|
||||
"pattern",
|
||||
"Find all keys matching the given pattern",
|
||||
0,
|
||||
"0.07" },
|
||||
{ "LASTSAVE",
|
||||
"-",
|
||||
"Get the UNIX time stamp of the last successful save to disk",
|
||||
9,
|
||||
"0.07" },
|
||||
{ "LINDEX",
|
||||
"key index",
|
||||
"Get an element from a list by its index",
|
||||
2,
|
||||
"0.07" },
|
||||
{ "LINSERT",
|
||||
"key BEFORE|AFTER pivot value",
|
||||
"Insert an element before or after another element in a list",
|
||||
2,
|
||||
"2.1.1" },
|
||||
{ "LLEN",
|
||||
"key",
|
||||
"Get the length of a list",
|
||||
2,
|
||||
"0.07" },
|
||||
{ "LPOP",
|
||||
"key",
|
||||
"Remove and get the first element in a list",
|
||||
2,
|
||||
"0.07" },
|
||||
{ "LPUSH",
|
||||
"key value",
|
||||
"Prepend a value to a list",
|
||||
2,
|
||||
"0.07" },
|
||||
{ "LPUSHX",
|
||||
"key value",
|
||||
"Prepend a value to a list, only if the list exists",
|
||||
2,
|
||||
"2.1.1" },
|
||||
{ "LRANGE",
|
||||
"key start stop",
|
||||
"Get a range of elements from a list",
|
||||
2,
|
||||
"0.07" },
|
||||
{ "LREM",
|
||||
"key count value",
|
||||
"Remove elements from a list",
|
||||
2,
|
||||
"0.07" },
|
||||
{ "LSET",
|
||||
"key index value",
|
||||
"Set the value of an element in a list by its index",
|
||||
2,
|
||||
"0.07" },
|
||||
{ "LTRIM",
|
||||
"key start stop",
|
||||
"Trim a list to the specified range",
|
||||
2,
|
||||
"0.07" },
|
||||
{ "MGET",
|
||||
"key [key ...]",
|
||||
"Get the values of all the given keys",
|
||||
1,
|
||||
"0.07" },
|
||||
{ "MONITOR",
|
||||
"-",
|
||||
"Listen for all requests received by the server in real time",
|
||||
9,
|
||||
"0.07" },
|
||||
{ "MOVE",
|
||||
"key db",
|
||||
"Move a key to another database",
|
||||
0,
|
||||
"0.07" },
|
||||
{ "MSET",
|
||||
"key value [key value ...]",
|
||||
"Set multiple keys to multiple values",
|
||||
1,
|
||||
"1.001" },
|
||||
{ "MSETNX",
|
||||
"key value [key value ...]",
|
||||
"Set multiple keys to multiple values, only if none of the keys exist",
|
||||
1,
|
||||
"1.001" },
|
||||
{ "MULTI",
|
||||
"-",
|
||||
"Mark the start of a transaction block",
|
||||
7,
|
||||
"1.1.95" },
|
||||
{ "PERSIST",
|
||||
"key",
|
||||
"Remove the expiration from a key",
|
||||
0,
|
||||
"2.1.2" },
|
||||
{ "PING",
|
||||
"-",
|
||||
"Ping the server",
|
||||
8,
|
||||
"0.07" },
|
||||
{ "PSUBSCRIBE",
|
||||
"pattern",
|
||||
"Listen for messages published to channels matching the given patterns",
|
||||
6,
|
||||
"1.3.8" },
|
||||
{ "PUBLISH",
|
||||
"channel message",
|
||||
"Post a message to a channel",
|
||||
6,
|
||||
"1.3.8" },
|
||||
{ "PUNSUBSCRIBE",
|
||||
"[pattern [pattern ...]]",
|
||||
"Stop listening for messages posted to channels matching the given patterns",
|
||||
6,
|
||||
"1.3.8" },
|
||||
{ "QUIT",
|
||||
"-",
|
||||
"Close the connection",
|
||||
8,
|
||||
"0.07" },
|
||||
{ "RANDOMKEY",
|
||||
"-",
|
||||
"Return a random key from the keyspace",
|
||||
0,
|
||||
"0.07" },
|
||||
{ "RENAME",
|
||||
"old new",
|
||||
"Rename a key",
|
||||
0,
|
||||
"0.07" },
|
||||
{ "RENAMENX",
|
||||
"old new",
|
||||
"Rename a key, only if the new key does not exist",
|
||||
0,
|
||||
"0.07" },
|
||||
{ "RPOP",
|
||||
"key",
|
||||
"Remove and get the last element in a list",
|
||||
2,
|
||||
"0.07" },
|
||||
{ "RPOPLPUSH",
|
||||
"source destination",
|
||||
"Remove the last element in a list, append it to another list and return it",
|
||||
2,
|
||||
"1.1" },
|
||||
{ "RPUSH",
|
||||
"key value",
|
||||
"Append a value to a list",
|
||||
2,
|
||||
"0.07" },
|
||||
{ "RPUSHX",
|
||||
"key value",
|
||||
"Append a value to a list, only if the list exists",
|
||||
2,
|
||||
"2.1.1" },
|
||||
{ "SADD",
|
||||
"key member",
|
||||
"Add a member to a set",
|
||||
3,
|
||||
"0.07" },
|
||||
{ "SAVE",
|
||||
"-",
|
||||
"Synchronously save the dataset to disk",
|
||||
9,
|
||||
"0.07" },
|
||||
{ "SCARD",
|
||||
"key",
|
||||
"Get the number of members in a set",
|
||||
3,
|
||||
"0.07" },
|
||||
{ "SDIFF",
|
||||
"key [key ...]",
|
||||
"Subtract multiple sets",
|
||||
3,
|
||||
"0.100" },
|
||||
{ "SDIFFSTORE",
|
||||
"destination key [key ...]",
|
||||
"Subtract multiple sets and store the resulting set in a key",
|
||||
3,
|
||||
"0.100" },
|
||||
{ "SELECT",
|
||||
"index",
|
||||
"Change the selected database for the current connection",
|
||||
8,
|
||||
"0.07" },
|
||||
{ "SET",
|
||||
"key value",
|
||||
"Set the string value of a key",
|
||||
1,
|
||||
"0.07" },
|
||||
{ "SETEX",
|
||||
"key timestamp value",
|
||||
"Set the value and expiration of a key",
|
||||
1,
|
||||
"1.3.10" },
|
||||
{ "SETNX",
|
||||
"key value",
|
||||
"Set the value of a key, only if the key does not exist",
|
||||
1,
|
||||
"0.07" },
|
||||
{ "SHUTDOWN",
|
||||
"-",
|
||||
"Synchronously save the dataset to disk and then shut down the server",
|
||||
9,
|
||||
"0.07" },
|
||||
{ "SINTER",
|
||||
"key [key ...]",
|
||||
"Intersect multiple sets",
|
||||
3,
|
||||
"0.07" },
|
||||
{ "SINTERSTORE",
|
||||
"destination key [key ...]",
|
||||
"Intersect multiple sets and store the resulting set in a key",
|
||||
3,
|
||||
"0.07" },
|
||||
{ "SISMEMBER",
|
||||
"key member",
|
||||
"Determine if a given value is a member of a set",
|
||||
3,
|
||||
"0.07" },
|
||||
{ "SLAVEOF",
|
||||
"host port",
|
||||
"Make the server a slave of another instance, or promote it as master",
|
||||
9,
|
||||
"0.100" },
|
||||
{ "SMEMBERS",
|
||||
"key",
|
||||
"Get all the members in a set",
|
||||
3,
|
||||
"0.07" },
|
||||
{ "SMOVE",
|
||||
"source destination member",
|
||||
"Move a member from one set to another",
|
||||
3,
|
||||
"0.091" },
|
||||
{ "SORT",
|
||||
"key [BY pattern] [LIMIT start count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]",
|
||||
"Sort the elements in a list, set or sorted set",
|
||||
0,
|
||||
"0.07" },
|
||||
{ "SPOP",
|
||||
"key",
|
||||
"Remove and return a random member from a set",
|
||||
3,
|
||||
"0.101" },
|
||||
{ "SRANDMEMBER",
|
||||
"key",
|
||||
"Get a random member from a set",
|
||||
3,
|
||||
"1.001" },
|
||||
{ "SREM",
|
||||
"key member",
|
||||
"Remove a member from a set",
|
||||
3,
|
||||
"0.07" },
|
||||
{ "STRLEN",
|
||||
"key",
|
||||
"Get the length of the value stored in a key",
|
||||
1,
|
||||
"2.1.2" },
|
||||
{ "SUBSCRIBE",
|
||||
"channel",
|
||||
"Listen for messages published to the given channels",
|
||||
6,
|
||||
"1.3.8" },
|
||||
{ "SUBSTR",
|
||||
"key start stop",
|
||||
"Get a substring of the string stored at a key",
|
||||
1,
|
||||
"1.3.4" },
|
||||
{ "SUNION",
|
||||
"key [key ...]",
|
||||
"Add multiple sets",
|
||||
3,
|
||||
"0.091" },
|
||||
{ "SUNIONSTORE",
|
||||
"destination key [key ...]",
|
||||
"Add multiple sets and store the resulting set in a key",
|
||||
3,
|
||||
"0.091" },
|
||||
{ "SYNC",
|
||||
"-",
|
||||
"Internal command used for replication",
|
||||
9,
|
||||
"0.07" },
|
||||
{ "TTL",
|
||||
"key",
|
||||
"Get the time to live for a key",
|
||||
0,
|
||||
"0.100" },
|
||||
{ "TYPE",
|
||||
"key",
|
||||
"Determine the type stored at key",
|
||||
0,
|
||||
"0.07" },
|
||||
{ "UNSUBSCRIBE",
|
||||
"[channel [channel ...]]",
|
||||
"Stop listening for messages posted to the given channels",
|
||||
6,
|
||||
"1.3.8" },
|
||||
{ "UNWATCH",
|
||||
"-",
|
||||
"Forget about all watched keys",
|
||||
7,
|
||||
"2.1.0" },
|
||||
{ "WATCH",
|
||||
"key [key ...]",
|
||||
"Watch the given keys to determine execution of the MULTI/EXEC block",
|
||||
7,
|
||||
"2.1.0" },
|
||||
{ "ZADD",
|
||||
"key score member",
|
||||
"Add a member to a sorted set, or update its score if it already exists",
|
||||
4,
|
||||
"1.1" },
|
||||
{ "ZCARD",
|
||||
"key",
|
||||
"Get the number of members in a sorted set",
|
||||
4,
|
||||
"1.1" },
|
||||
{ "ZCOUNT",
|
||||
"key min max",
|
||||
"Count the members in a sorted set with scores within the given values",
|
||||
4,
|
||||
"1.3.3" },
|
||||
{ "ZINCRBY",
|
||||
"key increment member",
|
||||
"Increment the score of a member in a sorted set",
|
||||
4,
|
||||
"1.1" },
|
||||
{ "ZINTERSTORE",
|
||||
"destination key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]",
|
||||
"Intersect multiple sorted sets and store the resulting sorted set in a new key",
|
||||
4,
|
||||
"1.3.10" },
|
||||
{ "ZRANGE",
|
||||
"key start stop",
|
||||
"Return a range of members in a sorted set, by index",
|
||||
4,
|
||||
"1.1" },
|
||||
{ "ZRANGEBYSCORE",
|
||||
"key min max",
|
||||
"Return a range of members in a sorted set, by score",
|
||||
4,
|
||||
"1.050" },
|
||||
{ "ZRANK",
|
||||
"key member",
|
||||
"Determine the index of a member in a sorted set",
|
||||
4,
|
||||
"1.3.4" },
|
||||
{ "ZREM",
|
||||
"key member",
|
||||
"Remove a member from a sorted set",
|
||||
4,
|
||||
"1.1" },
|
||||
{ "ZREMRANGEBYRANK",
|
||||
"key start stop",
|
||||
"Remove all members in a sorted set within the given indexes",
|
||||
4,
|
||||
"1.3.4" },
|
||||
{ "ZREMRANGEBYSCORE",
|
||||
"key min max",
|
||||
"Remove all members in a sorted set within the given scores",
|
||||
4,
|
||||
"1.1" },
|
||||
{ "ZREVRANGE",
|
||||
"key start stop",
|
||||
"Return a range of members in a sorted set, by index, with scores ordered from high to low",
|
||||
4,
|
||||
"1.1" },
|
||||
{ "ZREVRANK",
|
||||
"key member",
|
||||
"Determine the index of a member in a sorted set, with scores ordered from high to low",
|
||||
4,
|
||||
"1.3.4" },
|
||||
{ "ZSCORE",
|
||||
"key member",
|
||||
"Get the score associated with the given member in a sorted set",
|
||||
4,
|
||||
"1.1" },
|
||||
{ "ZUNIONSTORE",
|
||||
"destination key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]",
|
||||
"Add multiple sorted sets and store the resulting sorted set in a new key",
|
||||
4,
|
||||
"1.3.10" }
|
||||
};
|
||||
|
||||
#endif
|
170
src/redis-cli.c
170
src/redis-cli.c
@ -39,11 +39,13 @@
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "hiredis.h"
|
||||
#include "sds.h"
|
||||
#include "zmalloc.h"
|
||||
#include "linenoise.h"
|
||||
#include "help.h"
|
||||
|
||||
#define REDIS_NOTUSED(V) ((void) V)
|
||||
|
||||
@ -83,6 +85,149 @@ static long long mstime(void) {
|
||||
return mst;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Help functions
|
||||
*--------------------------------------------------------------------------- */
|
||||
|
||||
#define CLI_HELP_COMMAND 1
|
||||
#define CLI_HELP_GROUP 2
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
int argc;
|
||||
sds *argv;
|
||||
sds full;
|
||||
|
||||
/* Only used for help on commands */
|
||||
struct commandHelp *org;
|
||||
} helpEntry;
|
||||
|
||||
static helpEntry *helpEntries;
|
||||
static int helpEntriesLen;
|
||||
|
||||
static void cliInitHelp() {
|
||||
int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp);
|
||||
int groupslen = sizeof(commandGroups)/sizeof(char*);
|
||||
int i, len, pos = 0;
|
||||
helpEntry tmp;
|
||||
|
||||
helpEntriesLen = len = commandslen+groupslen;
|
||||
helpEntries = malloc(sizeof(helpEntry)*len);
|
||||
|
||||
for (i = 0; i < groupslen; i++) {
|
||||
tmp.argc = 1;
|
||||
tmp.argv = malloc(sizeof(sds));
|
||||
tmp.argv[0] = sdscatprintf(sdsempty(),"@%s",commandGroups[i]);
|
||||
tmp.full = tmp.argv[0];
|
||||
tmp.type = CLI_HELP_GROUP;
|
||||
tmp.org = NULL;
|
||||
helpEntries[pos++] = tmp;
|
||||
}
|
||||
|
||||
for (i = 0; i < commandslen; i++) {
|
||||
tmp.argv = sdssplitargs(commandHelp[i].name,&tmp.argc);
|
||||
tmp.full = sdsnew(commandHelp[i].name);
|
||||
tmp.type = CLI_HELP_COMMAND;
|
||||
tmp.org = &commandHelp[i];
|
||||
helpEntries[pos++] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Output command help to stdout. */
|
||||
static void cliOutputCommandHelp(struct commandHelp *help, int group) {
|
||||
printf("\r\n \x1b[1m%s\x1b[0m \x1b[90m%s\x1b[0m\r\n", help->name, help->params);
|
||||
printf(" \x1b[33msummary:\x1b[0m %s\r\n", help->summary);
|
||||
printf(" \x1b[33msince:\x1b[0m %s\r\n", help->since);
|
||||
if (group) {
|
||||
printf(" \x1b[33mgroup:\x1b[0m %s\r\n", commandGroups[help->group]);
|
||||
}
|
||||
}
|
||||
|
||||
/* Print generic help. */
|
||||
static void cliOutputGenericHelp() {
|
||||
printf(
|
||||
"redis-cli %s\r\n"
|
||||
"Type: \"help @<group>\" to get a list of commands in <group>\r\n"
|
||||
" \"help <command>\" for help on <command>\r\n"
|
||||
" \"help <tab>\" to get a list of possible help topics\r\n"
|
||||
" \"quit\" to exit\r\n",
|
||||
REDIS_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
/* Output all command help, filtering by group or command name. */
|
||||
static void cliOutputHelp(int argc, char **argv) {
|
||||
int i, j, len;
|
||||
int group = -1;
|
||||
helpEntry *entry;
|
||||
struct commandHelp *help;
|
||||
|
||||
if (argc == 0) {
|
||||
cliOutputGenericHelp();
|
||||
return;
|
||||
} else if (argc > 0 && argv[0][0] == '@') {
|
||||
len = sizeof(commandGroups)/sizeof(char*);
|
||||
for (i = 0; i < len; i++) {
|
||||
if (strcasecmp(argv[0]+1,commandGroups[i]) == 0) {
|
||||
group = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(argc > 0);
|
||||
for (i = 0; i < helpEntriesLen; i++) {
|
||||
entry = &helpEntries[i];
|
||||
if (entry->type != CLI_HELP_COMMAND) continue;
|
||||
|
||||
help = entry->org;
|
||||
if (group == -1) {
|
||||
/* Compare all arguments */
|
||||
if (argc == entry->argc) {
|
||||
for (j = 0; j < argc; j++) {
|
||||
if (strcasecmp(argv[j],entry->argv[j]) != 0) break;
|
||||
}
|
||||
if (j == argc) {
|
||||
cliOutputCommandHelp(help,1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (group == help->group) {
|
||||
cliOutputCommandHelp(help,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
|
||||
static void completionCallback(const char *buf, linenoiseCompletions *lc) {
|
||||
size_t startpos = 0;
|
||||
int mask;
|
||||
int i;
|
||||
size_t matchlen;
|
||||
sds tmp;
|
||||
|
||||
if (strncasecmp(buf,"help ",5) == 0) {
|
||||
startpos = 5;
|
||||
while (isspace(buf[startpos])) startpos++;
|
||||
mask = CLI_HELP_COMMAND | CLI_HELP_GROUP;
|
||||
} else {
|
||||
mask = CLI_HELP_COMMAND;
|
||||
}
|
||||
|
||||
for (i = 0; i < helpEntriesLen; i++) {
|
||||
if (!(helpEntries[i].type & mask)) continue;
|
||||
|
||||
matchlen = strlen(buf+startpos);
|
||||
if (strncasecmp(buf+startpos,helpEntries[i].full,matchlen) == 0) {
|
||||
tmp = sdsnewlen(buf,startpos);
|
||||
tmp = sdscat(tmp,helpEntries[i].full);
|
||||
linenoiseAddCompletion(lc,tmp);
|
||||
sdsfree(tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------
|
||||
* Networking / parsing
|
||||
*--------------------------------------------------------------------------- */
|
||||
@ -252,22 +397,6 @@ static int cliReadReply() {
|
||||
return REDIS_OK;
|
||||
}
|
||||
|
||||
static void showInteractiveHelp(void) {
|
||||
printf(
|
||||
"\n"
|
||||
"Welcome to redis-cli " REDIS_VERSION "!\n"
|
||||
"Just type any valid Redis command to see a pretty printed output.\n"
|
||||
"\n"
|
||||
"It is possible to quote strings, like in:\n"
|
||||
" set \"my key\" \"some string \\xff\\n\"\n"
|
||||
"\n"
|
||||
"You can find a list of valid Redis commands at\n"
|
||||
" http://code.google.com/p/redis/wiki/CommandReference\n"
|
||||
"\n"
|
||||
"Note: redis-cli supports line editing, use up/down arrows for history."
|
||||
"\n\n");
|
||||
}
|
||||
|
||||
static int cliSendCommand(int argc, char **argv, int repeat) {
|
||||
char *command = argv[0];
|
||||
size_t *argvlen;
|
||||
@ -279,8 +408,8 @@ static int cliSendCommand(int argc, char **argv, int repeat) {
|
||||
}
|
||||
|
||||
config.raw_output = !strcasecmp(command,"info");
|
||||
if (!strcasecmp(command,"help")) {
|
||||
showInteractiveHelp();
|
||||
if (!strcasecmp(command,"help") || !strcasecmp(command,"?")) {
|
||||
cliOutputHelp(--argc, ++argv);
|
||||
return REDIS_OK;
|
||||
}
|
||||
if (!strcasecmp(command,"shutdown")) config.shutdown = 1;
|
||||
@ -412,6 +541,8 @@ static void repl() {
|
||||
sds *argv;
|
||||
|
||||
config.interactive = 1;
|
||||
linenoiseSetCompletionCallback(completionCallback);
|
||||
|
||||
while((line = linenoise(context ? "redis> " : "not connected> ")) != NULL) {
|
||||
if (line[0] != '\0') {
|
||||
argv = sdssplitargs(line,&argc);
|
||||
@ -430,6 +561,8 @@ static void repl() {
|
||||
config.hostip = sdsnew(argv[1]);
|
||||
config.hostport = atoi(argv[2]);
|
||||
cliConnect(1);
|
||||
} else if (argc == 1 && !strcasecmp(argv[0],"clear")) {
|
||||
linenoiseClearScreen();
|
||||
} else {
|
||||
long long start_time = mstime(), elapsed;
|
||||
|
||||
@ -489,6 +622,7 @@ int main(int argc, char **argv) {
|
||||
config.historyfile = NULL;
|
||||
config.tty = isatty(fileno(stdout)) || (getenv("FAKETTY") != NULL);
|
||||
config.mb_sep = '\n';
|
||||
cliInitHelp();
|
||||
|
||||
if (getenv("HOME") != NULL) {
|
||||
config.historyfile = malloc(256);
|
||||
|
111
utils/generate-command-help.rb
Executable file
111
utils/generate-command-help.rb
Executable file
@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
GROUPS = [
|
||||
"generic",
|
||||
"string",
|
||||
"list",
|
||||
"set",
|
||||
"sorted_set",
|
||||
"hash",
|
||||
"pubsub",
|
||||
"transactions",
|
||||
"connection",
|
||||
"server"
|
||||
].freeze
|
||||
|
||||
GROUPS_BY_NAME = Hash[*
|
||||
GROUPS.each_with_index.map do |n,i|
|
||||
[n,i]
|
||||
end.flatten
|
||||
].freeze
|
||||
|
||||
def argument arg
|
||||
name = arg["name"].is_a?(Array) ? arg["name"].join(" ") : arg["name"]
|
||||
name = arg["enum"].join "|" if "enum" == arg["type"]
|
||||
name = arg["command"] + " " + name if arg["command"]
|
||||
if arg["multiple"]
|
||||
name = "#{name} [#{name} ...]"
|
||||
end
|
||||
if arg["optional"]
|
||||
name = "[#{name}]"
|
||||
end
|
||||
name
|
||||
end
|
||||
|
||||
def arguments command
|
||||
return "-" unless command["arguments"]
|
||||
command["arguments"].map do |arg|
|
||||
argument arg
|
||||
end.join " "
|
||||
end
|
||||
|
||||
def commands
|
||||
return @commands if @commands
|
||||
|
||||
require "net/http"
|
||||
require "net/https"
|
||||
require "json"
|
||||
require "uri"
|
||||
|
||||
url = URI.parse "https://github.com/antirez/redis-doc/raw/master/commands.json"
|
||||
client = Net::HTTP.new url.host, url.port
|
||||
client.use_ssl = true
|
||||
response = client.get url.path
|
||||
if response.is_a?(Net::HTTPSuccess)
|
||||
@commands = JSON.parse(response.body)
|
||||
else
|
||||
response.error!
|
||||
end
|
||||
end
|
||||
|
||||
def generate_groups
|
||||
GROUPS.map do |n|
|
||||
"\"#{n}\""
|
||||
end.join(",\n ");
|
||||
end
|
||||
|
||||
def generate_commands
|
||||
commands.to_a.sort do |x,y|
|
||||
x[0] <=> y[0]
|
||||
end.map do |key, command|
|
||||
group = GROUPS_BY_NAME[command["group"]]
|
||||
if group.nil?
|
||||
STDERR.puts "Please update groups array in #{__FILE__}"
|
||||
raise "Unknown group #{command["group"]}"
|
||||
end
|
||||
|
||||
ret = <<-SPEC
|
||||
{ "#{key}",
|
||||
"#{arguments(command)}",
|
||||
"#{command["summary"]}",
|
||||
#{group},
|
||||
"#{command["since"]}" }
|
||||
SPEC
|
||||
ret.strip
|
||||
end.join(",\n ")
|
||||
end
|
||||
|
||||
# Write to stdout
|
||||
puts <<-HELP_H
|
||||
/* Automatically generated by #{__FILE__}, do not edit. */
|
||||
|
||||
#ifndef __REDIS_HELP_H
|
||||
#define __REDIS_HELP_H
|
||||
|
||||
static char *commandGroups[] = {
|
||||
#{generate_groups}
|
||||
};
|
||||
|
||||
struct commandHelp {
|
||||
char *name;
|
||||
char *params;
|
||||
char *summary;
|
||||
int group;
|
||||
char *since;
|
||||
} commandHelp[] = {
|
||||
#{generate_commands}
|
||||
};
|
||||
|
||||
#endif
|
||||
HELP_H
|
||||
|
Loading…
Reference in New Issue
Block a user