1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2021 Pakfire development team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
28 #include <pakfire/arch.h>
29 #include <pakfire/dist.h>
30 #include <pakfire/downloader.h>
31 #include <pakfire/logging.h>
32 #include <pakfire/package.h>
33 #include <pakfire/packager.h>
34 #include <pakfire/pakfire.h>
35 #include <pakfire/parser.h>
36 #include <pakfire/private.h>
37 #include <pakfire/repo.h>
38 #include <pakfire/string.h>
39 #include <pakfire/util.h>
42 #define BASEURL "https://source.ipfire.org/source-3.x/"
44 #define PAKFIRE_MACROS_DIR "/usr/lib/pakfire/macros"
45 #define PAKFIRE_MACROS_GLOB_PATTERN PAKFIRE_MACROS_DIR "/*.macro"
47 static const char* pakfire_dist_excludes
[] = {
48 // Don't package any backup files
52 // Don't package any other package files
58 static int pakfire_makefile_set_defaults(struct pakfire
* pakfire
,
59 struct pakfire_parser
* parser
, const char* path
) {
64 pakfire_parser_set(parser
, NULL
, "epoch", "0", 0);
67 pakfire_parser_set(parser
, NULL
, "evr", "%{epoch}:%{version}-%{_release}", 0);
70 pakfire_parser_set(parser
, NULL
, "vendor", "%{DISTRO_VENDOR}", 0);
73 const char* name
= pakfire_get_distro_name(pakfire
);
75 pakfire_parser_set(parser
, NULL
, "DISTRO_NAME", name
, 0);
78 const char* id
= pakfire_get_distro_id(pakfire
);
80 pakfire_parser_set(parser
, NULL
, "DISTRO_SNAME", name
, 0);
83 const char* version_id
= pakfire_get_distro_version_id(pakfire
);
85 pakfire_parser_set(parser
, NULL
, "DISTRO_RELEASE", version_id
, 0);
88 const char* tag
= pakfire_get_distro_tag(pakfire
);
90 pakfire_parser_set(parser
, NULL
, "DISTRO_DISTTAG", tag
, 0);
93 const char* vendor
= pakfire_get_distro_vendor(pakfire
);
95 pakfire_parser_set(parser
, NULL
, "DISTRO_VENDOR", vendor
, 0);
98 const char* arch
= pakfire_get_arch(pakfire
);
100 pakfire_parser_set(parser
, NULL
, "DISTRO_ARCH", arch
, 0);
102 const char* platform
= pakfire_arch_platform(arch
);
104 pakfire_parser_set(parser
, NULL
, "DISTRO_PLATFORM", platform
, 0);
107 // Set DISTRO_MACHINE
108 r
= pakfire_arch_machine(buffer
, arch
, vendor
);
110 pakfire_parser_set(parser
, NULL
, "DISTRO_MACHINE", buffer
, 0);
112 // Set DISTRO_BUILDTARGET
113 r
= pakfire_arch_buildtarget(buffer
, arch
, vendor
);
115 pakfire_parser_set(parser
, NULL
, "DISTRO_BUILDTARGET", buffer
, 0);
120 const char* dirname
= pakfire_dirname(path
);
122 const char* root
= pakfire_get_path(pakfire
);
124 pakfire_parser_set(parser
, NULL
, "BASEDIR",
125 pakfire_path_relpath(root
, dirname
), 0);
128 long processors_online
= sysconf(_SC_NPROCESSORS_ONLN
);
130 // Set PARALLELISMFLAGS
131 if (processors_online
) {
132 pakfire_string_format(buffer
, "-j%ld", processors_online
);
133 pakfire_parser_set(parser
, "build", "PARALLELISMFLAGS", buffer
, 0);
139 int pakfire_read_makefile(struct pakfire_parser
** parser
, struct pakfire
* pakfire
,
140 const char* path
, struct pakfire_parser_error
** error
) {
143 *parser
= pakfire_parser_create(pakfire
, NULL
, NULL
, PAKFIRE_PARSER_FLAGS_EXPAND_COMMANDS
);
150 r
= pakfire_makefile_set_defaults(pakfire
, *parser
, path
);
156 DEBUG(pakfire
, "Searching for macros in %s\n", PAKFIRE_MACROS_GLOB_PATTERN
);
159 r
= glob(PAKFIRE_MACROS_GLOB_PATTERN
, 0, NULL
, &globmacros
);
175 ERROR(pakfire
, "glob() returned an unhandled error: %d\n", r
);
179 DEBUG(pakfire
, "Found %zu macro(s)\n", globmacros
.gl_pathc
);
182 for (unsigned int i
= 0; i
< globmacros
.gl_pathc
; i
++) {
184 r
= pakfire_parser_read_file(*parser
, globmacros
.gl_pathv
[i
], error
);
189 globfree(&globmacros
);
191 // Finally, parse the makefile
192 r
= pakfire_parser_read_file(*parser
, path
, error
);
194 ERROR(pakfire
, "Could not read makefile %s: %m\n", path
);
201 globfree(&globmacros
);
204 pakfire_parser_unref(*parser
);
211 static int pakfire_dist_create_downloader_and_mirrorlist(
212 struct pakfire
* pakfire
, struct pakfire_parser
* makefile
,
213 struct pakfire_downloader
** downloader
, struct pakfire_mirrorlist
** mirrorlist
) {
216 // Create the downloader
217 int r
= pakfire_downloader_create(downloader
, pakfire
);
219 ERROR(pakfire
, "Could not initialize downloader\n");
224 char* source_dl
= pakfire_parser_get(makefile
, NULL
, "source_dl");
226 // We do not need to create a mirrorlist if this isn't set
231 r
= pakfire_mirrorlist_create(mirrorlist
, pakfire
);
233 ERROR(pakfire
, "Could not create the mirrorlist\n");
238 const char* mirror
= strtok_r(source_dl
, " ", &p
);
241 r
= pakfire_mirrorlist_add_mirror(*mirrorlist
, mirror
);
245 mirror
= strtok_r(NULL
, " ", &p
);
258 static int pakfire_dist_add_source(struct pakfire
* pakfire
, struct pakfire_packager
* packager
,
259 struct pakfire_package
* pkg
, struct pakfire_downloader
* downloader
,
260 struct pakfire_mirrorlist
* mirrorlist
, const char* filename
) {
262 char archive_path
[PATH_MAX
];
263 char cache_path
[PATH_MAX
];
265 const char* name
= pakfire_package_get_string(pkg
, PAKFIRE_PKG_NAME
);
268 r
= pakfire_cache_path(pakfire
, cache_path
, "sources/%s/%s", name
, filename
);
272 // Download the file if it does not exist in the cache
273 if (access(cache_path
, R_OK
) != 0) {
274 r
= pakfire_downloader_retrieve(downloader
, BASEURL
, mirrorlist
,
275 NULL
, filename
, cache_path
, 0, NULL
, 0, 0);
280 pakfire_string_format(archive_path
, "/files/%s", filename
);
282 // Add file to package
283 return pakfire_packager_add(packager
, cache_path
, archive_path
);
286 static int pakfire_dist_add_sources(struct pakfire
* pakfire
, struct pakfire_packager
* packager
,
287 struct pakfire_package
* pkg
, struct pakfire_parser
* makefile
) {
289 char** sources
= pakfire_parser_get_split(makefile
, NULL
, "sources", ' ');
291 // Nothing to do if this variable is empty
295 struct pakfire_downloader
* downloader
= NULL
;
296 struct pakfire_mirrorlist
* mirrorlist
= NULL
;
298 // Create a downloader and mirrorlist
299 int r
= pakfire_dist_create_downloader_and_mirrorlist(pakfire
, makefile
,
300 &downloader
, &mirrorlist
);
304 // Add all files one by one
305 for (char** source
= sources
; *source
; source
++) {
306 DEBUG(pakfire
, "Adding source file %s\n", *source
);
308 r
= pakfire_dist_add_source(pakfire
, packager
, pkg
, downloader
, mirrorlist
, *source
);
310 ERROR(pakfire
, "Could not add '%s' to package: %m\n", *source
);
320 pakfire_downloader_unref(downloader
);
322 pakfire_mirrorlist_unref(mirrorlist
);
325 for (char** source
= sources
; *source
; source
++)
333 static int pakfire_dist_add_files(struct pakfire
* pakfire
, struct pakfire_packager
* packager
,
335 struct pakfire_filelist
* filelist
= NULL
;
338 // Find the parent directory
339 const char* dirname
= pakfire_dirname(path
);
343 DEBUG(pakfire
, "Adding all files in '%s' to package...\n", dirname
);
345 // Create a new filelist
346 r
= pakfire_filelist_create(&filelist
, pakfire
);
350 // Scan for any files
351 r
= pakfire_filelist_scan(filelist
, dirname
, NULL
, pakfire_dist_excludes
);
355 // Add all files to the package
356 r
= pakfire_packager_add_files(packager
, filelist
);
362 pakfire_filelist_unref(filelist
);
367 PAKFIRE_EXPORT
int pakfire_dist(struct pakfire
* pakfire
, const char* path
,
368 const char* target
, char** result
) {
369 struct pakfire_parser
* makefile
;
370 struct pakfire_parser_error
* error
= NULL
;
372 struct pakfire_packager
* packager
= NULL
;
373 struct pakfire_package
* pkg
= NULL
;
376 int r
= pakfire_read_makefile(&makefile
, pakfire
, path
, &error
);
379 pakfire_parser_error_unref(error
);
381 ERROR(pakfire
, "Could not read makefile: %m\n");
386 // The architecture is always "src"
387 r
= pakfire_parser_set(makefile
, NULL
, "arch", "src", 0);
389 ERROR(pakfire
, "Could not set architecture to 'src': %m\n");
393 // Get the package object
394 r
= pakfire_parser_create_package(makefile
, &pkg
, NULL
, NULL
, "src");
399 r
= pakfire_packager_create(&packager
, pakfire
, pkg
);
403 // Add all files in the directory
404 r
= pakfire_dist_add_files(pakfire
, packager
, path
);
408 // Add all source files (which might need to be downloaded)
409 r
= pakfire_dist_add_sources(pakfire
, packager
, pkg
, makefile
);
413 // Write the finished package
414 r
= pakfire_packager_finish_to_directory(packager
, target
, result
);
420 pakfire_packager_unref(packager
);
422 pakfire_package_unref(pkg
);
423 pakfire_parser_unref(makefile
);