This repository has been archived by the owner on Nov 9, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 5
/
rpg-parse-index.rb
140 lines (127 loc) · 3.97 KB
/
rpg-parse-index.rb
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
#!/usr/bin/env ruby
# The `rpg-parse-index` program reads a Rubygems "modern index" stream on
# standard input and writes a parseable version of the index data on standard
# output.
#
# About Rubygems Spec Indexes
# ---------------------------
#
# Rubygems spec index files are built with the `gem generate_index` command
# and are typically served from gem repositories at predefined locations. For
# example, the canonical Rubygems spec index lives at:
#
# http://rubygems.org/specs.4.8.gz
#
# Output Format Details
# ---------------------
#
# Spec indexes are gzip compressed. This program assumes uncompressed data
# on standard input. You will need to pipe the file off the network through
# `gzip -dc` before feeding it in here. To see the main release spec index
# on stdout, you might:
#
# curl -Ls http://rubygems.org/specs.4.8.gz | gzip -dc |
# rpg-parse-index
#
# A randomly selected bit of output from the above command:
#
# ...
# desert 0.5.3 ruby
# desert 0.5.2 ruby
# desutwo 0.0.3 ruby
# detective 0.3.0 ruby
# detective 0.2.0 ruby
# detective 0.1.0 ruby
# detective 0.0.0 ruby
# devball 0.7 ruby
# devball 0.6 ruby
# devball 0.5 ruby
# devball 0.4 ruby
# devball 0.3 ruby
# ...
#
# The format is:
#
# <name> <SP> <version> <SP> <platform> <LF>
#
# Where `<name>` and `<version>` are obvious and `<platform>` is an open field
# that can be anything. Popular `<platform>` values at time of writing are:
#
# $ rpg-parse-index < spec.4.8 | cut -f 3 | sort | uniq -c | sort -rn
# 48766 ruby
# 363 mswin32
# 265 x86-mswin32-60
# 176 java
# 95 x86-mingw32
# 90 x86-linux
# 87 x86-mswin32
# 52 i386-mswin32
# 46 darwin
# 32 universal-darwin-9
# 30 jruby
# ...
#
# Version Sorting
# ---------------
#
# Another important attribute of the output generated from this command is that
# it's sorted based on Rubygems version comparison rules. The first line of
# output for a given package is that package's "most recent" version. Adjacent
# lines are successively less recent.
#
# This allows the output from this command to be used with `sort -u` and
# `uniq(1)` to generate a most recent index. Utilities like `join(1)` may also
# be used on the output to perform relational operations with other package
# lists having the same format.
USAGE = <<BANNER
Usage: rpg-parse-index
Convert modern gemspec index to parseable text format.
Reads a gemspec index on standard input and writes a formatted version on
standard output. Output is sorted by package name and reverse version number.
This is a low level command used by the rpg package index machinery.
BANNER
if ARGV.include?('--help') || STDIN.tty?
puts USAGE
exit 2
end
# Main Program Logic
# ------------------
# Fake out `Marshal` by creating a mock Gem module and Version class. This
# removes the reliance on Rubygems and speeds things up considerably.
Object.send :remove_const, :Gem if Object.const_defined?(:Gem)
Kernel.send :remove_const, :Gem if Kernel.const_defined?(:Gem)
module Gem
class Version < Array
def marshal_load(data)
@string = data.first
replace @string.split('.')
map! { |p| p.to_i }
end
def prerelease?
@string.match(/[^0-9.]/)
end
def to_s
@string
end
end
end
# Load packages in from STDIN and unmarshal.
packages = Marshal.load(STDIN)
# XXX reject prerelease packages for now until we can deal with them.
packages.reject! { |name,version,platform| version.prerelease? }
# Sort packages by name and then reverse version number.
#
# TODO prelease version sorting.
packages.sort! do |(n1,v1,p1),(n2,v2,p2)|
if (cmp = (n1 <=> n2)) == 0
v2 <=> v1
else
cmp
end
end
# Finally, run over the sorted list and write a line of output for each package.
packages.each do |name,version,platform|
platform.gsub!(/[^A-Za-z0-9_-]/, '_')
puts "#{name} #{version} #{platform}"
end
# vim: tw=80 sw=2 ts=2 sts=0 expandtab