OSDN Git Service

Note relocation of m4 when packaging source distribution.
[mingw/mingw-get.git] / src / pkgbind.cpp
1 /*
2  * pkgbind.cpp
3  *
4  * $Id$
5  *
6  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
7  * Copyright (C) 2009, 2010, 2011, MinGW Project
8  *
9  *
10  * Implementation of repository binding for the pkgXmlDocument class.
11  *
12  *
13  * This is free software.  Permission is granted to copy, modify and
14  * redistribute this software, under the provisions of the GNU General
15  * Public License, Version 3, (or, at your option, any later version),
16  * as published by the Free Software Foundation; see the file COPYING
17  * for licensing details.
18  *
19  * Note, in particular, that this software is provided "as is", in the
20  * hope that it may prove useful, but WITHOUT WARRANTY OF ANY KIND; not
21  * even an implied WARRANTY OF MERCHANTABILITY, nor of FITNESS FOR ANY
22  * PARTICULAR PURPOSE.  Under no circumstances will the author, or the
23  * MinGW Project, accept liability for any damages, however caused,
24  * arising from the use of this software.
25  *
26  */
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 #include "dmh.h"
33 #include "pkgbase.h"
34 #include "pkgkeys.h"
35 #include "pkgopts.h"
36
37 class pkgRepository
38 {
39   /* A locally defined class to facilitate recursive retrieval
40    * of package lists, from any specified repository.
41    */
42   public:
43     pkgRepository( pkgXmlDocument*, pkgXmlNode*, pkgXmlNode*, bool );
44     ~pkgRepository(){};
45
46     void GetPackageList( const char* );
47     void GetPackageList( pkgXmlNode* );
48
49   private:
50     pkgXmlNode *dbase;
51     pkgXmlNode *repository;
52     pkgXmlDocument *owner;
53     bool force_update;
54 };
55
56 pkgRepository::pkgRepository
57 /*
58  * Constructor...
59  */
60 ( pkgXmlDocument *client, pkgXmlNode *db, pkgXmlNode *ref, bool mode ):
61 owner( client ), dbase( db ), repository( ref ), force_update( mode ){}
62
63 void pkgRepository::GetPackageList( const char *dname )
64 {
65   /* Helper to retrieve and recursively process a named package list.
66    *
67    * FIXME: having made this recursively process multiple catalogues,
68    * potentially from multiple independent repositories, we may have
69    * introduced potential for catalogue name clashes; we need to add
70    * name hashing in the local catalogue cache, to avoid conflicts.
71    */
72   if( dname != NULL )
73   {
74     const char *dfile;
75     if( (dfile = xmlfile( dname )) != NULL )
76     {
77       /* Check for a locally cached copy of the "package-list" file...
78        */
79       if( force_update || (access( dfile, F_OK ) != 0) )
80       {
81         /* When performing an "update", or if no local copy is available...
82          * Force a "sync", to fetch a copy from the public host.
83          */
84         dmh_printf( "Update catalogue: %s.xml\n", dname );
85         owner->SyncRepository( dname, repository );
86       }
87
88       /* We SHOULD now have a locally cached copy of the package-list;
89        * attempt to merge it into the active profile database...
90        */
91       pkgXmlDocument merge( dfile );
92       if( merge.IsOk() )
93       {
94         /* We successfully loaded the XML catalogue; refer to its
95          * root element...
96          */
97         if( pkgOptions()->Test( OPTION_VERBOSE ) > 1 )
98           dmh_printf( "Load catalogue: %s.xml\n", dname );
99         pkgXmlNode *catalogue, *pkglist;
100         if( (catalogue = merge.GetRoot()) != NULL )
101         {
102           /* ...read it, selecting each of the "package-collection"
103            * records contained within it...
104            */
105           pkglist = catalogue->FindFirstAssociate( package_collection_key );
106           while( pkglist != NULL )
107           {
108             /* ...and append a copy of each to the active profile...
109              */
110             dbase->LinkEndChild( pkglist->Clone() );
111
112             /* Move on to the next "package-collection" (if any)
113              * within the current catalogue...
114              */
115             pkglist = pkglist->FindNextAssociate( package_collection_key );
116           }
117
118           /* Recursively incorporate any additional package lists,
119            * which may be specified within the current catalogue...
120            */
121           GetPackageList( catalogue->FindFirstAssociate( package_list_key ) );
122         }
123       }
124       else
125       { /* The specified catalogue could not be successfully loaded;
126          * emit a warning diagnostic message, and otherwise ignore it.
127          */
128         dmh_notify( DMH_WARNING, "Load catalogue: FAILED: %s.xml\n", dname );
129       }
130
131       /* However we handled it, the XML file's path name in "dfile" was
132        * allocated on the heap; we lose its reference on termination of
133        * this loop, so we must free it to avoid a memory leak.
134        */
135       free( (void *)(dfile) );
136     }
137   }
138 }
139
140 void pkgRepository::GetPackageList( pkgXmlNode *catalogue )
141 {
142   /* Helper method to retrieve a set of package list specifications
143    * from a "package-list" catalogue; after processing the specified
144    * "catalogue" it iterates over any sibling XML elements which are
145    * also designated as being of the "package-list" type.
146    *
147    * Note: we assume that the passed catalogue element actually
148    * DOES represent a "package-list" element; we do not check this,
149    * because the class declaration is not exposed externally to this
150    * translation unit, and we only ever call this from within the
151    * unit, when we have a "package-list" element to process.
152    */
153   while( catalogue != NULL )
154   {
155     /* Evaluate each identified "package-list" catalogue in turn...
156      */
157     GetPackageList( catalogue->GetPropVal( catalogue_key, NULL ) );
158
159     /* A repository may comprise an arbitrary collection of software
160      * catalogues; move on, to process the next catalogue (if any) in
161      * the current repository collection.
162      */
163     catalogue = catalogue->FindNextAssociate( package_list_key );
164   }
165 }
166
167 pkgXmlNode *pkgXmlDocument::BindRepositories( bool force_update )
168 {
169   /* Identify the repositories specified in the application profile,
170    * and merge their associated package distribution lists into the
171    * active XML database, which is bound to the profile.
172    */
173   pkgXmlNode *dbase = GetRoot();
174
175   /* Before blindly proceeding, perform a sanity check...
176    * Verify that this XML database defines an application profile,
177    * and that the associated application is "mingw-get"...
178    */
179   if( (strcmp( dbase->GetName(), profile_key ) == 0)
180   &&  (strcmp( dbase->GetPropVal( application_key, "?" ), "mingw-get") == 0) )
181   {
182     /* Sanity check passed...
183      * Walk the XML data tree, selecting "repository" specifications...
184      */
185     pkgXmlNode *repository = dbase->FindFirstAssociate( repository_key );
186     while( repository != NULL )
187     {
188       /* For each "repository" specified, identify its "catalogues"...
189        */
190       pkgRepository client( this, dbase, repository, force_update );
191       pkgXmlNode *catalogue = repository->FindFirstAssociate( package_list_key );
192       if( catalogue == NULL )
193         /*
194          * This repository specification doesn't identify any named
195          * package list, so try the default, (which is named to match
196          * the XML key name for the "package-list" element)...
197          */
198         client.GetPackageList( package_list_key );
199
200       else
201         /* At least one package list catalogue is specified; load it,
202          * and any others which are explicitly identified...
203          */
204         client.GetPackageList( catalogue );
205
206       /* Similarly, a complete distribution may draw from an arbitrary set
207        * of distinct repositories; move on, to process the next repository
208        * specified (if any).
209        */
210       repository = repository->FindNextAssociate( repository_key );
211     }
212
213     /* On successful completion, return a pointer to the root node
214      * of the active XML profile.
215      */
216     return dbase;
217   }
218
219   /* Fall through on total failure to interpret the profile, returning
220    * NULL to indicate failure.
221    */
222   return NULL;
223 }
224
225 /* $RCSfile$: end of file */