ropes 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -14,7 +14,7 @@ It will generate the following files:
14
14
 
15
15
  ## Current status
16
16
 
17
- As of 0.0.1, it generates only `Releases`, `Releases.gpg`, `Packages` and `Packages.gz`.
17
+ As of 0.2.1, it generates only `Releases`, `Releases.gpg`, `Packages` and `Packages.gz`.
18
18
  This is enough to get a basic Ubuntu repository working. There is no yum support.
19
19
 
20
20
  ## Installation
@@ -51,8 +51,14 @@ for you.
51
51
 
52
52
  repo.add_file_by_path("some_custom_package.deb")
53
53
 
54
+ # For amd64 files
54
55
  File.open("Packages", "w") do |file|
55
- file.write repo.packages_file
56
+ file.write repo.packages_file("amd64")
57
+ end
58
+
59
+ # For i386
60
+ File.open("Packages", "w") do |file|
61
+ file.write repo.packages_file("i386")
56
62
  end
57
63
 
58
64
  File.open("Release", "w") do |file|
@@ -63,8 +69,14 @@ for you.
63
69
  file.write repo.release_file_gpg("/path/to/your/gpg.key")
64
70
  end
65
71
 
72
+ # For amd64
73
+ File.open("Packages.gz", "w") do |file|
74
+ file.write repo.packages_file_gz("amd64")
75
+ end
76
+
77
+ # For i386
66
78
  File.open("Packages.gz", "w") do |file|
67
- file.write repo.packages_file_gz
79
+ file.write repo.packages_file_gz("amd64")
68
80
  end
69
81
 
70
82
  ## Contributing
data/lib/ropes.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require "ropes/version"
2
- require "ropes/repository"
2
+ require "ropes/repository/debian"
3
3
 
4
4
  module Ropes
5
5
 
@@ -0,0 +1,179 @@
1
+ require 'debeasy'
2
+ require 'stringio'
3
+ require 'zlib'
4
+ require 'tempfile'
5
+ require 'digest'
6
+ require 'gpgme'
7
+ require 'uuid'
8
+
9
+ module Ropes
10
+
11
+ class Error < RuntimeError; end
12
+ class InvalidRepositoryType < Error; end
13
+
14
+ module Repository
15
+ class Apt
16
+
17
+ def initialize(options)
18
+ missing_options = %w{
19
+ origin
20
+ type
21
+ distribution
22
+ version
23
+ architectures
24
+ components
25
+ description
26
+ package_base}.reject do |required_option|
27
+ options.has_key?(required_option.to_sym)
28
+ end
29
+
30
+ raise "Missing options: #{missing_options.join(", ")}" unless missing_options.empty?
31
+
32
+ raise Error, "Architectures must be an array" unless options[:architectures].is_a? Array
33
+
34
+ @release_file = nil
35
+ @packages_file = nil
36
+ @packages_field_gz = nil
37
+
38
+ @options = options
39
+ @packages = []
40
+ @field_order = %w{
41
+ package
42
+ priority
43
+ section
44
+ installed_size
45
+ maintainer
46
+ architecture
47
+ source
48
+ version
49
+ depends
50
+ filename
51
+ size
52
+ MD5sum
53
+ SHA1
54
+ SHA256
55
+ description
56
+ description-md5
57
+ bugs
58
+ origin
59
+ supported
60
+ }
61
+ @mandatory_fields = %w{
62
+ package
63
+ version
64
+ architecture
65
+ maintainer
66
+ description
67
+ }
68
+ end
69
+
70
+ def add_file_by_path(path)
71
+ metadata = Debeasy.read(path).to_hash
72
+ if validate_metadata(metadata).empty?
73
+ @packages << metadata
74
+ else
75
+ raise "Missing mandatory fields on package: #{validate_metadata(metadata).join(", ")}"
76
+ end
77
+ end
78
+
79
+ def add_file_by_info(package)
80
+ if validate_metadata(package).empty?
81
+ if package.is_a? Hash
82
+ @packages << package
83
+ else
84
+ raise "Package metadata must be in hash format"
85
+ end
86
+ else
87
+ raise "Missing mandatory fields on package: #{validate_metadata(package).join(", ")}"
88
+ end
89
+ end
90
+
91
+ # Get the Packages file as a string
92
+
93
+ def packages_file(arch)
94
+ packages_for_arch = @packages.select {|p| p["architecture"] == arch}
95
+ entries = packages_for_arch.map do |package|
96
+ lines = []
97
+ @field_order.each do |field|
98
+ if package[field] != nil
99
+ case field
100
+ when "filename"
101
+ lines << packages_line(field.capitalize, "#{@options[:package_base]}/#{package[field]}")
102
+ when "installed_size"
103
+ lines << packages_line("Installed-Size", package[field])
104
+ when "SHA1", "SHA256", "MD5sum"
105
+ lines << packages_line(field, package[field])
106
+ else
107
+ lines << packages_line(field.capitalize, package[field])
108
+ end
109
+ end
110
+ end
111
+ lines.join("\n")
112
+ end
113
+ if entries.empty?
114
+ ""
115
+ else
116
+ entries.join("\n\n") + "\n"
117
+ end
118
+ end
119
+
120
+ # Get the Packages file as a gzip'ed string
121
+
122
+ def packages_file_gz(arch)
123
+ io = StringIO.new("w")
124
+ gz = Zlib::GzipWriter.new(io)
125
+ gz.write(packages_file(arch))
126
+ gz.close
127
+ io.string
128
+ end
129
+
130
+ # Get the Release file as a string
131
+
132
+ def release_file
133
+ lines = []
134
+ lines << "Origin: #{@options[:origin]}"
135
+ lines << "Label: #{@options[:origin]}"
136
+ lines << "Suite: #{@options[:distribution]}"
137
+ lines << "Version: #{@options[:version]}"
138
+ lines << "Codename: #{@options[:distribution]}"
139
+ lines << "Date: #{Time.new.utc.strftime '%a, %d %b %Y %H:%M:%S UTC'}"
140
+ lines << "Architectures: #{@options[:architectures].join(" ")}"
141
+ lines << "Components: #{@options[:components]}"
142
+ lines << "Description: #{@options[:description]}"
143
+ lines << "MD5Sum:"
144
+ @options[:architectures].each do |arch|
145
+ # Have to create the files in real life to get the real size
146
+ temp_packages_file = Tempfile.new("Packages")
147
+ temp_packages_file.write packages_file(arch)
148
+ temp_packages_file_gz = Tempfile.new("Packages.gz")
149
+ temp_packages_file_gz.write packages_file_gz(arch)
150
+ lines << " #{Digest::MD5.hexdigest(packages_file(arch))} #{temp_packages_file.size} #{@options[:components]}/binary-#{arch}/Packages"
151
+ lines << " #{Digest::MD5.hexdigest(packages_file_gz(arch))} #{temp_packages_file_gz.size} #{@options[:components]}/binary-#{arch}/Packages.gz"
152
+ end
153
+ lines.join("\n") + "\n"
154
+ end
155
+
156
+ # Get detached GPG signature of Release file
157
+
158
+ def release_file_gpg(path_to_gpgkey)
159
+ GPGME::Key.import(File.open(path_to_gpgkey))
160
+ GPGME::Crypto.new.sign(release_file, {
161
+ :mode => GPGME::SIG_MODE_DETACH,
162
+ :armor => true
163
+ })
164
+ end
165
+
166
+ private
167
+
168
+
169
+ def packages_line(field, value)
170
+ "#{field}: #{value}"
171
+ end
172
+
173
+ def validate_metadata(metadata_hash)
174
+ @mandatory_fields.reject {|field| metadata_hash.has_key?(field)}
175
+ end
176
+
177
+ end
178
+ end
179
+ end
File without changes
data/lib/ropes/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ropes
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
data/ropes.gemspec CHANGED
@@ -23,4 +23,7 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "rake"
24
24
  spec.add_dependency "debeasy"
25
25
  spec.add_dependency "gpgme"
26
+ spec.add_dependency "arr-pm"
27
+ spec.add_dependency "nokogiri"
28
+ spec.add_dependency "uuid"
26
29
  end
metadata CHANGED
@@ -1,18 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ropes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Andy Sykes
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2013-10-19 00:00:00.000000000 Z
12
+ date: 2013-12-16 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: bundler
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
19
  - - ~>
18
20
  - !ruby/object:Gem::Version
@@ -20,6 +22,7 @@ dependencies:
20
22
  type: :development
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
27
  - - ~>
25
28
  - !ruby/object:Gem::Version
@@ -27,48 +30,101 @@ dependencies:
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: rake
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
- - - '>='
35
+ - - ! '>='
32
36
  - !ruby/object:Gem::Version
33
37
  version: '0'
34
38
  type: :development
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
- - - '>='
43
+ - - ! '>='
39
44
  - !ruby/object:Gem::Version
40
45
  version: '0'
41
46
  - !ruby/object:Gem::Dependency
42
47
  name: debeasy
43
48
  requirement: !ruby/object:Gem::Requirement
49
+ none: false
44
50
  requirements:
45
- - - '>='
51
+ - - ! '>='
46
52
  - !ruby/object:Gem::Version
47
53
  version: '0'
48
54
  type: :runtime
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
51
58
  requirements:
52
- - - '>='
59
+ - - ! '>='
53
60
  - !ruby/object:Gem::Version
54
61
  version: '0'
55
62
  - !ruby/object:Gem::Dependency
56
63
  name: gpgme
57
64
  requirement: !ruby/object:Gem::Requirement
65
+ none: false
58
66
  requirements:
59
- - - '>='
67
+ - - ! '>='
60
68
  - !ruby/object:Gem::Version
61
69
  version: '0'
62
70
  type: :runtime
63
71
  prerelease: false
64
72
  version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
65
74
  requirements:
66
- - - '>='
75
+ - - ! '>='
67
76
  - !ruby/object:Gem::Version
68
77
  version: '0'
69
- description: |-
70
- Build apt and yum repositories from
71
- a directory, or from supplied information
78
+ - !ruby/object:Gem::Dependency
79
+ name: arr-pm
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: nokogiri
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: uuid
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ description: ! "Build apt and yum repositories from\n a directory,
127
+ or from supplied information"
72
128
  email:
73
129
  - github@tinycat.co.uk
74
130
  executables: []
@@ -81,31 +137,33 @@ files:
81
137
  - README.md
82
138
  - Rakefile
83
139
  - lib/ropes.rb
84
- - lib/ropes/repository.rb
140
+ - lib/ropes/repository/apt.rb
141
+ - lib/ropes/repository/yum.rb
85
142
  - lib/ropes/version.rb
86
143
  - ropes.gemspec
87
144
  homepage: https://github.com/andytinycat/ropes
88
145
  licenses:
89
146
  - MIT
90
- metadata: {}
91
147
  post_install_message:
92
148
  rdoc_options: []
93
149
  require_paths:
94
150
  - lib
95
151
  required_ruby_version: !ruby/object:Gem::Requirement
152
+ none: false
96
153
  requirements:
97
- - - '>='
154
+ - - ! '>='
98
155
  - !ruby/object:Gem::Version
99
156
  version: '0'
100
157
  required_rubygems_version: !ruby/object:Gem::Requirement
158
+ none: false
101
159
  requirements:
102
- - - '>='
160
+ - - ! '>='
103
161
  - !ruby/object:Gem::Version
104
162
  version: '0'
105
163
  requirements: []
106
164
  rubyforge_project:
107
- rubygems_version: 2.1.9
165
+ rubygems_version: 1.8.25
108
166
  signing_key:
109
- specification_version: 4
167
+ specification_version: 3
110
168
  summary: Build apt and yum repositories with Ruby
111
169
  test_files: []
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: f0340a39d71d97eed45a3581d0b888b7baecaf26
4
- data.tar.gz: aa6e407db435d64f5357122f501a378fa40cd60b
5
- SHA512:
6
- metadata.gz: f487454858ff5e087d7fd48df9c6836d61ec5d44b3eecd3f3f5ebf393c032a19c16ad78dd50463cd0a121e0ded135781780390ff895cc37300426a97775b927a
7
- data.tar.gz: ef54892b3d5374d2817c31f00f6d193f8346ffaf8df4b98e6a4d2d536efaadf3e22f680fe56da8c85169d1007f19ae967f4aa902ef1ca1a97859401632583320
@@ -1,178 +0,0 @@
1
- require 'debeasy'
2
- require 'stringio'
3
- require 'zlib'
4
- require 'tempfile'
5
- require 'digest'
6
- require 'gpgme'
7
- require 'uuid'
8
-
9
- module Ropes
10
-
11
- class Error < RuntimeError; end
12
- class InvalidRepositoryType < Error; end
13
-
14
- class Repository
15
-
16
- def initialize(options)
17
- missing_options = %w{
18
- origin
19
- type
20
- distribution
21
- version
22
- architectures
23
- components
24
- description
25
- package_base}.reject do |required_option|
26
- options.has_key?(required_option.to_sym)
27
- end
28
-
29
- raise "Missing options: #{missing_options.join(", ")}" unless missing_options.empty?
30
-
31
- raise InvalidRepositoryType, "Repository type #{options[:type]} is neither :apt or :yum" unless options[:type] == :yum or options[:type] == :apt
32
- raise Error, "Architectures must be an array" unless options[:architectures].is_a? Array
33
-
34
- @release_file = nil
35
- @packages_file = nil
36
- @packages_field_gz = nil
37
-
38
- @options = options
39
- @packages = []
40
- @field_order = %w{
41
- package
42
- priority
43
- section
44
- installed_size
45
- maintainer
46
- architecture
47
- source
48
- version
49
- depends
50
- filename
51
- size
52
- MD5sum
53
- SHA1
54
- SHA256
55
- description
56
- description-md5
57
- bugs
58
- origin
59
- supported
60
- }
61
- @mandatory_fields = %w{
62
- package
63
- version
64
- architecture
65
- maintainer
66
- description
67
- }
68
- end
69
-
70
- def add_file_by_path(path)
71
- metadata = Debeasy.read(path).to_hash
72
- if validate_metadata(metadata).empty?
73
- @packages << metadata
74
- else
75
- raise "Missing mandatory fields on package: #{validate_metadata(metadata).join(", ")}"
76
- end
77
- end
78
-
79
- def add_file_by_info(package)
80
- if validate_metadata(package).empty?
81
- if package.is_a? Hash
82
- @packages << package
83
- else
84
- raise "Package metadata must be in hash format"
85
- end
86
- else
87
- raise "Missing mandatory fields on package: #{validate_metadata(package).join(", ")}"
88
- end
89
- end
90
-
91
- # Get the Packages file as a string
92
-
93
- def packages_file(arch)
94
- packages_for_arch = @packages.select {|p| p["architecture"] == arch}
95
- entries = packages_for_arch.map do |package|
96
- lines = []
97
- @field_order.each do |field|
98
- if package[field] != nil
99
- case field
100
- when "filename"
101
- lines << packages_line(field.capitalize, "#{@options[:package_base]}/#{package[field]}")
102
- when "installed_size"
103
- lines << packages_line("Installed-Size", package[field])
104
- when "SHA1", "SHA256", "MD5sum"
105
- lines << packages_line(field, package[field])
106
- else
107
- lines << packages_line(field.capitalize, package[field])
108
- end
109
- end
110
- end
111
- lines.join("\n")
112
- end
113
- if entries.empty?
114
- ""
115
- else
116
- entries.join("\n\n") + "\n"
117
- end
118
- end
119
-
120
- # Get the Packages file as a gzip'ed string
121
-
122
- def packages_file_gz(arch)
123
- io = StringIO.new("w")
124
- gz = Zlib::GzipWriter.new(io)
125
- gz.write(packages_file(arch))
126
- gz.close
127
- io.string
128
- end
129
-
130
- # Get the Release file as a string
131
-
132
- def release_file
133
- lines = []
134
- lines << "Origin: #{@options[:origin]}"
135
- lines << "Label: #{@options[:origin]}"
136
- lines << "Suite: #{@options[:distribution]}"
137
- lines << "Version: #{@options[:version]}"
138
- lines << "Codename: #{@options[:distribution]}"
139
- lines << "Date: #{Time.new.utc.strftime '%a, %d %b %Y %H:%M:%S UTC'}"
140
- lines << "Architectures: #{@options[:architectures].join(" ")}"
141
- lines << "Components: #{@options[:components]}"
142
- lines << "Description: #{@options[:description]}"
143
- lines << "MD5Sum:"
144
- @options[:architectures].each do |arch|
145
- # Have to create the files in real life to get the real size
146
- temp_packages_file = Tempfile.new("Packages")
147
- temp_packages_file.write packages_file(arch)
148
- temp_packages_file_gz = Tempfile.new("Packages.gz")
149
- temp_packages_file_gz.write packages_file_gz(arch)
150
- lines << " #{Digest::MD5.hexdigest(packages_file(arch))} #{temp_packages_file.size} #{@options[:components]}/binary-#{arch}/Packages"
151
- lines << " #{Digest::MD5.hexdigest(packages_file_gz(arch))} #{temp_packages_file_gz.size} #{@options[:components]}/binary-#{arch}/Packages.gz"
152
- end
153
- lines.join("\n") + "\n"
154
- end
155
-
156
- # Get detached GPG signature of Release file
157
-
158
- def release_file_gpg(path_to_gpgkey)
159
- GPGME::Key.import(File.open(path_to_gpgkey))
160
- GPGME::Crypto.new.sign(release_file, {
161
- :mode => GPGME::SIG_MODE_DETACH,
162
- :armor => true
163
- })
164
- end
165
-
166
- private
167
-
168
-
169
- def packages_line(field, value)
170
- "#{field}: #{value}"
171
- end
172
-
173
- def validate_metadata(metadata_hash)
174
- @mandatory_fields.reject {|field| metadata_hash.has_key?(field)}
175
- end
176
-
177
- end
178
- end