Skip to content

Commit

Permalink
Update requires entries for the packages we build
Browse files Browse the repository at this point in the history
* Add build tool update_package_requires. Given a package info file and
  a repository cache file, it updates the minimum versions of the
  requires entries of the package info file according to what is
  provided by the repository.
* PreprocessPackageInfo rule: Use update_package_requires (with the
  HaikuPorts repository file).
  • Loading branch information
weinhold committed Oct 30, 2013
1 parent a4bdd98 commit 5774110
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 3 deletions.
18 changes: 16 additions & 2 deletions build/jam/PackageRules
Expand Up @@ -58,14 +58,23 @@ rule PreprocessPackageInfo source : directory : architecture
}

local revisionFile = [ DetermineHaikuRevision ] ;
local updateRequiresFiles ;
local haikuPortsRepositoryFile ;
if ! $(HAIKU_BOOTSTRAP_BUILD) {
updateRequiresFiles =
<build>update_package_requires
[ on <repository>HaikuPorts return $(HAIKU_REPOSITORY_CACHE_FILE) ]
;
}

MakeLocate $(target) : $(directory) ;
Depends $(target) : $(source) $(revisionFile) ;
Depends $(target) : $(source) $(revisionFile) $(updateRequiresFiles) ;

CCDEFS on $(target) = [ FDefines $(defines) ] ;
HAIKU_SED_REPLACEMENTS on $(target) = "-e s,$(sedReplacements),g" ;

PreprocessPackageInfo1 $(target) : $(source) $(revisionFile) ;
PreprocessPackageInfo1 $(target) : $(source) $(revisionFile)
$(updateRequiresFiles) ;

return $(target) ;
}
Expand All @@ -77,6 +86,11 @@ actions PreprocessPackageInfo1
sed $(HAIKU_SED_REPLACEMENTS) \
-e s,%HAIKU_VERSION%,$(HAIKU_VERSION)_${revision:-0}-1, < $(2[1]) \
| $(HOST_CC) -E -w $(CCDEFS) - -o $(1)

if [ -n "$(2[4]:E)" ]; then
$(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR)
"$(2[3])" "$(1)" "$(2[4])" || exit 1
fi
}


Expand Down
3 changes: 2 additions & 1 deletion src/tools/Jamfile
Expand Up @@ -109,7 +109,8 @@ SubInclude HAIKU_TOP src tools remote_disk_server ;
SubInclude HAIKU_TOP src tools resattr ;
SubInclude HAIKU_TOP src tools rman ;
SubInclude HAIKU_TOP src tools translation ;
SubInclude HAIKU_TOP src tools unflatten ;
SubInclude HAIKU_TOP src tools unzip ;
SubInclude HAIKU_TOP src tools update_package_requires ;
SubInclude HAIKU_TOP src tools vmdkimage ;
SubInclude HAIKU_TOP src tools unflatten ;
SubInclude HAIKU_TOP src tools zip ;
11 changes: 11 additions & 0 deletions src/tools/update_package_requires/Jamfile
@@ -0,0 +1,11 @@
SubDir HAIKU_TOP src tools update_package_requires ;

UsePrivateBuildHeaders shared ;

USES_BE_API on <build>update_package_requires = true ;

BuildPlatformMain <build>update_package_requires :
update_package_requires.cpp
:
libpackage_build.so $(HOST_LIBBE) $(HOST_LIBSUPC++) $(HOST_LIBSTDC++)
;
177 changes: 177 additions & 0 deletions src/tools/update_package_requires/update_package_requires.cpp
@@ -0,0 +1,177 @@
/*
* Copyright 2013, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/


#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <list>
#include <map>

#include <package/PackageInfo.h>
#include <package/PackageResolvable.h>
#include <package/PackageResolvableExpression.h>
#include <package/RepositoryCache.h>


using namespace BPackageKit;


typedef std::list<BPackageResolvable*> ProvidesList;


static const char* sProgramName = "update_package_requires";


#define DIE(result, msg...) \
do { \
fprintf(stderr, "*** " msg); \
fprintf(stderr, " : %s\n", strerror(result)); \
exit(5); \
} while(0)


static void
print_usage_and_exit(bool error)
{
fprintf(error ? stderr : stdout,
"Usage: %s <package info> <repository>\n"
"Updates the versions in the \"requires\" list of the given package\n"
"info file using the available package information from the given\n"
"repository cache file <repository>.\n",
sProgramName);
exit(error ? 1 : 0);
}


static void
update_requires_expression(BPackageResolvableExpression& expression,
const ProvidesList& providesList)
{
// find the best-matching provides
BPackageResolvable* bestProvides = NULL;
for (ProvidesList::const_iterator it = providesList.begin();
it != providesList.end(); ++it) {
BPackageResolvable* provides = *it;
if (!expression.Matches(*provides))
continue;

if (bestProvides == NULL || bestProvides->Version().InitCheck() != B_OK
|| (provides->Version().InitCheck() == B_OK
&& provides->Version().Compare(bestProvides->Version()) > 0)) {
bestProvides = provides;
}
}

if (bestProvides == NULL || bestProvides->Version().InitCheck() != B_OK)
return;

// Update the expression. Enforce the minimum found version, if the requires
// has no version requirement or also a minimum. Otherwise enforce the exact
// version found.
BPackageResolvableOperator newOperator = B_PACKAGE_RESOLVABLE_OP_EQUAL;
switch (expression.Operator()) {
case B_PACKAGE_RESOLVABLE_OP_LESS:
case B_PACKAGE_RESOLVABLE_OP_LESS_EQUAL:
case B_PACKAGE_RESOLVABLE_OP_EQUAL:
case B_PACKAGE_RESOLVABLE_OP_NOT_EQUAL:
break;
case B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL:
case B_PACKAGE_RESOLVABLE_OP_GREATER:
case B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT:
newOperator = B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL;
break;
}

expression.SetTo(expression.Name(), newOperator, bestProvides->Version());
}


int
main(int argc, const char* const* argv)
{
if (argc != 3)
print_usage_and_exit(true);

if (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0)
print_usage_and_exit(false);

const char* const packageInfoPath = argv[1];
const char* const repositoryCachePath = argv[2];

// read the repository cache
BRepositoryCache repositoryCache;
status_t error = repositoryCache.SetTo(repositoryCachePath);
if (error != B_OK) {
DIE(error, "failed to read repository cache file \"%s\"",
repositoryCachePath);
}

// create a map for all provides (name -> resolvable list)
typedef std::map<BString, ProvidesList> ProvidesMap;

ProvidesMap providesMap;

for (BRepositoryCache::Iterator it = repositoryCache.GetIterator();
const BPackageInfo* info = it.Next();) {
const BObjectList<BPackageResolvable>& provides = info->ProvidesList();
int32 count = provides.CountItems();
for (int32 i = 0; i < count; i++) {
BPackageResolvable* resolvable = provides.ItemAt(i);
ProvidesList& providesList = providesMap[resolvable->Name()];
providesList.push_back(resolvable);
}
}

// load the package info
BPackageInfo packageInfo;
error = packageInfo.ReadFromConfigFile(packageInfoPath);
if (error != B_OK)
DIE(error, "failed to read package info file \"%s\"", packageInfoPath);

// clone the package info's requires list
typedef std::list<BPackageResolvableExpression> RequiresList;
RequiresList requiresList;
int32 requiresCount = packageInfo.RequiresList().CountItems();
for (int32 i = 0; i < requiresCount; i++)
requiresList.push_back(*packageInfo.RequiresList().ItemAt(i));

// rebuild the requires list with updated versions
packageInfo.ClearRequiresList();
for (RequiresList::iterator it = requiresList.begin();
it != requiresList.end(); ++it) {
BPackageResolvableExpression expression = *it;
ProvidesMap::iterator foundIt = providesMap.find(expression.Name());
if (foundIt != providesMap.end())
update_requires_expression(expression, foundIt->second);

error = packageInfo.AddRequires(expression);
if (error != B_OK)
DIE(error, "failed to add requires item to package info");
}

// write updated package info
BString configString;
error = packageInfo.GetConfigString(configString);
if (error != B_OK)
DIE(error, "failed to get updated package info string");

FILE* file = fopen(packageInfoPath, "w");
if (file == NULL) {
DIE(errno, "failed to open package info file \"%s\" for writing",
packageInfoPath);
}

if (fwrite(configString.String(), configString.Length(), 1, file) != 1) {
DIE(errno, "failed to write updated package info file \"%s\"",
packageInfoPath);
}

fclose(file);

return 0;
}

0 comments on commit 5774110

Please sign in to comment.