]> cygwin.com Git - cygwin-apps/setup.git/blob - prereq.cc
2005-05-21 Brian Dessent <brian@dessent.net>
[cygwin-apps/setup.git] / prereq.cc
1 /*
2 * Copyright (c) 2005 Brian Dessent
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Brian Dessent <brian@dessent.net>
13 *
14 */
15
16 #if 0
17 static const char *cvsid =
18 "\n%%% $Id$\n";
19 #endif
20
21 #include "win32.h"
22 #include <commctrl.h>
23 #include <stdio.h>
24 #include <io.h>
25 #include <ctype.h>
26 #include <process.h>
27
28 #include "prereq.h"
29 #include "dialog.h"
30 #include "resource.h"
31 #include "state.h"
32 #include "propsheet.h"
33 #include "threebar.h"
34 #include "Generic.h"
35 #include "LogSingleton.h"
36 #include "ControlAdjuster.h"
37 #include "package_db.h"
38 #include "package_meta.h"
39 #include "msg.h"
40
41 // Sizing information.
42 static ControlAdjuster::ControlInfo PrereqControlsInfo[] = {
43 {IDC_PREREQ_CHECK, CP_LEFT, CP_BOTTOM},
44 {IDC_PREREQ_EDIT, CP_STRETCH, CP_STRETCH},
45 {0, CP_LEFT, CP_TOP}
46 };
47
48 extern ThreeBarProgressPage Progress;
49
50 // ---------------------------------------------------------------------------
51 // implements class PrereqPage
52 // ---------------------------------------------------------------------------
53
54 PrereqPage::PrereqPage ()
55 {
56 sizeProcessor.AddControlInfo (PrereqControlsInfo);
57 }
58
59 bool
60 PrereqPage::Create ()
61 {
62 return PropertyPage::Create (IDD_PREREQ);
63 }
64
65 void
66 PrereqPage::OnInit ()
67 {
68 // start with the checkbox set
69 CheckDlgButton (GetHWND (), IDC_PREREQ_CHECK, BST_CHECKED);
70
71 // set the edit-area to a larger font
72 SetDlgItemFont(IDC_PREREQ_EDIT, "MS Shell Dlg", 10);
73 }
74
75 void
76 PrereqPage::OnActivate()
77 {
78 // if we have gotten this far, then PrereqChecker has already run isMet
79 // and found that there were missing packages; so we can just call
80 // getUnmetString to format the results and display it
81
82 String s;
83 PrereqChecker p;
84 p.getUnmetString (s);
85 SetDlgItemText (GetHWND (), IDC_PREREQ_EDIT, s.c_str ());
86
87 SetFocus (GetDlgItem (IDC_PREREQ_CHECK));
88 }
89
90 long
91 PrereqPage::OnNext ()
92 {
93 HWND h = GetHWND ();
94
95 if (!IsDlgButtonChecked (h, IDC_PREREQ_CHECK))
96 {
97 // breakage imminent! danger, danger
98 int res = MessageBox (h,
99 "If you continue without correcting the listed conflicts, your "
100 "Cygwin installation will not function properly.\r\n"
101 "We strongly recommend that you let Setup install the listed packages.\r\n\r\n"
102 "Are you sure you want to proceed?",
103 "WARNING - Required Packages Not Selected",
104 MB_YESNO | MB_ICONEXCLAMATION | MB_DEFBUTTON2);
105 if (res == IDNO)
106 return -1;
107 else
108 log (LOG_PLAIN) <<
109 "NOTE! User refused suggested missing dependencies! "
110 "Expect some packages to give errors or not function at all." << endLog;
111 }
112 else
113 {
114 // add the missing requirements
115 PrereqChecker p;
116 p.selectMissing ();
117 }
118 if (source == IDC_SOURCE_CWD)
119 {
120 // Next, install
121 Progress.SetActivateTask (WM_APP_START_INSTALL);
122 }
123 else
124 {
125 // Next, start download from internet
126 Progress.SetActivateTask (WM_APP_START_DOWNLOAD);
127 }
128 return IDD_INSTATUS;
129 }
130
131 long
132 PrereqPage::OnBack ()
133 {
134 return IDD_CHOOSE;
135 }
136
137
138 // ---------------------------------------------------------------------------
139 // implements class PrereqChecker
140 // ---------------------------------------------------------------------------
141
142 // instantiate the static members
143 map <packagemeta *, vector <packagemeta *>, packagemeta_ltcomp> PrereqChecker::unmet;
144 trusts PrereqChecker::theTrust = TRUST_CURR;
145
146 /* This function builds a list of unmet dependencies to present to the user on
147 the PrereqPage propsheet. The data is stored as an associative map of
148 unmet[missing-package] = vector of packages that depend on missing-package */
149 bool
150 PrereqChecker::isMet ()
151 {
152 packagedb db;
153 bool foundUnmet = false;
154
155 // unmet is static - clear it each time this is called
156 unmet.clear ();
157
158 // loop through each package
159 for (vector <packagemeta *>::iterator n = db.packages.begin ();
160 n != db.packages.end (); ++n)
161 {
162 // if the package is installed or selected to be installed...
163 if ((*n)->desired)
164 {
165 // loop through each dependency
166 for (vector <vector <PackageSpecification *> *>::iterator i =
167 (*n)->desired.depends ()->begin ();
168 i != (*n)->desired.depends ()->end (); ++i)
169 {
170 // XXX: the following assumes that there is only a single
171 // node in each OR clause, which is currently the case.
172 // if setup is ever pushed to use AND/OR in "depends:"
173 // lines this will have to be updated
174 PackageSpecification *spec = (*i)->at(0);
175
176 packagemeta *pack = db.findBinary (*spec);
177 if (!pack)
178 continue; // asking for a package that doesn't exist - error?
179
180 if (pack->desired && spec->satisfies (pack->desired))
181 {
182 // dependency met
183 }
184 else
185 {
186 foundUnmet = true;
187 unmet[pack].push_back (*n);
188 }
189 }
190 }
191 }
192
193 return !foundUnmet;
194 }
195
196 /* Formats 'unmet' as a string for display to the user. */
197 void
198 PrereqChecker::getUnmetString (String &s)
199 {
200 s = "";
201
202 map <packagemeta *, vector <packagemeta *>, packagemeta_ltcomp>::iterator i;
203 for (i = unmet.begin(); i != unmet.end(); i++)
204 {
205 s = s + "Package: " + i->first->name + "\r\n\tRequired by: ";
206 for (unsigned int j = 0; j < i->second.size(); j++)
207 {
208 s += i->second[j]->name;
209 if (j != i->second.size() - 1)
210 s += ", ";
211 }
212 s += "\r\n\r\n";
213 }
214 }
215
216 /* Takes the keys of 'unmet' and selects them, using the current trust. */
217 void
218 PrereqChecker::selectMissing ()
219 {
220 packagedb db;
221
222 // provide a default, even though this should have been set for us
223 if (!theTrust)
224 theTrust = TRUST_CURR;
225
226 // get each of the keys of 'unmet'
227 map <packagemeta *, vector <packagemeta *>, packagemeta_ltcomp>::iterator i;
228 for (i = unmet.begin(); i != unmet.end(); i++)
229 {
230 packageversion vers = i->first->trustp (theTrust);
231 i->first->desired = vers;
232 vers.sourcePackage ().pick (false);
233
234 if (vers == i->first->installed)
235 {
236 vers.pick (false);
237 log (LOG_PLAIN) << "Adding required dependency " << i->first->name <<
238 ": Selecting already-installed version " <<
239 i->first->installed.Canonical_version () << "." << endLog;
240 }
241 else
242 {
243 vers.pick (vers.accessible ());
244 log (LOG_PLAIN) << "Adding required dependency " << i->first->name <<
245 ": Selecting version " << vers.Canonical_version () <<
246 " for installation." << endLog;
247 }
248 }
249 }
This page took 0.04749 seconds and 5 git commands to generate.