Skip to content

Commit dc777f9

Browse files
author
xml
committed
feat: Add lastore-upgrade-query tool
* using libapt-pkg to implement upgrade package detailed information query Task: https://pms.uniontech.com/task-view-384369.html
1 parent 298c2f8 commit dc777f9

5 files changed

Lines changed: 263 additions & 1 deletion

File tree

debian/control

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ Build-Depends:
2626
golang-github-spf13-cobra-dev,
2727
golang-github-stretchr-testify-dev,
2828
libsystemd-dev,
29+
libapt-pkg-dev,
30+
nlohmann-json3-dev,
2931
Standards-Version: 4.1.3
3032
Homepage: http://github.com/linuxdeepin/lastore-daemon
3133

makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ bin/lastore-agent:src/lastore-agent/*.c
3333
@mkdir -p bin
3434
gcc ${SECURITY_BUILD_OPTIONS} -W -Wall -D_GNU_SOURCE -o $@ $^ $(shell pkg-config --cflags --libs glib-2.0 libsystemd)
3535

36-
build: prepare bin/lastore-agent
36+
bin/lastore-upgrade-query: src/lastore-upgrade-query/*.cc
37+
@mkdir -p bin
38+
g++ ${SECURITY_BUILD_OPTIONS} -W -Wall -o $@ $^ $(shell pkg-config --cflags --libs apt-pkg) $(shell pkg-config --cflags --libs nlohmann_json)
39+
40+
build: prepare bin/lastore-agent bin/lastore-upgrade-query
3741
${GoPath} ${GOBUILD_CGO_FLAGS} ${GOBUILD} -o bin/lastore-daemon ${GOBUILD_OPTIONS} ${GOPKG_PREFIX}/src/lastore-daemon
3842
${GoPath} ${GOBUILD_CGO_FLAGS} ${GOBUILD} -o bin/lastore-tools ${GOBUILD_OPTIONS} ${GOPKG_PREFIX}/src/lastore-tools
3943
${GoPath} ${GOBUILD_CGO_FLAGS} ${GOBUILD} -o bin/lastore-smartmirror ${GOBUILD_OPTIONS} ${GOPKG_PREFIX}/src/lastore-smartmirror || echo "build failed, disable smartmirror support "
@@ -67,6 +71,7 @@ install: gen_mo
6771
cp bin/lastore-tools ${DESTDIR}${PREFIX}/usr/bin/
6872
cp bin/lastore-smartmirror ${DESTDIR}${PREFIX}/usr/bin/
6973
cp bin/lastore-agent ${DESTDIR}${PREFIX}/usr/bin/
74+
cp bin/lastore-upgrade-query ${DESTDIR}${PREFIX}/usr/bin/
7075
mkdir -p ${DESTDIR}${PREFIX}/usr/libexec/lastore-daemon && cp bin/lastore-daemon ${DESTDIR}${PREFIX}/usr/libexec/lastore-daemon
7176
cp bin/lastore-smartmirror-daemon ${DESTDIR}${PREFIX}/usr/libexec/lastore-daemon
7277

src/lastore-upgrade-query/main.cc

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include "upgrade_query.h"
2+
#include <iostream>
3+
#include <iomanip>
4+
#include <string>
5+
#include <nlohmann/json.hpp>
6+
7+
int main(int argc, char **argv) {
8+
std::string sourcelist = "";
9+
std::string sourcepart = "";
10+
bool outputJson = false;
11+
bool allowDowngrades = false;
12+
13+
// Support customizing sourcelist path via command line arguments
14+
for (int i = 1; i < argc; i++) {
15+
std::string arg = argv[i];
16+
if (arg == "--sourcelist" && i + 1 < argc) {
17+
sourcelist = argv[++i];
18+
} else if (arg == "--sourceparts" && i + 1 < argc) {
19+
sourcepart = argv[++i];
20+
} else if (arg == "-j" || arg == "--json") {
21+
outputJson = true;
22+
} else if (arg == "--allow-downgrades") {
23+
allowDowngrades = true;
24+
} else if (arg == "--help" || arg == "-h") {
25+
std::cout << "Usage: " << argv[0] << " [options]\n"
26+
<< "Options:\n"
27+
<< " --sourcelist <file> Specify custom sources.list file path\n"
28+
<< " --sourceparts <dir> Specify custom sources.list.d directory path\n"
29+
<< " -j, --json Output results in JSON format\n"
30+
<< " --allow-downgrades Allow downgrade installation\n"
31+
<< " --help, -h Show this help message\n";
32+
return 0;
33+
}
34+
}
35+
36+
std::vector<UpgradePackage> packages = GetUpgradePackages(sourcelist, sourcepart, allowDowngrades);
37+
38+
for (const auto& pkgItem : packages) {
39+
if (!pkgItem.Valid()) {
40+
std::cerr << "Invalid package: " << pkgItem.Name << std::endl;
41+
return 1;
42+
}
43+
}
44+
45+
if (outputJson) {
46+
nlohmann::json json_array = nlohmann::json::array();
47+
48+
for (const auto& pkg : packages) {
49+
json_array.push_back({
50+
{"name", pkg.Name},
51+
{"installed_version", pkg.InstalledVersion},
52+
{"candidate_version", pkg.CandidateVersion},
53+
{"architecture", pkg.Architecture},
54+
{"codename", pkg.Codename},
55+
{"component", pkg.Component},
56+
{"site", pkg.Site},
57+
{"filename", pkg.Filename},
58+
{"size", pkg.Size},
59+
{"installed_size", pkg.InstalledSize},
60+
{"hash", pkg.Hash}
61+
});
62+
}
63+
64+
std::cout << json_array.dump() << '\n';
65+
} else {
66+
std::cout << "\n=== Retrieved Package Information ===\n"
67+
<< "Total " << packages.size() << " packages found\n";
68+
69+
for (const auto& pkg : packages) {
70+
std::cout << "\nname: " << pkg.Name << "\n"
71+
<< "candidate_version: " << pkg.CandidateVersion << "\n";
72+
73+
if (!pkg.InstalledVersion.empty()) {
74+
std::cout << "installed_version: " << pkg.InstalledVersion << "\n";
75+
}
76+
77+
std::cout << "architecture: " << pkg.Architecture << "\n"
78+
<< "codename: " << pkg.Codename << "\n"
79+
<< "component: " << pkg.Component << "\n"
80+
<< "site: " << pkg.Site << "\n"
81+
<< "filename: " << pkg.Filename << "\n"
82+
<< "size: " << std::fixed << std::setprecision(2)
83+
<< pkg.Size / 1024.0 / 1024.0 << " MB\n"
84+
<< "installed_size: " << std::fixed << std::setprecision(2)
85+
<< pkg.InstalledSize / 1024.0 / 1024.0 << " MB\n"
86+
<< "hash: " << pkg.Hash << "\n";
87+
}
88+
}
89+
90+
return 0;
91+
}
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
#include <apt-pkg/init.h>
2+
#include <apt-pkg/cachefile.h>
3+
#include <apt-pkg/pkgcache.h>
4+
#include <apt-pkg/algorithms.h>
5+
#include <apt-pkg/pkgsystem.h>
6+
#include <apt-pkg/progress.h>
7+
#include <apt-pkg/error.h>
8+
#include <apt-pkg/acquire.h>
9+
#include <apt-pkg/upgrade.h>
10+
#include <apt-pkg/depcache.h>
11+
#include <apt-pkg/sourcelist.h>
12+
#include <apt-pkg/policy.h>
13+
#include <apt-pkg/pkgrecords.h>
14+
#include <apt-pkg/hashes.h>
15+
16+
#include <iostream>
17+
#include <vector>
18+
#include <string>
19+
#include <cstring>
20+
#include <cstdlib>
21+
22+
#include "upgrade_query.h"
23+
24+
bool UpgradePackage::Valid() const {
25+
if (Name.empty() ||
26+
CandidateVersion.empty() ||
27+
Architecture.empty() ||
28+
Codename.empty() ||
29+
Component.empty() ||
30+
Site.empty() ||
31+
Filename.empty() ||
32+
Hash.empty()) {
33+
return false;
34+
}
35+
36+
// Check uint64_t fields - they should not be 0
37+
if (Size == 0 || InstalledSize == 0) {
38+
return false;
39+
}
40+
41+
return true;
42+
}
43+
44+
UpgradePackage GetUpgradePackage(pkgCacheFile &Cache, pkgRecords &Recs, const pkgCache::PkgIterator &pkg) {
45+
UpgradePackage result;
46+
pkgCache::VerIterator candVer = Cache->GetCandidateVersion(pkg);
47+
48+
result.Name = pkg.Name();
49+
50+
// Fill installed version if present
51+
pkgCache::VerIterator curVer = pkg.CurrentVer();
52+
if (!curVer.end()) {
53+
result.InstalledVersion = curVer.VerStr();
54+
}
55+
56+
if (!candVer.end()) {
57+
result.CandidateVersion = candVer.VerStr();
58+
result.Architecture = candVer.Arch();
59+
result.Size = candVer->Size;
60+
result.InstalledSize = candVer->InstalledSize;
61+
62+
// Get file list to find repository information
63+
pkgCache::VerFileIterator vf = candVer.FileList();
64+
if (!vf.end()) {
65+
result.Codename = vf.File().Codename() ? vf.File().Codename() : "";
66+
result.Component = vf.File().Component() ? vf.File().Component() : "";
67+
68+
// Get download information
69+
pkgCache::PkgFileIterator pf = vf.File();
70+
if (!pf.end()) {
71+
result.Site = pf.Site() ? pf.Site() : "";
72+
}
73+
74+
// Use pkgRecords to get detailed download information
75+
pkgRecords::Parser& parser = Recs.Lookup(vf);
76+
result.Filename = parser.FileName();
77+
78+
// Get hash information
79+
HashStringList hashes = parser.Hashes();
80+
if (!hashes.empty()) {
81+
const HashString *hash = hashes.find(NULL);
82+
if (hash) {
83+
result.Hash = hash->toStr();
84+
}
85+
}
86+
}
87+
}
88+
89+
return result;
90+
}
91+
92+
std::vector<UpgradePackage> GetUpgradePackages(const std::string &sourcelist, const std::string &sourceparts, bool allow_downgrades) {
93+
std::vector<UpgradePackage> result;
94+
if (!pkgInitConfig(*_config)) {
95+
std::cerr << "Failed to initialize APT config" << std::endl;
96+
return result;
97+
}
98+
99+
if (!pkgInitSystem(*_config, _system)) {
100+
std::cerr << "Failed to initialize APT system" << std::endl;
101+
return result;
102+
}
103+
104+
// disable debug output
105+
_config->CndSet("quiet::NoProgress", true);
106+
_config->Set("quiet", 1);
107+
108+
_config->Set("APT::Get::allow-downgrades", allow_downgrades);
109+
110+
// If custom paths are provided, set configuration items
111+
if (!sourcelist.empty()) {
112+
_config->Set("Dir::Etc::sourcelist", sourcelist);
113+
}
114+
if (!sourceparts.empty()) {
115+
_config->Set("Dir::Etc::sourceparts", sourceparts);
116+
}
117+
118+
pkgCacheFile Cache;
119+
OpTextProgress Prog(*_config);
120+
if (!Cache.Open(&Prog, false)) {
121+
std::cerr << "Could not open cache" << std::endl;
122+
return result;
123+
}
124+
125+
APT::Upgrade::Upgrade(*Cache, APT::Upgrade::ALLOW_EVERYTHING);
126+
Cache->MarkAndSweep();
127+
128+
pkgRecords Recs(Cache);
129+
result.reserve(Cache->Head().PackageCount / 4); // Reserve approximate space
130+
131+
for (pkgCache::PkgIterator pkg = Cache->PkgBegin(); !pkg.end(); ++pkg) {
132+
const pkgDepCache::StateCache& state = (*Cache)[pkg];
133+
134+
if (state.NewInstall() || state.Upgrade()) {
135+
result.emplace_back(GetUpgradePackage(Cache, Recs, pkg));
136+
}
137+
}
138+
139+
return result;
140+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
3+
#include <vector>
4+
#include <string>
5+
#include <cstdint>
6+
7+
class UpgradePackage {
8+
public:
9+
std::string Name;
10+
std::string InstalledVersion;
11+
std::string CandidateVersion;
12+
std::string Architecture;
13+
std::string Codename;
14+
std::string Component;
15+
std::string Site;
16+
std::string Filename;
17+
uint64_t Size = 0;
18+
uint64_t InstalledSize = 0;
19+
std::string Hash;
20+
21+
bool Valid() const;
22+
};
23+
24+
std::vector<UpgradePackage> GetUpgradePackages(const std::string &sourcelist, const std::string &sourceparts, bool allow_downgrades = false);

0 commit comments

Comments
 (0)