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 #############################################################################*/
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/types.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 PAKFIRE_EXPORT
int pakfire_read_makefile(PakfireParser
* parser
, Pakfire pakfire
,
48 const char* path
, struct pakfire_parser_error
** error
) {
51 *parser
= pakfire_parser_create(pakfire
, NULL
, NULL
, PAKFIRE_PARSER_FLAGS_EXPAND_COMMANDS
);
58 char* dirname
= pakfire_dirname(path
);
60 const char* root
= pakfire_get_path(pakfire
);
62 pakfire_parser_set(*parser
, NULL
, "BASEDIR", pakfire_path_relpath(root
, dirname
));
68 DEBUG(pakfire
, "Searching for macros in %s\n", PAKFIRE_MACROS_GLOB_PATTERN
);
71 r
= glob(PAKFIRE_MACROS_GLOB_PATTERN
, 0, NULL
, &globmacros
);
87 ERROR(pakfire
, "glob() returned an unhandled error: %d\n", r
);
91 DEBUG(pakfire
, "Found %zu macro(s)\n", globmacros
.gl_pathc
);
94 for (unsigned int i
= 0; i
< globmacros
.gl_pathc
; i
++) {
96 r
= pakfire_parser_read_file(*parser
, globmacros
.gl_pathv
[i
], error
);
101 globfree(&globmacros
);
103 // Finally, parse the makefile
104 r
= pakfire_parser_read_file(*parser
, path
, error
);
111 globfree(&globmacros
);
114 pakfire_parser_unref(*parser
);
121 static int pakfire_dist_create_downloader_and_mirrorlist(
122 Pakfire pakfire
, PakfireParser makefile
,
123 struct pakfire_downloader
** downloader
, struct pakfire_mirrorlist
** mirrorlist
) {
124 // Create the downloader
125 int r
= pakfire_downloader_create(downloader
, pakfire
);
127 ERROR(pakfire
, "Could not initialize downloader\n");
132 char** source_dls
= pakfire_parser_get_split(makefile
, NULL
, "source_dl", ' ');
134 // We do not need to create a mirrorlist if this isn't set
139 r
= pakfire_mirrorlist_create(mirrorlist
, pakfire
);
141 ERROR(pakfire
, "Could not create the mirrorlist\n");
146 for (char** source_dl
= source_dls
; *source_dl
; source_dl
++) {
147 r
= pakfire_mirrorlist_add_mirror(*mirrorlist
, *source_dl
);
157 for (char** source_dl
= source_dls
; *source_dl
; source_dl
++)
165 static int pakfire_dist_add_source(Pakfire pakfire
, struct pakfire_packager
* packager
,
166 PakfirePackage pkg
, struct pakfire_downloader
* downloader
,
167 struct pakfire_mirrorlist
* mirrorlist
, const char* filename
) {
169 char archive_path
[PATH_MAX
];
170 char cache_path
[PATH_MAX
];
172 const char* name
= pakfire_package_get_name(pkg
);
173 pakfire_make_cache_path(pakfire
, cache_path
, "sources/%s/%s", name
, filename
);
175 // Download the file if it does not exist in the cache
176 if (access(cache_path
, R_OK
) != 0) {
177 r
= pakfire_downloader_retrieve(downloader
, BASEURL
, mirrorlist
,
178 NULL
, filename
, cache_path
, 0);
183 pakfire_string_format(archive_path
, "files/%s", filename
);
185 // Add file to package
186 return pakfire_packager_add(packager
, cache_path
, archive_path
);
189 static int pakfire_dist_add_sources(Pakfire pakfire
, struct pakfire_packager
* packager
,
190 PakfirePackage pkg
, PakfireParser makefile
) {
192 char** sources
= pakfire_parser_get_split(makefile
, NULL
, "sources", ' ');
194 // Nothing to do if this variable is empty
198 struct pakfire_downloader
* downloader
= NULL
;
199 struct pakfire_mirrorlist
* mirrorlist
= NULL
;
201 // Create a downloader and mirrorlist
202 int r
= pakfire_dist_create_downloader_and_mirrorlist(pakfire
, makefile
,
203 &downloader
, &mirrorlist
);
207 // Add all files one by one
208 for (char** source
= sources
; *source
; source
++) {
209 DEBUG(pakfire
, "Adding source file %s\n", *source
);
211 r
= pakfire_dist_add_source(pakfire
, packager
, pkg
, downloader
, mirrorlist
, *source
);
213 ERROR(pakfire
, "Could not add '%s' to package: %s\n", *source
, strerror(errno
));
223 pakfire_downloader_unref(downloader
);
225 pakfire_mirrorlist_unref(mirrorlist
);
228 for (char** source
= sources
; *source
; source
++)
236 static int pakfire_dist_add_files(Pakfire pakfire
, struct pakfire_packager
* packager
,
240 // Find the parent directory
241 char* dirname
= pakfire_dirname(path
);
245 DEBUG(pakfire
, "Adding all files in '%s' to package...\n", dirname
);
251 FTS
* f
= fts_open(paths
, FTS_NOCHDIR
|FTS_NOSTAT
, NULL
);
256 FTSENT
* fent
= fts_read(f
);
261 if (fent
->fts_info
& FTS_F
) {
262 const char* filename
= pakfire_path_relpath(dirname
, fent
->fts_path
);
266 DEBUG(pakfire
, "Adding '%s' to package...\n", filename
);
268 r
= pakfire_packager_add(packager
, fent
->fts_path
, filename
);
274 // If fts_read() encountered an error, errno will be set
292 PAKFIRE_EXPORT
int pakfire_dist(Pakfire pakfire
, const char* path
, const char* target
) {
293 PakfireParser makefile
;
294 struct pakfire_parser_error
* error
= NULL
;
296 struct pakfire_packager
* packager
= NULL
;
297 PakfirePackage pkg
= NULL
;
299 char tempfile
[PATH_MAX
] = "";
301 // Open the target directory
302 DIR* d
= opendir(target
);
309 int r
= pakfire_read_makefile(&makefile
, pakfire
, path
, &error
);
312 pakfire_parser_error_unref(error
);
317 PakfireRepo repo
= pakfire_get_repo(pakfire
, "@dummy");
321 // Get the package object
322 r
= pakfire_parser_create_package(makefile
, &pkg
, repo
, NULL
, "src");
327 r
= pakfire_packager_create(&packager
, pkg
);
331 // Add all files in the directory
332 r
= pakfire_dist_add_files(pakfire
, packager
, path
);
336 // Add all source files (which might need to be downloaded)
337 r
= pakfire_dist_add_sources(pakfire
, packager
, pkg
, makefile
);
341 snprintf(tempfile
, PATH_MAX
- 1, "%s/.pakfire-dist.XXXXXX", target
);
343 // Create a temporary result file
344 FILE* f
= pakfire_mktemp(tempfile
);
348 // Write the finished package
349 r
= pakfire_packager_finish(packager
, f
);
351 ERROR(pakfire
, "pakfire_packager_finish() failed: %s\n", strerror(errno
));
358 const char* filename
= pakfire_packager_filename(packager
);
362 // Move the temporary file to destination
363 r
= renameat(AT_FDCWD
, tempfile
, dfd
, filename
);
368 // Remove the temporary file
374 pakfire_packager_unref(packager
);
376 pakfire_package_unref(pkg
);
378 pakfire_repo_unref(repo
);
379 pakfire_parser_unref(makefile
);