aboutsummaryrefslogtreecommitdiff
path: root/doc/programmingwithpaludis.html.skel
blob: 76eb2bcd049a3c730f568c2cfa5fdedaed362002 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="en" xml:lang="en">
<head>
<title>Paludis, the Other Package Mangler</title>
<link rel="stylesheet" href="paludis.css" type="text/css" />
</head>
<body>
@HEADER@

<h1>Programming with Paludis, the Other Package Mangler</h1>

<p>You can get a <a href="http://paludis.pioto.org/trac/browser/">Subversion
    checkout</a> of <code>trunk/</code> rather than working off a tarball. If you're
planning to submit patches, you'll have to do this.</p>

<p>It's best to start by skimming over the main program to get a feel for how
everything fits together. The interface code is kept in the src/ directory,
and library code is in paludis/ .</p>

<h2>Basics</h2>

<p>There are currently two APIs available:</p>

<ul>
    <li>The C++ API. This offers the full range of functionality. <a
        href="doxygen/html/">Full Doxygen documentation</a> is available.</li>
    <li>The Ruby API. This offers a subset of the functionality and is aimed at script and utility
    authors. Not every class or method is currently available; support for more classes and
    methods can be added as needed. Some things (for example, defining new Environment subclasses)
    will likely never be available through this interface. <a href="ruby/">Full
        Rdoc documentation</a> is available.</li>
</ul>

<p>A basic C++ application will look something like:</p>

<pre>
@BASIC_CPP_APP@
</pre>

<p>Compile this using <code>g++ -Wall -lpaludis
    -lpaludisenvironments</code>. If your compiler lacks tr1 support, you
may also need <code>-I/usr/include/paludis/compat</code>.</p>

<p>The same application written in Ruby will look something like:</p>

<pre>
@BASIC_RUBY_APP@
</pre>

<p>Notice how various Rubyisms (singleton styles, question mark methods, constants
for enums) are used. The Ruby interface aims to be natural to Ruby programmers
and behave like a Ruby library, rather than being an exact translation.</p>

<p>Make sure you can run both of these examples before reading on.</p>

<h2>Common Patterns</h2>

<p>A number of common patterns are used throughout the code.</p>

<h3>Iterators</h3>

<p>STL style iterator pairs crop up in various places. Where this happens, there is
usually a member typedef named <code>Iterator</code> or <code>FooIterator</code>,
along with members named <code>begin</code> and <code>end</code> or <code>begin_foo</code>
and <code>end_foo</code>. See <a href="doxygen/html/References.html">TCppSL</a>
if you are unfamiliar with this style.</p>

<p>The underlying iterator format is usually hidden from the library programmer by a
<code>libwrapiter::ForwardIterator</code>. This is to speed up compile times and to avoid breaking
lots of things when underlying data types change.</p>

<p>Ruby works better with blocks than external iterators. Thus, instead of providing
<code>begin_foo</code> and <code>end_foo</code> methods, Ruby classes typically have
a single <code>foo</code> member function that returns an array made from the
iterator range. This is slower, but much easier.</p>

<h3>Pointers</h3>

<p>We make extensive use of <code>std::tr1::shared_ptr</code>. Make sure you know how it
works. See <a href="doc/html/References.html">TCppSLE</a>.</p>

<p>This is all hidden in the Ruby interface. You shouldn't have to care about
memory management.</p>

<h3>Validated Names</h3>

<p>Rather than using <code>std::string</code> for package, category etc names, we have a wrapper
class template called <code>paludis::Validated</code>, and a bunch of typedefs
(<code>paludis::CategoryNamePart</code>, <code>paludis::PackageNamePart</code>,
<code>paludis::SlotName</code> etc). This gives a couple of benefits:</p>

<ul>
    <li>It catches certain screwups (e.g. passing the wrong parameter types) at
    compile time.</li>
    <li>It means exceptions caused by weird data (e.g. from user input) are caught at a sensible
    place, rather than sometime weird later on.</li>
</ul>

<p>Ruby doesn't do static checking, so it just uses raw <code>String</code>
instances for all of these.</p>

<h3>Collections</h3>

<p>Sometimes we need to pass around a collection of items. The
<code>paludis::SortedCollection</code>,
<code>paludis::SequentialCollection</code> and
<code>paludis::AssociativeCollection</code> wrappers handle this.
They are passed around via smart pointers to avoid copying.</p>

<p>The basic classes are abstract. Use
<code>paludis::SortedCollection::Concrete</code> etc if you need
to make one yourself.</p>

<p>In Ruby these are converted to arrays.</p>

<h3>Smart Records</h3>

<p>Smart records are a bit smarter than Plain Old Data structs. They might define comparison
operators and constructors. They're used in quite a few places. Try not to worry
about how these work internally unless you want to get a very sore head.</p>

<p>Some smart records support named parameter constructors. A typical call to one of these
looks like:</p>

<pre>
PackageDatabaseEntry my_pde(PackageDatabaseEntryParams::create()
        .package(QualifiedPackageName("app-editors/vim"))
        .version(VersionSpec("7.0.147"))
        .repository(RepositoryName("gentoo")));
</pre>

<p>Named parameters can be specified in any order.</p>

<h3>Stringify</h3>

<p>Many types can be converted to a <code>std::string</code> for display
purposes. The <code>paludis::stringify()</code>
template function will handle this. It also works for any internal and standard library data
type that can be written to a <code>std::ostream</code>.</p>

<h2>The Environment</h2>

<p>At the heart of the Paludis API is a <code>paludis::Environment</code> subclass instance. All
non-trivial clients will use one of the Environment subclasses as their starting
point for obtaining data (<code>Environment</code> itself contains abstract members and cannot
be used directly).</p>

<h3>PaludisEnvironment and PortageEnvironment</h3>

<p>The <code>paludis::PaludisEnvironment</code> and <code>paludis::PortageEnvironment</code>
classes should be used when user configuration is to be honoured. These classes are not usually
created directly; instead, <code>paludis::EnvironmentMaker</code> is used to obtain an
instance:</p>

<pre>
    std::string my_spec_string(...);
    std::tr1::shared_ptr&lt;paludis::Environment&gt; env(
            paludis::EnvironmentMaker::get_instance()-&lt;make_from_spec(my_spec_string));
</pre>

<p>The specification string should usually be the command line parameter value for <code>-E</code>
or <code>--environment</code>. An empty string will give the default <code>PaludisEnvironment</code>
or <code>PortageEnvironment</code>.</p>

<p>When using <code>EnvironmentMaker</code>, linking should include
<code>-lpaludisenvironments</code>.</p>

<p>In Ruby, instances must be obtained using <code>Paludis::EnvironmentMaker</code>.</p>

<h3>NoConfigEnvironment</h3>

<p>The <code>paludis::NoConfigEnvironment</code> class should be used when user configuration should
not be read, and instead the repository should be from a single particular directory.
Multiple instances of this environment can be created if necessary.</p>

<p>When using <code>NoConfigEnvironment</code>, linking should include
<code>-lpaludisnoconfigenvironment</code>.</p>

<p>In Ruby the class is <code>Paludis::NoConfigEnvironment</code>.</p>

<h3>Other Environments</h3>

<p>The <code>paludis::qa::QAEnvironment</code> class is used for QA environments. There is also a
<code>paludis::TestEnvironment</code> class that is used in some test cases. These are less useful
for most client authors.</p>

<p>In Ruby the class for a QA environment is <code>Paludis::QA::QAEnvironment</code>, there is 
currently no Ruby wrapper for the test environment.</p>

<h2>The Package Database</h2>

<p>Every <code>paludis::Environment</code> has a
<code>paludis::PackageDatabase</code>, which can be obtained
via the <code>paludis::Environment::package_database()</code> method.</p>

<p>The <code>PackageDatabase</code> contains a number of
<code>paludis::Repository</code> subclass instances. These
can be obtained using the
paludis<code>::PackageDatabase::begin_repositories()</code> and
<code>paludis::PackageDatabase::end_repositories()</code> pair or the
<code>paludis::PackageDatabase::fetch_repository()</code> method.</p>

<p>The <code>PackageDatabase</code> also provides a number of utility functions.
<code>paludis::PackageDatabase::query()</code>
can be used to fetch a <code>paludis::PackageDatabaseEntryCollection</code> containing packages
matching a particular <code>paludis::PackageDepSpec</code>.
<code>paludis::PackageDatabase::fetch_unique_qualified_package_name()</code>
can be used to convert a <code>paludis::PackageNamePart</code> with no
associated <code>paludis::CategoryNamePart</code> into
a full <code>paludis::QualifiedPackageName</code>.</p>

<p>In Ruby, the class is <code>Paludis::PackageDatabase</code> and an instance can
only be obtained by calling <code>some_environment.package_database</code>.
Rather than providing iterator pairs, repositories are available through the
<code>repositories</code> method, whose return value behaves like an array of
<code>Paludis::Repository</code> subclass instances. The
<code>fetch_repository</code>, <code>query</code> and
<code>fetch_unique_qualified_package_name</code> methods are available.</p>

<h2>Repositories</h2>

<p>The <code>paludis::Repository</code> class is an abstract base class representing a
repository. Each <code>paludis::Repository</code> subclass provides various core functions,
along with various optional others based upon the repository's capabilities.</p>

<p>The commonly used subclasses are:</p>

<ul>
    <li>paludis::PortageRepository, which is used for Gentoo-style ebuild
    repositories.</li>
    <li>paludis::VDBRepository, which is used for installed packages.</li>
    <li>paludis::VirtualsRepository, which is used for old-style virtuals.</li>
    <li>paludis::InstalledVirtualsRepository, which is used for old-style
    provided virtuals.</li>
</ul>

<p>Others include:</p>

<ul>
<li>paludis::CRANRepository, which is used for CRAN packages.</li>
<li>paludis::CRANInstalledRepository, which is used for installed CRAN
packages.</li>
<li>paludis::FakeRepository, which is used for some test cases.</li>
</ul>

<p>Repository creation is usually handled by the
<code>paludis::Environment</code> subclass and its
<code>associated paludis::PackageDatabase</code>. In Ruby, this is the only way to gain access
to a repository.</p>

<p>All repositories provide some basic functions for querying their contents. Commonly used
functions are <code>paludis::Repository::version_metadata()</code>,
<code>paludis::Repository::has_category_named()</code>,
<code>paludis::Repository::has_package_named()</code>,
<code>paludis::Repository::category_names()</code>,
<code>paludis::Repository::package_names()</code>,
<code>paludis::Repository::version_specs()</code> and
<code>paludis::Repository::has_version()</code>. These are available through Ruby; the has_ functions
have a question mark suffix as per Ruby convention.</p>

<p>Additional capabilities are available through optional interfaces. These can be accessed
via members named <code>paludis::Repository::mask_interface</code>,
<code>paludis::Repository::sets_interface</code>
and so on -- these members will either be a pointer to the interface or a zero
pointer.</p>

<p>A full list of optional capabilities can be seen in the documentation for
<code>paludis::RepositoryCapabilities</code>,
from which paludis::Repository inherits.</p>

<p>In Ruby, this works a bit differently. Members that return either a self reference or nil
are available for each interface. They are named as their C++ equivalents.</p>

@FOOTER@
</body>
</html>