chemruby 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README +120 -0
- data/Rakefile +195 -0
- data/ext/extconf.rb +4 -0
- data/ext/subcomp.c +416 -0
- data/lib/chem.rb +130 -0
- data/lib/chem/appl.rb +1 -0
- data/lib/chem/appl/chem3dole.rb +36 -0
- data/lib/chem/appl/tinker/nucleic.rb +40 -0
- data/lib/chem/appl/tinker/tinker_reader.rb +43 -0
- data/lib/chem/data.rb +4 -0
- data/lib/chem/data/atomic_weight.rb +124 -0
- data/lib/chem/data/character.rb +2 -0
- data/lib/chem/data/electronegativity.rb +14 -0
- data/lib/chem/data/periodic_table.rb +6 -0
- data/lib/chem/data/prime_numbers.rb +1 -0
- data/lib/chem/data/vdw_radii.rb +1 -0
- data/lib/chem/db.rb +64 -0
- data/lib/chem/db/cansmi.rb +234 -0
- data/lib/chem/db/cdx.rb +1525 -0
- data/lib/chem/db/eps.rb +164 -0
- data/lib/chem/db/g98.rb +909 -0
- data/lib/chem/db/gspan.rb +130 -0
- data/lib/chem/db/iupac.rb +5 -0
- data/lib/chem/db/iupac/a_1.rb +46 -0
- data/lib/chem/db/iupac/iuparser.rb +226 -0
- data/lib/chem/db/iupac/iuparser.ry +97 -0
- data/lib/chem/db/iupac/postfix.rb +2 -0
- data/lib/chem/db/kcf.rb +390 -0
- data/lib/chem/db/kcf_glycan.rb +19 -0
- data/lib/chem/db/kegg.rb +516 -0
- data/lib/chem/db/linucs/linparser.rb +144 -0
- data/lib/chem/db/linucs/linucs.ry +53 -0
- data/lib/chem/db/mdl.rb +379 -0
- data/lib/chem/db/molconnz.rb +12 -0
- data/lib/chem/db/mopac.rb +88 -0
- data/lib/chem/db/msi.rb +107 -0
- data/lib/chem/db/pdb_dic.rb +115 -0
- data/lib/chem/db/pdf.rb +131 -0
- data/lib/chem/db/pubchem.rb +113 -0
- data/lib/chem/db/rmagick.rb +70 -0
- data/lib/chem/db/sdf.rb +37 -0
- data/lib/chem/db/smbl.rb +88 -0
- data/lib/chem/db/smiles.rb +2 -0
- data/lib/chem/db/smiles/smiles.ry +203 -0
- data/lib/chem/db/smiles/smiparser.rb +375 -0
- data/lib/chem/db/swf.rb +74 -0
- data/lib/chem/db/sybyl.rb +150 -0
- data/lib/chem/db/tinker.rb +77 -0
- data/lib/chem/db/types/type_cansmi.rb +9 -0
- data/lib/chem/db/types/type_cdx.rb +24 -0
- data/lib/chem/db/types/type_gspan.rb +31 -0
- data/lib/chem/db/types/type_kcf.rb +28 -0
- data/lib/chem/db/types/type_kcf_glycan.rb +26 -0
- data/lib/chem/db/types/type_kegg.rb +92 -0
- data/lib/chem/db/types/type_mdl.rb +31 -0
- data/lib/chem/db/types/type_pdf.rb +33 -0
- data/lib/chem/db/types/type_png.rb +31 -0
- data/lib/chem/db/types/type_rxn.rb +25 -0
- data/lib/chem/db/types/type_sdf.rb +25 -0
- data/lib/chem/db/types/type_sybyl.rb +30 -0
- data/lib/chem/db/types/type_xyz.rb +26 -0
- data/lib/chem/db/vector.rb +128 -0
- data/lib/chem/db/xyz.rb +39 -0
- data/lib/chem/model.rb +119 -0
- data/lib/chem/model/skeleton.rb +37 -0
- data/lib/chem/utils.rb +11 -0
- data/lib/chem/utils/geometry.rb +27 -0
- data/lib/chem/utils/graph_db.rb +146 -0
- data/lib/chem/utils/math.rb +17 -0
- data/lib/chem/utils/prop.rb +123 -0
- data/lib/chem/utils/sssr.rb +101 -0
- data/lib/chem/utils/sub.rb +78 -0
- data/lib/chem/utils/transform.rb +110 -0
- data/lib/chem/utils/traverse.rb +37 -0
- data/lib/chem/utils/ullmann.rb +134 -0
- data/lib/graph.rb +41 -0
- data/lib/graph/cluster.rb +20 -0
- data/lib/graph/morgan.rb +38 -0
- data/sample/frequent_subgraph.rb +46 -0
- data/sample/images/ex1.rb +11 -0
- data/sample/images/ex2.rb +4 -0
- data/sample/images/ex3.rb +5 -0
- data/sample/images/ex4.rb +17 -0
- data/sample/images/ex5.rb +10 -0
- data/sample/images/mol/adenine.mol +26 -0
- data/sample/images/mol/atp.mol +69 -0
- data/sample/images/temp/ex5.mol +344 -0
- data/sample/kegg_db.rb +116 -0
- data/setup.rb +1551 -0
- data/test/all.rb +6 -0
- data/test/coord_test.rb +17 -0
- data/test/ctab_test.rb +31 -0
- data/test/data/A_21.tar.gz +0 -0
- data/test/data/A_21/aceanthrylene.cdx +0 -0
- data/test/data/A_21/aceanthrylene.mol +40 -0
- data/test/data/A_21/acenaphthylene.cdx +0 -0
- data/test/data/A_21/acenaphthylene.mol +31 -0
- data/test/data/A_21/acephenanthrylene.cdx +0 -0
- data/test/data/A_21/acephenanthrylene.mol +40 -0
- data/test/data/A_21/anthracene.cdx +0 -0
- data/test/data/A_21/anthracene.mol +35 -0
- data/test/data/A_21/as-indacene.cdx +0 -0
- data/test/data/A_21/as-indacene.mol +31 -0
- data/test/data/A_21/azulene.cdx +0 -0
- data/test/data/A_21/azulene.mol +26 -0
- data/test/data/A_21/biphenylene.cdx +0 -0
- data/test/data/A_21/biphenylene.mol +31 -0
- data/test/data/A_21/chrysene.cdx +0 -0
- data/test/data/A_21/chrysene.mol +44 -0
- data/test/data/A_21/coronen.cdx +0 -0
- data/test/data/A_21/coronen.mol +59 -0
- data/test/data/A_21/fluoranthene.cdx +0 -0
- data/test/data/A_21/fluoranthene.mol +40 -0
- data/test/data/A_21/fluorene.cdx +0 -0
- data/test/data/A_21/fluorene.mol +33 -0
- data/test/data/A_21/heptacene.cdx +0 -0
- data/test/data/A_21/heptacene.mol +71 -0
- data/test/data/A_21/heptalene.cdx +0 -0
- data/test/data/A_21/heptalene.mol +30 -0
- data/test/data/A_21/heptaphene.cdx +0 -0
- data/test/data/A_21/heptaphene.mol +71 -0
- data/test/data/A_21/hexacene.cdx +0 -0
- data/test/data/A_21/hexacene.mol +62 -0
- data/test/data/A_21/hexaphene.cdx +0 -0
- data/test/data/A_21/hexaphene.mol +62 -0
- data/test/data/A_21/indene.cdx +0 -0
- data/test/data/A_21/indene.mol +24 -0
- data/test/data/A_21/iupac.txt +41 -0
- data/test/data/A_21/naphthacene.cdx +0 -0
- data/test/data/A_21/naphthacene.mol +44 -0
- data/test/data/A_21/naphthalene.cdx +0 -0
- data/test/data/A_21/naphthalene.mol +26 -0
- data/test/data/A_21/ovalene.cdx +0 -0
- data/test/data/A_21/ovalene.mol +78 -0
- data/test/data/A_21/pentacene.cdx +0 -0
- data/test/data/A_21/pentacene.mol +53 -0
- data/test/data/A_21/pentalene.cdx +0 -0
- data/test/data/A_21/pentalene.mol +22 -0
- data/test/data/A_21/pentaphene.cdx +0 -0
- data/test/data/A_21/pentaphene.mol +53 -0
- data/test/data/A_21/perylene.cdx +0 -0
- data/test/data/A_21/perylene.mol +49 -0
- data/test/data/A_21/phenalene.cdx +0 -0
- data/test/data/A_21/phenalene.mol +33 -0
- data/test/data/A_21/phenanthrene.cdx +0 -0
- data/test/data/A_21/phenanthrene.mol +35 -0
- data/test/data/A_21/picene.cdx +0 -0
- data/test/data/A_21/picene.mol +53 -0
- data/test/data/A_21/pleiadene.cdx +0 -0
- data/test/data/A_21/pleiadene.mol +44 -0
- data/test/data/A_21/pyranthrene.cdx +0 -0
- data/test/data/A_21/pyranthrene.mol +72 -0
- data/test/data/A_21/pyrene.cdx +0 -0
- data/test/data/A_21/pyrene.mol +40 -0
- data/test/data/A_21/rubicene.cdx +0 -0
- data/test/data/A_21/rubicene.mol +63 -0
- data/test/data/A_21/s-indacene.cdx +0 -0
- data/test/data/A_21/s-indacene.mol +31 -0
- data/test/data/A_21/tetraphenylene.cdx +0 -0
- data/test/data/A_21/tetraphenylene.mol +57 -0
- data/test/data/A_21/trinaphthylene.cdx +0 -0
- data/test/data/A_21/trinaphthylene.mol +71 -0
- data/test/data/A_21/triphenylene.cdx +0 -0
- data/test/data/A_21/triphenylene.mol +44 -0
- data/test/data/C00147.kcf +25 -0
- data/test/data/G00147.kcf +13 -0
- data/test/data/atp.mol +69 -0
- data/test/data/cyclohexane.mol +17 -0
- data/test/data/cyclohexane.ps +485 -0
- data/test/data/fullerene.mol +155 -0
- data/test/data/glycan +33 -0
- data/test/data/hypericin.cdx +0 -0
- data/test/data/hypericin.cdxml +596 -0
- data/test/data/hypericin.chm +0 -0
- data/test/data/hypericin.ct +85 -0
- data/test/data/hypericin.f1d +0 -0
- data/test/data/hypericin.f1q +0 -0
- data/test/data/hypericin.gif +0 -0
- data/test/data/hypericin.mol +88 -0
- data/test/data/hypericin.mol2 +159 -0
- data/test/data/hypericin.msm +123 -0
- data/test/data/hypericin.pdf +359 -0
- data/test/data/hypericin.png +0 -0
- data/test/data/hypericin.ps +0 -0
- data/test/data/hypericin.skc +0 -0
- data/test/data/hypericin2.gif +0 -0
- data/test/data/hypericin2.ps +0 -0
- data/test/data/kegg/genomes/hsa/hsa_enzyme.list +4 -0
- data/test/data/kegg/genomes/hsa/hsa_pfam.list +4 -0
- data/test/data/kegg/ligand/mol/C00147.mol +26 -0
- data/test/data/kegg/ligand/reaction +14 -0
- data/test/data/kegg/ligand/reaction.lst +1 -0
- data/test/data/kegg/ligand/reaction_mapformula.lst +3 -0
- data/test/data/reaction +14 -0
- data/test/data/reaction.lst +1 -0
- data/test/data/reaction_mapformula.lst +3 -0
- data/test/data/rxn/C00001.mol +6 -0
- data/test/data/rxn/C00011.mol +10 -0
- data/test/data/rxn/C00014.mol +6 -0
- data/test/data/rxn/C01010.mol +18 -0
- data/test/data/rxn/sample.rxn +50 -0
- data/test/data/rxn/substitution.rxn +45 -0
- data/test/data/test.eps +0 -0
- data/test/data/test.mol +28 -0
- data/test/data/test.sdf +143 -0
- data/test/data/test.skc +0 -0
- data/test/data/test.xyz +4 -0
- data/test/data/test_lf.sdf +143 -0
- data/test/heavy_test_pubchem.rb +16 -0
- data/test/multiple_test.rb +22 -0
- data/test/test_adj.rb +54 -0
- data/test/test_canonical_smiles.rb +46 -0
- data/test/test_cdx.rb +32 -0
- data/test/test_chem.rb +18 -0
- data/test/test_cluster.rb +19 -0
- data/test/test_db.rb +11 -0
- data/test/test_eps.rb +24 -0
- data/test/test_geometry.rb +11 -0
- data/test/test_gspan.rb +28 -0
- data/test/test_iupac.rb +36 -0
- data/test/test_kcf.rb +24 -0
- data/test/test_kcf_glycan.rb +10 -0
- data/test/test_kegg.rb +118 -0
- data/test/test_linucs.rb +21 -0
- data/test/test_mdl.rb +45 -0
- data/test/test_mol2.rb +62 -0
- data/test/test_morgan.rb +21 -0
- data/test/test_pdf.rb +12 -0
- data/test/test_prop.rb +86 -0
- data/test/test_rmagick.rb +15 -0
- data/test/test_sbdb.rb +23 -0
- data/test/test_sdf.rb +30 -0
- data/test/test_smiles.rb +84 -0
- data/test/test_sssr.rb +18 -0
- data/test/test_sub.rb +47 -0
- data/test/test_subcomp.rb +37 -0
- data/test/test_traverse.rb +29 -0
- data/test/test_writer.rb +13 -0
- data/test/test_xyz.rb +15 -0
- data/test/type_test.rb +25 -0
- metadata +290 -0
data/sample/kegg_db.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
|
2
|
+
$: << 'lib'
|
3
|
+
$: << 'ext'
|
4
|
+
$: << '/home/tanaka/proj/sqliter/lib'
|
5
|
+
$: << '/home/tanaka/proj/sqliter/ext'
|
6
|
+
|
7
|
+
require 'sqliter'
|
8
|
+
require 'table'
|
9
|
+
require 'chem'
|
10
|
+
|
11
|
+
module Chem
|
12
|
+
module Molecule
|
13
|
+
include RRecord
|
14
|
+
|
15
|
+
table_text "adj_matrix"
|
16
|
+
table_text "filename"
|
17
|
+
table_text "n_nodes", :method => "nodes.length"
|
18
|
+
table_number "n_edges", :method => "edges.length"# table_number NOT IMPLEMENTED YET!!!
|
19
|
+
table_number "n_carbonds", :method => "nodes.find_all{|node| node.element == :C}.length"
|
20
|
+
table_number "n_nitrogens", :method => "nodes.find_all{|node| node.element == :N}.length"
|
21
|
+
#table_number "n_carbons", :methods => "node_types."
|
22
|
+
def node_types
|
23
|
+
nodes.collect{|node| Element2Number[node.element]}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
if false#true
|
30
|
+
db = RDataBase.new("temp/test.db")
|
31
|
+
table = db.new_table(Chem::Molecule)
|
32
|
+
|
33
|
+
Dir["/home/tanaka/share/data/kegg/ligand/mol/C000*.mol"].each do |file|
|
34
|
+
puts file
|
35
|
+
next unless File.exist?(file)
|
36
|
+
mol = Chem.open_mol(file)
|
37
|
+
table.push(mol)
|
38
|
+
end
|
39
|
+
else # search
|
40
|
+
def find mol
|
41
|
+
db = RDataBase.new("temp/test.db")
|
42
|
+
stmt = db.prepare("select filename, adj_matrix, node_types from table0 where n_nodes = ? and n_edges = ?;")
|
43
|
+
stmt.bind(mol.nodes.length.to_s, mol.edges.length.to_s)
|
44
|
+
end
|
45
|
+
query = Chem.open_mol("/home/tanaka/share/data/kegg/ligand/mol/C00147.mol")
|
46
|
+
|
47
|
+
mols = find query
|
48
|
+
mols.each do |filename, n_edges|
|
49
|
+
p filename
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
__END__
|
55
|
+
table.select(["n_nodes", "31"])
|
56
|
+
|
57
|
+
__END__
|
58
|
+
|
59
|
+
mol1 =
|
60
|
+
mol2 = Chem.open_mol("/home/tanaka/share/data/kegg/ligand/mol/C%05d.mol" % 3)
|
61
|
+
|
62
|
+
p mol2.match_by_ullmann(mol1)
|
63
|
+
|
64
|
+
__END__
|
65
|
+
|
66
|
+
table = RTable.new(Chem::Molecule)
|
67
|
+
|
68
|
+
1.upto(10) do |n|
|
69
|
+
file = "/home/tanaka/share/data/kegg/ligand/mol/C%05d.mol" % n
|
70
|
+
next unless File.exist?(file)
|
71
|
+
mol = Chem.open_mol(file)
|
72
|
+
table.push(mol)
|
73
|
+
end
|
74
|
+
|
75
|
+
table.save("kegg.db")
|
76
|
+
|
77
|
+
__END__
|
78
|
+
|
79
|
+
# if true
|
80
|
+
# p Chem.open_mol("/home/tanaka/share/data/kegg/ligand/mol/C03580.mol").match_by_ullmann($mol)
|
81
|
+
# end
|
82
|
+
|
83
|
+
# __END__
|
84
|
+
|
85
|
+
# open("false.txt").each do |line|
|
86
|
+
# file = "/home/tanaka/share/data/kegg/ligand/mol/#{line.chop}.mol"
|
87
|
+
# next unless File.exist?(file)
|
88
|
+
# mol2 = Chem.open_mol(file)
|
89
|
+
|
90
|
+
# puts "%s %3d %3d %s" % [line.chop, mol2.nodes.length, mol2.edges.length, mol2.match_by_ullmann($mol).inspect]
|
91
|
+
# end
|
92
|
+
# __END__
|
93
|
+
|
94
|
+
|
95
|
+
def check name
|
96
|
+
file = "/home/tanaka/share/data/kegg/ligand/mol/#{name}.mol"
|
97
|
+
return nil if !File.exist?(file)
|
98
|
+
mol2 = Chem.open_mol(file)
|
99
|
+
#mol.match_by_ullmann(mol2)
|
100
|
+
mol2.match_by_ullmann($mol)
|
101
|
+
end
|
102
|
+
|
103
|
+
# check("C00040")
|
104
|
+
|
105
|
+
#__END__
|
106
|
+
|
107
|
+
open("false.txt", "w") do |out|
|
108
|
+
%w(C00002 C00003 C00004 C00005 C00006 C00008 C00010 C00016 C00019 C00020 C00021 C00024 C00040 C00053 C00054 C00083 C00091 C00100 C00131 C00136 C00147 C00154 C00170 C00194 C00206 C00212 C00223 C00224 C00264 C00313 C00323 C00332 C00356 C00360 C00371 C00406 C00411 C00412 C00498 C00510 C00512 C00527 C00531 C00540 C00559 C00566 C00575 C00582 C00605 C00630 C00640 C00658 C00683 C00728 C00798 C00821 C00827 C00845 C00857 C00877 C00882 C00888 C00894 C00895 C00904 C00920 C00939 C00946 C00968 C01011 C01033 C01063 C01086 C01122 C01137 C01144 C01201 C01213 C01260 C01291 C01352 C01367 C01469 C01513 C01610 C01655 C01794 C01832 C01882 C01894 C01920 C01942 C01944 C02015 C02029 C02030 C02041 C02050 C02060 C02187 C02232 C02247 C02249 C02331 C02335 C02353 C02411 C02451 C02509 C02557 C02577 C02593 C02609 C02611 C02784 C02792 C02801 C02802 C02843 C02860 C02864 C02939 C02944 C02949 C02973 C03035 C03058 C03060 C03069 C03160 C03188 C03218 C03221 C03231 C03237 C03246 C03293 C03300 C03344 C03345 C03357 C03361 C03391 C03416 C03423 C03460 C03462 C03466 C03483 C03561 C03568 C03580 C03595 C03673 C03685 C03709 C03724 C03794 C03795 C03815 C03850 C03851 C03883 C04013 C04030 C04047 C04058 C04083 C04154 C04159 C04307 C04316 C04348 C04380 C04405 C04422 C04425 C04432 C04512 C04644 C04675 C04713 C04760 C04779 C04856 C04899 C05056 C05057 C05065 C05067 C05116 C05117 C05165 C05195 C05198 C05231 C05232 C05258 C05259 C05260 C05262 C05263 C05264 C05265 C05266 C05267 C05268 C05269 C05270 C05271 C05272 C05273 C05274 C05275 C05276 C05279 C05280 C05329 C05337 C05338 C05342 C05447 C05448 C05449 C05450 C05460 C05461 C05467 C05560 C05668 C05686 C05691 C05692 C05696 C05921 C05983 C05989 C05993 C05997 C05998 C06000 C06027 C06028 C06192 C06197 C06322 C06387 C06397 C06398 C06433 C06434 C06506 C06507 C06508 C06509 C06510 C06625 C06671 C06714 C06715 C06723 C06736 C06737 C06743 C06749 C07024 C07025 C07026 C07027 C07028 C07029 C07030 C07031 C07032 C07118 C07160 C07195 C07296 C07297 C07302 C07303 C07343 C07347 C07348 C07624 C08083 C08272 C08431 C08434 C08435 C09809 C09810 C09811 C09812 C09813 C09817 C09818 C09819 C09820 C09821 C09823 C09824 C09825 C11062 C11263 C11266 C11277 C11407 C11421 C11448 C11462 C11500 C11618 C11929 C11934 C11935 C11936 C11945 C11946 C11947 C11948 C11949 C12092 C12203).each do |name|
|
109
|
+
result = check name
|
110
|
+
unless result
|
111
|
+
out.puts name
|
112
|
+
end
|
113
|
+
puts "%s %s" % [name, result.inspect]
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
data/setup.rb
ADDED
@@ -0,0 +1,1551 @@
|
|
1
|
+
#
|
2
|
+
# setup.rb
|
3
|
+
#
|
4
|
+
# Copyright (c) 2000-2005 Minero Aoki
|
5
|
+
#
|
6
|
+
# This program is free software.
|
7
|
+
# You can distribute/modify this program under the terms of
|
8
|
+
# the GNU LGPL, Lesser General Public License version 2.1.
|
9
|
+
#
|
10
|
+
|
11
|
+
unless Enumerable.method_defined?(:map) # Ruby 1.4.6
|
12
|
+
module Enumerable
|
13
|
+
alias map collect
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
unless File.respond_to?(:read) # Ruby 1.6
|
18
|
+
def File.read(fname)
|
19
|
+
open(fname) {|f|
|
20
|
+
return f.read
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
unless Errno.const_defined?(:ENOTEMPTY) # Windows?
|
26
|
+
module Errno
|
27
|
+
class ENOTEMPTY
|
28
|
+
# We do not raise this exception, implementation is not needed.
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def File.binread(fname)
|
34
|
+
open(fname, 'rb') {|f|
|
35
|
+
return f.read
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
# for corrupted Windows' stat(2)
|
40
|
+
def File.dir?(path)
|
41
|
+
File.directory?((path[-1,1] == '/') ? path : path + '/')
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
class ConfigTable
|
46
|
+
|
47
|
+
include Enumerable
|
48
|
+
|
49
|
+
def initialize(rbconfig)
|
50
|
+
@rbconfig = rbconfig
|
51
|
+
@items = []
|
52
|
+
@table = {}
|
53
|
+
# options
|
54
|
+
@install_prefix = nil
|
55
|
+
@config_opt = nil
|
56
|
+
@verbose = true
|
57
|
+
@no_harm = false
|
58
|
+
@libsrc_pattern = '*.rb'
|
59
|
+
end
|
60
|
+
|
61
|
+
attr_accessor :install_prefix
|
62
|
+
attr_accessor :config_opt
|
63
|
+
|
64
|
+
attr_writer :verbose
|
65
|
+
|
66
|
+
def verbose?
|
67
|
+
@verbose
|
68
|
+
end
|
69
|
+
|
70
|
+
attr_writer :no_harm
|
71
|
+
|
72
|
+
def no_harm?
|
73
|
+
@no_harm
|
74
|
+
end
|
75
|
+
|
76
|
+
attr_accessor :libsrc_pattern
|
77
|
+
|
78
|
+
def [](key)
|
79
|
+
lookup(key).resolve(self)
|
80
|
+
end
|
81
|
+
|
82
|
+
def []=(key, val)
|
83
|
+
lookup(key).set val
|
84
|
+
end
|
85
|
+
|
86
|
+
def names
|
87
|
+
@items.map {|i| i.name }
|
88
|
+
end
|
89
|
+
|
90
|
+
def each(&block)
|
91
|
+
@items.each(&block)
|
92
|
+
end
|
93
|
+
|
94
|
+
def key?(name)
|
95
|
+
@table.key?(name)
|
96
|
+
end
|
97
|
+
|
98
|
+
def lookup(name)
|
99
|
+
@table[name] or setup_rb_error "no such config item: #{name}"
|
100
|
+
end
|
101
|
+
|
102
|
+
def add(item)
|
103
|
+
@items.push item
|
104
|
+
@table[item.name] = item
|
105
|
+
end
|
106
|
+
|
107
|
+
def remove(name)
|
108
|
+
item = lookup(name)
|
109
|
+
@items.delete_if {|i| i.name == name }
|
110
|
+
@table.delete_if {|name, i| i.name == name }
|
111
|
+
item
|
112
|
+
end
|
113
|
+
|
114
|
+
def load_script(path, inst = nil)
|
115
|
+
if File.file?(path)
|
116
|
+
MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def savefile
|
121
|
+
'.config'
|
122
|
+
end
|
123
|
+
|
124
|
+
def load_savefile
|
125
|
+
begin
|
126
|
+
File.foreach(savefile()) do |line|
|
127
|
+
k, v = *line.split(/=/, 2)
|
128
|
+
self[k] = v.strip
|
129
|
+
end
|
130
|
+
rescue Errno::ENOENT
|
131
|
+
setup_rb_error $!.message + "\n#{File.basename($0)} config first"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def save
|
136
|
+
@items.each {|i| i.value }
|
137
|
+
File.open(savefile(), 'w') {|f|
|
138
|
+
@items.each do |i|
|
139
|
+
f.printf "%s=%s\n", i.name, i.value if i.value? and i.value
|
140
|
+
end
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
def load_standard_entries
|
145
|
+
standard_entries(@rbconfig).each do |ent|
|
146
|
+
add ent
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def standard_entries(rbconfig)
|
151
|
+
c = rbconfig
|
152
|
+
|
153
|
+
rubypath = c['bindir'] + '/' + c['ruby_install_name']
|
154
|
+
|
155
|
+
major = c['MAJOR'].to_i
|
156
|
+
minor = c['MINOR'].to_i
|
157
|
+
teeny = c['TEENY'].to_i
|
158
|
+
version = "#{major}.#{minor}"
|
159
|
+
|
160
|
+
# ruby ver. >= 1.4.4?
|
161
|
+
newpath_p = ((major >= 2) or
|
162
|
+
((major == 1) and
|
163
|
+
((minor >= 5) or
|
164
|
+
((minor == 4) and (teeny >= 4)))))
|
165
|
+
|
166
|
+
if c['rubylibdir']
|
167
|
+
# V > 1.6.3
|
168
|
+
libruby = "#{c['prefix']}/lib/ruby"
|
169
|
+
librubyver = c['rubylibdir']
|
170
|
+
librubyverarch = c['archdir']
|
171
|
+
siteruby = c['sitedir']
|
172
|
+
siterubyver = c['sitelibdir']
|
173
|
+
siterubyverarch = c['sitearchdir']
|
174
|
+
elsif newpath_p
|
175
|
+
# 1.4.4 <= V <= 1.6.3
|
176
|
+
libruby = "#{c['prefix']}/lib/ruby"
|
177
|
+
librubyver = "#{c['prefix']}/lib/ruby/#{version}"
|
178
|
+
librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
|
179
|
+
siteruby = c['sitedir']
|
180
|
+
siterubyver = "$siteruby/#{version}"
|
181
|
+
siterubyverarch = "$siterubyver/#{c['arch']}"
|
182
|
+
else
|
183
|
+
# V < 1.4.4
|
184
|
+
libruby = "#{c['prefix']}/lib/ruby"
|
185
|
+
librubyver = "#{c['prefix']}/lib/ruby/#{version}"
|
186
|
+
librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}"
|
187
|
+
siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby"
|
188
|
+
siterubyver = siteruby
|
189
|
+
siterubyverarch = "$siterubyver/#{c['arch']}"
|
190
|
+
end
|
191
|
+
parameterize = lambda {|path|
|
192
|
+
path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')
|
193
|
+
}
|
194
|
+
|
195
|
+
if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
|
196
|
+
makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
|
197
|
+
else
|
198
|
+
makeprog = 'make'
|
199
|
+
end
|
200
|
+
|
201
|
+
[
|
202
|
+
ExecItem.new('installdirs', 'std/site/home',
|
203
|
+
'std: install under libruby; site: install under site_ruby; home: install under $HOME')\
|
204
|
+
{|val, table|
|
205
|
+
case val
|
206
|
+
when 'std'
|
207
|
+
table['rbdir'] = '$librubyver'
|
208
|
+
table['sodir'] = '$librubyverarch'
|
209
|
+
when 'site'
|
210
|
+
table['rbdir'] = '$siterubyver'
|
211
|
+
table['sodir'] = '$siterubyverarch'
|
212
|
+
when 'home'
|
213
|
+
setup_rb_error '$HOME was not set' unless ENV['HOME']
|
214
|
+
table['prefix'] = ENV['HOME']
|
215
|
+
table['rbdir'] = '$libdir/ruby'
|
216
|
+
table['sodir'] = '$libdir/ruby'
|
217
|
+
end
|
218
|
+
},
|
219
|
+
PathItem.new('prefix', 'path', c['prefix'],
|
220
|
+
'path prefix of target environment'),
|
221
|
+
PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
|
222
|
+
'the directory for commands'),
|
223
|
+
PathItem.new('libdir', 'path', parameterize.call(c['libdir']),
|
224
|
+
'the directory for libraries'),
|
225
|
+
PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
|
226
|
+
'the directory for shared data'),
|
227
|
+
PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
|
228
|
+
'the directory for man pages'),
|
229
|
+
PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
|
230
|
+
'the directory for system configuration files'),
|
231
|
+
PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']),
|
232
|
+
'the directory for local state data'),
|
233
|
+
PathItem.new('libruby', 'path', libruby,
|
234
|
+
'the directory for ruby libraries'),
|
235
|
+
PathItem.new('librubyver', 'path', librubyver,
|
236
|
+
'the directory for standard ruby libraries'),
|
237
|
+
PathItem.new('librubyverarch', 'path', librubyverarch,
|
238
|
+
'the directory for standard ruby extensions'),
|
239
|
+
PathItem.new('siteruby', 'path', siteruby,
|
240
|
+
'the directory for version-independent aux ruby libraries'),
|
241
|
+
PathItem.new('siterubyver', 'path', siterubyver,
|
242
|
+
'the directory for aux ruby libraries'),
|
243
|
+
PathItem.new('siterubyverarch', 'path', siterubyverarch,
|
244
|
+
'the directory for aux ruby binaries'),
|
245
|
+
PathItem.new('rbdir', 'path', '$siterubyver',
|
246
|
+
'the directory for ruby scripts'),
|
247
|
+
PathItem.new('sodir', 'path', '$siterubyverarch',
|
248
|
+
'the directory for ruby extentions'),
|
249
|
+
PathItem.new('rubypath', 'path', rubypath,
|
250
|
+
'the path to set to #! line'),
|
251
|
+
ProgramItem.new('rubyprog', 'name', rubypath,
|
252
|
+
'the ruby program using for installation'),
|
253
|
+
ProgramItem.new('makeprog', 'name', makeprog,
|
254
|
+
'the make program to compile ruby extentions'),
|
255
|
+
SelectItem.new('shebang', 'all/ruby/never', 'ruby',
|
256
|
+
'shebang line (#!) editing mode'),
|
257
|
+
BoolItem.new('without-ext', 'yes/no', 'no',
|
258
|
+
'does not compile/install ruby extentions')
|
259
|
+
]
|
260
|
+
end
|
261
|
+
private :standard_entries
|
262
|
+
|
263
|
+
def load_multipackage_entries
|
264
|
+
multipackage_entries().each do |ent|
|
265
|
+
add ent
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def multipackage_entries
|
270
|
+
[
|
271
|
+
PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
|
272
|
+
'package names that you want to install'),
|
273
|
+
PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
|
274
|
+
'package names that you do not want to install')
|
275
|
+
]
|
276
|
+
end
|
277
|
+
private :multipackage_entries
|
278
|
+
|
279
|
+
ALIASES = {
|
280
|
+
'std-ruby' => 'librubyver',
|
281
|
+
'stdruby' => 'librubyver',
|
282
|
+
'rubylibdir' => 'librubyver',
|
283
|
+
'archdir' => 'librubyverarch',
|
284
|
+
'site-ruby-common' => 'siteruby', # For backward compatibility
|
285
|
+
'site-ruby' => 'siterubyver', # For backward compatibility
|
286
|
+
'bin-dir' => 'bindir',
|
287
|
+
'bin-dir' => 'bindir',
|
288
|
+
'rb-dir' => 'rbdir',
|
289
|
+
'so-dir' => 'sodir',
|
290
|
+
'data-dir' => 'datadir',
|
291
|
+
'ruby-path' => 'rubypath',
|
292
|
+
'ruby-prog' => 'rubyprog',
|
293
|
+
'ruby' => 'rubyprog',
|
294
|
+
'make-prog' => 'makeprog',
|
295
|
+
'make' => 'makeprog'
|
296
|
+
}
|
297
|
+
|
298
|
+
def fixup
|
299
|
+
ALIASES.each do |ali, name|
|
300
|
+
@table[ali] = @table[name]
|
301
|
+
end
|
302
|
+
@items.freeze
|
303
|
+
@table.freeze
|
304
|
+
@options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/
|
305
|
+
end
|
306
|
+
|
307
|
+
def parse_opt(opt)
|
308
|
+
m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}"
|
309
|
+
m.to_a[1,2]
|
310
|
+
end
|
311
|
+
|
312
|
+
def dllext
|
313
|
+
@rbconfig['DLEXT']
|
314
|
+
end
|
315
|
+
|
316
|
+
def value_config?(name)
|
317
|
+
lookup(name).value?
|
318
|
+
end
|
319
|
+
|
320
|
+
class Item
|
321
|
+
def initialize(name, template, default, desc)
|
322
|
+
@name = name.freeze
|
323
|
+
@template = template
|
324
|
+
@value = default
|
325
|
+
@default = default
|
326
|
+
@description = desc
|
327
|
+
end
|
328
|
+
|
329
|
+
attr_reader :name
|
330
|
+
attr_reader :description
|
331
|
+
|
332
|
+
attr_accessor :default
|
333
|
+
alias help_default default
|
334
|
+
|
335
|
+
def help_opt
|
336
|
+
"--#{@name}=#{@template}"
|
337
|
+
end
|
338
|
+
|
339
|
+
def value?
|
340
|
+
true
|
341
|
+
end
|
342
|
+
|
343
|
+
def value
|
344
|
+
@value
|
345
|
+
end
|
346
|
+
|
347
|
+
def resolve(table)
|
348
|
+
@value.gsub(%r<\$([^/]+)>) { table[$1] }
|
349
|
+
end
|
350
|
+
|
351
|
+
def set(val)
|
352
|
+
@value = check(val)
|
353
|
+
end
|
354
|
+
|
355
|
+
private
|
356
|
+
|
357
|
+
def check(val)
|
358
|
+
setup_rb_error "config: --#{name} requires argument" unless val
|
359
|
+
val
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
class BoolItem < Item
|
364
|
+
def config_type
|
365
|
+
'bool'
|
366
|
+
end
|
367
|
+
|
368
|
+
def help_opt
|
369
|
+
"--#{@name}"
|
370
|
+
end
|
371
|
+
|
372
|
+
private
|
373
|
+
|
374
|
+
def check(val)
|
375
|
+
return 'yes' unless val
|
376
|
+
unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
|
377
|
+
setup_rb_error "config: --#{@name} accepts only yes/no for argument"
|
378
|
+
end
|
379
|
+
(/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
class PathItem < Item
|
384
|
+
def config_type
|
385
|
+
'path'
|
386
|
+
end
|
387
|
+
|
388
|
+
private
|
389
|
+
|
390
|
+
def check(path)
|
391
|
+
setup_rb_error "config: --#{@name} requires argument" unless path
|
392
|
+
path[0,1] == '$' ? path : File.expand_path(path)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
class ProgramItem < Item
|
397
|
+
def config_type
|
398
|
+
'program'
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
class SelectItem < Item
|
403
|
+
def initialize(name, selection, default, desc)
|
404
|
+
super
|
405
|
+
@ok = selection.split('/')
|
406
|
+
end
|
407
|
+
|
408
|
+
def config_type
|
409
|
+
'select'
|
410
|
+
end
|
411
|
+
|
412
|
+
private
|
413
|
+
|
414
|
+
def check(val)
|
415
|
+
unless @ok.include?(val.strip)
|
416
|
+
setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
|
417
|
+
end
|
418
|
+
val.strip
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
class ExecItem < Item
|
423
|
+
def initialize(name, selection, desc, &block)
|
424
|
+
super name, selection, nil, desc
|
425
|
+
@ok = selection.split('/')
|
426
|
+
@action = block
|
427
|
+
end
|
428
|
+
|
429
|
+
def config_type
|
430
|
+
'exec'
|
431
|
+
end
|
432
|
+
|
433
|
+
def value?
|
434
|
+
false
|
435
|
+
end
|
436
|
+
|
437
|
+
def resolve(table)
|
438
|
+
setup_rb_error "$#{name()} wrongly used as option value"
|
439
|
+
end
|
440
|
+
|
441
|
+
undef set
|
442
|
+
|
443
|
+
def evaluate(val, table)
|
444
|
+
v = val.strip.downcase
|
445
|
+
unless @ok.include?(v)
|
446
|
+
setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})"
|
447
|
+
end
|
448
|
+
@action.call v, table
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
class PackageSelectionItem < Item
|
453
|
+
def initialize(name, template, default, help_default, desc)
|
454
|
+
super name, template, default, desc
|
455
|
+
@help_default = help_default
|
456
|
+
end
|
457
|
+
|
458
|
+
attr_reader :help_default
|
459
|
+
|
460
|
+
def config_type
|
461
|
+
'package'
|
462
|
+
end
|
463
|
+
|
464
|
+
private
|
465
|
+
|
466
|
+
def check(val)
|
467
|
+
unless File.dir?("packages/#{val}")
|
468
|
+
setup_rb_error "config: no such package: #{val}"
|
469
|
+
end
|
470
|
+
val
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
class MetaConfigEnvironment
|
475
|
+
def intiailize(config, installer)
|
476
|
+
@config = config
|
477
|
+
@installer = installer
|
478
|
+
end
|
479
|
+
|
480
|
+
def config_names
|
481
|
+
@config.names
|
482
|
+
end
|
483
|
+
|
484
|
+
def config?(name)
|
485
|
+
@config.key?(name)
|
486
|
+
end
|
487
|
+
|
488
|
+
def bool_config?(name)
|
489
|
+
@config.lookup(name).config_type == 'bool'
|
490
|
+
end
|
491
|
+
|
492
|
+
def path_config?(name)
|
493
|
+
@config.lookup(name).config_type == 'path'
|
494
|
+
end
|
495
|
+
|
496
|
+
def value_config?(name)
|
497
|
+
@config.lookup(name).config_type != 'exec'
|
498
|
+
end
|
499
|
+
|
500
|
+
def add_config(item)
|
501
|
+
@config.add item
|
502
|
+
end
|
503
|
+
|
504
|
+
def add_bool_config(name, default, desc)
|
505
|
+
@config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
|
506
|
+
end
|
507
|
+
|
508
|
+
def add_path_config(name, default, desc)
|
509
|
+
@config.add PathItem.new(name, 'path', default, desc)
|
510
|
+
end
|
511
|
+
|
512
|
+
def set_config_default(name, default)
|
513
|
+
@config.lookup(name).default = default
|
514
|
+
end
|
515
|
+
|
516
|
+
def remove_config(name)
|
517
|
+
@config.remove(name)
|
518
|
+
end
|
519
|
+
|
520
|
+
# For only multipackage
|
521
|
+
def packages
|
522
|
+
raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer
|
523
|
+
@installer.packages
|
524
|
+
end
|
525
|
+
|
526
|
+
# For only multipackage
|
527
|
+
def declare_packages(list)
|
528
|
+
raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer
|
529
|
+
@installer.packages = list
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
end # class ConfigTable
|
534
|
+
|
535
|
+
|
536
|
+
# This module requires: #verbose?, #no_harm?
|
537
|
+
module FileOperations
|
538
|
+
|
539
|
+
def mkdir_p(dirname, prefix = nil)
|
540
|
+
dirname = prefix + File.expand_path(dirname) if prefix
|
541
|
+
$stderr.puts "mkdir -p #{dirname}" if verbose?
|
542
|
+
return if no_harm?
|
543
|
+
|
544
|
+
# Does not check '/', it's too abnormal.
|
545
|
+
dirs = File.expand_path(dirname).split(%r<(?=/)>)
|
546
|
+
if /\A[a-z]:\z/i =~ dirs[0]
|
547
|
+
disk = dirs.shift
|
548
|
+
dirs[0] = disk + dirs[0]
|
549
|
+
end
|
550
|
+
dirs.each_index do |idx|
|
551
|
+
path = dirs[0..idx].join('')
|
552
|
+
Dir.mkdir path unless File.dir?(path)
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
def rm_f(path)
|
557
|
+
$stderr.puts "rm -f #{path}" if verbose?
|
558
|
+
return if no_harm?
|
559
|
+
force_remove_file path
|
560
|
+
end
|
561
|
+
|
562
|
+
def rm_rf(path)
|
563
|
+
$stderr.puts "rm -rf #{path}" if verbose?
|
564
|
+
return if no_harm?
|
565
|
+
remove_tree path
|
566
|
+
end
|
567
|
+
|
568
|
+
def remove_tree(path)
|
569
|
+
if File.symlink?(path)
|
570
|
+
remove_file path
|
571
|
+
elsif File.dir?(path)
|
572
|
+
remove_tree0 path
|
573
|
+
else
|
574
|
+
force_remove_file path
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
def remove_tree0(path)
|
579
|
+
Dir.foreach(path) do |ent|
|
580
|
+
next if ent == '.'
|
581
|
+
next if ent == '..'
|
582
|
+
entpath = "#{path}/#{ent}"
|
583
|
+
if File.symlink?(entpath)
|
584
|
+
remove_file entpath
|
585
|
+
elsif File.dir?(entpath)
|
586
|
+
remove_tree0 entpath
|
587
|
+
else
|
588
|
+
force_remove_file entpath
|
589
|
+
end
|
590
|
+
end
|
591
|
+
begin
|
592
|
+
Dir.rmdir path
|
593
|
+
rescue Errno::ENOTEMPTY
|
594
|
+
# directory may not be empty
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
def move_file(src, dest)
|
599
|
+
force_remove_file dest
|
600
|
+
begin
|
601
|
+
File.rename src, dest
|
602
|
+
rescue
|
603
|
+
File.open(dest, 'wb') {|f|
|
604
|
+
f.write File.binread(src)
|
605
|
+
}
|
606
|
+
File.chmod File.stat(src).mode, dest
|
607
|
+
File.unlink src
|
608
|
+
end
|
609
|
+
end
|
610
|
+
|
611
|
+
def force_remove_file(path)
|
612
|
+
begin
|
613
|
+
remove_file path
|
614
|
+
rescue
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
def remove_file(path)
|
619
|
+
File.chmod 0777, path
|
620
|
+
File.unlink path
|
621
|
+
end
|
622
|
+
|
623
|
+
def install(from, dest, mode, prefix = nil)
|
624
|
+
$stderr.puts "install #{from} #{dest}" if verbose?
|
625
|
+
return if no_harm?
|
626
|
+
|
627
|
+
realdest = prefix ? prefix + File.expand_path(dest) : dest
|
628
|
+
realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
|
629
|
+
str = File.binread(from)
|
630
|
+
if diff?(str, realdest)
|
631
|
+
verbose_off {
|
632
|
+
rm_f realdest if File.exist?(realdest)
|
633
|
+
}
|
634
|
+
File.open(realdest, 'wb') {|f|
|
635
|
+
f.write str
|
636
|
+
}
|
637
|
+
File.chmod mode, realdest
|
638
|
+
|
639
|
+
File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
|
640
|
+
if prefix
|
641
|
+
f.puts realdest.sub(prefix, '')
|
642
|
+
else
|
643
|
+
f.puts realdest
|
644
|
+
end
|
645
|
+
}
|
646
|
+
end
|
647
|
+
end
|
648
|
+
|
649
|
+
def diff?(new_content, path)
|
650
|
+
return true unless File.exist?(path)
|
651
|
+
new_content != File.binread(path)
|
652
|
+
end
|
653
|
+
|
654
|
+
def command(*args)
|
655
|
+
$stderr.puts args.join(' ') if verbose?
|
656
|
+
system(*args) or raise RuntimeError,
|
657
|
+
"system(#{args.map{|a| a.inspect }.join(' ')}) failed"
|
658
|
+
end
|
659
|
+
|
660
|
+
def ruby(*args)
|
661
|
+
command config('rubyprog'), *args
|
662
|
+
end
|
663
|
+
|
664
|
+
def make(task = nil)
|
665
|
+
command(*[config('makeprog'), task].compact)
|
666
|
+
end
|
667
|
+
|
668
|
+
def extdir?(dir)
|
669
|
+
File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb")
|
670
|
+
end
|
671
|
+
|
672
|
+
def files_of(dir)
|
673
|
+
Dir.open(dir) {|d|
|
674
|
+
return d.select {|ent| File.file?("#{dir}/#{ent}") }
|
675
|
+
}
|
676
|
+
end
|
677
|
+
|
678
|
+
DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn )
|
679
|
+
|
680
|
+
def directories_of(dir)
|
681
|
+
Dir.open(dir) {|d|
|
682
|
+
return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT
|
683
|
+
}
|
684
|
+
end
|
685
|
+
|
686
|
+
end
|
687
|
+
|
688
|
+
|
689
|
+
# This module requires: #srcdir_root, #objdir_root, #relpath
|
690
|
+
module HookScriptAPI
|
691
|
+
|
692
|
+
def get_config(key)
|
693
|
+
@config[key]
|
694
|
+
end
|
695
|
+
|
696
|
+
alias config get_config
|
697
|
+
|
698
|
+
# obsolete: use metaconfig to change configuration
|
699
|
+
def set_config(key, val)
|
700
|
+
@config[key] = val
|
701
|
+
end
|
702
|
+
|
703
|
+
#
|
704
|
+
# srcdir/objdir (works only in the package directory)
|
705
|
+
#
|
706
|
+
|
707
|
+
def curr_srcdir
|
708
|
+
"#{srcdir_root()}/#{relpath()}"
|
709
|
+
end
|
710
|
+
|
711
|
+
def curr_objdir
|
712
|
+
"#{objdir_root()}/#{relpath()}"
|
713
|
+
end
|
714
|
+
|
715
|
+
def srcfile(path)
|
716
|
+
"#{curr_srcdir()}/#{path}"
|
717
|
+
end
|
718
|
+
|
719
|
+
def srcexist?(path)
|
720
|
+
File.exist?(srcfile(path))
|
721
|
+
end
|
722
|
+
|
723
|
+
def srcdirectory?(path)
|
724
|
+
File.dir?(srcfile(path))
|
725
|
+
end
|
726
|
+
|
727
|
+
def srcfile?(path)
|
728
|
+
File.file?(srcfile(path))
|
729
|
+
end
|
730
|
+
|
731
|
+
def srcentries(path = '.')
|
732
|
+
Dir.open("#{curr_srcdir()}/#{path}") {|d|
|
733
|
+
return d.to_a - %w(. ..)
|
734
|
+
}
|
735
|
+
end
|
736
|
+
|
737
|
+
def srcfiles(path = '.')
|
738
|
+
srcentries(path).select {|fname|
|
739
|
+
File.file?(File.join(curr_srcdir(), path, fname))
|
740
|
+
}
|
741
|
+
end
|
742
|
+
|
743
|
+
def srcdirectories(path = '.')
|
744
|
+
srcentries(path).select {|fname|
|
745
|
+
File.dir?(File.join(curr_srcdir(), path, fname))
|
746
|
+
}
|
747
|
+
end
|
748
|
+
|
749
|
+
end
|
750
|
+
|
751
|
+
|
752
|
+
class ToplevelInstaller
|
753
|
+
|
754
|
+
Version = '3.4.0'
|
755
|
+
Copyright = 'Copyright (c) 2000-2005 Minero Aoki'
|
756
|
+
|
757
|
+
TASKS = [
|
758
|
+
[ 'all', 'do config, setup, then install' ],
|
759
|
+
[ 'config', 'saves your configurations' ],
|
760
|
+
[ 'show', 'shows current configuration' ],
|
761
|
+
[ 'setup', 'compiles ruby extentions and others' ],
|
762
|
+
[ 'install', 'installs files' ],
|
763
|
+
[ 'test', 'run all tests in test/' ],
|
764
|
+
[ 'clean', "does `make clean' for each extention" ],
|
765
|
+
[ 'distclean',"does `make distclean' for each extention" ]
|
766
|
+
]
|
767
|
+
|
768
|
+
def ToplevelInstaller.invoke
|
769
|
+
config = ConfigTable.new(load_rbconfig())
|
770
|
+
config.load_standard_entries
|
771
|
+
config.load_multipackage_entries if multipackage?
|
772
|
+
config.fixup
|
773
|
+
klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller)
|
774
|
+
klass.new(File.dirname($0), config).invoke
|
775
|
+
end
|
776
|
+
|
777
|
+
def ToplevelInstaller.multipackage?
|
778
|
+
File.dir?(File.dirname($0) + '/packages')
|
779
|
+
end
|
780
|
+
|
781
|
+
def ToplevelInstaller.load_rbconfig
|
782
|
+
if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
|
783
|
+
ARGV.delete(arg)
|
784
|
+
load File.expand_path(arg.split(/=/, 2)[1])
|
785
|
+
$".push 'rbconfig.rb'
|
786
|
+
else
|
787
|
+
require 'rbconfig'
|
788
|
+
end
|
789
|
+
::Config::CONFIG
|
790
|
+
end
|
791
|
+
|
792
|
+
def initialize(ardir_root, config)
|
793
|
+
@ardir = File.expand_path(ardir_root)
|
794
|
+
@config = config
|
795
|
+
# cache
|
796
|
+
@valid_task_re = nil
|
797
|
+
end
|
798
|
+
|
799
|
+
def config(key)
|
800
|
+
@config[key]
|
801
|
+
end
|
802
|
+
|
803
|
+
def inspect
|
804
|
+
"#<#{self.class} #{__id__()}>"
|
805
|
+
end
|
806
|
+
|
807
|
+
def invoke
|
808
|
+
run_metaconfigs
|
809
|
+
case task = parsearg_global()
|
810
|
+
when nil, 'all'
|
811
|
+
parsearg_config
|
812
|
+
init_installers
|
813
|
+
exec_config
|
814
|
+
exec_setup
|
815
|
+
exec_install
|
816
|
+
else
|
817
|
+
case task
|
818
|
+
when 'config', 'test'
|
819
|
+
;
|
820
|
+
when 'clean', 'distclean'
|
821
|
+
@config.load_savefile if File.exist?(@config.savefile)
|
822
|
+
else
|
823
|
+
@config.load_savefile
|
824
|
+
end
|
825
|
+
__send__ "parsearg_#{task}"
|
826
|
+
init_installers
|
827
|
+
__send__ "exec_#{task}"
|
828
|
+
end
|
829
|
+
end
|
830
|
+
|
831
|
+
def run_metaconfigs
|
832
|
+
@config.load_script "#{@ardir}/metaconfig"
|
833
|
+
end
|
834
|
+
|
835
|
+
def init_installers
|
836
|
+
@installer = Installer.new(@config, @ardir, File.expand_path('.'))
|
837
|
+
end
|
838
|
+
|
839
|
+
#
|
840
|
+
# Hook Script API bases
|
841
|
+
#
|
842
|
+
|
843
|
+
def srcdir_root
|
844
|
+
@ardir
|
845
|
+
end
|
846
|
+
|
847
|
+
def objdir_root
|
848
|
+
'.'
|
849
|
+
end
|
850
|
+
|
851
|
+
def relpath
|
852
|
+
'.'
|
853
|
+
end
|
854
|
+
|
855
|
+
#
|
856
|
+
# Option Parsing
|
857
|
+
#
|
858
|
+
|
859
|
+
def parsearg_global
|
860
|
+
while arg = ARGV.shift
|
861
|
+
case arg
|
862
|
+
when /\A\w+\z/
|
863
|
+
setup_rb_error "invalid task: #{arg}" unless valid_task?(arg)
|
864
|
+
return arg
|
865
|
+
when '-q', '--quiet'
|
866
|
+
@config.verbose = false
|
867
|
+
when '--verbose'
|
868
|
+
@config.verbose = true
|
869
|
+
when '--help'
|
870
|
+
print_usage $stdout
|
871
|
+
exit 0
|
872
|
+
when '--version'
|
873
|
+
puts "#{File.basename($0)} version #{Version}"
|
874
|
+
exit 0
|
875
|
+
when '--copyright'
|
876
|
+
puts Copyright
|
877
|
+
exit 0
|
878
|
+
else
|
879
|
+
setup_rb_error "unknown global option '#{arg}'"
|
880
|
+
end
|
881
|
+
end
|
882
|
+
nil
|
883
|
+
end
|
884
|
+
|
885
|
+
def valid_task?(t)
|
886
|
+
valid_task_re() =~ t
|
887
|
+
end
|
888
|
+
|
889
|
+
def valid_task_re
|
890
|
+
@valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/
|
891
|
+
end
|
892
|
+
|
893
|
+
def parsearg_no_options
|
894
|
+
unless ARGV.empty?
|
895
|
+
setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}"
|
896
|
+
end
|
897
|
+
end
|
898
|
+
|
899
|
+
alias parsearg_show parsearg_no_options
|
900
|
+
alias parsearg_setup parsearg_no_options
|
901
|
+
alias parsearg_test parsearg_no_options
|
902
|
+
alias parsearg_clean parsearg_no_options
|
903
|
+
alias parsearg_distclean parsearg_no_options
|
904
|
+
|
905
|
+
def parsearg_config
|
906
|
+
evalopt = []
|
907
|
+
set = []
|
908
|
+
@config.config_opt = []
|
909
|
+
while i = ARGV.shift
|
910
|
+
if /\A--?\z/ =~ i
|
911
|
+
@config.config_opt = ARGV.dup
|
912
|
+
break
|
913
|
+
end
|
914
|
+
name, value = *@config.parse_opt(i)
|
915
|
+
if @config.value_config?(name)
|
916
|
+
@config[name] = value
|
917
|
+
else
|
918
|
+
evalopt.push [name, value]
|
919
|
+
end
|
920
|
+
set.push name
|
921
|
+
end
|
922
|
+
evalopt.each do |name, value|
|
923
|
+
@config.lookup(name).evaluate value, @config
|
924
|
+
end
|
925
|
+
# Check if configuration is valid
|
926
|
+
set.each do |n|
|
927
|
+
@config[n] if @config.value_config?(n)
|
928
|
+
end
|
929
|
+
end
|
930
|
+
|
931
|
+
def parsearg_install
|
932
|
+
@config.no_harm = false
|
933
|
+
@config.install_prefix = ''
|
934
|
+
while a = ARGV.shift
|
935
|
+
case a
|
936
|
+
when '--no-harm'
|
937
|
+
@config.no_harm = true
|
938
|
+
when /\A--prefix=/
|
939
|
+
path = a.split(/=/, 2)[1]
|
940
|
+
path = File.expand_path(path) unless path[0,1] == '/'
|
941
|
+
@config.install_prefix = path
|
942
|
+
else
|
943
|
+
setup_rb_error "install: unknown option #{a}"
|
944
|
+
end
|
945
|
+
end
|
946
|
+
end
|
947
|
+
|
948
|
+
def print_usage(out)
|
949
|
+
out.puts 'Typical Installation Procedure:'
|
950
|
+
out.puts " $ ruby #{File.basename $0} config"
|
951
|
+
out.puts " $ ruby #{File.basename $0} setup"
|
952
|
+
out.puts " # ruby #{File.basename $0} install (may require root privilege)"
|
953
|
+
out.puts
|
954
|
+
out.puts 'Detailed Usage:'
|
955
|
+
out.puts " ruby #{File.basename $0} <global option>"
|
956
|
+
out.puts " ruby #{File.basename $0} [<global options>] <task> [<task options>]"
|
957
|
+
|
958
|
+
fmt = " %-24s %s\n"
|
959
|
+
out.puts
|
960
|
+
out.puts 'Global options:'
|
961
|
+
out.printf fmt, '-q,--quiet', 'suppress message outputs'
|
962
|
+
out.printf fmt, ' --verbose', 'output messages verbosely'
|
963
|
+
out.printf fmt, ' --help', 'print this message'
|
964
|
+
out.printf fmt, ' --version', 'print version and quit'
|
965
|
+
out.printf fmt, ' --copyright', 'print copyright and quit'
|
966
|
+
out.puts
|
967
|
+
out.puts 'Tasks:'
|
968
|
+
TASKS.each do |name, desc|
|
969
|
+
out.printf fmt, name, desc
|
970
|
+
end
|
971
|
+
|
972
|
+
fmt = " %-24s %s [%s]\n"
|
973
|
+
out.puts
|
974
|
+
out.puts 'Options for CONFIG or ALL:'
|
975
|
+
@config.each do |item|
|
976
|
+
out.printf fmt, item.help_opt, item.description, item.help_default
|
977
|
+
end
|
978
|
+
out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
|
979
|
+
out.puts
|
980
|
+
out.puts 'Options for INSTALL:'
|
981
|
+
out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
|
982
|
+
out.printf fmt, '--prefix=path', 'install path prefix', ''
|
983
|
+
out.puts
|
984
|
+
end
|
985
|
+
|
986
|
+
#
|
987
|
+
# Task Handlers
|
988
|
+
#
|
989
|
+
|
990
|
+
def exec_config
|
991
|
+
@installer.exec_config
|
992
|
+
@config.save # must be final
|
993
|
+
end
|
994
|
+
|
995
|
+
def exec_setup
|
996
|
+
@installer.exec_setup
|
997
|
+
end
|
998
|
+
|
999
|
+
def exec_install
|
1000
|
+
@installer.exec_install
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
def exec_test
|
1004
|
+
@installer.exec_test
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
def exec_show
|
1008
|
+
@config.each do |i|
|
1009
|
+
printf "%-20s %s\n", i.name, i.value if i.value?
|
1010
|
+
end
|
1011
|
+
end
|
1012
|
+
|
1013
|
+
def exec_clean
|
1014
|
+
@installer.exec_clean
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
def exec_distclean
|
1018
|
+
@installer.exec_distclean
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
end # class ToplevelInstaller
|
1022
|
+
|
1023
|
+
|
1024
|
+
class ToplevelInstallerMulti < ToplevelInstaller
|
1025
|
+
|
1026
|
+
include FileOperations
|
1027
|
+
|
1028
|
+
def initialize(ardir_root, config)
|
1029
|
+
super
|
1030
|
+
@packages = directories_of("#{@ardir}/packages")
|
1031
|
+
raise 'no package exists' if @packages.empty?
|
1032
|
+
@root_installer = Installer.new(@config, @ardir, File.expand_path('.'))
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
def run_metaconfigs
|
1036
|
+
@config.load_script "#{@ardir}/metaconfig", self
|
1037
|
+
@packages.each do |name|
|
1038
|
+
@config.load_script "#{@ardir}/packages/#{name}/metaconfig"
|
1039
|
+
end
|
1040
|
+
end
|
1041
|
+
|
1042
|
+
attr_reader :packages
|
1043
|
+
|
1044
|
+
def packages=(list)
|
1045
|
+
raise 'package list is empty' if list.empty?
|
1046
|
+
list.each do |name|
|
1047
|
+
raise "directory packages/#{name} does not exist"\
|
1048
|
+
unless File.dir?("#{@ardir}/packages/#{name}")
|
1049
|
+
end
|
1050
|
+
@packages = list
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
def init_installers
|
1054
|
+
@installers = {}
|
1055
|
+
@packages.each do |pack|
|
1056
|
+
@installers[pack] = Installer.new(@config,
|
1057
|
+
"#{@ardir}/packages/#{pack}",
|
1058
|
+
"packages/#{pack}")
|
1059
|
+
end
|
1060
|
+
with = extract_selection(config('with'))
|
1061
|
+
without = extract_selection(config('without'))
|
1062
|
+
@selected = @installers.keys.select {|name|
|
1063
|
+
(with.empty? or with.include?(name)) \
|
1064
|
+
and not without.include?(name)
|
1065
|
+
}
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
def extract_selection(list)
|
1069
|
+
a = list.split(/,/)
|
1070
|
+
a.each do |name|
|
1071
|
+
setup_rb_error "no such package: #{name}" unless @installers.key?(name)
|
1072
|
+
end
|
1073
|
+
a
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
def print_usage(f)
|
1077
|
+
super
|
1078
|
+
f.puts 'Inluded packages:'
|
1079
|
+
f.puts ' ' + @packages.sort.join(' ')
|
1080
|
+
f.puts
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
#
|
1084
|
+
# Task Handlers
|
1085
|
+
#
|
1086
|
+
|
1087
|
+
def exec_config
|
1088
|
+
run_hook 'pre-config'
|
1089
|
+
each_selected_installers {|inst| inst.exec_config }
|
1090
|
+
run_hook 'post-config'
|
1091
|
+
@config.save # must be final
|
1092
|
+
end
|
1093
|
+
|
1094
|
+
def exec_setup
|
1095
|
+
run_hook 'pre-setup'
|
1096
|
+
each_selected_installers {|inst| inst.exec_setup }
|
1097
|
+
run_hook 'post-setup'
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
def exec_install
|
1101
|
+
run_hook 'pre-install'
|
1102
|
+
each_selected_installers {|inst| inst.exec_install }
|
1103
|
+
run_hook 'post-install'
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
def exec_test
|
1107
|
+
run_hook 'pre-test'
|
1108
|
+
each_selected_installers {|inst| inst.exec_test }
|
1109
|
+
run_hook 'post-test'
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
def exec_clean
|
1113
|
+
rm_f @config.savefile
|
1114
|
+
run_hook 'pre-clean'
|
1115
|
+
each_selected_installers {|inst| inst.exec_clean }
|
1116
|
+
run_hook 'post-clean'
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
def exec_distclean
|
1120
|
+
rm_f @config.savefile
|
1121
|
+
run_hook 'pre-distclean'
|
1122
|
+
each_selected_installers {|inst| inst.exec_distclean }
|
1123
|
+
run_hook 'post-distclean'
|
1124
|
+
end
|
1125
|
+
|
1126
|
+
#
|
1127
|
+
# lib
|
1128
|
+
#
|
1129
|
+
|
1130
|
+
def each_selected_installers
|
1131
|
+
Dir.mkdir 'packages' unless File.dir?('packages')
|
1132
|
+
@selected.each do |pack|
|
1133
|
+
$stderr.puts "Processing the package `#{pack}' ..." if verbose?
|
1134
|
+
Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
|
1135
|
+
Dir.chdir "packages/#{pack}"
|
1136
|
+
yield @installers[pack]
|
1137
|
+
Dir.chdir '../..'
|
1138
|
+
end
|
1139
|
+
end
|
1140
|
+
|
1141
|
+
def run_hook(id)
|
1142
|
+
@root_installer.run_hook id
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
# module FileOperations requires this
|
1146
|
+
def verbose?
|
1147
|
+
@config.verbose?
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
# module FileOperations requires this
|
1151
|
+
def no_harm?
|
1152
|
+
@config.no_harm?
|
1153
|
+
end
|
1154
|
+
|
1155
|
+
end # class ToplevelInstallerMulti
|
1156
|
+
|
1157
|
+
|
1158
|
+
class Installer
|
1159
|
+
|
1160
|
+
FILETYPES = %w( bin lib ext data conf man )
|
1161
|
+
|
1162
|
+
include FileOperations
|
1163
|
+
include HookScriptAPI
|
1164
|
+
|
1165
|
+
def initialize(config, srcroot, objroot)
|
1166
|
+
@config = config
|
1167
|
+
@srcdir = File.expand_path(srcroot)
|
1168
|
+
@objdir = File.expand_path(objroot)
|
1169
|
+
@currdir = '.'
|
1170
|
+
end
|
1171
|
+
|
1172
|
+
def inspect
|
1173
|
+
"#<#{self.class} #{File.basename(@srcdir)}>"
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
#
|
1177
|
+
# Hook Script API base methods
|
1178
|
+
#
|
1179
|
+
|
1180
|
+
def srcdir_root
|
1181
|
+
@srcdir
|
1182
|
+
end
|
1183
|
+
|
1184
|
+
def objdir_root
|
1185
|
+
@objdir
|
1186
|
+
end
|
1187
|
+
|
1188
|
+
def relpath
|
1189
|
+
@currdir
|
1190
|
+
end
|
1191
|
+
|
1192
|
+
#
|
1193
|
+
# Config Access
|
1194
|
+
#
|
1195
|
+
|
1196
|
+
# module FileOperations requires this
|
1197
|
+
def verbose?
|
1198
|
+
@config.verbose?
|
1199
|
+
end
|
1200
|
+
|
1201
|
+
# module FileOperations requires this
|
1202
|
+
def no_harm?
|
1203
|
+
@config.no_harm?
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
def verbose_off
|
1207
|
+
begin
|
1208
|
+
save, @config.verbose = @config.verbose?, false
|
1209
|
+
yield
|
1210
|
+
ensure
|
1211
|
+
@config.verbose = save
|
1212
|
+
end
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
#
|
1216
|
+
# TASK config
|
1217
|
+
#
|
1218
|
+
|
1219
|
+
def exec_config
|
1220
|
+
exec_task_traverse 'config'
|
1221
|
+
end
|
1222
|
+
|
1223
|
+
def config_dir_bin(rel)
|
1224
|
+
end
|
1225
|
+
|
1226
|
+
def config_dir_lib(rel)
|
1227
|
+
end
|
1228
|
+
|
1229
|
+
def config_dir_man(rel)
|
1230
|
+
end
|
1231
|
+
|
1232
|
+
def config_dir_ext(rel)
|
1233
|
+
extconf if extdir?(curr_srcdir())
|
1234
|
+
end
|
1235
|
+
|
1236
|
+
def extconf
|
1237
|
+
ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt
|
1238
|
+
end
|
1239
|
+
|
1240
|
+
def config_dir_data(rel)
|
1241
|
+
end
|
1242
|
+
|
1243
|
+
def config_dir_conf(rel)
|
1244
|
+
end
|
1245
|
+
|
1246
|
+
#
|
1247
|
+
# TASK setup
|
1248
|
+
#
|
1249
|
+
|
1250
|
+
def exec_setup
|
1251
|
+
exec_task_traverse 'setup'
|
1252
|
+
end
|
1253
|
+
|
1254
|
+
def setup_dir_bin(rel)
|
1255
|
+
files_of(curr_srcdir()).each do |fname|
|
1256
|
+
adjust_shebang "#{curr_srcdir()}/#{fname}"
|
1257
|
+
end
|
1258
|
+
end
|
1259
|
+
|
1260
|
+
def adjust_shebang(path)
|
1261
|
+
return if no_harm?
|
1262
|
+
tmpfile = File.basename(path) + '.tmp'
|
1263
|
+
begin
|
1264
|
+
File.open(path, 'rb') {|r|
|
1265
|
+
first = r.gets
|
1266
|
+
return unless File.basename(first.sub(/\A\#!/, '').split[0].to_s) == 'ruby'
|
1267
|
+
$stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
|
1268
|
+
File.open(tmpfile, 'wb') {|w|
|
1269
|
+
w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
|
1270
|
+
w.write r.read
|
1271
|
+
}
|
1272
|
+
}
|
1273
|
+
move_file tmpfile, File.basename(path)
|
1274
|
+
ensure
|
1275
|
+
File.unlink tmpfile if File.exist?(tmpfile)
|
1276
|
+
end
|
1277
|
+
end
|
1278
|
+
|
1279
|
+
def setup_dir_lib(rel)
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
def setup_dir_man(rel)
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
def setup_dir_ext(rel)
|
1286
|
+
make if extdir?(curr_srcdir())
|
1287
|
+
end
|
1288
|
+
|
1289
|
+
def setup_dir_data(rel)
|
1290
|
+
end
|
1291
|
+
|
1292
|
+
def setup_dir_conf(rel)
|
1293
|
+
end
|
1294
|
+
|
1295
|
+
#
|
1296
|
+
# TASK install
|
1297
|
+
#
|
1298
|
+
|
1299
|
+
def exec_install
|
1300
|
+
rm_f 'InstalledFiles'
|
1301
|
+
exec_task_traverse 'install'
|
1302
|
+
end
|
1303
|
+
|
1304
|
+
def install_dir_bin(rel)
|
1305
|
+
install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
def install_dir_lib(rel)
|
1309
|
+
install_files rubyscripts(), "#{config('rbdir')}/#{rel}", 0644
|
1310
|
+
end
|
1311
|
+
|
1312
|
+
def install_dir_ext(rel)
|
1313
|
+
return unless extdir?(curr_srcdir())
|
1314
|
+
install_files rubyextentions('.'),
|
1315
|
+
"#{config('sodir')}/#{File.dirname(rel)}",
|
1316
|
+
0555
|
1317
|
+
end
|
1318
|
+
|
1319
|
+
def install_dir_data(rel)
|
1320
|
+
install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644
|
1321
|
+
end
|
1322
|
+
|
1323
|
+
def install_dir_conf(rel)
|
1324
|
+
# FIXME: should not remove current config files
|
1325
|
+
# (rename previous file to .old/.org)
|
1326
|
+
install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644
|
1327
|
+
end
|
1328
|
+
|
1329
|
+
def install_dir_man(rel)
|
1330
|
+
install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644
|
1331
|
+
end
|
1332
|
+
|
1333
|
+
def install_files(list, dest, mode)
|
1334
|
+
mkdir_p dest, @config.install_prefix
|
1335
|
+
list.each do |fname|
|
1336
|
+
install fname, dest, mode, @config.install_prefix
|
1337
|
+
end
|
1338
|
+
end
|
1339
|
+
|
1340
|
+
def rubyscripts
|
1341
|
+
glob_select(@config.libsrc_pattern, targetfiles())
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
def rubyextentions(dir)
|
1345
|
+
ents = glob_select("*.#{@config.dllext}", targetfiles())
|
1346
|
+
if ents.empty?
|
1347
|
+
setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
|
1348
|
+
end
|
1349
|
+
ents
|
1350
|
+
end
|
1351
|
+
|
1352
|
+
def targetfiles
|
1353
|
+
mapdir(existfiles() - hookfiles())
|
1354
|
+
end
|
1355
|
+
|
1356
|
+
def mapdir(ents)
|
1357
|
+
ents.map {|ent|
|
1358
|
+
if File.exist?(ent)
|
1359
|
+
then ent # objdir
|
1360
|
+
else "#{curr_srcdir()}/#{ent}" # srcdir
|
1361
|
+
end
|
1362
|
+
}
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
# picked up many entries from cvs-1.11.1/src/ignore.c
|
1366
|
+
JUNK_FILES = %w(
|
1367
|
+
core RCSLOG tags TAGS .make.state
|
1368
|
+
.nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
|
1369
|
+
*~ *.old *.bak *.BAK *.orig *.rej _$* *$
|
1370
|
+
|
1371
|
+
*.org *.in .*
|
1372
|
+
)
|
1373
|
+
|
1374
|
+
def existfiles
|
1375
|
+
glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.')))
|
1376
|
+
end
|
1377
|
+
|
1378
|
+
def hookfiles
|
1379
|
+
%w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
|
1380
|
+
%w( config setup install clean ).map {|t| sprintf(fmt, t) }
|
1381
|
+
}.flatten
|
1382
|
+
end
|
1383
|
+
|
1384
|
+
def glob_select(pat, ents)
|
1385
|
+
re = globs2re([pat])
|
1386
|
+
ents.select {|ent| re =~ ent }
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
def glob_reject(pats, ents)
|
1390
|
+
re = globs2re(pats)
|
1391
|
+
ents.reject {|ent| re =~ ent }
|
1392
|
+
end
|
1393
|
+
|
1394
|
+
GLOB2REGEX = {
|
1395
|
+
'.' => '\.',
|
1396
|
+
'$' => '\$',
|
1397
|
+
'#' => '\#',
|
1398
|
+
'*' => '.*'
|
1399
|
+
}
|
1400
|
+
|
1401
|
+
def globs2re(pats)
|
1402
|
+
/\A(?:#{
|
1403
|
+
pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|')
|
1404
|
+
})\z/
|
1405
|
+
end
|
1406
|
+
|
1407
|
+
#
|
1408
|
+
# TASK test
|
1409
|
+
#
|
1410
|
+
|
1411
|
+
TESTDIR = 'test'
|
1412
|
+
|
1413
|
+
def exec_test
|
1414
|
+
unless File.directory?('test')
|
1415
|
+
$stderr.puts 'no test in this package' if verbose?
|
1416
|
+
return
|
1417
|
+
end
|
1418
|
+
$stderr.puts 'Running tests...' if verbose?
|
1419
|
+
require 'test/unit'
|
1420
|
+
runner = Test::Unit::AutoRunner.new(true)
|
1421
|
+
runner.to_run << TESTDIR
|
1422
|
+
runner.run
|
1423
|
+
end
|
1424
|
+
|
1425
|
+
#
|
1426
|
+
# TASK clean
|
1427
|
+
#
|
1428
|
+
|
1429
|
+
def exec_clean
|
1430
|
+
exec_task_traverse 'clean'
|
1431
|
+
rm_f @config.savefile
|
1432
|
+
rm_f 'InstalledFiles'
|
1433
|
+
end
|
1434
|
+
|
1435
|
+
def clean_dir_bin(rel)
|
1436
|
+
end
|
1437
|
+
|
1438
|
+
def clean_dir_lib(rel)
|
1439
|
+
end
|
1440
|
+
|
1441
|
+
def clean_dir_ext(rel)
|
1442
|
+
return unless extdir?(curr_srcdir())
|
1443
|
+
make 'clean' if File.file?('Makefile')
|
1444
|
+
end
|
1445
|
+
|
1446
|
+
def clean_dir_data(rel)
|
1447
|
+
end
|
1448
|
+
|
1449
|
+
def clean_dir_conf(rel)
|
1450
|
+
end
|
1451
|
+
|
1452
|
+
#
|
1453
|
+
# TASK distclean
|
1454
|
+
#
|
1455
|
+
|
1456
|
+
def exec_distclean
|
1457
|
+
exec_task_traverse 'distclean'
|
1458
|
+
rm_f @config.savefile
|
1459
|
+
rm_f 'InstalledFiles'
|
1460
|
+
end
|
1461
|
+
|
1462
|
+
def distclean_dir_bin(rel)
|
1463
|
+
end
|
1464
|
+
|
1465
|
+
def distclean_dir_lib(rel)
|
1466
|
+
end
|
1467
|
+
|
1468
|
+
def distclean_dir_ext(rel)
|
1469
|
+
return unless extdir?(curr_srcdir())
|
1470
|
+
make 'distclean' if File.file?('Makefile')
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
def distclean_dir_data(rel)
|
1474
|
+
end
|
1475
|
+
|
1476
|
+
def distclean_dir_conf(rel)
|
1477
|
+
end
|
1478
|
+
|
1479
|
+
#
|
1480
|
+
# lib
|
1481
|
+
#
|
1482
|
+
|
1483
|
+
def exec_task_traverse(task)
|
1484
|
+
run_hook "pre-#{task}"
|
1485
|
+
FILETYPES.each do |type|
|
1486
|
+
if config('without-ext') == 'yes' and type == 'ext'
|
1487
|
+
$stderr.puts 'skipping ext/* by user option' if verbose?
|
1488
|
+
next
|
1489
|
+
end
|
1490
|
+
traverse task, type, "#{task}_dir_#{type}"
|
1491
|
+
end
|
1492
|
+
run_hook "post-#{task}"
|
1493
|
+
end
|
1494
|
+
|
1495
|
+
def traverse(task, rel, mid)
|
1496
|
+
dive_into(rel) {
|
1497
|
+
run_hook "pre-#{task}"
|
1498
|
+
__send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
|
1499
|
+
directories_of(curr_srcdir()).each do |d|
|
1500
|
+
traverse task, "#{rel}/#{d}", mid
|
1501
|
+
end
|
1502
|
+
run_hook "post-#{task}"
|
1503
|
+
}
|
1504
|
+
end
|
1505
|
+
|
1506
|
+
def dive_into(rel)
|
1507
|
+
return unless File.dir?("#{@srcdir}/#{rel}")
|
1508
|
+
|
1509
|
+
dir = File.basename(rel)
|
1510
|
+
Dir.mkdir dir unless File.dir?(dir)
|
1511
|
+
prevdir = Dir.pwd
|
1512
|
+
Dir.chdir dir
|
1513
|
+
$stderr.puts '---> ' + rel if verbose?
|
1514
|
+
@currdir = rel
|
1515
|
+
yield
|
1516
|
+
Dir.chdir prevdir
|
1517
|
+
$stderr.puts '<--- ' + rel if verbose?
|
1518
|
+
@currdir = File.dirname(rel)
|
1519
|
+
end
|
1520
|
+
|
1521
|
+
def run_hook(id)
|
1522
|
+
path = [ "#{curr_srcdir()}/#{id}",
|
1523
|
+
"#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) }
|
1524
|
+
return unless path
|
1525
|
+
begin
|
1526
|
+
instance_eval File.read(path), path, 1
|
1527
|
+
rescue
|
1528
|
+
raise if $DEBUG
|
1529
|
+
setup_rb_error "hook #{path} failed:\n" + $!.message
|
1530
|
+
end
|
1531
|
+
end
|
1532
|
+
|
1533
|
+
end # class Installer
|
1534
|
+
|
1535
|
+
|
1536
|
+
class SetupError < StandardError; end
|
1537
|
+
|
1538
|
+
def setup_rb_error(msg)
|
1539
|
+
raise SetupError, msg
|
1540
|
+
end
|
1541
|
+
|
1542
|
+
if $0 == __FILE__
|
1543
|
+
begin
|
1544
|
+
ToplevelInstaller.invoke
|
1545
|
+
rescue SetupError
|
1546
|
+
raise if $DEBUG
|
1547
|
+
$stderr.puts $!.message
|
1548
|
+
$stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
|
1549
|
+
exit 1
|
1550
|
+
end
|
1551
|
+
end
|