mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-01-18 04:58:51 +02:00
Improve behavior of the repo-ls command.
* Exclude linefeed when there is no output to avoid a blank line. * Honor filter when adding . path or listing a single file.
This commit is contained in:
parent
237ba54d20
commit
6fe60a2428
@ -41,6 +41,15 @@
|
||||
|
||||
<p>Fix expression when recursion enabled in <code>storageInfoListP()</code>.</p>
|
||||
</release-item>
|
||||
|
||||
<release-item>
|
||||
<release-item-contributor-list>
|
||||
<release-item-reviewer id="stefan.fercot"/>
|
||||
<release-item-reviewer id="cynthia.shang"/>
|
||||
</release-item-contributor-list>
|
||||
|
||||
<p>Improve behavior of the <cmd>repo-ls</cmd> command.</p>
|
||||
</release-item>
|
||||
</release-development-list>
|
||||
</release-core-list>
|
||||
|
||||
|
@ -9,6 +9,7 @@ Repository List Command
|
||||
#include "common/io/handleWrite.h"
|
||||
#include "common/log.h"
|
||||
#include "common/memContext.h"
|
||||
#include "common/regExp.h"
|
||||
#include "common/type/json.h"
|
||||
#include "common/type/string.h"
|
||||
#include "config/config.h"
|
||||
@ -45,13 +46,8 @@ storageListRenderCallback(void *data, const StorageInfo *info)
|
||||
}
|
||||
|
||||
// Add seperator character
|
||||
if (!listData->first)
|
||||
{
|
||||
if (listData->json)
|
||||
ioWrite(listData->write, COMMA_BUF);
|
||||
else
|
||||
ioWrite(listData->write, LF_BUF);
|
||||
}
|
||||
if (!listData->first && listData->json)
|
||||
ioWrite(listData->write, COMMA_BUF);
|
||||
else
|
||||
listData->first = false;
|
||||
|
||||
@ -103,6 +99,7 @@ storageListRenderCallback(void *data, const StorageInfo *info)
|
||||
else
|
||||
{
|
||||
ioWrite(listData->write, BUFSTR(info->name));
|
||||
ioWrite(listData->write, LF_BUF);
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN_VOID();
|
||||
@ -134,8 +131,10 @@ storageListRender(IoWrite *write)
|
||||
else if (strLstSize(cfgCommandParam()) > 1)
|
||||
THROW(ParamInvalidError, "only one path may be specified");
|
||||
|
||||
// Get output
|
||||
// Get options
|
||||
bool json = strEqZ(cfgOptionStr(cfgOptOutput), "json") ? true : false;
|
||||
const String *expression = cfgOptionStrNull(cfgOptFilter);
|
||||
RegExp *regExp = expression == NULL ? NULL : regExpNew(expression);
|
||||
|
||||
// Render the info list
|
||||
StorageListRenderCallbackData data =
|
||||
@ -155,24 +154,30 @@ storageListRender(IoWrite *write)
|
||||
|
||||
if (info.exists && info.type == storageTypeFile)
|
||||
{
|
||||
info.name = DOT_STR;
|
||||
storageListRenderCallback(&data, &info);
|
||||
if (regExp == NULL || regExpMatch(regExp, storagePathP(storageRepo(), path)))
|
||||
{
|
||||
info.name = DOT_STR;
|
||||
storageListRenderCallback(&data, &info);
|
||||
}
|
||||
}
|
||||
// Else try to list the path
|
||||
else
|
||||
{
|
||||
// The path will always be reported as existing so we don't get different results from storage that does not support paths
|
||||
if (data.json)
|
||||
if (data.json && (regExp == NULL || regExpMatch(regExp, DOT_STR)))
|
||||
storageListRenderCallback(&data, &(StorageInfo){.type = storageTypePath, .name = DOT_STR});
|
||||
|
||||
// List content of the path
|
||||
storageInfoListP(
|
||||
storageRepo(), path, storageListRenderCallback, &data, .sortOrder = sortOrder,
|
||||
.expression = cfgOptionStrNull(cfgOptFilter), .recurse = cfgOptionBool(cfgOptRecurse));
|
||||
storageRepo(), path, storageListRenderCallback, &data, .sortOrder = sortOrder, .expression = expression,
|
||||
.recurse = cfgOptionBool(cfgOptRecurse));
|
||||
}
|
||||
|
||||
if (data.json)
|
||||
{
|
||||
ioWrite(data.write, BRACER_BUF);
|
||||
ioWrite(data.write, LF_BUF);
|
||||
}
|
||||
|
||||
ioWriteClose(data.write);
|
||||
|
||||
@ -190,7 +195,6 @@ cmdStorageList(void)
|
||||
TRY_BEGIN()
|
||||
{
|
||||
storageListRender(ioHandleWriteNew(STRDEF("stdout"), STDOUT_FILENO));
|
||||
ioHandleWriteOneStr(STDOUT_FILENO, LF_STR);
|
||||
}
|
||||
// Ignore write errors because it's possible (even likely) that this output is being piped to something like head which
|
||||
// will exit when it gets what it needs and leave us writing to a broken pipe. It would be better to just ignore the broken
|
||||
|
@ -54,7 +54,7 @@ testRun(void)
|
||||
strNewBuf(output),
|
||||
"{"
|
||||
"\".\":{\"type\":\"path\"}"
|
||||
"}",
|
||||
"}\n",
|
||||
" check output");
|
||||
|
||||
// Empty directory
|
||||
@ -73,9 +73,26 @@ testRun(void)
|
||||
strNewBuf(output),
|
||||
"{"
|
||||
"\".\":{\"type\":\"path\"}"
|
||||
"}",
|
||||
"}\n",
|
||||
" check output");
|
||||
|
||||
output = bufNew(0);
|
||||
cfgOptionSet(cfgOptFilter, cfgSourceParam, VARSTRDEF("\\."));
|
||||
TEST_RESULT_VOID(storageListRender(ioBufferWriteNew(output)), "empty directory with filter match (json)");
|
||||
TEST_RESULT_STR_Z(
|
||||
strNewBuf(output),
|
||||
"{"
|
||||
"\".\":{\"type\":\"path\"}"
|
||||
"}\n",
|
||||
" check output");
|
||||
|
||||
output = bufNew(0);
|
||||
cfgOptionSet(cfgOptFilter, cfgSourceParam, VARSTRDEF("2$"));
|
||||
TEST_RESULT_VOID(storageListRender(ioBufferWriteNew(output)), "empty directory with no filter match (json)");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "{}\n", " check output");
|
||||
|
||||
cfgOptionSet(cfgOptFilter, cfgSourceParam, NULL);
|
||||
|
||||
// Add path and file
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
cfgOptionSet(cfgOptSort, cfgSourceParam, VARSTRDEF("asc"));
|
||||
@ -90,7 +107,7 @@ testRun(void)
|
||||
output = bufNew(0);
|
||||
cfgOptionSet(cfgOptOutput, cfgSourceParam, VARSTRDEF("text"));
|
||||
TEST_RESULT_VOID(storageListRender(ioBufferWriteNew(output)), "path and file (text)");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "aaa\nbbb\nlink\npipe", " check output");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "aaa\nbbb\nlink\npipe\n", " check output");
|
||||
|
||||
output = bufNew(0);
|
||||
cfgOptionSet(cfgOptOutput, cfgSourceParam, VARSTRDEF("json"));
|
||||
@ -103,7 +120,7 @@ testRun(void)
|
||||
"\"bbb\":{\"type\":\"path\"},"
|
||||
"\"link\":{\"type\":\"link\",\"destination\":\"../bbb\"},"
|
||||
"\"pipe\":{\"type\":\"special\"}"
|
||||
"}",
|
||||
"}\n",
|
||||
" check output");
|
||||
|
||||
// Reverse sort
|
||||
@ -113,7 +130,7 @@ testRun(void)
|
||||
output = bufNew(0);
|
||||
cfgOptionSet(cfgOptOutput, cfgSourceParam, VARSTRDEF("text"));
|
||||
TEST_RESULT_VOID(storageListRender(ioBufferWriteNew(output)), "path and file (text)");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "pipe\nlink\nbbb\naaa", " check output");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "pipe\nlink\nbbb\naaa\n", " check output");
|
||||
|
||||
// Recurse
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@ -123,7 +140,7 @@ testRun(void)
|
||||
output = bufNew(0);
|
||||
cfgOptionSet(cfgOptOutput, cfgSourceParam, VARSTRDEF("text"));
|
||||
TEST_RESULT_VOID(storageListRender(ioBufferWriteNew(output)), "filter");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "pipe\nlink\nbbb/ccc\nbbb\naaa", " check output");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "pipe\nlink\nbbb/ccc\nbbb\naaa\n", " check output");
|
||||
|
||||
// Filter
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@ -133,7 +150,7 @@ testRun(void)
|
||||
output = bufNew(0);
|
||||
cfgOptionSet(cfgOptOutput, cfgSourceParam, VARSTRDEF("text"));
|
||||
TEST_RESULT_VOID(storageListRender(ioBufferWriteNew(output)), "filter");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "aaa", " check output");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "aaa\n", " check output");
|
||||
|
||||
// Subdirectory
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
@ -144,7 +161,7 @@ testRun(void)
|
||||
output = bufNew(0);
|
||||
cfgOptionSet(cfgOptOutput, cfgSourceParam, VARSTRDEF("text"));
|
||||
TEST_RESULT_VOID(storageListRender(ioBufferWriteNew(output)), "subdirectory");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "ccc", " check output");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "ccc\n", " check output");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
// Redirect stdout to a file
|
||||
@ -166,7 +183,6 @@ testRun(void)
|
||||
strLstAddZ(argListTmp, "ccc");
|
||||
harnessCfgLoad(cfgCmdRepoLs, argListTmp);
|
||||
|
||||
output = bufNew(0);
|
||||
TEST_ERROR(storageListRender(ioBufferWriteNew(output)), ParamInvalidError, "only one path may be specified");
|
||||
|
||||
// File
|
||||
@ -176,13 +192,29 @@ testRun(void)
|
||||
strLstAddZ(argList, "--output=json");
|
||||
harnessCfgLoad(cfgCmdRepoLs, argList);
|
||||
|
||||
output = bufNew(0);
|
||||
TEST_RESULT_VOID(storageListRender(ioBufferWriteNew(output)), "file (json)");
|
||||
TEST_RESULT_STR_Z(
|
||||
strNewBuf(output),
|
||||
"{"
|
||||
"\".\":{\"type\":\"file\",\"size\":8,\"time\":1578671569}"
|
||||
"}",
|
||||
"}\n",
|
||||
" check output");
|
||||
|
||||
output = bufNew(0);
|
||||
cfgOptionSet(cfgOptFilter, cfgSourceParam, VARSTRDEF("\\/aaa$"));
|
||||
TEST_RESULT_VOID(storageListRender(ioBufferWriteNew(output)), "file (json)");
|
||||
TEST_RESULT_STR_Z(
|
||||
strNewBuf(output),
|
||||
"{"
|
||||
"\".\":{\"type\":\"file\",\"size\":8,\"time\":1578671569}"
|
||||
"}\n",
|
||||
" check output");
|
||||
|
||||
output = bufNew(0);
|
||||
cfgOptionSet(cfgOptFilter, cfgSourceParam, VARSTRDEF("bbb$"));
|
||||
TEST_RESULT_VOID(storageListRender(ioBufferWriteNew(output)), "file (json)");
|
||||
TEST_RESULT_STR_Z(strNewBuf(output), "{}\n", " check output");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
|
Loading…
x
Reference in New Issue
Block a user