GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/publish/cmd_diff.cc
Date: 2024-04-28 02:33:07
Exec Total Coverage
Lines: 0 122 0.0%
Branches: 0 404 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5 #include "cvmfs_config.h"
6 #include "cmd_diff.h"
7
8 #ifndef __STDC_FORMAT_MACROS
9 #define __STDC_FORMAT_MACROS
10 #endif
11
12 #include <inttypes.h>
13
14 #include <cassert>
15 #include <string>
16 #include <vector>
17
18 #include "catalog_counters.h"
19 #include "directory_entry.h"
20 #include "history.h"
21 #include "publish/except.h"
22 #include "publish/repository.h"
23 #include "publish/settings.h"
24 #include "sanitizer.h"
25 #include "util/logging.h"
26 #include "util/pointer.h"
27 #include "util/string.h"
28
29 namespace {
30
31 class DiffReporter : public publish::DiffListener {
32 public:
33 DiffReporter(bool show_header, bool machine_readable, bool ignore_timediff)
34 : show_header_(show_header)
35 , machine_readable_(machine_readable)
36 , ignore_timediff_(ignore_timediff)
37 {}
38 virtual ~DiffReporter() {}
39
40
41 virtual void OnInit(const history::History::Tag &from_tag,
42 const history::History::Tag &to_tag)
43 {
44 if (!show_header_)
45 return;
46
47 if (machine_readable_) {
48 LogCvmfs(kLogCvmfs, kLogStdout,
49 "# line descriptor: A - add, R - remove, M - modify, "
50 "S - statistics; modify flags: S - size, M - mode, T - timestamp, "
51 "C - content, L - symlink target; entry types: F - regular file, "
52 "S - symbolic link, D - directory, N - nested catalog");
53 } else {
54 LogCvmfs(kLogCvmfs, kLogStdout,
55 "DELTA: %s/r%" PRIu64 " (%s) --> %s/r%" PRIu64 " (%s)",
56 from_tag.name.c_str(), from_tag.revision,
57 StringifyTime(from_tag.timestamp, true).c_str(),
58 to_tag.name.c_str(), to_tag.revision,
59 StringifyTime(to_tag.timestamp, true).c_str());
60 }
61 }
62
63
64 virtual void OnStats(const catalog::DeltaCounters &delta) {
65 std::string operation = machine_readable_ ? "S " : "d(";
66 std::string type_file = machine_readable_ ? "F" : "# regular files):";
67 std::string type_symlink = machine_readable_ ? "S" : "# symlinks):";
68 std::string type_directory = machine_readable_ ? "D" : "# directories):";
69 std::string type_catalog = machine_readable_ ? "N" : "# catalogs):";
70 int64_t diff_file = delta.self.regular_files + delta.subtree.regular_files;
71 int64_t diff_symlink = delta.self.symlinks + delta.subtree.symlinks;
72 int64_t diff_catalog = delta.self.nested_catalogs +
73 delta.subtree.nested_catalogs;
74 // Nested catalogs make internally two directory entries
75 int64_t diff_directory = delta.self.directories +
76 delta.subtree.directories - diff_catalog;
77 LogCvmfs(kLogCvmfs, kLogStdout, "%s%s %" PRId64, operation.c_str(),
78 type_file.c_str(), diff_file);
79 LogCvmfs(kLogCvmfs, kLogStdout, "%s%s %" PRId64, operation.c_str(),
80 type_symlink.c_str(), diff_symlink);
81 LogCvmfs(kLogCvmfs, kLogStdout, "%s%s %" PRId64, operation.c_str(),
82 type_directory.c_str(), diff_directory);
83 LogCvmfs(kLogCvmfs, kLogStdout, "%s%s %" PRId64, operation.c_str(),
84 type_catalog.c_str(), diff_catalog);
85 }
86
87
88 virtual void OnAdd(const std::string &path,
89 const catalog::DirectoryEntry &entry)
90 {
91 std::string operation = machine_readable_ ? "A" : "add";
92 if (machine_readable_) {
93 LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak, "%s %s %s",
94 operation.c_str(), PrintEntryType(entry).c_str(), path.c_str());
95 if (!entry.IsDirectory()) {
96 LogCvmfs(kLogCvmfs, kLogStdout, " +%" PRIu64, entry.size());
97 } else {
98 LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak, "\n");
99 }
100 } else {
101 LogCvmfs(kLogCvmfs, kLogStdout, "%s %s %s +%" PRIu64 " bytes",
102 path.c_str(), operation.c_str(),
103 PrintEntryType(entry).c_str(), entry.size());
104 }
105 }
106
107
108 virtual void OnRemove(const std::string &path,
109 const catalog::DirectoryEntry &entry)
110 {
111 std::string operation = machine_readable_ ? "R" : "remove";
112 if (machine_readable_) {
113 LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak, "%s %s %s",
114 operation.c_str(), PrintEntryType(entry).c_str(), path.c_str());
115 if (!entry.IsDirectory()) {
116 LogCvmfs(kLogCvmfs, kLogStdout, " -%" PRIu64, entry.size());
117 } else {
118 LogCvmfs(kLogCvmfs, kLogStdout, "");
119 }
120 } else {
121 LogCvmfs(kLogCvmfs, kLogStdout, "%s %s %s -%" PRIu64 " bytes",
122 path.c_str(), operation.c_str(),
123 PrintEntryType(entry).c_str(), entry.size());
124 }
125 }
126
127
128 virtual void OnModify(const std::string &path,
129 const catalog::DirectoryEntry &entry_from,
130 const catalog::DirectoryEntry &entry_to)
131 {
132 catalog::DirectoryEntryBase::Differences diff =
133 entry_from.CompareTo(entry_to);
134 if (ignore_timediff_) {
135 diff = diff & ~catalog::DirectoryEntryBase::Difference::kMtime;
136 if (diff == 0)
137 return;
138 }
139 if (entry_from.IsDirectory() || entry_to.IsDirectory()) {
140 diff = diff & ~catalog::DirectoryEntryBase::Difference::kSize;
141 if (diff == 0)
142 return;
143 }
144
145 std::string type_from = PrintEntryType(entry_from);
146 std::string type_to = PrintEntryType(entry_to);
147 std::string type = type_from;
148 if (type_from != type_to) {
149 type += machine_readable_ ? type_to : ("->" + type_to);
150 }
151
152 std::string operation = machine_readable_ ? "M" : "modify";
153 if (machine_readable_) {
154 LogCvmfs(kLogCvmfs, kLogStdout, "%s%s %s %s", operation.c_str(),
155 PrintDifferences(diff).c_str(), type.c_str(), path.c_str());
156 } else {
157 LogCvmfs(kLogCvmfs, kLogStdout, "%s %s %s%s", path.c_str(),
158 operation.c_str(), type.c_str(), PrintDifferences(diff).c_str());
159 }
160 }
161
162 private:
163 std::string PrintDifferences(catalog::DirectoryEntryBase::Differences diff) {
164 std::vector<std::string> result_list;
165 if (diff & catalog::DirectoryEntryBase::Difference::kName)
166 result_list.push_back(machine_readable_ ? "N" : "name");
167 if (diff & catalog::DirectoryEntryBase::Difference::kLinkcount)
168 result_list.push_back(machine_readable_ ? "I" : "link-count");
169 if (diff & catalog::DirectoryEntryBase::Difference::kSize)
170 result_list.push_back(machine_readable_ ? "S" : "size");
171 if (diff & catalog::DirectoryEntryBase::Difference::kMode)
172 result_list.push_back(machine_readable_ ? "M" : "mode");
173 if (diff & catalog::DirectoryEntryBase::Difference::kMtime)
174 result_list.push_back(machine_readable_ ? "T" : "timestamp");
175 if (diff & catalog::DirectoryEntryBase::Difference::kSymlink)
176 result_list.push_back(machine_readable_ ? "L" : "symlink-target");
177 if (diff & catalog::DirectoryEntryBase::Difference::kChecksum)
178 result_list.push_back(machine_readable_ ? "C" : "content");
179 if (diff & catalog::DirectoryEntryBase::Difference::kHardlinkGroup)
180 result_list.push_back(machine_readable_ ? "G" : "hardlink-group");
181 if (diff &
182 catalog::DirectoryEntryBase::Difference::kNestedCatalogTransitionFlags)
183 {
184 result_list.push_back(machine_readable_ ? "N" : "nested-catalog");
185 }
186 if (diff & catalog::DirectoryEntryBase::Difference::kChunkedFileFlag)
187 result_list.push_back(machine_readable_ ? "P" : "chunked-file");
188 if (diff & catalog::DirectoryEntryBase::Difference::kHasXattrsFlag)
189 result_list.push_back(machine_readable_ ? "X" : "xattrs");
190 if (diff & catalog::DirectoryEntryBase::Difference::kExternalFileFlag)
191 result_list.push_back(machine_readable_ ? "E" : "external-file");
192 if (diff & catalog::DirectoryEntryBase::Difference::kBindMountpointFlag)
193 result_list.push_back(machine_readable_ ? "B" : "bind-mountpoint");
194 if (diff & catalog::DirectoryEntryBase::Difference::kHiddenFlag)
195 result_list.push_back(machine_readable_ ? "H" : "hidden");
196 if (diff & catalog::DirectoryEntryBase::Difference::kDirectIoFlag)
197 result_list.push_back(machine_readable_ ? "D" : "direct-io");
198
199 return machine_readable_ ? ("[" + JoinStrings(result_list, "") + "]")
200 : (" [" + JoinStrings(result_list, ", ") + "]");
201 }
202
203 std::string PrintEntryType(const catalog::DirectoryEntry &entry) {
204 if (entry.IsRegular()) return machine_readable_ ? "F" : "file";
205 else if (entry.IsLink()) return machine_readable_ ? "S" : "symlink";
206 else if (entry.IsDirectory()) return machine_readable_ ? "D" : "directory";
207 else
208 return machine_readable_ ? "U" : "unknown";
209 }
210
211 bool show_header_;
212 bool machine_readable_;
213 bool ignore_timediff_;
214 }; // class DiffReporter
215
216 } // anonymous namespace
217
218
219 namespace publish {
220
221 int CmdDiff::Main(const Options &options) {
222 SettingsBuilder builder;
223
224 if (options.Has("worktree")) {
225 UniquePtr<SettingsPublisher> settings(builder.CreateSettingsPublisher(
226 options.plain_args().empty() ? "" : options.plain_args()[0].value_str));
227 settings->SetIsSilent(true);
228 settings->GetTransaction()->SetDryRun(true);
229 settings->GetTransaction()->SetPrintChangeset(true);
230 Publisher publisher(*settings);
231 publisher.Sync();
232 return 0;
233 }
234
235 SettingsRepository settings = builder.CreateSettingsRepository(
236 options.plain_args().empty() ? "" : options.plain_args()[0].value_str);
237
238 std::string from = options.GetStringDefault("from", "trunk-previous");
239 std::string to = options.GetStringDefault("to", "trunk");
240
241 if (options.Has("keychain")) {
242 settings.GetKeychain()->SetKeychainDir(options.GetString("keychain"));
243 }
244 Repository repository(settings);
245
246 DiffReporter diff_reporter(options.Has("header"),
247 options.Has("machine-readable"),
248 options.Has("ignore-timediff"));
249 repository.Diff(from, to, &diff_reporter);
250
251 return 0;
252 }
253
254 } // namespace publish
255