2 * Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
15 #include <package/PackageInfo.h>
16 #include <package/PackageResolvable.h>
17 #include <package/PackageResolvableExpression.h>
18 #include <package/RepositoryCache.h>
21 using namespace BPackageKit
;
24 typedef std::list
<BPackageResolvable
*> ProvidesList
;
27 static const char* sProgramName
= "update_package_requires";
30 #define DIE(result, msg...) \
32 fprintf(stderr, "*** " msg); \
33 fprintf(stderr, " : %s\n", strerror(result)); \
39 print_usage_and_exit(bool error
)
41 fprintf(error
? stderr
: stdout
,
42 "Usage: %s <package info> <repository>\n"
43 "Updates the versions in the \"requires\" list of the given package\n"
44 "info file using the available package information from the given\n"
45 "repository cache file <repository>.\n",
52 update_requires_expression(BPackageResolvableExpression
& expression
,
53 const ProvidesList
& providesList
)
55 // find the best-matching provides
56 BPackageResolvable
* bestProvides
= NULL
;
57 for (ProvidesList::const_iterator it
= providesList
.begin();
58 it
!= providesList
.end(); ++it
) {
59 BPackageResolvable
* provides
= *it
;
60 if (!expression
.Matches(*provides
))
63 if (bestProvides
== NULL
|| bestProvides
->Version().InitCheck() != B_OK
64 || (provides
->Version().InitCheck() == B_OK
65 && provides
->Version().Compare(bestProvides
->Version()) > 0)) {
66 bestProvides
= provides
;
70 if (bestProvides
== NULL
|| bestProvides
->Version().InitCheck() != B_OK
)
73 // Update the expression. Enforce the minimum found version, if the requires
74 // has no version requirement or also a minimum. Otherwise enforce the exact
76 BPackageResolvableOperator newOperator
= B_PACKAGE_RESOLVABLE_OP_EQUAL
;
77 switch (expression
.Operator()) {
78 case B_PACKAGE_RESOLVABLE_OP_LESS
:
79 case B_PACKAGE_RESOLVABLE_OP_LESS_EQUAL
:
80 case B_PACKAGE_RESOLVABLE_OP_EQUAL
:
81 case B_PACKAGE_RESOLVABLE_OP_NOT_EQUAL
:
83 case B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL
:
84 case B_PACKAGE_RESOLVABLE_OP_GREATER
:
85 case B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT
:
86 newOperator
= B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL
;
90 expression
.SetTo(expression
.Name(), newOperator
, bestProvides
->Version());
95 main(int argc
, const char* const* argv
)
98 print_usage_and_exit(true);
100 if (strcmp(argv
[1], "-h") == 0 || strcmp(argv
[1], "--help") == 0)
101 print_usage_and_exit(false);
103 const char* const packageInfoPath
= argv
[1];
104 const char* const repositoryCachePath
= argv
[2];
106 // read the repository cache
107 BRepositoryCache repositoryCache
;
108 status_t error
= repositoryCache
.SetTo(repositoryCachePath
);
110 DIE(error
, "failed to read repository cache file \"%s\"",
111 repositoryCachePath
);
114 // create a map for all provides (name -> resolvable list)
115 typedef std::map
<BString
, ProvidesList
> ProvidesMap
;
117 ProvidesMap providesMap
;
119 for (BRepositoryCache::Iterator it
= repositoryCache
.GetIterator();
120 const BPackageInfo
* info
= it
.Next();) {
121 const BObjectList
<BPackageResolvable
>& provides
= info
->ProvidesList();
122 int32 count
= provides
.CountItems();
123 for (int32 i
= 0; i
< count
; i
++) {
124 BPackageResolvable
* resolvable
= provides
.ItemAt(i
);
125 ProvidesList
& providesList
= providesMap
[resolvable
->Name()];
126 providesList
.push_back(resolvable
);
130 // load the package info
131 BPackageInfo packageInfo
;
132 error
= packageInfo
.ReadFromConfigFile(packageInfoPath
);
134 DIE(error
, "failed to read package info file \"%s\"", packageInfoPath
);
136 // clone the package info's requires list
137 typedef std::list
<BPackageResolvableExpression
> RequiresList
;
138 RequiresList requiresList
;
139 int32 requiresCount
= packageInfo
.RequiresList().CountItems();
140 for (int32 i
= 0; i
< requiresCount
; i
++)
141 requiresList
.push_back(*packageInfo
.RequiresList().ItemAt(i
));
143 // rebuild the requires list with updated versions
144 packageInfo
.ClearRequiresList();
145 for (RequiresList::iterator it
= requiresList
.begin();
146 it
!= requiresList
.end(); ++it
) {
147 BPackageResolvableExpression expression
= *it
;
148 ProvidesMap::iterator foundIt
= providesMap
.find(expression
.Name());
149 if (foundIt
!= providesMap
.end())
150 update_requires_expression(expression
, foundIt
->second
);
152 error
= packageInfo
.AddRequires(expression
);
154 DIE(error
, "failed to add requires item to package info");
157 // write updated package info
158 BString configString
;
159 error
= packageInfo
.GetConfigString(configString
);
161 DIE(error
, "failed to get updated package info string");
163 FILE* file
= fopen(packageInfoPath
, "w");
165 DIE(errno
, "failed to open package info file \"%s\" for writing",
169 if (fwrite(configString
.String(), configString
.Length(), 1, file
) != 1) {
170 DIE(errno
, "failed to write updated package info file \"%s\"",