mirror of
https://github.com/libvirt/libvirt.git
synced 2026-10-02 12:20:06 -05:00
Add a completer callback for local file paths used as command output, where the target file may not exist yet. Use it for 'dump', 'save', and 'blockcopy' commands, and fix 'screenshot' to use it instead of vshCompletePathLocalExisting. Partially-fixes: https://gitlab.com/libvirt/libvirt/-/work_items/9 Signed-off-by: Radoslaw Smigielski <rsmigiel@redhat.com> Reviewed-by: Peter Krempa <pkrempa@redhat.com>
208 lines
5.8 KiB
C
208 lines
5.8 KiB
C
/*
|
|
* vsh-completer.c: virsh completer callbacks
|
|
*
|
|
* Copyright (C) 2017 Red Hat, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include "vsh-completer.h"
|
|
|
|
/**
|
|
* A completer callback is a function that accepts three arguments:
|
|
*
|
|
* @ctl: virsh control structure
|
|
* @cmd: parsed input
|
|
* @flags: optional flags to alter completer's behaviour
|
|
*
|
|
* The @ctl contains connection to the daemon (should the
|
|
* completer need it). Any completer that requires a connection
|
|
* must check whether connection is still alive.
|
|
*
|
|
* The @cmd contains parsed user input which might be missing
|
|
* some arguments (if user is still typing the command), but may
|
|
* already contain important data. For instance if the completer
|
|
* needs domain XML it may inspect @cmd to find --domain. Using
|
|
* existing wrappers is advised. If @cmd does not contain all
|
|
* necessary bits, completer might return sensible defaults (i.e.
|
|
* generic values not tailored to specific use case) or return
|
|
* NULL (i.e. no strings are offered to the user for completion).
|
|
*
|
|
* The @flags contains a .completer_flags value defined for each
|
|
* use or 0 if no .completer_flags were specified. If a completer
|
|
* is generic enough @flags can be used to alter its behaviour.
|
|
* For instance, a completer to fetch names of domains can use
|
|
* @flags to return names of only domains in a particular state
|
|
* that the command accepts.
|
|
*
|
|
* Under no circumstances should a completer output anything.
|
|
* Neither to stdout nor to stderr. This would harm the user
|
|
* experience.
|
|
*/
|
|
|
|
|
|
/**
|
|
* vshEnumComplete:
|
|
* @last: The number of element in enum (pass VIR_XXX_LAST)
|
|
* @intToStr: integer to string conversion (pass virXXXTypeToString)
|
|
*
|
|
* Convenient function to generate completions across all values
|
|
* of given enum. The enum, or values we want to generate, must
|
|
* start at 0 and be continuous until @last.
|
|
*
|
|
* Returns: string list of completions.
|
|
*/
|
|
char **
|
|
vshEnumComplete(unsigned int last,
|
|
const char *(*intToStr)(int))
|
|
{
|
|
char **ret = NULL;
|
|
size_t i;
|
|
|
|
ret = g_new0(char *, last + 1);
|
|
|
|
for (i = 0; i < last; i++)
|
|
ret[i] = g_strdup(intToStr(i));
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* vshCommaStringListComplete:
|
|
* @input: user input so far
|
|
* @options: ALL options available for argument
|
|
*
|
|
* Some arguments to our commands accept the following form:
|
|
*
|
|
* virsh command --arg str1,str2,str3
|
|
*
|
|
* This does not play nicely with our completer functions, because
|
|
* they have to return strings prepended with user's input. For
|
|
* instance:
|
|
*
|
|
* str1,str2,str3,strA
|
|
* str1,str2,str3,strB
|
|
* str1,str2,str3,strC
|
|
*
|
|
* This helper function takes care of that. In this specific case
|
|
* it would be called as follows:
|
|
*
|
|
* vshCommaStringListComplete("str1,str2,str3",
|
|
* {"strA", "strB", "strC", NULL});
|
|
*
|
|
* Returns: string list of completions on success,
|
|
* NULL otherwise.
|
|
*/
|
|
char **
|
|
vshCommaStringListComplete(const char *input,
|
|
const char **options)
|
|
{
|
|
const size_t optionsLen = g_strv_length((char **) options);
|
|
g_autofree char *inputCopy = NULL;
|
|
g_auto(GStrv) inputList = NULL;
|
|
g_auto(GStrv) ret = NULL;
|
|
size_t nret = 0;
|
|
size_t i;
|
|
|
|
if (STREQ_NULLABLE(input, " "))
|
|
input = NULL;
|
|
|
|
if (input) {
|
|
char *comma = NULL;
|
|
|
|
inputCopy = g_strdup(input);
|
|
|
|
if ((comma = strrchr(inputCopy, ',')))
|
|
*comma = '\0';
|
|
else
|
|
g_clear_pointer(&inputCopy, g_free);
|
|
}
|
|
|
|
if (inputCopy && !(inputList = g_strsplit(inputCopy, ",", 0)))
|
|
return NULL;
|
|
|
|
ret = g_new0(char *, optionsLen + 1);
|
|
|
|
for (i = 0; i < optionsLen; i++) {
|
|
if (inputList &&
|
|
g_strv_contains((const char **)inputList, options[i]))
|
|
continue;
|
|
|
|
if (inputCopy)
|
|
ret[nret] = g_strdup_printf("%s,%s", inputCopy, options[i]);
|
|
else
|
|
ret[nret] = g_strdup(options[i]);
|
|
|
|
nret++;
|
|
}
|
|
|
|
return g_steal_pointer(&ret);
|
|
}
|
|
|
|
|
|
/**
|
|
* vshCompletePathLocalExisting:
|
|
*
|
|
* Complete a path to a existing file used as input. The file is used as input
|
|
* for virsh so only local files are considered.
|
|
*
|
|
* Note: For now this is a no-op. Readline does the correct thing.
|
|
*/
|
|
char **
|
|
vshCompletePathLocalExisting(vshControl *ctl G_GNUC_UNUSED,
|
|
const vshCmd *cmd G_GNUC_UNUSED,
|
|
unsigned int completerflags G_GNUC_UNUSED)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* vshCompletePathLocalCreate:
|
|
*
|
|
* Complete a path to local file used as output.
|
|
* The outout file may not exist yet.
|
|
*
|
|
* Note: For now this is a no-op.
|
|
*/
|
|
char **
|
|
vshCompletePathLocalCreate(vshControl *ctl G_GNUC_UNUSED,
|
|
const vshCmd *cmd G_GNUC_UNUSED,
|
|
unsigned int completerflags G_GNUC_UNUSED)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* vshCompleteEmpty:
|
|
*
|
|
* Complete nothing. For cases where an user input is required and we can't
|
|
* suggest anything.
|
|
*
|
|
* TODO: This is currently just an annotation, readline still completes local
|
|
* file list.
|
|
*/
|
|
char **
|
|
vshCompleteEmpty(vshControl *ctl G_GNUC_UNUSED,
|
|
const vshCmd *cmd G_GNUC_UNUSED,
|
|
unsigned int completerflags G_GNUC_UNUSED)
|
|
{
|
|
return NULL;
|
|
}
|