Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions HACKING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Hacking on synaptic

## Dependencies

On Debian or Ubuntu the quickest way to get everything is

sudo apt build-dep synaptic

The authoritative list is `Build-Depends` in `debian/control`.

## Building

meson setup build
ninja -C build

The binary is `build/gtk/synaptic`. Build options live in
`meson_options.txt`; list them and their current values with

meson configure build

and change one with e.g. `meson configure build -Dpkg_hold=true`.

## Running the tests

ninja -C build test

is the `make test` equivalent. For more control use meson directly:

meson test -C build --print-errorlogs
meson test -C build test_rsources
meson test -C build test_rsources --gtest-args='--gtest_shuffle --gtest_repeat=5'

`test_rsources` uses GoogleTest and is only built when `gtest` is found.
`-Dtests=enabled` makes a missing `libgtest-dev` a configure error, which is
what the Debian package build does; `-Dtests=disabled` skips it.

`tests/test_gtkpkglist` is an interactive viewer for the package list widget,
not a test, so it is built but not registered with `meson test`.

## Style checks

ninja -C build lint # whitespace errors introduced relative to master
ninja -C build clang-format-check # formatting per .clang-format

`./fmt` runs clang-format in place over every C++ file under `common/`,
`gtk/` and `tests/`; for a single file use `clang-format -i path/to/file.cc`.
Boolean arguments at call sites are annotated systemd style, e.g.
`GetListOfFilesInDir(Dir, ext, /* SortList */ true)`.

## Building the Debian package

gbp buildpackage

or plain `dpkg-buildpackage -us -uc`; `debian/gbp.conf` holds the branch
layout for git-buildpackage.
144 changes: 99 additions & 45 deletions common/rsources.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,12 @@
#include <apt-pkg/error.h>
#include <apt-pkg/fileutl.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/tagfile.h>
#include <cctype>
#include <cstring>
#include <dirent.h>
#include <fstream>
#include <iostream>
#include <list>
#include <string>
#include <sys/stat.h>
#include <vector>

using namespace std;
Expand All @@ -67,6 +65,11 @@ SourcesList::SourceRecord *SourcesList::AddSourceNode(SourceRecord &rec)
return newrec;
}

static string ExpandArch(const string &S)
{
return SubstVar(S, "$(ARCH)", _config->Find("APT::Architecture"));
}

bool SourcesList::ReadSourcePart(string listpath)
{
// cout << "SourcesList::ReadSourcePart() "<< listpath << endl;
Expand Down Expand Up @@ -141,8 +144,7 @@ bool SourcesList::ReadSourcePart(string listpath)
if (ParseQuoteWord(p, Section) == true)
return _error->Error(_("Syntax error in line %s"), buf);

rec.Dist =
SubstVar(rec.Dist, "$(ARCH)", _config->Find("APT::Architecture"));
rec.Dist = ExpandArch(rec.Dist);

AddSourceNode(rec);
continue;
Expand Down Expand Up @@ -179,54 +181,94 @@ bool SourcesList::ReadSourcePart(string listpath)
return record_ok;
}

bool SourcesList::ReadSourceDir(string Dir)
// copy libapt:sourcelist.cc FindMultiValue()
// TODO: expose in libapt as pkgTagSection::FindMultiValue() and drop this
static vector<string> FindMultiValue(const pkgTagSection &Sec,
const char *Field)
{
// cout << "SourcesList::ReadSourceDir() " << Dir << endl;

DIR *D = opendir(Dir.c_str());
if (D == 0)
return _error->Errno("opendir", _("Unable to read %s"), Dir.c_str());

vector<string> List;
for (struct dirent *Ent = readdir(D); Ent != 0; Ent = readdir(D)) {
if (Ent->d_name[0] == '.')
continue;
string value = Sec.FindS(Field);
replace_if(value.begin(), value.end(), isspace_ascii, ' ');
vector<string> parts = VectorizeString(value, ' ');
parts.erase(remove_if(parts.begin(),
parts.end(),
[](const string &s) { return s.empty(); }),
parts.end());
return parts;
}

// Skip bad file names ala run-parts
const char *C = Ent->d_name;
for (; *C != 0; C++)
if (isalpha(*C) == 0 && isdigit(*C) == 0 && *C != '_' && *C != '-' &&
*C != '.')
break;
if (*C != 0)
continue;
bool SourcesList::ReadDeb822SourcePart(string path)
{
FileFd Fd;
// FileFd::Open() already queued an error with the errno
if (Fd.Open(path, FileFd::ReadOnly) == false)
return false;

// Only look at files ending in .list to skip .rpmnew etc files
if (strcmp(Ent->d_name + strlen(Ent->d_name) - 5, ".list") != 0)
pkgTagFile Tags(&Fd, pkgTagFile::SUPPORT_COMMENTS);
pkgTagSection Sec;
bool record_ok = true;
while (Tags.Step(Sec)) {
SourceRecord rec;
rec.SourceFile = path;
rec.Format = Deb822;

bool types_ok = true;
for (const string &T : FindMultiValue(Sec, "Types"))
if (rec.SetType(T) == false)
types_ok = false;
if (!types_ok || rec.Type == 0) {
record_ok = false;
continue;
}
// absent means enabled (like in libapt)
string Enabled = Sec.FindS("Enabled");
if (Enabled.empty() == false && StringToBool(Enabled) == false)
rec.Type |= Disabled;

// expanded like SetURI() does it, but without its trailing slash, which
// only makes sense for a single URI
vector<string> uris = FindMultiValue(Sec, "URIs");
for (string &uri : uris)
uri = ExpandArch(uri);
rec.URI = APT::String::Join(uris, " ");
// apt expands $(ARCH) in deb822 suites too
vector<string> suites = FindMultiValue(Sec, "Suites");
for (string &suite : suites)
suite = ExpandArch(suite);
rec.Dist = APT::String::Join(suites, " ");

vector<string> comps = FindMultiValue(Sec, "Components");
rec.NumSections = comps.size();
rec.Sections = new string[rec.NumSections];
for (unsigned short i = 0; i < rec.NumSections; i++)
rec.Sections[i] = comps[i];

// Make sure it is a file and not something else
string File = flCombine(Dir, Ent->d_name);
struct stat St;
if (stat(File.c_str(), &St) != 0 || S_ISREG(St.st_mode) == 0)
continue;
List.push_back(File);
AddSourceNode(rec);
}
closedir(D);

sort(List.begin(), List.end());
return record_ok;
}

// Read the files
for (vector<string>::const_iterator I = List.begin(); I != List.end(); I++)
if (ReadSourcePart(*I) == false)
return false;
return true;
bool SourcesList::ReadSourceDir(string Dir)
{
bool ok = true;
for (const string &File :
GetListOfFilesInDir(Dir,
vector<string>{"list", "sources"},
/* SortList */ true)) {
if (flExtension(File) == "sources")
ok = ReadDeb822SourcePart(File) && ok;
else
ok = ReadSourcePart(File) && ok;
}
return ok;
}

bool SourcesList::ReadSources()
{
// cout << "SourcesList::ReadSources() " << endl;

// libapt queued notices about odd files in sources.list.d when it read them
// at startup and they were shown then; do not queue them again on success
_error->PushToStack();
bool Res = true;

string Parts = _config->FindDir("Dir::Etc::sourceparts");
Expand All @@ -236,6 +278,10 @@ bool SourcesList::ReadSources()
if (FileExists(Main) == true)
Res &= ReadSourcePart(Main);

if (Res)
_error->RevertToStack();
else
_error->MergeWithStack();
return Res;
}

Expand Down Expand Up @@ -304,7 +350,9 @@ bool SourcesList::UpdateSources()
for (list<SourceRecord *>::iterator it = SourceRecords.begin();
it != SourceRecords.end();
it++) {
if ((*it)->SourceFile == "")
// we cannot represent a deb822 in a SourceRecord yet so skip
// writing until we can represent and write them
if ((*it)->SourceFile == "" || (*it)->Format == Deb822)
continue;
filenames.push_front((*it)->SourceFile);
}
Expand Down Expand Up @@ -373,7 +421,14 @@ bool SourcesList::SourceRecord::SetType(string S)
return true;
}

string SourcesList::SourceRecord::GetType()
string SourcesList::SourceRecord::TypeLabel() const
{
if ((Type & Deb) != 0 && (Type & DebSrc) != 0)
return "deb deb-src";
return GetType();
}

string SourcesList::SourceRecord::GetType() const
{
if ((Type & Deb) != 0)
return "deb";
Expand Down Expand Up @@ -402,9 +457,7 @@ bool SourcesList::SourceRecord::SetURI(string S)
if (S.find(':') == string::npos)
return false;

S = SubstVar(S, "$(ARCH)", _config->Find("APT::Architecture"));
S = SubstVar(S, "$(VERSION)", _config->Find("APT::DistroVersion"));
URI = S;
URI = ExpandArch(S);

// append a / to the end if one is not already there
if (URI[URI.size() - 1] != '/')
Expand All @@ -428,6 +481,7 @@ SourcesList::SourceRecord &SourcesList::SourceRecord::operator=(
NumSections = rhs.NumSections;
Comment = rhs.Comment;
SourceFile = rhs.SourceFile;
Format = rhs.Format;

return *this;
}
Expand Down
12 changes: 10 additions & 2 deletions common/rsources.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ class SourcesList
RepomdSrc = 1 << 9
};

// record the type because deb822 is read-only for now
// (until we can fully represent it)
enum FileFormat { OneLine, Deb822 };

struct SourceRecord
{
unsigned int Type;
Expand All @@ -57,12 +61,15 @@ class SourcesList
unsigned short NumSections;
std::string Comment;
std::string SourceFile;
FileFormat Format;

bool SetType(std::string);
std::string GetType();
std::string GetType() const;
// For display: "deb deb-src" when a stanza declares both types
std::string TypeLabel() const;
bool SetURI(std::string);

SourceRecord() : Type(0), Sections(0), NumSections(0)
SourceRecord() : Type(0), Sections(0), NumSections(0), Format(OneLine)
{}
~SourceRecord()
{
Expand Down Expand Up @@ -98,6 +105,7 @@ class SourcesList
void RemoveSource(SourceRecord *&);
void SwapSources(SourceRecord *&, SourceRecord *&);
bool ReadSourcePart(std::string listpath);
bool ReadDeb822SourcePart(std::string path);
bool ReadSourceDir(std::string Dir);
bool ReadSources();
bool UpdateSources();
Expand Down
2 changes: 1 addition & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ Source: synaptic
Section: admin
Priority: optional
Maintainer: Michael Vogt <mvo@debian.org>
Build-Depends: debhelper-compat (= 12), gettext, meson, ninja-build, libapt-pkg-dev, libgtk-3-dev, libvte-2.91-dev, libpolkit-gobject-1-dev, libsm-dev, lsb-release, libxapian-dev, xmlto
Build-Depends: debhelper-compat (= 12), gettext, meson, ninja-build, libapt-pkg-dev, libgtk-3-dev, libvte-2.91-dev, libpolkit-gobject-1-dev, libsm-dev, lsb-release, libxapian-dev, xmlto, libgtest-dev
Build-Conflicts: librpm-dev
Standards-Version: 4.5.0
Vcs-Git: https://github.com/mvo5/synaptic.git
Expand Down
3 changes: 2 additions & 1 deletion debian/rules
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ DIST = $(shell lsb_release -i -s)
DHFLAGS=--parallel
MESON_FLAGS= --prefix=/usr \
--localstatedir=/var/lib/synaptic \
-Dpkg_hold=true
-Dpkg_hold=true \
-Dtests=enabled

%:
dh $@ $(DHFLAGS) --buildsystem=meson --without autoreconf --without autotools-dev
Expand Down
14 changes: 14 additions & 0 deletions gtk/gtkbuilder/window_repositories.ui
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,20 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label_source_hint">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="xalign">0</property>
<property name="wrap">True</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
Expand Down
Loading