melai 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+ Gemfile.lock
15
+ .rvmrc
16
+
17
+ # YARD artifacts
18
+ .yardoc
19
+ _yardoc
20
+ doc/
21
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in melai.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Mike Fiedler
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.
@@ -0,0 +1,67 @@
1
+ # Melai
2
+
3
+ Melai is a command-line tool to create software package repositories for
4
+ APT and YUM package management tools.
5
+
6
+ ## Installation
7
+ This tool is a standalone tool, and should be installed wither via RubyGems:
8
+
9
+ $ gem install melai
10
+
11
+ If you'd rather install dependencies and install from source:
12
+
13
+ $ bundle install && rake install
14
+
15
+ ## Usage
16
+
17
+ ### Requirements
18
+ Some prerequisites are needed, and exist currently on Debian/Ubuntu based distros.
19
+
20
+ * `apt-ftparchive` (Debian-style packages) - `sudo apt-get install apt-utils`
21
+ * `createrepo` (RedHat-style packages) - `sudo apt-get install createrepo`
22
+
23
+ Both of these external tools are needed to build the required repo metadata.
24
+
25
+ NOTE: This process cannot be run on RedHat/CentOS yet - as they do not have the
26
+ tools to work with Debian-style packages.
27
+
28
+ ## Execution
29
+
30
+ An example:
31
+
32
+ melai -r newrepo create -p sourcepackages -u "http://mypackageserver.com/myrepo"
33
+
34
+ Another way is to initialize a config, and use that:
35
+
36
+ melai -r newrepo initconfig
37
+
38
+ This will create a file named `~/.melai.rc`. Edit it to contain your values:
39
+
40
+ ---
41
+ :help: false
42
+ :r: newrepo
43
+ :repos-path: newrepo
44
+ commands:
45
+ :create:
46
+ :pkgs-path: sourcepackages
47
+ :url-root: "http://mypackageserver.com/myrepo"
48
+ :list: {}
49
+ :destroy: {}
50
+ :p: tmpfoo
51
+ :pkgs-path: tmpfoo
52
+ :u: "http://mypackageserver.com/myrepo"
53
+ :url-root: "http://mypackageserver.com/myrepo"
54
+ :list: {}
55
+ :destroy: {}
56
+
57
+ Then you can run `melai create` with no arguments.
58
+ See [here](https://github.com/davetron5000/gli/wiki/Config) for more details.
59
+
60
+ ## Contributing
61
+
62
+ 1. Fork it
63
+ 1. Create your feature branch (`git checkout -b my-new-feature`)
64
+ 1. Test your changes (`rake test`)
65
+ 1. Commit your changes (`git commit -am 'Added some feature'`)
66
+ 1. Push to the branch (`git push origin my-new-feature`)
67
+ 1. Create new Pull Request
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
3
+ require 'cucumber'
4
+ require 'cucumber/rake/task'
5
+
6
+ task :default => [:install, :test]
7
+
8
+ desc "Run tests"
9
+ task :test => [:features, :tailor]
10
+
11
+ Cucumber::Rake::Task.new(:features) do |t|
12
+ # t.cucumber_opts = ['--format pretty -x']
13
+
14
+ t.cucumber_opts = ['--format', 'progress', '-x']
15
+ t.cucumber_opts += ['features']
16
+
17
+ # This turns on the GLI debugging backtraces
18
+ t.cucumber_opts += ['GLI_DEBUG=true']
19
+ end
20
+
21
+ # https://github.com/turboladen/tailor
22
+ require 'tailor/rake_task'
23
+ Tailor::RakeTask.new do |task|
24
+ task.file_set('lib/**/*.rb', 'code') do |style|
25
+ style.max_line_length 100, level: :warn
26
+ style.max_code_lines_in_method 50, level: :warn
27
+ end
28
+ task.file_set('bin/*', 'binaries') do |style|
29
+ style.max_line_length 100, level: :warn
30
+ end
31
+ end
32
+
33
+ require 'rdoc/task'
34
+ Rake::RDocTask.new do |rd|
35
+ rd.main = "README.md"
36
+ rd.rdoc_files.include("README.md","lib/**/*.rb","bin/**/*")
37
+ rd.title = 'melai'
38
+ end
39
+
40
+ # File lib/tasks/notes.rake
41
+ desc "Find notes in code"
42
+ task :notes do
43
+ puts `grep --exclude=Rakefile -r 'OPTIMIZE:\\|FIXME:\\|TODO:' .`
44
+ end
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env ruby
2
+ # $: << File.expand_path(File.dirname(File.realpath(__FILE__)) + '/../lib')
3
+ # require 'rubygems'
4
+
5
+ require 'gli'
6
+ require_relative '../lib/melai'
7
+
8
+ include GLI
9
+
10
+ program_desc "Describe your application here"
11
+
12
+ version Melai::VERSION
13
+
14
+ # desc "Describe some switch here"
15
+ # switch [:s, :switch]
16
+
17
+ desc "Root directory for repositories, relative to current directory"
18
+ default_value "repo"
19
+ arg_name "REPOS_PATH"
20
+ flag [:r, "repos-path"]
21
+
22
+ # https://github.com/davetron5000/gli/wiki/Config
23
+ config_file '.melai.rc'
24
+
25
+ desc "Create a repository structure"
26
+ command :create do |c|
27
+ # TODO: add a force option to rebuild from scratch
28
+
29
+ c.desc "Source directory containing all packages, relative to current directory"
30
+ c.default_value "srcpkgs"
31
+ c.arg_name "PKGS_PATH"
32
+ c.flag [:p, "pkgs-path"]
33
+
34
+ c.desc "FQDN of the web server, must include http:// and desired docroot"
35
+ c.default_value "http://somewhere.com/repo"
36
+ c.arg_name "URL_ROOT"
37
+ c.flag [:u, "url-root"]
38
+
39
+ c.action do |global_options, options, args|
40
+ repositories_path = File.absolute_path(global_options[:r])
41
+ packages_path = File.absolute_path(options[:p])
42
+ url_root = options[:u]
43
+ $melai.create(repositories_path, packages_path, url_root)
44
+ end
45
+ end
46
+
47
+ desc "List all packages in a directory"
48
+ command :list do |c|
49
+
50
+ c.desc "Source directory containing all packages"
51
+ c.default_value "srcpkgs"
52
+ c.arg_name "PKGS_PATH"
53
+ c.flag [:p, "pkgs-path"]
54
+
55
+ c.action do |global_options, options, args|
56
+ puts $melai.list(options[:p])
57
+ end
58
+ end
59
+
60
+ desc "Destroy the repository directory completely"
61
+ command :destroy do |c|
62
+ c.action do |global_options, options, args|
63
+ # TODO: Add a --force option
64
+ # TODO: Add a "Are you sure? (y/n)" prompt
65
+ $melai.destroy(global_options[:r])
66
+ end
67
+ end
68
+
69
+
70
+ pre do |global, command, options, args|
71
+ # Pre logic here
72
+ # Return true to proceed; false to abort and not call the
73
+ # chosen command
74
+ # Use skips_pre before a command to skip this block
75
+ # on that command only
76
+ # true
77
+ $melai = Melai::CommandHandler.new
78
+ # TODO: Why do I have to extend the CommandHandler class? Inclusion?
79
+ $melai.extend(Melai::DirHelpers)
80
+ $melai.extend(Melai::PackageHelpers)
81
+ $melai.extend(Melai::StringHelpers)
82
+ end
83
+
84
+ post do |global, command, options, args|
85
+ # Post logic here
86
+ # Use skips_post before a command to skip this
87
+ # block on that command only
88
+ end
89
+
90
+ on_error do |exception|
91
+ # Error logic here
92
+ # return false to skip default error handling
93
+ true
94
+ end
95
+
96
+ exit GLI.run(ARGV)
97
+
98
+
99
+ # module Melai
100
+ # cmd_line = CommandLine.new(ARGV)
101
+ # # review, status = Linter.check(cmd_line)
102
+ # # printer = cmd_line.show_context? ? ContextOutput.new : SummaryOutput.new
103
+ # # printer.output(review)
104
+ # exit status.to_i
105
+ # end
106
+ #
107
+ #
108
+ #
@@ -0,0 +1,26 @@
1
+ Feature: Set up the repository directory
2
+ In order to increase the amount of confidence in repeatable package repositories,
3
+ As an operator
4
+ I want to set up all the directories I need
5
+
6
+ Scenario: Listing an empty source directory returns no files
7
+ Given a directory named "emptysrcpkgs"
8
+ When I successfully run `melai list -p emptysrcpkgs`
9
+ Then the output should contain exactly ""
10
+
11
+ Scenario: List all package files in a source directory
12
+ Given a directory named "srcpkgs"
13
+ And an empty file named "srcpkgs/example-1.0.deb"
14
+ And an empty file named "srcpkgs/example-1.0.rpm"
15
+ When I successfully run `melai list -p srcpkgs`
16
+ Then the output should contain:
17
+ """
18
+ srcpkgs/example-1.0.deb
19
+ srcpkgs/example-1.0.rpm
20
+ """
21
+
22
+ # Final step, cleans up
23
+ Scenario: A repository directory exists and I want to destroy it
24
+ Given a directory named "repo"
25
+ When I successfully run `melai -r repo destroy`
26
+ Then a directory named "repo" should not exist
@@ -0,0 +1,45 @@
1
+ Feature: Create repositories from files
2
+ In order provide packages to end users,
3
+ As an operator
4
+ I want to create multiple repositories from a set of files
5
+
6
+ Background:
7
+ Given I double `apt-ftparchive` with exit status 0
8
+ And I double `createrepo` with exit status 0
9
+
10
+ Scenario: Create a repository for source packages in a semi-flat directory
11
+ Given an empty file named "srcpkgs/foo-1.0.0.i686.rpm"
12
+ And an empty file named "srcpkgs/foo-1.0.0.i386.deb"
13
+ And an empty file named "srcpkgs/ubuntu/foo-1.0.0-bar.i386.deb"
14
+ When I successfully run `melai -r repo create -p srcpkgs`
15
+ Then a directory named "repo/redhat/1.0/i686/RPMS" should exist
16
+ And a directory named "repo/redhat/os/i686/RPMS" should exist
17
+ And a directory named "repo/debian-sysvinit/dists/dist/10gen/binary-i386" should exist
18
+ And a directory named "repo/ubuntu-upstart/dists/dist/10gen/binary-i386" should exist
19
+
20
+ Scenario Outline: Create a repository directory structure for a given file
21
+ Given a directory named "repo" does not exist
22
+ And an empty file named <SrcFile>
23
+ When I successfully run `melai -r repo create -p srcpkgs`
24
+ Then a directory named <RepoDir> should exist
25
+ Examples:
26
+ | SrcFile | RepoDir |
27
+ | "srcpkgs/redhat/foo-2.0.0.i686.rpm" | "repo/redhat/os/i686/RPMS" |
28
+ | "srcpkgs/redhat/foo-2.0.1.i686.rpm" | "repo/redhat/2.0/i686/RPMS" |
29
+ | "srcpkgs/redhat/foo-2.0.2.x86_64.rpm" | "repo/redhat/2.0/x86_64/RPMS" |
30
+ | "srcpkgs/debian/foo-2.0.0.i386.deb" | "repo/debian-sysvinit/dists/dist/10gen/binary-i386/" |
31
+ | "srcpkgs/redhat/os/i686/RPMS/bar-server-2.0.6-version_1.i686.rpm" | "repo/redhat/os/i686/RPMS/" |
32
+ | "srcpkgs/redhat/os/i686/RPMS/bar-unstable-2.1.0-version_1.i686.rpm" | "repo/redhat/2.1/i686/RPMS/" |
33
+ | "srcpkgs/redhat/os/i686/RPMS/bar18-server-1.8.5-version_1.i686.rpm" | "repo/redhat/1.8/i686/RPMS/" |
34
+ | "srcpkgs/redhat/os/i686/RPMS/bar-2.0.6-version_1.i686.rpm" | "repo/redhat/2.0/i686/RPMS/" |
35
+
36
+ Scenario Outline: Create a repository file
37
+ Given a directory named "repo" does not exist
38
+ And an empty file named <SrcFile>
39
+ When I successfully run `melai -r repo create -p srcpkgs`
40
+ Then a file named <RepoTemplate> should exist
41
+ Examples:
42
+ | SrcFile | RepoTemplate |
43
+ | "srcpkgs/redhat/foo-2.0.0.i686.rpm" | "repo/redhat/os/i686/RPMS/10gen.repo" |
44
+ | "srcpkgs/debian/foo-2.0.0.i386.deb" | "repo/debian-sysvinit/dists/dist/10gen/binary-i386/10gen.list" |
45
+ | "srcpkgs/ubuntu/foo-2.0.0.i386.deb" | "repo/ubuntu-upstart/dists/dist/10gen/binary-i386/10gen.list" |
@@ -0,0 +1,5 @@
1
+ # It doesn't look lik there is currently a defined method in aruba for
2
+ # directories that should not exist.
3
+ Given /^a directory named "([^"]*)" does not exist$/ do |directory|
4
+ check_directory_presence([directory], false)
5
+ end
@@ -0,0 +1,15 @@
1
+ # Set up the environment for testing
2
+ require 'aruba/cucumber'
3
+ require 'aruba-doubles/cucumber'
4
+
5
+ Before do
6
+ @aruba_timeout_seconds = 5
7
+ # @dirs = ["tmp/aruba"]
8
+ end
9
+
10
+ After do |s|
11
+ # Tell Cucumber to quit after this scenario is done - if it failed.
12
+ # This is useful to inspect the 'tmp/aruba' directory before any other
13
+ # steps are executed and clear it out.
14
+ Cucumber.wants_to_quit = true if s.failed?
15
+ end
@@ -0,0 +1,80 @@
1
+ # require 'rubygems'
2
+ require_relative 'melai/version'
3
+ require_relative 'melai/dir_helpers'
4
+ require_relative 'melai/package_helpers'
5
+ require_relative 'melai/string_helpers'
6
+
7
+ module Melai
8
+ #
9
+ # This module is the main module. Creates a class of CommandHandler.
10
+ # Not entirely sure if the code is structured correctly. Might have to
11
+ # rethink module vs class locations, based on inheritance.
12
+ #
13
+ class CommandHandler
14
+
15
+ # Creates/updates a symlink-based repository structure
16
+ #
17
+ # @param [String] a directory to build into
18
+ # @param [String] a directory containing the source packages
19
+ def create(repositories_path, packages_path, url_root)
20
+ puts "Creating a repository at #{repositories_path}."
21
+ ensure_directory(repositories_path)
22
+
23
+ # Accumulate a Hash keyed by repository filesystem path
24
+ # whose values are hashes of {:needs_update => bool,
25
+ # :arch => String, :variant => String }
26
+ repositories = Hash.new
27
+
28
+ find_packages(packages_path).each do |package_path|
29
+ package_metadata(package_path, repositories_path).each do |metadata|
30
+ repository_path = metadata[:repository_path]
31
+ needs_update = ensure_symlink(metadata[:symlink_path], metadata[:package_path])
32
+
33
+ if repositories.include?(repository_path)
34
+ repositories[repository_path][:needs_update] ||= needs_update
35
+ else
36
+ repositories[repository_path] = {
37
+ :needs_update => needs_update,
38
+ :variant => metadata[:variant],
39
+ :arch => metadata[:arch],
40
+ :repository_path => metadata[:repository_path],
41
+ :repository_prefix => metadata[:repository_prefix]
42
+ }
43
+ end
44
+ end
45
+ end
46
+
47
+ # Now we have a Hash of all the repo directories that need updating by a value of 'true'
48
+ repositories.each do |repository_path, metadata|
49
+ next unless metadata[:needs_update]
50
+
51
+ repo_template(metadata, repositories_path, url_root)
52
+ update_repo_metadata(metadata, repositories_path, packages_path)
53
+ end
54
+ end
55
+
56
+ # List all package files found
57
+ #
58
+ # @param [String] a directory containing the source packages
59
+ # @return [Array] an array of filenames
60
+ def list(packages_path)
61
+ find_packages(packages_path)
62
+ end
63
+
64
+ # Destroy the repository directory completely.
65
+ # This is a glorified `rm -fr repo/` command, with a simple guard.
66
+ #
67
+ # @param [String] the root of repository directory
68
+ def destroy(repositories_path)
69
+ if repositories_path == "/"
70
+ exit_now!("WTF are you trying to do?", 1)
71
+ elsif Dir.exists?(repositories_path)
72
+ puts "Removing the entire #{repositories_path}"
73
+ FileUtils.remove_dir repositories_path
74
+ puts "It's gone!"
75
+ else
76
+ puts "Nothing there... idiot."
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,43 @@
1
+ module Melai
2
+
3
+ # This module provides some helper methods, specificlally pertaining
4
+ # to directory creation, removal, searching, et al.
5
+ module DirHelpers
6
+
7
+ # Get any files with a known package extension
8
+ #
9
+ # @param [String] a directory to evaluate
10
+ # @return [Array] an array of filenmes
11
+ def find_packages(packages_path)
12
+ packages = File.join(packages_path, "**", "*.{rpm,deb}")
13
+ return Dir.glob(packages).sort()
14
+ end
15
+
16
+ # Ensure a directory exists
17
+ #
18
+ # @param [String] a directory to evaluate
19
+ # @return [Bool] true if the directory was created, false if already exists
20
+ def ensure_directory(directory)
21
+ unless File.directory?(directory)
22
+ FileUtils.mkdir_p(directory)
23
+ return true
24
+ end
25
+ return false
26
+ end
27
+
28
+ # Ensure a symlink exists
29
+ #
30
+ # @param [String] symlink_name: /foo/bar/i-am-a-symlink.rpm
31
+ # @param [String] original_file: /baz/i-am-a-real-file.rpm
32
+ # @return [Bool] true if the link was created, false if already exists
33
+ def ensure_symlink(symlink_name, original_file)
34
+ unless File.symlink?(symlink_name)
35
+ ensure_directory(File.dirname(symlink_name))
36
+ target = File.absolute_path(original_file)
37
+ File.symlink(target, symlink_name)
38
+ return true
39
+ end
40
+ return false
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,168 @@
1
+ require 'erb'
2
+ require 'tempfile'
3
+ require 'mixlib/shellout'
4
+ require_relative 'dir_helpers'
5
+ require_relative 'string_helpers'
6
+
7
+ module Melai
8
+
9
+ # This module provides some package helper methods
10
+ module PackageHelpers
11
+
12
+ # Return an array of package metadata hashes. Each
13
+ # array element describes a particular repository
14
+ # that this package should be a member of.
15
+ def package_metadata(package_path, repositories_path)
16
+ case File.extname(package_path)
17
+ when '.rpm'
18
+ return rpm_package_metadata(package_path, repositories_path)
19
+ when '.deb'
20
+ if File.fnmatch('*ubuntu*', package_path)
21
+ return ubuntu_package_metadata(package_path, repositories_path)
22
+ else File.fnmatch('*debian*', package_path)
23
+ return debian_package_metadata(package_path, repositories_path)
24
+ end
25
+ end
26
+ end
27
+
28
+ def repo_template(metadata, repositories_path, url_root)
29
+ repository_path = metadata[:repository_path]
30
+ case repository_path
31
+ when /redhat/
32
+ source = "redhat.repo.erb"
33
+ target = "10gen.repo"
34
+ url_path = File.join(metadata[:repository_prefix], metadata[:variant], metadata[:arch])
35
+ else
36
+ source = "debian.list.erb"
37
+ target = "10gen.list"
38
+ url_path = File.join(metadata[:repository_prefix])
39
+ end
40
+
41
+ here = File.dirname(__FILE__)
42
+ template = ERB.new(File.read(File.join(here, "..", "..", "templates", source)))
43
+ output = File.new(File.join(repository_path, target), "w")
44
+ output.write(template.result(binding))
45
+ end
46
+
47
+ def update_repo_metadata(metadata, repositories_path, packages_path)
48
+ repository_path = metadata[:repository_path]
49
+
50
+ # e.g /data/packages/cache/debian-sysvinit/dists/
51
+ cache_path = File.join(packages_path, "cache", metadata[:repository_prefix])
52
+ ensure_directory(cache_path)
53
+
54
+ case repository_path
55
+ when /redhat/
56
+ begin
57
+ # e.g. repo/redhat/2.0/x86_64/
58
+ variant_dir = File.join(repositories_path,
59
+ metadata[:repository_prefix],
60
+ metadata[:variant],
61
+ metadata[:arch])
62
+
63
+ shell_out("createrepo --pretty -c #{cache_path} #{variant_dir}")
64
+ rescue Exception=>e
65
+ exit_now!("Could not complete createrepo:\n#{e}", 1)
66
+ end
67
+
68
+ else
69
+ # Do Debian-style repo builds
70
+ here = File.dirname(__FILE__)
71
+ fileloc = File.join(here, "../..", "templates", "apt-ftparchive.conf.erb")
72
+ template = ERB.new(File.read(fileloc))
73
+ output = Tempfile.new("apt-ftparchive.conf")
74
+ output.write(template.result(binding))
75
+ output.close()
76
+
77
+ begin
78
+ # Generates the Packages, Contents files
79
+ shell_out("apt-ftparchive generate #{output.path}")
80
+
81
+ # Generate the Release files on stdout
82
+ variant_dir = File.join(repositories_path,
83
+ metadata[:repository_prefix],
84
+ "dists",
85
+ metadata[:variant])
86
+
87
+ result = shell_out("apt-ftparchive -c #{output.path} release #{variant_dir}")
88
+
89
+ # Dump the Release stdout to a Release file
90
+ release_file = File.join(variant_dir, "Release.new")
91
+ File.open(release_file, "w").write(result.stdout)
92
+ # This ensures that the Release file is not included within itself
93
+ File.rename(release_file, File.join(variant_dir, "Release"))
94
+
95
+ # TODO: GPG Sign the Release file
96
+
97
+ rescue Exception=>e
98
+ exit_now!("Could not complete apt-ftparchive:\n#{e}", 1)
99
+ end
100
+ end
101
+ end
102
+
103
+ private
104
+
105
+ def shell_out(command)
106
+ proc = Mixlib::ShellOut.new(command)
107
+ proc.run_command
108
+ proc.error!
109
+ return proc
110
+ end
111
+
112
+ def rpm_package_metadata(package_path, repositories_path)
113
+ generate_metadata(package_path, repositories_path, ["os"]) do |variant, arch|
114
+ # Return path segments, relative to repositories_path,
115
+ # necessary to construct a path to the correct directory
116
+ # for RPM packages in the given variant and arch.
117
+ ["redhat", variant, arch, "RPMS"]
118
+ end
119
+ end
120
+
121
+ def debian_package_metadata(package_path, repositories_path)
122
+ generate_metadata(package_path, repositories_path, ["dist"]) do |variant, arch|
123
+ # Return path segments, relative to repositories_path,
124
+ # necessary to construct a path to the correct directory
125
+ # for Debian packages in the given variant and arch.
126
+ ["debian-sysvinit", "dists", variant, "10gen", "binary-#{arch}"]
127
+ end
128
+ end
129
+
130
+ def ubuntu_package_metadata(package_path, repositories_path)
131
+ generate_metadata(package_path, repositories_path, ["dist"]) do |variant, arch|
132
+ # Return path segments, relative to repositories_path,
133
+ # necessary to construct a path to the correct directory
134
+ # for Ubuntu packages in the given variant and arch.
135
+ ["ubuntu-upstart", "dists", variant, "10gen", "binary-#{arch}"]
136
+ end
137
+ end
138
+
139
+ def generate_metadata(package_path, repositories_path, variants)
140
+ # Since we want to provide both a 'base' variant and a version-specific
141
+ # one, we build an array of variants based on the the version maj.min
142
+ version, dist = get_version_from_filename(package_path)
143
+ arch = get_arch_from_filename(package_path)
144
+
145
+ variants << dist
146
+
147
+ package_metadata = []
148
+ variants.each do |variant|
149
+ # This is where the link will end up
150
+ path_segments = yield variant, arch
151
+ repository_path = File.join(repositories_path, *path_segments)
152
+ repository_prefix = path_segments[0]
153
+
154
+ # Create a symlink from the source file to the destination directories
155
+ package_metadata << {
156
+ :symlink_path => File.join(repository_path, File.basename(package_path)),
157
+ :package_path => package_path,
158
+ :variant => variant,
159
+ :arch => arch,
160
+ :repository_path => repository_path,
161
+ :repository_prefix => repository_prefix
162
+ }
163
+ end
164
+
165
+ return package_metadata
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,40 @@
1
+ require 'versionomy'
2
+
3
+ module Melai
4
+
5
+ # This module provides some string helper methods
6
+ module StringHelpers
7
+
8
+ # Find the arch name within a filename
9
+ #
10
+ # @params [String] A filename
11
+ # @return [String] the arch name
12
+ def get_arch_from_filename(filename)
13
+ case
14
+ when matched = filename.match(/(i686|x86_64|i386|amd64)/)
15
+ arch = matched[0]
16
+ else
17
+ return 'unknown'
18
+ end
19
+ end
20
+
21
+ # Find the version within a filename
22
+ #
23
+ # @params [String] A filename
24
+ # @return [Object] the version object, Versionomy-style
25
+ # @return [String] The Major + Minor versions
26
+ def get_version_from_filename(filename)
27
+ version = Versionomy.parse(/(\d+)\.(\d+)\.(\d+)/.match(filename).to_s)
28
+ # TODO: If we start packaging prerelease/rc packages, try:
29
+ # (\d+)\.(\d+)\.(\d+)(?:-[^\.]+)?
30
+ dist = [version.major, version.minor].join(".")
31
+ return version, dist
32
+ end
33
+
34
+ # TODO: needs work, currently unused
35
+ def get_unstable_from_filename(filename)
36
+ unstable = /unstable/.match(filename)
37
+ return unstable
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ module Melai
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,38 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/melai/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+
6
+ gem.name = 'melai'
7
+ gem.summary = %q{melai builds multi-platform repositories for a given list of package files}
8
+ gem.description = %q{Build your repositories with melai}
9
+ gem.version = Melai::VERSION
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.require_paths = ['lib']
15
+
16
+
17
+ # GLI (Github-Like Interface) http://davetron5000.github.com/gli/
18
+ gem.add_dependency 'gli'
19
+
20
+ # versiononmy http://dazuma.github.com/versionomy/
21
+ gem.add_dependency 'versionomy'
22
+
23
+ # MixLib::ShellOut to perform system-level commands
24
+ gem.add_dependency 'mixlib-shellout'
25
+
26
+ gem.add_development_dependency 'rake'
27
+ gem.add_development_dependency 'aruba'
28
+ gem.add_development_dependency 'aruba-doubles'
29
+ gem.add_development_dependency 'pry'
30
+
31
+ # tailor, for style. https://github.com/turboladen/tailor
32
+ gem.add_development_dependency 'tailor'
33
+
34
+ gem.authors = ["Mike Fiedler"]
35
+ gem.email = ["miketheman@gmail.com"]
36
+ gem.homepage = "http://www.miketheman.net"
37
+
38
+ end
@@ -0,0 +1,4 @@
1
+ = melai
2
+
3
+ consider changing to ronn
4
+ http://rtomayko.github.com/ronn/ronn.1.html
@@ -0,0 +1,26 @@
1
+ Dir {
2
+ ArchiveDir "<%= repositories_path %>/<%= metadata[:repository_prefix] %>";
3
+ CacheDir "<%= cache_path %>";
4
+ };
5
+
6
+ Tree "dists/<%= metadata[:variant] %>" {
7
+ Sections "10gen";
8
+ Architectures "i386 amd64";
9
+ };
10
+
11
+ APT::FTPArchive {
12
+ MD5 true;
13
+ SHA1 true;
14
+ SHA256 true;
15
+ SHA512 true;
16
+ Release {
17
+ Origin "10gen";
18
+ Label "10gen";
19
+ Suite "10gen";
20
+ Version "<%= metadata[:variant] %>";
21
+ Codename "<%= metadata[:variant] %>";
22
+ Architectures "i386 amd64";
23
+ Components "10gen";
24
+ Description "10gen packages";
25
+ };
26
+ };
@@ -0,0 +1,2 @@
1
+ # This file provides the 10gen software repository
2
+ deb <%= url_root %>/<%= url_path %> <%= metadata[:variant] %> 10gen
@@ -0,0 +1,6 @@
1
+ # This file provides the 10gen software repository
2
+ [10gen]
3
+ name=10gen Repository
4
+ baseurl=<%= url_root %>/<%= url_path %>
5
+ gpgcheck=0
6
+ enabled=1
metadata ADDED
@@ -0,0 +1,198 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: melai
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mike Fiedler
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-16 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: gli
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: versionomy
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: mixlib-shellout
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: aruba
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
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: aruba-doubles
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
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: pry
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
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
+ - !ruby/object:Gem::Dependency
127
+ name: tailor
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ type: :development
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ description: Build your repositories with melai
143
+ email:
144
+ - miketheman@gmail.com
145
+ executables:
146
+ - melai
147
+ extensions: []
148
+ extra_rdoc_files: []
149
+ files:
150
+ - .gitignore
151
+ - Gemfile
152
+ - LICENSE
153
+ - README.md
154
+ - Rakefile
155
+ - bin/melai
156
+ - features/directories.feature
157
+ - features/repository.feature
158
+ - features/step_definitions/directories_steps.rb
159
+ - features/support/env.rb
160
+ - lib/melai.rb
161
+ - lib/melai/dir_helpers.rb
162
+ - lib/melai/package_helpers.rb
163
+ - lib/melai/string_helpers.rb
164
+ - lib/melai/version.rb
165
+ - melai.gemspec
166
+ - melai.rdoc
167
+ - templates/apt-ftparchive.conf.erb
168
+ - templates/debian.list.erb
169
+ - templates/redhat.repo.erb
170
+ homepage: http://www.miketheman.net
171
+ licenses: []
172
+ post_install_message:
173
+ rdoc_options: []
174
+ require_paths:
175
+ - lib
176
+ required_ruby_version: !ruby/object:Gem::Requirement
177
+ none: false
178
+ requirements:
179
+ - - ! '>='
180
+ - !ruby/object:Gem::Version
181
+ version: '0'
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ none: false
184
+ requirements:
185
+ - - ! '>='
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ requirements: []
189
+ rubyforge_project:
190
+ rubygems_version: 1.8.24
191
+ signing_key:
192
+ specification_version: 3
193
+ summary: melai builds multi-platform repositories for a given list of package files
194
+ test_files:
195
+ - features/directories.feature
196
+ - features/repository.feature
197
+ - features/step_definitions/directories_steps.rb
198
+ - features/support/env.rb