Fix other packages list
[packages.grml.org.git] / update.rb
1 #!/usr/bin/env ruby
2 require 'git'
3 require 'erb'
4 require 'yaml'
5 require 'net/http'
6 require 'uri'
7 require 'zlib'
8 require 'yaml'
9
10 DEBUG = false
11
12 def build_used_package_list(source_uri)
13   source_uri.map do |source_uri|
14     fetch_file(source_uri).split("\n").reject do |l|
15       l.strip.start_with?('#') or l.strip == ""
16     end
17   end.flatten
18 end
19
20 def parse_debian_sources(data)
21   data.split("\n").push('').inject({}) do |pkgs, l|
22     l.rstrip!
23     pkg = pkgs[:_tmp] || {}
24     if pkg[:_tmp]
25       if l[0..0] == ' '
26         pkg[:_tmp][:data] << l.strip
27       else
28         pkg[pkg[:_tmp][:hdr]] = pkg[:_tmp][:data].compact
29         pkg.delete :_tmp
30       end
31     end
32     unless pkg[:_tmp]
33       if l == '':
34         pkgs[pkg['Package'][0]] = pkg
35         pkg = nil
36       else
37         hdr, data = l.strip.split(':', 2)
38         data.strip! unless data.nil?
39         pkg[:_tmp] = {:hdr => hdr, :data => [data]}
40       end
41     end
42     if pkg.nil?
43       pkgs.delete :_tmp
44     else
45       pkgs[:_tmp] = pkg
46     end
47     pkgs
48   end
49 end
50
51 def build_package_list(repos, used, sources)
52   data = {}
53   repos.each do |pkg, path|
54     g = Git.bare(working_dir = path)
55     next if not g.ls_tree('HEAD')["tree"].keys.include?("debian")
56
57     current_head = g.gcommit('HEAD')
58     next if not current_head.parent
59
60     p = {
61       :head_is_tagged => false,
62       :used => {},
63       :name => pkg,
64       :version => nil,
65       :has_tags => false,
66       :version_in_repo => nil
67     }
68     used.each do |dist,l|
69       p[:used][dist] = l.include?(pkg)
70     end
71     if sources[pkg]
72       p[:version_in_repo] = sources[pkg]['Version'][0]
73     end
74
75     for tag in g.tags.reverse
76       p[:has_tags] = true
77       t = g.gcommit(tag.name)
78       next if not t.parent
79       #$stderr.puts "#{pkg}: Checking tag #{tag.name}: tag parent: #{t.parent.sha} HEAD: #{current_head.parent.sha}"
80       if t.parent.sha === current_head.parent.sha
81         p[:head_is_tagged] = true
82         p[:version] = tag.name
83         break
84       end
85     end
86
87     data[pkg] = p
88   end
89   data
90 end
91
92 def fetch_file(uri)
93   response = Net::HTTP.get_response(URI.parse(uri))
94   body = response.body
95   if uri.match(/\.gz$/)
96     body = Zlib::GzipReader.new(StringIO.new(body.to_s)).read
97   end
98   body
99 end
100
101 def update_git_repos(git_repos)
102   git_repos.each do |name, path|
103     out = %x{cd #{path} && git remote update --prune 2>&1}
104     puts "#{name}: " + out if DEBUG
105   end
106 end
107
108 template = ERB.new <<-EOF
109 <!doctype html>
110 <head>
111   <meta charset="utf-8">
112   <title>Grml.org Package Index</title>
113   <link rel="stylesheet" href="style.css">
114 </head>
115 <body>
116   <header>
117   <h1>All Grml packages</h1>
118   </header>
119   <div id="main">
120   <table>
121   <tr>
122   <th>Package</th><th>Git</th><th>Download</th><th>Git Fresh?</th><th>grml-testing</th><th>In FULL?</th>
123   </tr>
124   <% packages.keys.sort.each do |pn|
125   p = packages[pn]
126   %>
127   <tr>
128   <td><%= p[:name] %></td>
129   <td class="git"><a href="http://git.grml.org/?p=<%= p[:name] %>.git;a=summary">Git</a></td>
130   <td class="download">
131     <% if p[:has_tags] %>
132     <a href="http://deb.grml.org/pool/main/<%= p[:name][0..0] %>/<%= p[:name] %>/">Download</a>
133     <% end %>
134   </td>
135   <% if p[:head_is_tagged] %>
136   <td class="ok">Version <%= p[:version] %></td>
137   <% else %>
138   <td class="error <% if p[:used][:full] %>important<% end %>">Untagged changes</td>
139   <% end %>
140   <td><%= p[:version_in_repo] || "" %></td>
141   <td class="installed"><%= p[:used][:full] ? "Yes" : "No" %></td>
142   </tr>
143   <% end %>
144   </table>
145   </div>
146   <div>
147   Other packages: <%= other_packages.join(" ") %>
148   </div>
149   <footer>
150   <p>Last update: <%= Time.now.to_s %></p>
151   </footer>
152 </body>
153 </html>
154 EOF
155
156 used_packages = {
157   :full => build_used_package_list([
158                                     'http://git.grml.org/?p=grml-live.git;a=blob_plain;f=etc/grml/fai/config/package_config/GRMLBASE',
159                                     'http://git.grml.org/?p=grml-live.git;a=blob_plain;f=etc/grml/fai/config/package_config/GRML_FULL',
160                                    ]),
161 }
162 sources = parse_debian_sources(fetch_file('http://deb.grml.org/dists/grml-testing/main/source/Sources.gz'))
163
164 git_repos = Hash[*(Dir.glob('git/*.git').map do |p| [File.basename(p, '.git'), p] end.flatten)]
165
166 update_git_repos git_repos
167
168 packages = build_package_list(git_repos, used_packages, sources)
169 other_packages = (sources.keys - git_repos.keys)
170
171 File.open('index.html.new','w') do |f|
172   f.write template.result(binding)
173 end
174 File.open('packages.yaml.new','w') do |f|
175   f.write packages.to_yaml
176 end
177
178 FileUtils.mv 'index.html.new', 'index.html'
179 FileUtils.mv 'packages.yaml.new', 'packages.yaml'
180