1
0
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:
David Steele 2020-06-11 13:17:35 -04:00 committed by GitHub
parent 237ba54d20
commit 6fe60a2428
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 24 deletions

View File

@ -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>

View File

@ -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

View File

@ -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");
}
// *****************************************************************************************************************************