1 /*#############################################################################
3 # Pakfire - The IPFire package management system #
4 # Copyright (C) 2013 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 #############################################################################*/
24 #include <solv/transaction.h>
26 #include <pakfire/archive.h>
27 #include <pakfire/db.h>
28 #include <pakfire/downloader.h>
29 #include <pakfire/execute.h>
30 #include <pakfire/i18n.h>
31 #include <pakfire/logging.h>
32 #include <pakfire/package.h>
33 #include <pakfire/pakfire.h>
34 #include <pakfire/private.h>
35 #include <pakfire/repo.h>
36 #include <pakfire/transaction.h>
37 #include <pakfire/types.h>
38 #include <pakfire/util.h>
40 struct pakfire_transaction
{
44 Transaction
* transaction
;
46 PakfireArchive
* archives
;
47 PakfirePackage
* packages
;
51 static pakfire_step_type_t
pakfire_transaction_get_step_type(
52 struct pakfire_transaction
* transaction
, PakfirePackage pkg
) {
53 int type
= transaction_type(transaction
->transaction
, pakfire_package_id(pkg
),
54 SOLVER_TRANSACTION_SHOW_ACTIVE
|SOLVER_TRANSACTION_CHANGE_IS_REINSTALL
);
56 // Translate solver types into our own types
58 case SOLVER_TRANSACTION_INSTALL
:
59 case SOLVER_TRANSACTION_MULTIINSTALL
:
60 return PAKFIRE_STEP_INSTALL
;
62 case SOLVER_TRANSACTION_REINSTALL
:
63 case SOLVER_TRANSACTION_MULTIREINSTALL
:
64 return PAKFIRE_STEP_REINSTALL
;
66 case SOLVER_TRANSACTION_ERASE
:
67 return PAKFIRE_STEP_ERASE
;
69 case SOLVER_TRANSACTION_DOWNGRADE
:
70 return PAKFIRE_STEP_DOWNGRADE
;
72 case SOLVER_TRANSACTION_UPGRADE
:
73 return PAKFIRE_STEP_UPGRADE
;
75 case SOLVER_TRANSACTION_OBSOLETES
:
76 return PAKFIRE_STEP_OBSOLETE
;
78 // Anything we don't care about
79 case SOLVER_TRANSACTION_IGNORE
:
80 case SOLVER_TRANSACTION_REINSTALLED
:
81 case SOLVER_TRANSACTION_DOWNGRADED
:
83 return PAKFIRE_STEP_IGNORE
;
87 static void pakfire_transaction_free_archives_and_packages(
88 struct pakfire_transaction
* transaction
) {
89 if (transaction
->archives
) {
90 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
91 if (transaction
->archives
[i
])
92 pakfire_archive_unref(transaction
->archives
[i
]);
93 free(transaction
->archives
);
95 transaction
->archives
= NULL
;
98 if (transaction
->packages
) {
99 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
100 if (transaction
->packages
[i
])
101 pakfire_package_unref(transaction
->packages
[i
]);
102 free(transaction
->packages
);
104 transaction
->packages
= NULL
;
108 static void pakfire_transaction_free(struct pakfire_transaction
* transaction
) {
109 pakfire_transaction_free_archives_and_packages(transaction
);
111 transaction_free(transaction
->transaction
);
113 pakfire_unref(transaction
->pakfire
);
117 static int pakfire_transaction_import_transaction(
118 struct pakfire_transaction
* transaction
, Transaction
* t
) {
119 // Free any previous content
120 pakfire_transaction_free_archives_and_packages(transaction
);
122 // Order the transaction
123 transaction_order(t
, 0);
126 transaction
->num
= t
->steps
.count
;
128 // Allocate space for packages
129 transaction
->packages
= calloc(transaction
->num
, sizeof(*transaction
->packages
));
130 if (!transaction
->packages
)
133 // Allocate space for archives
134 transaction
->archives
= calloc(transaction
->num
, sizeof(*transaction
->archives
));
135 if (!transaction
->archives
)
138 // Create all packages
139 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
140 transaction
->packages
[i
] = pakfire_package_create_from_solvable(
141 transaction
->pakfire
, t
->steps
.elements
[i
]);
147 int pakfire_transaction_create(struct pakfire_transaction
** transaction
,
148 Pakfire pakfire
, Transaction
* trans
) {
149 struct pakfire_transaction
* t
= calloc(1, sizeof(*t
));
153 // Store reference to Pakfire
154 t
->pakfire
= pakfire_ref(pakfire
);
156 // Initialize the reference counter
159 // Clone the transaction to keep a copy of it
160 t
->transaction
= transaction_create_clone(trans
);
164 // Import transaction
165 int r
= pakfire_transaction_import_transaction(t
, t
->transaction
);
173 pakfire_transaction_free(t
);
178 PAKFIRE_EXPORT
struct pakfire_transaction
* pakfire_transaction_ref(
179 struct pakfire_transaction
* transaction
) {
180 transaction
->nrefs
++;
185 PAKFIRE_EXPORT
struct pakfire_transaction
* pakfire_transaction_unref(
186 struct pakfire_transaction
* transaction
) {
187 if (--transaction
->nrefs
> 0)
190 pakfire_transaction_free(transaction
);
194 PAKFIRE_EXPORT
size_t pakfire_transaction_count(struct pakfire_transaction
* transaction
) {
195 return transaction
->num
;
198 static ssize_t
pakfire_transaction_installsizechange(struct pakfire_transaction
* transaction
) {
199 ssize_t sizechange
= transaction_calc_installsizechange(transaction
->transaction
);
201 // Convert from kbytes to bytes
202 return sizechange
* 1024;
205 PAKFIRE_EXPORT ssize_t
pakfire_transaction_downloadsize(struct pakfire_transaction
* transaction
) {
208 for (unsigned int i
= 0; i
< transaction
->num
; i
++)
209 size
+= pakfire_package_get_downloadsize(transaction
->packages
[i
]);
214 static void pakfire_transaction_add_headline(char** str
, size_t width
, const char* headline
) {
215 asprintf(str
, "%s%s\n", *str
, headline
);
218 static void pakfire_transaction_add_newline(char** str
, size_t width
) {
219 asprintf(str
, "%s\n", *str
);
222 static void pakfire_transaction_add_line(char** str
, size_t width
, const char* name
,
223 const char* arch
, const char* version
, const char* repo
, const char* size
) {
224 // XXX need to adapt to size
225 asprintf(str
, "%s %-21s %-8s %-21s %-18s %6s \n", *str
, name
, arch
, version
, repo
, size
);
228 static void pakfire_transaction_add_package(char** str
, size_t width
, PakfirePackage pkg
) {
231 PakfireRepo repo
= pakfire_package_get_repo(pkg
);
234 pakfire_format_size(size
, sizeof(size
) - 1, pakfire_package_get_size(pkg
));
236 pakfire_transaction_add_line(str
, width
,
237 pakfire_package_get_name(pkg
),
238 pakfire_package_get_arch(pkg
),
239 pakfire_package_get_evr(pkg
),
240 pakfire_repo_get_name(repo
),
244 pakfire_repo_unref(repo
);
247 static void pakfire_transaction_add_package_change(char** str
, size_t width
,
248 PakfirePackage old_pkg
, PakfirePackage new_pkg
) {
249 // Print the new package first
250 pakfire_transaction_add_package(str
, width
, new_pkg
);
252 asprintf(str
, "%s --> %s\n", *str
, pakfire_package_get_nevra(old_pkg
));
255 static void pakfire_transaction_add_separator(char** str
, size_t width
) {
257 asprintf(str
, "%s=", *str
);
260 asprintf(str
, "%s\n", *str
);
263 static void pakfire_transaction_add_usage_line(char** str
, size_t width
, const char* headline
, ssize_t size
) {
265 pakfire_format_size(buffer
, sizeof(buffer
) - 1, size
);
267 asprintf(str
, "%s%-21s: %s\n", *str
, headline
, buffer
);
270 PAKFIRE_EXPORT
char* pakfire_transaction_dump(struct pakfire_transaction
* transaction
, size_t width
) {
274 Pool
* pool
= transaction
->transaction
->pool
;
276 SOLVER_TRANSACTION_SHOW_OBSOLETES
|
277 SOLVER_TRANSACTION_OBSOLETE_IS_UPGRADE
;
280 pakfire_transaction_add_separator(&string
, width
);
281 pakfire_transaction_add_line(&string
, width
,
288 pakfire_transaction_add_separator(&string
, width
);
291 queue_init(&classes
);
294 transaction_classify(transaction
->transaction
, mode
, &classes
);
300 The classes queue now contains a list of all classes as a tuple of:
302 * The number of packages in this class
303 * The from ID (for arch/vendor change)
304 * The to ID (for arch/vendor change)
306 for (int i
= 0; i
< classes
.count
; i
+= 4) {
307 Id
class = classes
.elements
[i
];
308 unsigned int count
= classes
.elements
[i
+1];
310 const char* from
= pool_id2str(pool
, classes
.elements
[i
+2]);
311 const char* to
= pool_id2str(pool
, classes
.elements
[i
+3]);
314 case SOLVER_TRANSACTION_INSTALL
:
316 pakfire_string_format(headline
, _("Installing %u packages:"), count
);
318 pakfire_string_set(headline
, _("Installing one package:"));
321 case SOLVER_TRANSACTION_REINSTALLED
:
323 pakfire_string_format(headline
, _("Reinstalling %u packages:"), count
);
325 pakfire_string_set(headline
, _("Reinstalling one package:"));
328 case SOLVER_TRANSACTION_ERASE
:
330 pakfire_string_format(headline
, _("Removing %u packages:"), count
);
332 pakfire_string_set(headline
, _("Removing one package:"));
335 case SOLVER_TRANSACTION_UPGRADED
:
337 pakfire_string_format(headline
, _("Updating %u packages:"), count
);
339 pakfire_string_set(headline
, _("Updating one package:"));
342 case SOLVER_TRANSACTION_DOWNGRADED
:
344 pakfire_string_format(headline
, _("Downgrading %u packages:"), count
);
346 pakfire_string_set(headline
, _("Downgrading one package:"));
349 case SOLVER_TRANSACTION_CHANGED
:
351 pakfire_string_format(headline
, _("Changing %u packages:"), count
);
353 pakfire_string_set(headline
, _("Changing one package:"));
356 case SOLVER_TRANSACTION_ARCHCHANGE
:
358 pakfire_string_format(headline
,
359 _("%u architecture changes from '%s' to '%s':"), count
, from
, to
);
361 pakfire_string_format(headline
,
362 _("One architecture change from '%s' to '%s':"), from
, to
);
365 case SOLVER_TRANSACTION_VENDORCHANGE
:
367 pakfire_string_format(headline
,
368 _("%u vendor changes from '%s' to '%s':"), count
, from
, to
);
370 pakfire_string_format(headline
,
371 _("One vendor change from '%s' to '%s':"), from
, to
);
374 case SOLVER_TRANSACTION_IGNORE
:
378 // Show what we are doing
379 pakfire_transaction_add_headline(&string
, width
, headline
);
381 // Fetch packages in this class
382 transaction_classify_pkgs(transaction
->transaction
, mode
, class,
383 classes
.elements
[i
+2], classes
.elements
[i
+3], &pkgs
);
386 for (int j
= 0; j
< pkgs
.count
; j
++) {
387 PakfirePackage old_pkg
= pakfire_package_create_from_solvable(
388 transaction
->pakfire
, pkgs
.elements
[j
]);
389 PakfirePackage new_pkg
= NULL
;
392 case SOLVER_TRANSACTION_UPGRADED
:
393 case SOLVER_TRANSACTION_DOWNGRADED
:
394 new_pkg
= pakfire_package_create_from_solvable(transaction
->pakfire
,
395 transaction_obs_pkg(transaction
->transaction
, pkgs
.elements
[j
]));
397 pakfire_transaction_add_package_change(&string
, width
, old_pkg
, new_pkg
);
401 pakfire_transaction_add_package(&string
, width
, old_pkg
);
405 pakfire_package_unref(old_pkg
);
407 pakfire_package_unref(new_pkg
);
411 pakfire_transaction_add_newline(&string
, width
);
414 queue_free(&classes
);
418 pakfire_transaction_add_headline(&string
, width
, _("Transaction Summary"));
419 pakfire_transaction_add_separator(&string
, width
);
421 // How much do we need to download?
422 size_t downloadsize
= pakfire_transaction_downloadsize(transaction
);
424 if (downloadsize
> 0)
425 pakfire_transaction_add_usage_line(&string
, width
,
426 _("Total Download Size"), downloadsize
);
428 // How much more space do we need?
429 ssize_t sizechange
= pakfire_transaction_installsizechange(transaction
);
430 pakfire_transaction_add_usage_line(&string
, width
,
431 (sizechange
>= 0) ? _("Installed Size") : _("Freed Size"), sizechange
);
433 // Remove trailing newline
434 pakfire_remove_trailing_newline(string
);
436 DEBUG(transaction
->pakfire
, "Transaction: %s\n", string
);
441 static int pakfire_transaction_verify(struct pakfire_transaction
* transaction
,
442 PakfirePackage pkg
, PakfireArchive archive
) {
443 // Nothing to do if this step does not have an archive
447 // Verify the archive
448 pakfire_archive_verify_status_t status
= pakfire_archive_verify(archive
);
452 const char* error
= pakfire_archive_verify_strerror(status
);
453 ERROR(transaction
->pakfire
, "Archive verification failed: %s\n", error
);
459 static int pakfire_transaction_run_script(struct pakfire_transaction
* transaction
,
460 struct pakfire_db
* db
, pakfire_scriptlet_type type
, PakfirePackage pkg
, PakfireArchive archive
) {
461 struct pakfire_scriptlet
* scriptlet
= NULL
;
463 // Fetch scriptlet from archive if possible
465 scriptlet
= pakfire_archive_get_scriptlet(archive
, type
);
467 scriptlet
= pakfire_db_get_scriptlet(db
, pkg
, type
);
469 // Nothing to do if there are no scriptlets
474 DEBUG(transaction
->pakfire
, "Found scriptlet:\n%.*s",
475 (int)scriptlet
->size
, (const char*)scriptlet
->data
);
477 // Detect what kind of script this is and run it
478 if (pakfire_scriptlet_is_shell_script(scriptlet
)) {
479 pakfire_execute_script(transaction
->pakfire
, scriptlet
->data
, scriptlet
->size
,
480 NULL
, 0, NULL
, NULL
);
482 ERROR(transaction
->pakfire
, "Scriptlet is of an unknown kind\n");
488 static int pakfire_transaction_extract(struct pakfire_transaction
* transaction
,
489 PakfirePackage pkg
, PakfireArchive archive
) {
490 // Extract payload to the root of the Pakfire instance
491 int r
= pakfire_archive_extract(archive
, NULL
);
493 ERROR(transaction
->pakfire
, "Could not extract package %s: %s\n",
494 pakfire_package_get_nevra(pkg
), strerror(errno
));
498 // Is it necessary to call ldconfig?
499 PakfireFilelist filelist
= pakfire_archive_get_filelist(archive
);
501 int need_ldconfig
= pakfire_filelist_contains(filelist
, "*/lib*.so.?");
503 // Update the runtime linker cache
505 pakfire_execute_ldconfig(transaction
->pakfire
);
507 pakfire_filelist_unref(filelist
);
513 static int pakfire_transaction_erase(struct pakfire_transaction
* transaction
,
514 PakfirePackage pkg
, PakfireArchive archive
) {
515 // Update the runtime linker cache after all files have been removed
516 pakfire_execute_ldconfig(transaction
->pakfire
);
521 static const char* pakfire_action_type_string(pakfire_action_type_t type
) {
523 case PAKFIRE_ACTION_NOOP
:
526 case PAKFIRE_ACTION_VERIFY
:
529 case PAKFIRE_ACTION_EXECUTE
:
532 case PAKFIRE_ACTION_PRETRANS
:
535 case PAKFIRE_ACTION_POSTTRANS
:
542 static int pakfire_transaction_run_step(struct pakfire_transaction
* transaction
,
543 struct pakfire_db
* db
, const pakfire_action_type_t action
, PakfirePackage pkg
, PakfireArchive archive
) {
549 DEBUG(transaction
->pakfire
, "Running %s for %s\n",
550 pakfire_action_type_string(action
), pakfire_package_get_nevra(pkg
));
552 pakfire_step_type_t type
= pakfire_transaction_get_step_type(transaction
, pkg
);
557 case PAKFIRE_ACTION_VERIFY
:
558 r
= pakfire_transaction_verify(transaction
, pkg
, archive
);
561 // Run the pre-transaction scripts
562 case PAKFIRE_ACTION_PRETRANS
:
564 case PAKFIRE_STEP_INSTALL
:
565 case PAKFIRE_STEP_REINSTALL
:
566 r
= pakfire_transaction_run_script(transaction
, db
,
567 PAKFIRE_SCRIPTLET_PRETRANSIN
, pkg
, archive
);
570 case PAKFIRE_STEP_UPGRADE
:
571 case PAKFIRE_STEP_DOWNGRADE
:
572 r
= pakfire_transaction_run_script(transaction
, db
,
573 PAKFIRE_SCRIPTLET_PRETRANSUP
, pkg
, archive
);
576 case PAKFIRE_STEP_ERASE
:
577 case PAKFIRE_STEP_OBSOLETE
:
578 r
= pakfire_transaction_run_script(transaction
, db
,
579 PAKFIRE_SCRIPTLET_PRETRANSUN
, pkg
, archive
);
582 case PAKFIRE_STEP_IGNORE
:
587 // Run the post-transaction scripts
588 case PAKFIRE_ACTION_POSTTRANS
:
590 case PAKFIRE_STEP_INSTALL
:
591 case PAKFIRE_STEP_REINSTALL
:
592 r
= pakfire_transaction_run_script(transaction
, db
,
593 PAKFIRE_SCRIPTLET_POSTTRANSIN
, pkg
, archive
);
596 case PAKFIRE_STEP_UPGRADE
:
597 case PAKFIRE_STEP_DOWNGRADE
:
598 r
= pakfire_transaction_run_script(transaction
, db
,
599 PAKFIRE_SCRIPTLET_POSTTRANSUP
, pkg
, archive
);
602 case PAKFIRE_STEP_ERASE
:
603 case PAKFIRE_STEP_OBSOLETE
:
604 r
= pakfire_transaction_run_script(transaction
, db
,
605 PAKFIRE_SCRIPTLET_POSTTRANSUN
, pkg
, archive
);
608 case PAKFIRE_STEP_IGNORE
:
613 // Execute the action of this script
614 case PAKFIRE_ACTION_EXECUTE
:
616 case PAKFIRE_STEP_INSTALL
:
617 case PAKFIRE_STEP_REINSTALL
:
618 r
= pakfire_transaction_run_script(transaction
, db
,
619 PAKFIRE_SCRIPTLET_PREIN
, pkg
, archive
);
623 r
= pakfire_transaction_extract(transaction
, pkg
, archive
);
627 // Remove package metadata first when reinstalling
628 if (type
== PAKFIRE_STEP_REINSTALL
) {
629 r
= pakfire_db_remove_package(db
, pkg
);
634 r
= pakfire_db_add_package(db
, pkg
, archive
);
638 r
= pakfire_transaction_run_script(transaction
, db
,
639 PAKFIRE_SCRIPTLET_POSTIN
, pkg
, archive
);
642 case PAKFIRE_STEP_UPGRADE
:
643 case PAKFIRE_STEP_DOWNGRADE
:
644 r
= pakfire_transaction_run_script(transaction
, db
,
645 PAKFIRE_SCRIPTLET_PREUP
, pkg
, archive
);
649 r
= pakfire_transaction_extract(transaction
, pkg
, archive
);
653 r
= pakfire_db_add_package(db
, pkg
, archive
);
657 r
= pakfire_transaction_run_script(transaction
, db
,
658 PAKFIRE_SCRIPTLET_POSTUP
, pkg
, archive
);
661 case PAKFIRE_STEP_ERASE
:
662 case PAKFIRE_STEP_OBSOLETE
:
663 r
= pakfire_transaction_run_script(transaction
, db
,
664 PAKFIRE_SCRIPTLET_PREUN
, pkg
, archive
);
668 r
= pakfire_transaction_erase(transaction
, pkg
, archive
);
672 r
= pakfire_db_remove_package(db
, pkg
);
676 r
= pakfire_transaction_run_script(transaction
, db
,
677 PAKFIRE_SCRIPTLET_POSTUN
, pkg
, archive
);
680 case PAKFIRE_STEP_IGNORE
:
686 case PAKFIRE_ACTION_NOOP
:
691 ERROR(transaction
->pakfire
, "Step has failed: %s\n", strerror(r
));
696 static int pakfire_transaction_run_steps(struct pakfire_transaction
* transaction
,
697 struct pakfire_db
* db
, const pakfire_action_type_t action
) {
700 // Walk through all steps
701 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
702 r
= pakfire_transaction_run_step(transaction
, db
, action
,
703 transaction
->packages
[i
], transaction
->archives
[i
]);
705 // End loop if action was unsuccessful
707 DEBUG(transaction
->pakfire
, "Step %d failed: %s\n", i
, strerror(errno
));
715 static int pakfire_transaction_open_archives(struct pakfire_transaction
* transaction
) {
716 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
717 PakfirePackage pkg
= transaction
->packages
[i
];
720 pakfire_step_type_t type
= pakfire_transaction_get_step_type(transaction
, pkg
);
722 // Do we need the archive?
724 case PAKFIRE_STEP_INSTALL
:
725 case PAKFIRE_STEP_REINSTALL
:
726 case PAKFIRE_STEP_UPGRADE
:
727 case PAKFIRE_STEP_DOWNGRADE
:
728 case PAKFIRE_STEP_OBSOLETE
:
731 case PAKFIRE_STEP_ERASE
:
732 case PAKFIRE_STEP_IGNORE
:
736 transaction
->archives
[i
] = pakfire_package_get_archive(pkg
);
737 if (!transaction
->archives
[i
]) {
738 ERROR(transaction
->pakfire
, "Could not open archive for %s: %s\n",
739 pakfire_package_get_nevra(pkg
), strerror(errno
));
747 PAKFIRE_EXPORT
int pakfire_transaction_run(struct pakfire_transaction
* transaction
) {
748 PakfireRepo repo
= NULL
;
749 struct pakfire_db
* db
;
752 DEBUG(transaction
->pakfire
, "Running Transaction %p\n", transaction
);
755 r
= pakfire_transaction_open_archives(transaction
);
760 r
= pakfire_db_open(&db
, transaction
->pakfire
, PAKFIRE_DB_READWRITE
);
762 ERROR(transaction
->pakfire
, "Could not open the database\n");
767 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_VERIFY
);
771 // Execute all pre transaction actions
772 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_PRETRANS
);
776 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_EXECUTE
);
780 // Execute all post transaction actions
781 r
= pakfire_transaction_run_steps(transaction
, db
, PAKFIRE_ACTION_POSTTRANS
);
785 DEBUG(transaction
->pakfire
, "The transaction has finished successfully\n");
787 // Reload database for next transaction
789 repo
= pakfire_get_installed_repo(transaction
->pakfire
);
793 // Reload the database
794 r
= pakfire_db_load(db
, repo
);
798 pakfire_repo_unref(repo
);
799 pakfire_db_unref(db
);
804 static int pakfire_transaction_download_package(struct pakfire_transaction
* transaction
,
805 struct pakfire_downloader
* downloader
, PakfirePackage pkg
) {
807 PakfireRepo repo
= NULL
;
808 struct pakfire_mirrorlist
* mirrorlist
= NULL
;
810 // Fetch the repository to download from
811 repo
= pakfire_package_get_repo(pkg
);
816 const char* baseurl
= pakfire_repo_get_baseurl(repo
);
819 mirrorlist
= pakfire_repo_get_mirrorlist(repo
);
821 // Where to store the package?
822 const char* path
= pakfire_package_get_path(pkg
);
826 // What file to download?
827 const char* filename
= pakfire_package_get_filename(pkg
);
831 const char* nevra
= pakfire_package_get_nevra(pkg
);
835 // Add transfer to downloader
836 r
= pakfire_downloader_add_transfer(downloader
, baseurl
, mirrorlist
,
837 nevra
, filename
, path
, 0);
841 pakfire_mirrorlist_unref(mirrorlist
);
843 pakfire_repo_unref(repo
);
848 static int pakfire_transaction_package_needs_download(
849 struct pakfire_transaction
* transaction
, PakfirePackage pkg
) {
850 pakfire_step_type_t type
= pakfire_transaction_get_step_type(transaction
, pkg
);
852 case PAKFIRE_STEP_INSTALL
:
853 case PAKFIRE_STEP_REINSTALL
:
854 case PAKFIRE_STEP_DOWNGRADE
:
855 case PAKFIRE_STEP_UPGRADE
:
858 // No need to download for these steps
863 // No download required if this package is already installed
864 if (pakfire_package_is_installed(pkg
))
867 const char* path
= pakfire_package_get_path(pkg
);
869 // Does the file exist?
870 int r
= access(path
, R_OK
);
874 // This package needs to be downloaded
878 PAKFIRE_EXPORT
int pakfire_transaction_download(struct pakfire_transaction
* transaction
) {
879 struct pakfire_downloader
* downloader
;
882 // Initialize the downloader
883 r
= pakfire_downloader_create(&downloader
, transaction
->pakfire
);
885 ERROR(transaction
->pakfire
, "Could not initialize downloader: %s\n",
890 // Add all packages that need to be downloaded
891 for (unsigned int i
= 0; i
< transaction
->num
; i
++) {
892 PakfirePackage pkg
= transaction
->packages
[i
];
894 if (!pakfire_transaction_package_needs_download(transaction
, pkg
))
898 r
= pakfire_transaction_download_package(transaction
, downloader
, pkg
);
903 // Run the downloader
904 r
= pakfire_downloader_run(downloader
);
907 pakfire_downloader_unref(downloader
);