Skip to content

Commit

Permalink
Implement autobuild "template" system (prototype)
Browse files Browse the repository at this point in the history
Remove endless boilerplate to perform the same steps in each
package by just declaring which kind of buildsystem the package uses
using the new Autobuild: spec tag.

Autobuild macros are just regular parametric macros which can be invoked
manually from specs too, which should help with reuse and handling
complicated cases.

As such , this will only work for simple and/or "perfect" upstream projects
of course. In reality many/most packages need further tweaking, but this
can now be easily done with the new append/prepend modes of the build
scriptlets.

The implementation looks more complicated than one might expect because
we want the full spec processing to take place on these parts, rather
than just macro expansion. That covers things like the special facilities
of %prep and their side-effects, %if-conditionals, possible error
handling and so on.

Add automake upstream amhello-1.0.tar.gz as an test-case of a rather
hands-free autobuild. Pretending it's a noarch package is ugly, but
handling arch-specifity in the test-suite is uglier.

Fixes: rpm-software-management#1087
  • Loading branch information
pmatilai committed Oct 27, 2023
1 parent ed59d17 commit e2b5b92
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 0 deletions.
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
67 changes: 67 additions & 0 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
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
%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.
22 changes: 22 additions & 0 deletions tests/data/SPECS/amhello.spec
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Name: amhello
Version: 1.0
Release: 1
Source: %{name}-%{version}.tar.gz
License: GPLv2
Summary: Autotools example
# This isn't, but to simplify test-suite
BuildArch: noarch
Autobuild: autotools

%description
%{summary}

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

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

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

# This isn't a noarch package really of course, but it simplifies things here
runroot rpmbuild -bb \
--define "_prefix /usr" \
--define "_binaries_in_noarch_packages_terminate_build 0" \
--define "_docdir_fmt %%{NAME}" \
--quiet /data/SPECS/amhello.spec

RPMTEST_CHECK([
runroot rpm -qpl /build/RPMS/noarch/amhello-1.0-1.noarch.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

0 comments on commit e2b5b92

Please sign in to comment.