Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a declarative autobuild system (prototype) #2620

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
9 changes: 9 additions & 0 deletions build/parsePreamble.c
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,14 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
multiToken = 1;

switch (tag) {
case RPMTAG_AUTOBUILD:
SINGLE_TOKEN_ONLY;
if (rpmCharCheck(spec, field,
ALLOWED_CHARS_NAME, ALLOWED_FIRSTCHARS_NAME))
{
goto exit;
}
break;
case RPMTAG_NAME:
SINGLE_TOKEN_ONLY;
if (rpmCharCheck(spec, field,
Expand Down Expand Up @@ -1080,6 +1088,7 @@ static struct PreambleRec_s const preambleList[] = {
{RPMTAG_BUILDPREREQ, 0, 1, 0, LEN_AND_STR("buildprereq")},
{RPMTAG_BUILDREQUIRES, 0, 0, 0, LEN_AND_STR("buildrequires")},
{RPMTAG_AUTOREQPROV, 0, 0, 0, LEN_AND_STR("autoreqprov")},
{RPMTAG_AUTOBUILD, 0, 0, 1, LEN_AND_STR("autobuild")},
{RPMTAG_AUTOREQ, 0, 0, 0, LEN_AND_STR("autoreq")},
{RPMTAG_AUTOPROV, 0, 0, 0, LEN_AND_STR("autoprov")},
{RPMTAG_DOCDIR, 0, 0, 0, LEN_AND_STR("docdir")},
Expand Down
82 changes: 77 additions & 5 deletions build/parseSpec.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#define ISMACRO(s,m,len) (rstreqn((s), (m), len) && !risalpha((s)[len]))
#define ISMACROWITHARG(s,m,len) (rstreqn((s), (m), len) && (risblank((s)[len]) || !(s)[len]))

static rpmRC parseSpecParts(rpmSpec spec, const char *pattern);

typedef struct OpenFileInfo {
char * fileName;
FILE *fp;
Expand Down Expand Up @@ -891,6 +893,68 @@ static int parseEmpty(rpmSpec spec, int prevParsePart)
return res;
}

static rpmRC parseAutosect(rpmSpec spec,
const char *prefix, const char *section, StringBuf sb)
{
rpmRC rc = RPMRC_OK;

if (sb == NULL) {
char *mn = rstrscat(NULL, "autobuild_", prefix, "_", section, NULL);
if (rpmMacroIsParametric(NULL, mn)) {
char *path = NULL;
FD_t fd = rpmMkTempFile(NULL, &path);
if (fd) {
char *buf = rstrscat(NULL, "%", section, "\n",
"%{", mn, "}", NULL);
size_t blen = strlen(buf);
if (Fwrite(buf, blen, 1, fd) < blen)
rc = RPMRC_FAIL;
Fclose(fd);
}
if (fd == NULL || rc) {
rpmlog(RPMLOG_ERR, _("failed to write autobuild %%%s %s: %s\n"),
section, path, strerror(errno));
} else {
rc = parseSpecParts(spec, path);
}
unlink(path);
free(path);
}
free(mn);
}
return rc;
}

struct autosect_s {
const char *name;
StringBuf sb;
};

static rpmRC parseAutobuild(rpmSpec spec)
{
rpmRC rc = RPMRC_OK;
char *autobuild = rpmExpand("%{?autobuild}", NULL);
if (*autobuild) {
/* XXX we should have APIs for this stuff */
struct autosect_s autosectList[] = {
{ "prep", spec->prep },
{ "conf", spec->conf },
{ "generate_depends", spec->buildrequires },
{ "build", spec->build },
{ "install", spec->install },
{ "check", spec->check },
{ "clean", spec->clean },
{ NULL, NULL }
};

for (struct autosect_s *as = autosectList; !rc && as->name; as++) {
rc = parseAutosect(spec, autobuild, as->name, as->sb);
}
}
free(autobuild);
return rc;
}

static rpmSpec parseSpec(const char *specFile, rpmSpecFlags flags,
const char *buildRoot, int recursing);

Expand Down Expand Up @@ -1048,6 +1112,9 @@ static rpmRC parseSpecSection(rpmSpec *specptr, int secondary)
}
}

if (!secondary && parseAutobuild(spec))
goto errxit;

/* Add arch for each package */
addArch(spec);

Expand Down Expand Up @@ -1184,17 +1251,15 @@ rpmSpec rpmSpecParse(const char *specFile, rpmSpecFlags flags,
return spec;
}

rpmRC parseGeneratedSpecs(rpmSpec spec)
static rpmRC parseSpecParts(rpmSpec spec, const char *pattern)
{
ARGV_t argv = NULL;
int argc = 0;
int i;
rpmRC rc = RPMRC_OK;

char * specPattern = rpmGenPath("%{specpartsdir}", NULL, "*.specpart");
/* rpmGlob returns files sorted */
if (rpmGlob(specPattern, &argc, &argv) == 0) {
for (i = 0; i < argc; i++) {
if (rpmGlob(pattern, &argc, &argv) == 0) {
for (int i = 0; i < argc; i++) {
rpmlog(RPMLOG_NOTICE, "Reading %s\n", argv[i]);
pushOFI(spec, argv[i]);
snprintf(spec->fileStack->readBuf, spec->fileStack->readBufLen,
Expand All @@ -1207,6 +1272,13 @@ rpmRC parseGeneratedSpecs(rpmSpec spec)
}
argvFree(argv);
}
return rc;
}

rpmRC parseGeneratedSpecs(rpmSpec spec)
{
char * specPattern = rpmGenPath("%{specpartsdir}", NULL, "*.specpart");
rpmRC rc = parseSpecParts(spec, specPattern);
free(specPattern);
if (!rc) {
rc = finalizeSpec(spec);
Expand Down
1 change: 1 addition & 0 deletions include/rpm/rpmtag.h
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ typedef enum rpmTag_e {
RPMTAG_PREUNTRANSFLAGS = 5107, /* i */
RPMTAG_POSTUNTRANSFLAGS = 5108, /* i */
RPMTAG_SYSUSERS = 5109, /* s[] extension */
RPMTAG_AUTOBUILD = 5110, /* internal */

RPMTAG_FIRSTFREE_TAG /*!< internal */
} rpmTag;
Expand Down
9 changes: 9 additions & 0 deletions macros.in
Original file line number Diff line number Diff line change
Expand Up @@ -1349,5 +1349,14 @@ end
end
}

# example autobuild macros for autotools
%autobuild_autotools_prep() %autosetup -p1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand %prep being part of this. It's not going to differ from one build system to another, and including it in the %build -a steps increases the number of spec files that won't be able to use autobuild because they need to perform some sort of pre-build shenanigans. (Running sed on some of the extracted files, extracting additional %SOURCEN tarballs, etc...)

Copy link
Member Author

@pmatilai pmatilai Nov 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, the %prep part is here more for demo purposes than something we'd want to ship for real. Instead we should probably just automatically add "%autosetup -p1" %prep section to everything that has sources and does not have a prep. I don't understand the remark about %build -a though. If you need to do pre-build shenanigans, you do it in one %prep -a for the earliest opportunity (assuming automatically added %prep %autosetup) , or in %conf -p/-a or %build -p, as appropriate.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, there was a reason %prep is a part of this: language ecosystems may have source formats outside the tarball realm, and in those cases we'd rather just have the ecosystem define %prep as they see fit, using their native tools. Ruby is an example here - rpm shouldn't have to know about .gem.

As for the rest, we could indeed just autopopulate %prep with a generic "%autosetup -p1" when Autobuild is set, but I'm not sure it's somehow better than doing it explicitly in the autobuild definition. It's just one line in the definition, and there could be other ecosystem preferences I guess. Thoughts welcome certainly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...and that's what the last fixup does: add autobuild defaults that will be applied if there's no build-system specific section. Only probably makes sense for %prep and %clean but the mechanism is generic so supporting the all makes no difference in code.

%autobuild_autotools_conf() %configure
%autobuild_autotools_build() %make_build
%autobuild_autotools_install()\
%make_install\
test -d po && %find_lang %{name} ||:

# \endverbatim
#*/

Binary file added tests/data/SOURCES/amhello-1.0.tar.gz
Binary file not shown.
20 changes: 20 additions & 0 deletions tests/data/SPECS/amhello.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Name: amhello
Version: 1.0
Release: 1
Source: %{name}-%{version}.tar.gz
License: GPLv2
Summary: Autotools example
Autobuild: autotools

%description
%{summary}

%build -a
cat << EOF > README.distro
Add some distro specific notes.
EOF

%files
%doc README.distro
%{_bindir}/hello
%{_docdir}/%{name}
21 changes: 21 additions & 0 deletions tests/rpmbuild.at
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,27 @@ GPL
[])
RPMTEST_CLEANUP

AT_SETUP([rpmbuild -b autobuild])
AT_KEYWORDS([build])
RPMDB_INIT

runroot rpmbuild -bb \
--define "_prefix /usr" \
--define "_docdir_fmt %%{NAME}" \
--quiet /data/SPECS/amhello.spec

RPMTEST_CHECK([
runroot rpm -qpl --noartifact /build/RPMS/*/amhello-1.0-1.*.rpm
],
[0],
[/usr/bin/hello
/usr/share/doc/amhello
/usr/share/doc/amhello/README
/usr/share/doc/amhello/README.distro
],
[ignore])
RPMTEST_CLEANUP

AT_SETUP([rpmbuild -b steps])
AT_KEYWORDS([build])
RPMDB_INIT
Expand Down