aboutsummaryrefslogtreecommitdiff
blob: f4e89abde2480c56edeaa5fb696256fe5eb9c628 (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
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.10: http://docutils.sourceforge.net/" />
<title>Developer Instructions</title>
<style type="text/css">

/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7514 2012-09-14 14:27:12Z milde $
:Copyright: This stylesheet has been placed in the public domain.

Default cascading style sheet for the HTML output of Docutils.

See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/

/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
  border: 0 }

table.borderless td, table.borderless th {
  /* Override padding for "table.docutils td" with "! important".
     The right padding separates the table cells. */
  padding: 0 0.5em 0 0 ! important }

.first {
  /* Override more specific margin styles with "! important". */
  margin-top: 0 ! important }

.last, .with-subtitle {
  margin-bottom: 0 ! important }

.hidden {
  display: none }

a.toc-backref {
  text-decoration: none ;
  color: black }

blockquote.epigraph {
  margin: 2em 5em ; }

dl.docutils dd {
  margin-bottom: 0.5em }

object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
  overflow: hidden;
}

/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
  font-weight: bold }
*/

div.abstract {
  margin: 2em 5em }

div.abstract p.topic-title {
  font-weight: bold ;
  text-align: center }

div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
  margin: 2em ;
  border: medium outset ;
  padding: 1em }

div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
  font-weight: bold ;
  font-family: sans-serif }

div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
  color: red ;
  font-weight: bold ;
  font-family: sans-serif }

/* Uncomment (and remove this text!) to get reduced vertical space in
   compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
  margin-bottom: 0.5em }

div.compound .compound-last, div.compound .compound-middle {
  margin-top: 0.5em }
*/

div.dedication {
  margin: 2em 5em ;
  text-align: center ;
  font-style: italic }

div.dedication p.topic-title {
  font-weight: bold ;
  font-style: normal }

div.figure {
  margin-left: 2em ;
  margin-right: 2em }

div.footer, div.header {
  clear: both;
  font-size: smaller }

div.line-block {
  display: block ;
  margin-top: 1em ;
  margin-bottom: 1em }

div.line-block div.line-block {
  margin-top: 0 ;
  margin-bottom: 0 ;
  margin-left: 1.5em }

div.sidebar {
  margin: 0 0 0.5em 1em ;
  border: medium outset ;
  padding: 1em ;
  background-color: #ffffee ;
  width: 40% ;
  float: right ;
  clear: right }

div.sidebar p.rubric {
  font-family: sans-serif ;
  font-size: medium }

div.system-messages {
  margin: 5em }

div.system-messages h1 {
  color: red }

div.system-message {
  border: medium outset ;
  padding: 1em }

div.system-message p.system-message-title {
  color: red ;
  font-weight: bold }

div.topic {
  margin: 2em }

h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
  margin-top: 0.4em }

h1.title {
  text-align: center }

h2.subtitle {
  text-align: center }

hr.docutils {
  width: 75% }

img.align-left, .figure.align-left, object.align-left {
  clear: left ;
  float: left ;
  margin-right: 1em }

img.align-right, .figure.align-right, object.align-right {
  clear: right ;
  float: right ;
  margin-left: 1em }

img.align-center, .figure.align-center, object.align-center {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

.align-left {
  text-align: left }

.align-center {
  clear: both ;
  text-align: center }

.align-right {
  text-align: right }

/* reset inner alignment in figures */
div.align-right {
  text-align: inherit }

/* div.align-center * { */
/*   text-align: left } */

ol.simple, ul.simple {
  margin-bottom: 1em }

ol.arabic {
  list-style: decimal }

ol.loweralpha {
  list-style: lower-alpha }

ol.upperalpha {
  list-style: upper-alpha }

ol.lowerroman {
  list-style: lower-roman }

ol.upperroman {
  list-style: upper-roman }

p.attribution {
  text-align: right ;
  margin-left: 50% }

p.caption {
  font-style: italic }

p.credits {
  font-style: italic ;
  font-size: smaller }

p.label {
  white-space: nowrap }

p.rubric {
  font-weight: bold ;
  font-size: larger ;
  color: maroon ;
  text-align: center }

p.sidebar-title {
  font-family: sans-serif ;
  font-weight: bold ;
  font-size: larger }

p.sidebar-subtitle {
  font-family: sans-serif ;
  font-weight: bold }

p.topic-title {
  font-weight: bold }

pre.address {
  margin-bottom: 0 ;
  margin-top: 0 ;
  font: inherit }

pre.literal-block, pre.doctest-block, pre.math, pre.code {
  margin-left: 2em ;
  margin-right: 2em }

pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}

span.classifier {
  font-family: sans-serif ;
  font-style: oblique }

span.classifier-delimiter {
  font-family: sans-serif ;
  font-weight: bold }

span.interpreted {
  font-family: sans-serif }

span.option {
  white-space: nowrap }

span.pre {
  white-space: pre }

span.problematic {
  color: red }

span.section-subtitle {
  /* font-size relative to parent (h1..h6 element) */
  font-size: 80% }

table.citation {
  border-left: solid 1px gray;
  margin-left: 1px }

table.docinfo {
  margin: 2em 4em }

table.docutils {
  margin-top: 0.5em ;
  margin-bottom: 0.5em }

table.footnote {
  border-left: solid 1px black;
  margin-left: 1px }

table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
  padding-left: 0.5em ;
  padding-right: 0.5em ;
  vertical-align: top }

table.docutils th.field-name, table.docinfo th.docinfo-name {
  font-weight: bold ;
  text-align: left ;
  white-space: nowrap ;
  padding-left: 0 }

h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
  font-size: 100% }

ul.auto-toc {
  list-style-type: none }

</style>
</head>
<body>
<div class="document" id="developer-instructions">
<h1 class="title">Developer Instructions</h1>

<div class="section" id="g-sorcery-overview">
<h1>g-sorcery overview</h1>
<p><strong>g-sorcery</strong> is a framework aimed to easy development of ebuild
generators.</p>
<p>Some terms used in this guide:</p>
<ul>
<li><dl class="first docutils">
<dt><strong>3rd party software provider</strong> or <strong>repository</strong></dt>
<dd><p class="first last">A system of software distribution like CTAN or CPAN that
provides packages for some domain (e.g. TeX packages or elisp
packages for emacs).</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>backend</strong></dt>
<dd><p class="first last">A tool developed using <strong>g-sorcery</strong> framework that provides
support for repositories of a given type.</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>overlay</strong></dt>
<dd><p class="first last">Usual Gentoo overlay.</p>
</dd>
</dl>
</li>
</ul>
<p><strong>g-sorcery</strong> consists of different parts:</p>
<ul>
<li><dl class="first docutils">
<dt><strong>package_db.PackageDB</strong></dt>
<dd><p class="first last">A package database. It holds information about all available
packages in a given repository.</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>package_db.DBGenerator</strong></dt>
<dd><p class="first last">A fabric that creates PackageDB object and fills it with information.</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>backend.Backend</strong></dt>
<dd><p class="first last">Backend that processes user commands.</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>ebuild</strong></dt>
<dd><p class="first last">Module with different ebuild generators.</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>eclass</strong></dt>
<dd><p class="first last">Module with eclass generators.</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>metadata.MetadataGenerator</strong></dt>
<dd><p class="first last">Metadata generator.</p>
</dd>
</dl>
</li>
</ul>
<p>Also there are other modules and classes that will be described later.</p>
<p>Usually repositories of a given type provide some kind of database. It can
be just a plain ASCII file, xmlrpc interface or just a joint set of web-pages.
This database describes what packages are available and how to install them.</p>
<p>Also usually there is an upstream tool for repositories of a given type that
allows installation of available packages. The main problem when using
such tools is that package mangler you use is not aware of them and they are
not aware of your package manager.</p>
<p>The idea of <strong>g-sorcery</strong> is to convert a database provided by a repository
into well defined format and then generate an overlay with ebuilds.
Then available packages can be installed as usual <strong>Gentoo</strong> packages.</p>
<p>So there are two phases of backend operation:</p>
<ul class="simple">
<li>synchronize with repository database</li>
<li>populate overlay using obtained information</li>
</ul>
<p>There are two ways of using backend:</p>
<ul class="simple">
<li>run it as a CLI tool manually</li>
<li>use its integration with layman</li>
</ul>
</div>
<div class="section" id="backend-structure">
<h1>Backend structure</h1>
<p>The only mandatory module in a backend is called <strong>backend</strong>. It should contain
at least one variable called <strong>instance</strong> that has a <strong>__call__</strong> method that
takes 4 arguments. These arguments are:</p>
<ul class="simple">
<li>self</li>
<li>command line arguments</li>
<li>backend config</li>
<li>g-sorcery config</li>
</ul>
<p>Usually <strong>instance</strong> variable should be an instance of a class g_sorcery.backend.Backend
or derived class.</p>
<p>g_sorcery.backend.Backend constructor takes 8 arguments. They are:</p>
<ul class="simple">
<li>self</li>
<li>Package database generator class</li>
<li>Two ebuild generator classes</li>
<li>Eclass generator class</li>
<li>Metadata generator class</li>
<li>Package database class</li>
<li>Boolean variable that defines method of database generation</li>
</ul>
<p>There are two ebuild generator classes as there are two scenarios of using backend on user
side: generate the entire overlay tree (possibly by layman) or generate a given ebuild
and its dependencies. In a first case it would be very bad idea to have sources in ebuild's
SRC_URI as during manifest generation for an overlay all the sources would be downloaded
to the user's comuter that inevitably would made user really happy. So one ebuild generator
generates ebuild with empty SRC_URI. Note that a mechanism for downloading of sources during
ebuild merging should be provided. For an example see <strong>git-2</strong> eclass from the main tree or
any eclass from backends provided with g-sorcery if you want to implement such a mechanism or
use eclass <strong>g-sorcery</strong> provided by standard eclass generator (can be found in data directory
of <strong>g_sorcery</strong> package).</p>
<p>Usually downloading and parsing of a database from a repository is an easy operation. But sometimes
there could exist some problems. Hence exists the last parameter in Backend constructor that
allows syncing with already generated database available somewhere in Internet (see <strong>gs-pypi</strong>
for an example of using it).</p>
<p>To do something usefull backend should customize any classes from g-sorcery it needs
and define backend.instance variable using those classes. Other two things backend should do are:</p>
<ul class="simple">
<li>install a binary that calls g-sorcery with appropriate backend name (see man g-sorcery)</li>
<li>install a config that allows g-sorcery find appropriate backend module</li>
</ul>
<p>A binary should just pass arguments to g-sorcery. For a backend named gs-elpa it could look like</p>
<pre class="code literal-block">
#!/bin/bash

g-sorcery g-elpa $&#64;
</pre>
<div class="section" id="backend-config">
<h2>Backend config</h2>
<p>Backend config is just a JSON file with a dictionary. There are two mandatory entries:</p>
<ul>
<li><dl class="first docutils">
<dt>package</dt>
<dd><p class="first last">Its value should be a string with a package containing backend.</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>repositories</dt>
<dd><p class="first last">A dictionary describing available repositories. Should have at least one entry.</p>
</dd>
</dl>
</li>
</ul>
<p>Backend config should have a name BACKEND.js and should be installed under <strong>/etc/g-sorcery</strong>
directory. BACKEND here is a backend name which was used in a g-sorcery call.</p>
<p>An entry in repositories dictionary as key should have a repository name and should be a dictionary
with repository properties. The only mandatory property is <strong>repo_uri</strong> in case database is
generated using info downloaded from the repository or <strong>db_uri</strong> in case database is
just synced with another already generated database. Also there can be a <strong>masters</strong> entry that
contains a list of overlays this repository depends on. If present it should contain at least
<strong>gentoo</strong> entry.</p>
<p>A simple backend config:</p>
<pre class="code literal-block">
 {
   &quot;package&quot;: &quot;gs_elpa&quot;,
   &quot;repositories&quot;: {
     &quot;gnu-elpa&quot;: {
       &quot;repo_uri&quot;: &quot;http://elpa.gnu.org/packages/&quot;
     },
     &quot;marmalade&quot;: {
       &quot;repo_uri&quot;: &quot;http://marmalade-repo.org/packages/&quot;,
       &quot;masters&quot;: [&quot;gentoo&quot;, &quot;gnu-elpa&quot;]
     },
     &quot;melpa&quot;: {
       &quot;repo_uri&quot;: &quot;http://melpa.milkbox.net/packages/&quot;,
       &quot;masters&quot;: [&quot;gentoo&quot;, &quot;gnu-elpa&quot;]
     }
   }
}
</pre>
</div>
</div>
<div class="section" id="package-database">
<h1>Package database</h1>
<div class="section" id="directory-layout">
<h2>Directory layout</h2>
<p>Package database is a directory tree with JSON files. The layout of this tree looks like:</p>
<pre class="code literal-block">
db dir
    manifest.json: database manifest
    categories.json: information about categories
    category1
        packages.json: packages information
    category2
    ...
</pre>
</div>
<div class="section" id="packagedb-class">
<h2>PackageDB class</h2>
<p>PackageDB class is aimed for interaction with package database. It has methods that allow
to add categories and packages and to do queries on them. Usually you do not want to customize this
class. But in case you want there is number of methods that can be redifend.</p>
<p>First of all if you have a database that should be synced with another already generate database
you can redifine URI to be used for syncing using <strong>get_real_db_uri</strong> method.</p>
<p>There is a number of hooks that are called after package, category or the whole database is
written/read:</p>
<ul class="simple">
<li>additional_write_version</li>
<li>additional_write_package</li>
<li>additional_write_category</li>
<li>additional_write</li>
<li>additional_read_version</li>
<li>additional_read_package</li>
<li>additional_read_category</li>
<li>additional_read</li>
</ul>
<p>Note that before add any package you should add a category for it using <strong>add_category</strong>.
Then packages can be added using <strong>add_package</strong>. PackageDB currently does not write changes
automatically, so you should call <strong>write_and_manifest</strong> after changes are done. This is not relevant
for database changing in <strong>process_data</strong> method of database generator as there all changes
are written by other methods it calls internally after <strong>process_data</strong>.</p>
</div>
<div class="section" id="json-serializable-objects">
<h2>JSON serializable objects</h2>
<p>If you need to store an object in a database it should be JSON serializable in terms of
g_sorcery.serialization module. It means it should define two methods:</p>
<ul class="simple">
<li>usual method <strong>serialize</strong> that returns a JSON serializable object in terms of standard Python
json module</li>
<li>class method <strong>deserialize</strong> that takes a value returned by <strong>serialize</strong> and constructs new instance
of your class using it</li>
</ul>
</div>
<div class="section" id="dependency-handling">
<h2>Dependency handling</h2>
<p>There is a special class g_sorcery.g_collections.Dependency aimed to handle dependencies.
Its constructor takes two mandatory parameters:</p>
<ul class="simple">
<li>category</li>
<li>package</li>
</ul>
<p>and two additional parameters:</p>
<ul class="simple">
<li>version</li>
<li>operator</li>
</ul>
<p>These two are the same as version and operator used in the usual package atom.</p>
<p>For storing dependency lists in a database you should use a collection
g_sorcery.g_collections.serializable_elist. Its constructor takes an iterable and a
separator that will be used to separate items when this collection is printed. In case of
storing dependencies for using them in ebuild's DEPEND variable a separator should be &quot;nt&quot;.</p>
<p>Ebuild data for every package version must have a &quot;dependencies&quot; entry. This entry is used
by backend during deciding which ebuilds should be generated. So make sure it does not have
any external dependencies.</p>
</div>
</div>
<div class="section" id="package-database-generator">
<h1>Package database generator</h1>
<div class="section" id="customizing-dbgenerator">
<h2>Customizing DBGenerator</h2>
<p>To do something usefull you should customize package_db.DBGenerator class.
With this aim you should subclass it and define some methods. Here they are:</p>
<ul>
<li><dl class="first docutils">
<dt>get_download_uries</dt>
<dd><p class="first">Get a list with download URI entries.
Each entry has one of the following formats:</p>
<ol class="arabic">
<li><p class="first">String with URI.</p>
</li>
<li><dl class="first docutils">
<dt>A dictionary with entries:</dt>
<dd><ul class="first simple">
<li>uri: URI.</li>
<li>parser: Parser to be applied to downloaded data.</li>
<li>open_file: Whether parser accepts file objects.</li>
<li>open_mode: Open mode for a downloaded file.</li>
</ul>
<p class="last">The only mandatory entry is uri.</p>
</dd>
</dl>
</li>
</ol>
<p class="last">The default implementation returns [backend_config[&quot;repositories&quot;][REPOSITORY][&quot;repo_uri&quot;]].</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>parse_data</dt>
<dd><p class="first last">This method parses a file downloaded from a repository
and returns its content in any form you think useful.
There is no useful default implementation of this method.</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt>process_data</dt>
<dd><p class="first last">This method should fill a package database with entries using
already downloaded and parsed data.</p>
</dd>
</dl>
</li>
</ul>
<p>Generally speaking these are all the method you should implement.</p>
</div>
<div class="section" id="value-convertion">
<h2>Value convertion</h2>
<p>During database generation you may need to convert some values provided by repository
(e.g license names that can not coincide with those used in Gentoo). With this aim
you can use <strong>convert</strong> function. To understand how it works see its sources in
g_sorcery.package_db.DBGenerator and as an example CTAN backend.</p>
<p>Here is a very short example. If you want to convert licenses in the same way for all
repositories of this type you just add <strong>common_config</strong> entry to backend config which
looks like:</p>
<pre class="code literal-block">
&quot;common_config&quot;: {
  &quot;licenses&quot;: {
   &quot;apache2&quot;: &quot;Apache-2.0&quot;,
   &quot;artistic&quot;: &quot;Artistic&quot;,
   &quot;Artistic2&quot;: &quot;Artistic-2&quot;,
   &quot;gpl&quot;: &quot;GPL-1&quot;,
   &quot;gpl2&quot;: &quot;GPL-2&quot;,
   &quot;gpl3&quot;: &quot;GPL-3&quot;,
   &quot;knuth&quot;: &quot;TeX&quot;,
   &quot;lgpl&quot;: &quot;LGPL-2&quot;,
   &quot;lgpl2.1&quot;: &quot;LGPL-2.1&quot;,
   &quot;lppl&quot;: &quot;LPPL-1.2&quot;,
   &quot;lppl1&quot;: &quot;LPPL-1.2&quot;,
   &quot;lppl1.2&quot;: &quot;LPPL-1.2&quot;,
   &quot;lppl1.3&quot;: &quot;LPPL-1.3c&quot;
  }
}
</pre>
<p>And then call in your <strong>process_data</strong> method</p>
<pre class="code literal-block">
license = self.convert([common_config, config], &quot;licenses&quot;, repo_license)
</pre>
<p>Where <strong>common_config</strong>, <strong>config</strong> are config provided as arguments to your <strong>process_data</strong> method
and <strong>repo_license</strong> is a license name used by the repository.</p>
<p>There is a special conversion function used for dependencies: <strong>convert_dependency</strong>. To use it you should
usually redefine <strong>convert_internal_dependency</strong> and <strong>convert_external_dependency</strong>. To decide whether
a dependency is external database generator uses <strong>external</strong> entry in config.</p>
<p>You may want to test whether there is a given value in given entry in config. To do it use
<strong>in_config</strong> function.</p>
</div>
</div>
<div class="section" id="eclass-generator">
<h1>Eclass generator</h1>
<p>Usualy you do not want to modify eclass generator. Currently it is very simple: it just returns eclasses
from a given directory. So all you should do is populating a directory with eclasses and then
inheriting g_sorcery.eclass.EclassGenerator and defining a directory in constructor. It should look
like</p>
<pre class="code literal-block">
class ElpaEclassGenerator(EclassGenerator):
    &quot;&quot;&quot;
    Implementation of eclass generator. Only specifies a data directory.
    &quot;&quot;&quot;
    def __init__(self):
        super(ElpaEclassGenerator, self).__init__(os.path.join(get_pkgpath(__file__), 'data'))
</pre>
<p>Eclass generator always provides <strong>g-sorcery</strong> eclass. It overrides <em>src_unpack</em> function
so if <em>DIGEST_SOURCES</em> variable is not set sources are fetched during unpack from <em>${REPO_URI}${SOURCEFILE}</em>.
If <em>DIGEST_SOURCES</em> variable is set usual unpack function is called.</p>
</div>
<div class="section" id="ebuild-generator">
<h1>Ebuild generator</h1>
<p>There is a number of ebuild generators in g_sorcery.ebuild module. The DefaultEbuildGenerator
is a recommended one. To use it you should inherit it and define an ebuild layout in constructor.</p>
<p>Layout has entries for vars and inherited eclasses. Each entry is a list.
Entries are processed in the following order:</p>
<ul class="simple">
<li>vars_before_inherit</li>
<li>inherit</li>
<li>vars_after_inherit</li>
<li>vars_after_description</li>
<li>vars_after_keywords</li>
</ul>
<p><strong>inherit</strong> entry is just a list of eclass names.</p>
<p><strong>vars*</strong> entries are lists of variables in two possible formats:</p>
<ol class="arabic">
<li><p class="first">A string with variable name</p>
</li>
<li><dl class="first docutils">
<dt>A dictinary with entries:</dt>
<dd><ul class="first last simple">
<li>name: variable name</li>
<li>value: variable value</li>
<li>raw: if present, no quotation of value will be done</li>
</ul>
</dd>
</dl>
</li>
</ol>
<p>Variable names are automatically transformed to the upper-case during ebuild generation.</p>
<p>An example of ebuild generator:</p>
<pre class="code literal-block">
Layout = collections.namedtuple(&quot;Layout&quot;,
    [&quot;vars_before_inherit&quot;, &quot;inherit&quot;,
     &quot;vars_after_description&quot;, &quot;vars_after_keywords&quot;])

class ElpaEbuildWithoutDigestGenerator(DefaultEbuildGenerator):
    &quot;&quot;&quot;
    Implementation of ebuild generator without sources digesting.
    &quot;&quot;&quot;
    def __init__(self, package_db):

        vars_before_inherit = \
          [&quot;repo_uri&quot;, &quot;source_type&quot;, &quot;realname&quot;]

        inherit = [&quot;g-elpa&quot;]

        vars_after_description = \
          [&quot;homepage&quot;]

        vars_after_keywords = \
          [&quot;depend&quot;, &quot;rdepend&quot;]

        layout = Layout(vars_before_inherit, inherit,
                    vars_after_description, vars_after_keywords)

        super(ElpaEbuildWithoutDigestGenerator, self).__init__(package_db, layout)
</pre>
</div>
<div class="section" id="metadata-generator">
<h1>Metadata generator</h1>
<p>To use metadata generator you should just define some variables in ebuild data.</p>
<div class="section" id="xml-schema-format">
<h2>XML schema format</h2>
<p>Metadata generator uses a XML schema in format defined in g_sorcery.metadata module.
Schema is a list of entries. Each entry describes one XML tag.
Entry is a dictionary. Dictionary keys are:</p>
<ul>
<li><dl class="first docutils">
<dt><strong>name</strong></dt>
<dd><p class="first last">Name of a tag</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>multiple</strong></dt>
<dd><p class="first last">Defines if a given tag can be used more then one time. It is a tuple. First element
of a tuple is boolean. If it is set a tag can be repeated. Second element is a string.
If it is not empty, it defines a name for an attribute
that will distinguish different entries of a tag.</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>required</strong></dt>
<dd><p class="first last">Boolean that defines if a given tag is required.</p>
</dd>
</dl>
</li>
<li><dl class="first docutils">
<dt><strong>subtags</strong></dt>
<dd><p class="first last">List of subtags.</p>
</dd>
</dl>
</li>
</ul>
</div>
<div class="section" id="data-dictionary-format">
<h2>Data dictionary format</h2>
<p>The part of ebuild data used for metadata generation should have data dictionary format
also defined in g_sorcery.metadata.</p>
<p>Keys correspond to tags from a schema with the same name.
If a tag is not multiple without subkeys value is just a
string with text for the tag.
If tag is multiple value is a list with entries
corresponding to a single tag.
If tag has subtags value is a dictionary with entries
corresponding to subkeys and <strong>text</strong> entry corresponding
to text for the tag.
If tag should have attributes value is a tuple or list with
0 element containing an attribute and 1 element containing
a value for the tag as described previously.</p>
</div>
<div class="section" id="metadata-xml-schema">
<h2>Metadata XML schema</h2>
<p>Metadata XML schema looks like</p>
<pre class="code literal-block">
default_schema = [{'name' : 'herd',
                   'multiple' : (True, &quot;&quot;),
                   'required' : False,
                   'subtags' : []},

                   {'name' : 'maintainer',
                   'multiple' : (True, &quot;&quot;),
                   'required' : False,
                   'subtags' : [{'name' : 'email',
                                 'multiple' : (False, &quot;&quot;),
                                 'required' : True,
                                 'subtags' : []},
                                 {'name' : 'name',
                                 'multiple' : (False, &quot;&quot;),
                                 'required' : False,
                                 'subtags' : []},
                                 {'name' : 'description',
                                 'multiple' : (False, &quot;&quot;),
                                 'required' : False,
                                 'subtags' : []},
                                 ]
                    },

                    {'name' : 'longdescription',
                     'multiple' : (False, &quot;&quot;),
                     'required' : False,
                     'subtags' : []},

                     {'name' : 'use',
                     'multiple' : (False, &quot;&quot;),
                     'required' : False,
                     'subtags' : [{'name' : 'flag',
                                 'multiple' : (True, &quot;name&quot;),
                                 'required' : True,
                                 'subtags' : []}]
                     },

                     {'name' : 'upstream',
                     'multiple' : (False, &quot;&quot;),
                     'required' : False,
                     'subtags' : [{'name' : 'maintainer',
                                 'multiple' : (True, &quot;&quot;),
                                 'required' : False,
                                 'subtags' : [{'name' : 'name',
                                               'multiple' : (False, &quot;&quot;),
                                               'required' : True,
                                               'subtags' : []},
                                               {'name' : 'email',
                                               'multiple' : (False, &quot;&quot;),
                                               'required' : False,
                                               'subtags' : []}]},
                                {'name' : 'changelog',
                                 'multiple' : (False, &quot;&quot;),
                                 'required' : False,
                                 'subtags' : []},
                                 {'name' : 'doc',
                                 'multiple' : (False, &quot;&quot;),
                                 'required' : False,
                                 'subtags' : []},
                                 {'name' : 'bugs-to',
                                 'multiple' : (False, &quot;&quot;),
                                 'required' : False,
                                 'subtags' : []},
                                 {'name' : 'remote-id',
                                 'multiple' : (False, &quot;&quot;),
                                 'required' : False,
                                 'subtags' : []},
                                ]
                        },
                   ]
</pre>
<p>So to have metadata.xml filled with e.g. maintainer info you should add to ebuild data
something like</p>
<pre class="code literal-block">
{'maintainer' : [{'email' : 'piatlicki&#64;gmail.com',
                  'name' : 'Jauhien Piatlicki'}]}
</pre>
</div>
</div>
<div class="section" id="layman-integration">
<h1>Layman integration</h1>
<p>There is a <strong>layman</strong> integration for <strong>g-sorcery</strong> (thanks to Brian Dolbec and Auke Booij here).
To use it you just need to install an xml file describing your repositories in
<strong>/etc/layman/overlays</strong> directory. For our example of backend config we could write an xml file
that looks like</p>
<pre class="code literal-block">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE repositories SYSTEM &quot;/dtd/repositories.dtd&quot;&gt;
&lt;repositories xmlns=&quot;&quot; version=&quot;1.0&quot;&gt;
&lt;repo quality=&quot;experimental&quot; status=&quot;unofficial&quot;&gt;
    &lt;name&gt;gnu-elpa&lt;/name&gt;
    &lt;description&gt;packages for emacs&lt;/description&gt;
    &lt;homepage&gt;http://elpa.gnu.org/&lt;/homepage&gt;
    &lt;owner&gt;
      &lt;email&gt;piatlicki&#64;gmail.com&lt;/email&gt;
      &lt;name&gt;Jauhien Piatlicki&lt;/name&gt;
    &lt;/owner&gt;
    &lt;source type=&quot;g-sorcery&quot;&gt;gs-elpa gnu-elpa&lt;/source&gt;
&lt;/repo&gt;
&lt;repo quality=&quot;experimental&quot; status=&quot;unofficial&quot;&gt;
    &lt;name&gt;marmalade&lt;/name&gt;
    &lt;description&gt;packages for emacs&lt;/description&gt;
    &lt;homepage&gt;http://marmalade-repo.org/&lt;/homepage&gt;
    &lt;owner&gt;
      &lt;email&gt;piatlicki&#64;gmail.com&lt;/email&gt;
      &lt;name&gt;Jauhien Piatlicki&lt;/name&gt;
    &lt;/owner&gt;
    &lt;source type=&quot;g-sorcery&quot;&gt;gs-elpa marmalade&lt;/source&gt;
&lt;/repo&gt;
&lt;repo quality=&quot;experimental&quot; status=&quot;unofficial&quot;&gt;
    &lt;name&gt;melpa&lt;/name&gt;
    &lt;description&gt;packages for emacs&lt;/description&gt;
    &lt;homepage&gt;http://melpa.milkbox.net&lt;/homepage&gt;
    &lt;owner&gt;
      &lt;email&gt;piatlicki&#64;gmail.com&lt;/email&gt;
      &lt;name&gt;Jauhien Piatlicki&lt;/name&gt;
    &lt;/owner&gt;
    &lt;source type=&quot;g-sorcery&quot;&gt;gs-elpa melpa&lt;/source&gt;
&lt;/repo&gt;
&lt;/repositories&gt;
</pre>
<p>In entries <strong>&lt;source type=&quot;g-sorcery&quot;&gt;gs-elpa melpa&lt;/source&gt;</strong> the source type
should always be <strong>g-sorcery</strong>, <strong>gs-elpa</strong> is backend name and <strong>melpa</strong> is repository name.</p>
<p>For full description of format of this file see <strong>layman</strong> documentation.</p>
</div>
<div class="section" id="summary">
<h1>Summary</h1>
<p>So to create your own backend you should write a module named <strong>backend</strong> and define there
a variable named <strong>instance</strong> that is an instance of g_sorcery.backend.Backend class. Or something
that quacks like this class.</p>
<p>Before doing it you should have defined classes you pass to it as parameters. They should be database
generator, two ebuild generators, eclass and metadata generators.</p>
<p>Also you should write an executable that calls g-sorcery and some configs.</p>
<p>To have better understanding you can look at gs-elpa and gs-pypi backends available
in g-sorcery repository. Also available tests could be usefull.</p>
<p>Note that there is a tool for editing generated database named <strong>gs-db-tool</strong>.</p>
</div>
</div>
</body>
</html>