ropes 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Mjg3YzUwYjBmNTFiMmQ4MGI1NGJiMjdkZWJkMTFlNjQ3NGNlOGU5Yg==
5
+ data.tar.gz: !binary |-
6
+ NDJmMzAzMWVlZGI1YmJiMjMwMjUwZWFmYjZmNmZiNzQ1ZDYxMzM1Mw==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NDBmY2Q0Y2Y5ZDIxNGIyNTBhOGM2ODg4ZmFjN2RhZGMwYmNhZGM0OTAyYmRm
10
+ YTkxZDcwN2QyNTU3ZjY0YTIwOGI4M2Q2YmM1OTgzZjQ5OGYwMjA1YTQ0Mzky
11
+ OTQxMTVhMjE2MWQ2MTk4MWY5NjJjMjIyMjAyMTI5YjEzZmYwYTE=
12
+ data.tar.gz: !binary |-
13
+ YWNjZGUzZDk0MmIwYWE3Yzk2ODUwOWVhNGQzNDUzNTYxZWQyODI4ODA5YTdh
14
+ ZTVmMWM2ZTFjZWU0ZjlmNjYyNTMyYmE0YzUwMDkzYjk0ZmM5OWE2NGMyOGEw
15
+ M2MwZTY3NDRhNjYzNWJhYmFjMGVmZmVkZGQ3Mjc3MmY3NTZlYWQ=
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .ruby-version
19
+ .ruby-gemset
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ropes.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andy Sykes
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # Ropes
2
+
3
+ This is a simple gem you can use either programmatically or via a simple utility to build
4
+ apt and yum repositories from either a directory of package files, or from information
5
+ you supply.
6
+
7
+ It will generate the following files:
8
+ * `Releases`
9
+ * `Releases.gpg` (if you specify a GPG key to use)
10
+ * `Contents-{arch}.gz`
11
+ * `Packages`
12
+ * `Packages.gz`
13
+ * `Packages.bz2`
14
+
15
+ ## Current status
16
+
17
+ As of 0.0.1, it generates only `Releases`, `Releases.gpg`, `Packages` and `Packages.gz`.
18
+ This is enough to get a basic Ubuntu repository working. There is no yum support.
19
+
20
+ ## Installation
21
+
22
+ Add this line to your application's Gemfile:
23
+
24
+ gem 'ropes'
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install ropes
33
+
34
+ ## Usage
35
+
36
+ Here's an example of creating a repository object, adding a few packages to it,
37
+ then retrieving the various repository files. It's your reponsibility at the moment
38
+ to put files in the correct places - once there's a command line tool, it'll do this
39
+ for you.
40
+
41
+ repo = Ropes::Repository.new({
42
+ :origin => "andytinycat",
43
+ :type => :apt,
44
+ :distribution => "precise",
45
+ :version => "12.04",
46
+ :architecture => "amd64",
47
+ :components => "main",
48
+ :description => "testing",
49
+ :package_base => "packages"
50
+ })
51
+
52
+ repo.add_file_by_path("some_custom_package.deb")
53
+
54
+ File.open("Packages", "w") do |file|
55
+ file.write repo.packages_file
56
+ end
57
+
58
+ File.open("Release", "w") do |file|
59
+ file.write repo.release_file
60
+ end
61
+
62
+ File.open("Release.gpg", "w") do |file|
63
+ file.write repo.release_file_gpg("/path/to/your/gpg.key")
64
+ end
65
+
66
+ File.open("Packages.gz", "w") do |file|
67
+ file.write repo.packages_file_gz
68
+ end
69
+
70
+ ## Contributing
71
+
72
+ 1. Fork it
73
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
74
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
75
+ 4. Push to the branch (`git push origin my-new-feature`)
76
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,173 @@
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
+ architecture
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
+
33
+ @release_file = nil
34
+ @packages_file = nil
35
+ @packages_field_gz = nil
36
+
37
+ @options = options
38
+ @packages = []
39
+ @field_order = %w{
40
+ package
41
+ priority
42
+ section
43
+ installed_size
44
+ maintainer
45
+ architecture
46
+ source
47
+ version
48
+ depends
49
+ filename
50
+ size
51
+ MD5sum
52
+ SHA1
53
+ SHA256
54
+ description
55
+ description-md5
56
+ bugs
57
+ origin
58
+ supported
59
+ }
60
+ @mandatory_fields = %w{
61
+ package
62
+ version
63
+ architecture
64
+ maintainer
65
+ description
66
+ }
67
+ end
68
+
69
+ def add_file_by_path(path)
70
+ metadata = Debeasy.read(path).to_hash
71
+ if validate_metadata(metadata).empty?
72
+ @packages << metadata
73
+ else
74
+ raise "Missing mandatory fields on package: #{validate_metadata(metadata).join(", ")}"
75
+ end
76
+ end
77
+
78
+ def add_file_by_info(package)
79
+ if validate_metadata(path).empty?
80
+ if package.is_a? Hash
81
+ @packages << package
82
+ else
83
+ raise "Package metadata must be in hash format"
84
+ end
85
+ else
86
+ raise "Missing mandatory fields on package: #{validate_metadata(metadata).join(", ")}"
87
+ end
88
+ end
89
+
90
+ # Get the Packages file as a string
91
+
92
+ def packages_file
93
+ return @packages_file unless @packages_file.nil?
94
+ entries = @packages.map do |package|
95
+ lines = []
96
+ @field_order.each do |field|
97
+ if package[field] != nil
98
+ case field
99
+ when "filename"
100
+ lines << packages_line(field.capitalize, "#{@options[:package_base]}/#{package[field]}")
101
+ when "installed_size"
102
+ lines << packages_line("Installed-Size", package[field])
103
+ when "SHA1", "SHA256", "MD5sum"
104
+ lines << packages_line(field, package[field])
105
+ else
106
+ lines << packages_line(field.capitalize, package[field])
107
+ end
108
+ end
109
+ end
110
+ lines.join("\n")
111
+ end
112
+ @packages_file = entries.join("\n\n") + "\n"
113
+ end
114
+
115
+ # Get the Packages file as a gzip'ed string
116
+
117
+ def packages_file_gz
118
+ io = StringIO.new("w")
119
+ gz = Zlib::GzipWriter.new(io)
120
+ gz.write(packages_file())
121
+ gz.close
122
+ io.string
123
+ end
124
+
125
+ # Get the Release file as a string
126
+
127
+ def release_file
128
+
129
+ # Have to create the files in real life to get the real size
130
+ temp_packages_file = Tempfile.new("Packages")
131
+ temp_packages_file.write packages_file
132
+ temp_packages_file_gz= Tempfile.new("Packages.gz")
133
+ temp_packages_file_gz.write packages_file_gz
134
+
135
+ lines = []
136
+ lines << "Origin: #{@options[:origin]}"
137
+ lines << "Label: #{@options[:origin]}"
138
+ lines << "Suite: #{@options[:distribution]}"
139
+ lines << "Version: #{@options[:version]}"
140
+ lines << "Codename: #{@options[:distribution]}"
141
+ lines << "Date: #{Time.new.utc.strftime '%a, %d %b %Y %H:%M:%S UTC'}"
142
+ lines << "Architectures: #{@options[:architecture]}"
143
+ lines << "Components: #{@options[:components]}"
144
+ lines << "Description: #{@options[:description]}"
145
+ lines << "MD5Sum:"
146
+ lines << " #{Digest::MD5.hexdigest(packages_file)} #{temp_packages_file.size} #{@options[:components]}/binary-#{@options[:architecture]}/Packages"
147
+ lines << " #{Digest::MD5.hexdigest(packages_file_gz)} #{temp_packages_file_gz.size} #{@options[:components]}/binary-#{@options[:architecture]}/Packages.gz"
148
+ lines.join("\n") + "\n"
149
+ end
150
+
151
+ # Get detached GPG signature of Release file
152
+
153
+ def release_file_gpg(path_to_gpgkey)
154
+ GPGME::Key.import(File.open(path_to_gpgkey))
155
+ GPGME::Crypto.new.sign(release_file, {
156
+ :mode => GPGME::SIG_MODE_DETACH,
157
+ :armor => true
158
+ })
159
+ end
160
+
161
+ private
162
+
163
+
164
+ def packages_line(field, value)
165
+ "#{field}: #{value}"
166
+ end
167
+
168
+ def validate_metadata(metadata_hash)
169
+ @mandatory_fields.reject {|field| metadata_hash.has_key?(field)}
170
+ end
171
+
172
+ end
173
+ end
@@ -0,0 +1,3 @@
1
+ module Ropes
2
+ VERSION = "0.0.1"
3
+ end
data/lib/ropes.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "ropes/version"
2
+ require "ropes/repository"
3
+
4
+ module Ropes
5
+
6
+ end
data/ropes.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ropes/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ropes"
8
+ spec.version = Ropes::VERSION
9
+ spec.authors = ["Andy Sykes"]
10
+ spec.email = ["github@tinycat.co.uk"]
11
+ spec.description = %q{Build apt and yum repositories from
12
+ a directory, or from supplied information}
13
+ spec.summary = %q{Build apt and yum repositories with Ruby}
14
+ spec.homepage = "https://github.com/andytinycat/ropes"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake"
24
+ spec.add_dependency "debeasy"
25
+ spec.add_dependency "gpgme"
26
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ropes
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andy Sykes
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: debeasy
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: gpgme
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: ! "Build apt and yum repositories from\n a directory,
70
+ or from supplied information"
71
+ email:
72
+ - github@tinycat.co.uk
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - lib/ropes.rb
83
+ - lib/ropes/repository.rb
84
+ - lib/ropes/version.rb
85
+ - ropes.gemspec
86
+ homepage: https://github.com/andytinycat/ropes
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.0.7
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: Build apt and yum repositories with Ruby
110
+ test_files: []