Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL
4 : * Purpose: gdal "vsi sync" subcommand
5 : * Author: Even Rouault <even dot rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2025, Even Rouault <even dot rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "gdalalg_vsi_sync.h"
14 :
15 : #include "cpl_string.h"
16 : #include "cpl_vsi.h"
17 : #include "cpl_vsi_error.h"
18 :
19 : //! @cond Doxygen_Suppress
20 :
21 : #ifndef _
22 : #define _(x) (x)
23 : #endif
24 :
25 : /************************************************************************/
26 : /* GDALVSISyncAlgorithm::GDALVSISyncAlgorithm() */
27 : /************************************************************************/
28 :
29 5 : GDALVSISyncAlgorithm::GDALVSISyncAlgorithm()
30 5 : : GDALAlgorithm(NAME, DESCRIPTION, HELP_URL)
31 : {
32 5 : AddProgressArg();
33 : {
34 : auto &arg =
35 10 : AddArg("source", 0, _("Source file or directory name"), &m_source)
36 5 : .SetPositional()
37 5 : .SetMinCharCount(1)
38 5 : .SetRequired();
39 5 : SetAutoCompleteFunctionForFilename(arg, 0);
40 : }
41 : {
42 : auto &arg =
43 : AddArg("destination", 0, _("Destination file or directory name"),
44 10 : &m_destination)
45 5 : .SetPositional()
46 5 : .SetMinCharCount(1)
47 5 : .SetRequired();
48 5 : SetAutoCompleteFunctionForFilename(arg, 0);
49 : }
50 :
51 5 : AddArg("recursive", 'r', _("Synchronize recursively"), &m_recursive);
52 :
53 10 : AddArg("strategy", 0, _("Synchronization strategy"), &m_strategy)
54 5 : .SetDefault(m_strategy)
55 5 : .SetChoices("timestamp", "ETag", "overwrite");
56 :
57 5 : AddNumThreadsArg(&m_numThreads, &m_numThreadsStr);
58 5 : }
59 :
60 : /************************************************************************/
61 : /* GDALVSISyncAlgorithm::RunImpl() */
62 : /************************************************************************/
63 :
64 4 : bool GDALVSISyncAlgorithm::RunImpl(GDALProgressFunc pfnProgress,
65 : void *pProgressData)
66 : {
67 8 : CPLStringList aosOptions;
68 4 : aosOptions.SetNameValue("RECURSIVE", m_recursive ? "YES" : "NO");
69 4 : aosOptions.SetNameValue("STRATEGY", m_strategy.c_str());
70 4 : aosOptions.SetNameValue("NUM_THREADS", CPLSPrintf("%d", m_numThreads));
71 :
72 4 : if (!VSISync(m_source.c_str(), m_destination.c_str(), aosOptions.List(),
73 : pfnProgress, pProgressData, nullptr))
74 : {
75 : VSIStatBufL sStat;
76 3 : VSIErrorReset();
77 3 : const auto nOldErrorNum = VSIGetLastErrorNo();
78 3 : if (VSIStatL(m_source.c_str(), &sStat) != 0)
79 : {
80 2 : if (nOldErrorNum != VSIGetLastErrorNo())
81 : {
82 1 : ReportError(CE_Failure, CPLE_FileIO,
83 : "'%s' cannot be accessed. %s: %s", m_source.c_str(),
84 : VSIErrorNumToString(VSIGetLastErrorNo()),
85 : VSIGetLastErrorMsg());
86 : }
87 : else
88 : {
89 1 : ReportError(CE_Failure, CPLE_FileIO,
90 : "'%s' does not exist or cannot be accessed",
91 : m_source.c_str());
92 : }
93 : }
94 : else
95 : {
96 1 : ReportError(CE_Failure, CPLE_FileIO,
97 : "%s could not be synchronised with %s",
98 : m_source.c_str(), m_destination.c_str());
99 : }
100 3 : return false;
101 : }
102 1 : return true;
103 : }
104 :
105 : //! @endcond
|