vanagon 0.3.18

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.
Files changed (80) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +13 -0
  3. data/README.md +175 -0
  4. data/bin/build +33 -0
  5. data/bin/devkit +22 -0
  6. data/bin/repo +26 -0
  7. data/bin/ship +15 -0
  8. data/lib/vanagon.rb +8 -0
  9. data/lib/vanagon/common.rb +2 -0
  10. data/lib/vanagon/common/pathname.rb +87 -0
  11. data/lib/vanagon/common/user.rb +25 -0
  12. data/lib/vanagon/component.rb +157 -0
  13. data/lib/vanagon/component/dsl.rb +307 -0
  14. data/lib/vanagon/component/source.rb +66 -0
  15. data/lib/vanagon/component/source/git.rb +60 -0
  16. data/lib/vanagon/component/source/http.rb +158 -0
  17. data/lib/vanagon/driver.rb +112 -0
  18. data/lib/vanagon/engine/base.rb +82 -0
  19. data/lib/vanagon/engine/docker.rb +40 -0
  20. data/lib/vanagon/engine/local.rb +40 -0
  21. data/lib/vanagon/engine/pooler.rb +85 -0
  22. data/lib/vanagon/errors.rb +28 -0
  23. data/lib/vanagon/extensions/string.rb +11 -0
  24. data/lib/vanagon/optparse.rb +62 -0
  25. data/lib/vanagon/platform.rb +245 -0
  26. data/lib/vanagon/platform/deb.rb +71 -0
  27. data/lib/vanagon/platform/dsl.rb +293 -0
  28. data/lib/vanagon/platform/osx.rb +100 -0
  29. data/lib/vanagon/platform/rpm.rb +76 -0
  30. data/lib/vanagon/platform/rpm/wrl.rb +39 -0
  31. data/lib/vanagon/platform/solaris_10.rb +182 -0
  32. data/lib/vanagon/platform/solaris_11.rb +138 -0
  33. data/lib/vanagon/platform/swix.rb +35 -0
  34. data/lib/vanagon/project.rb +251 -0
  35. data/lib/vanagon/project/dsl.rb +218 -0
  36. data/lib/vanagon/utilities.rb +299 -0
  37. data/spec/fixures/component/invalid-test-fixture.json +3 -0
  38. data/spec/fixures/component/mcollective.service +1 -0
  39. data/spec/fixures/component/test-fixture.json +4 -0
  40. data/spec/lib/vanagon/common/pathname_spec.rb +103 -0
  41. data/spec/lib/vanagon/common/user_spec.rb +36 -0
  42. data/spec/lib/vanagon/component/dsl_spec.rb +443 -0
  43. data/spec/lib/vanagon/component/source/git_spec.rb +19 -0
  44. data/spec/lib/vanagon/component/source/http_spec.rb +43 -0
  45. data/spec/lib/vanagon/component/source_spec.rb +99 -0
  46. data/spec/lib/vanagon/component_spec.rb +22 -0
  47. data/spec/lib/vanagon/engine/base_spec.rb +40 -0
  48. data/spec/lib/vanagon/engine/docker_spec.rb +40 -0
  49. data/spec/lib/vanagon/engine/pooler_spec.rb +54 -0
  50. data/spec/lib/vanagon/platform/deb_spec.rb +60 -0
  51. data/spec/lib/vanagon/platform/dsl_spec.rb +128 -0
  52. data/spec/lib/vanagon/platform/rpm_spec.rb +41 -0
  53. data/spec/lib/vanagon/platform/solaris_11_spec.rb +44 -0
  54. data/spec/lib/vanagon/platform_spec.rb +53 -0
  55. data/spec/lib/vanagon/project/dsl_spec.rb +203 -0
  56. data/spec/lib/vanagon/project_spec.rb +44 -0
  57. data/spec/lib/vanagon/utilities_spec.rb +140 -0
  58. data/templates/Makefile.erb +116 -0
  59. data/templates/deb/changelog.erb +5 -0
  60. data/templates/deb/conffiles.erb +3 -0
  61. data/templates/deb/control.erb +21 -0
  62. data/templates/deb/dirs.erb +3 -0
  63. data/templates/deb/docs.erb +1 -0
  64. data/templates/deb/install.erb +3 -0
  65. data/templates/deb/postinst.erb +46 -0
  66. data/templates/deb/postrm.erb +15 -0
  67. data/templates/deb/prerm.erb +17 -0
  68. data/templates/deb/rules.erb +25 -0
  69. data/templates/osx/postinstall.erb +24 -0
  70. data/templates/osx/preinstall.erb +19 -0
  71. data/templates/osx/project-installer.xml.erb +19 -0
  72. data/templates/rpm/project.spec.erb +217 -0
  73. data/templates/solaris/10/depend.erb +3 -0
  74. data/templates/solaris/10/pkginfo.erb +13 -0
  75. data/templates/solaris/10/postinstall.erb +37 -0
  76. data/templates/solaris/10/preinstall.erb +7 -0
  77. data/templates/solaris/10/preremove.erb +6 -0
  78. data/templates/solaris/10/proto.erb +5 -0
  79. data/templates/solaris/11/p5m.erb +73 -0
  80. metadata +172 -0
@@ -0,0 +1,35 @@
1
+ class Vanagon
2
+ class Platform
3
+ class RPM
4
+ class Swix < Vanagon::Platform::RPM
5
+ # The specific bits used to generate an SWIX package for a given project
6
+ #
7
+ # @param project [Vanagon::Project] project to build a SWIX package of
8
+ # @return [Array] list of commands required to build the SWIX package
9
+ # for the given project from an rpm
10
+ def generate_package(project)
11
+ target_dir = project.repo ? output_dir(project.repo) : output_dir
12
+
13
+ commands = super(project)
14
+ pkgname_swix = package_name(project)
15
+ pkgname_rpm = pkgname_swix.sub(/swix$/, 'rpm')
16
+ commands += ["echo 'format: 1' > ./output/#{target_dir}/manifest.txt",
17
+ "echo \"primaryRpm: #{pkgname_rpm}\" >> ./output/#{target_dir}/manifest.txt",
18
+ "echo #{pkgname_rpm}-sha1: `sha1sum ./output/#{target_dir}/#{pkgname_rpm}`",
19
+ "cd ./output/#{target_dir}/ && zip #{pkgname_swix} manifest.txt #{pkgname_rpm}",
20
+ "rm ./output/#{target_dir}/manifest.txt ./output/#{target_dir}/#{pkgname_rpm}"]
21
+
22
+ commands
23
+ end
24
+
25
+ # Method to derive the package name for the project
26
+ #
27
+ # @param project [Vanagon::Project] project to name
28
+ # @return [String] name of the SWIX package for this project
29
+ def package_name(project)
30
+ "#{project.name}-#{project.version}-#{project.release}.#{os_name}#{os_version}.#{project.noarch ? 'noarch' : @architecture}.swix"
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,251 @@
1
+ require 'vanagon/component'
2
+ require 'vanagon/platform'
3
+ require 'vanagon/project/dsl'
4
+ require 'vanagon/utilities'
5
+ require 'ostruct'
6
+
7
+ class Vanagon
8
+ class Project
9
+ include Vanagon::Utilities
10
+ attr_accessor :components, :settings, :platform, :configdir, :name
11
+ attr_accessor :version, :directories, :license, :description, :vendor
12
+ attr_accessor :homepage, :requires, :user, :repo, :noarch, :identifier
13
+ attr_accessor :cleanup, :version_file, :release, :replaces, :provides
14
+
15
+ # Loads a given project from the configdir
16
+ #
17
+ # @param name [String] the name of the project
18
+ # @param configdir [String] the path to the project config file
19
+ # @param platform [Vanagon::Platform] platform to build against
20
+ # @param include_components [List] optional list restricting the loaded components
21
+ # @return [Vanagon::Project] the project as specified in the project config
22
+ # @raise if the instance_eval on Project fails, the exception is reraised
23
+ def self.load_project(name, configdir, platform, include_components = [])
24
+ projfile = File.join(configdir, "#{name}.rb")
25
+ code = File.read(projfile)
26
+ dsl = Vanagon::Project::DSL.new(name, platform, include_components)
27
+ dsl.instance_eval(code, __FILE__, __LINE__)
28
+ dsl._project
29
+ rescue => e
30
+ puts "Error loading project '#{name}' using '#{projfile}':"
31
+ puts e
32
+ puts e.backtrace.join("\n")
33
+ raise e
34
+ end
35
+
36
+ # Project constructor. Takes just the name. Also sets the @name and
37
+ # @platform, and initializes @components, @directories and @settings.
38
+ #
39
+ # @param name [String] name of the project
40
+ # @param platform [Vanagon::Platform] platform for the project to be built for
41
+ # @return [Vanagon::Project] the project with the given name and platform
42
+ def initialize(name, platform)
43
+ @name = name
44
+ @components = []
45
+ @requires = []
46
+ @directories = []
47
+ @settings = {}
48
+ @platform = platform
49
+ @release = "1"
50
+ @replaces = []
51
+ @provides = []
52
+ end
53
+
54
+ # Magic getter to retrieve settings in the project
55
+ def method_missing(method, *args)
56
+ if @settings.has_key?(method)
57
+ return @settings[method]
58
+ end
59
+ end
60
+
61
+ # Collects all sources and patches into the provided workdir
62
+ #
63
+ # @param workdir [String] directory to stage sources into
64
+ def fetch_sources(workdir)
65
+ @components.each do |component|
66
+ component.get_source(workdir)
67
+ # Fetch secondary sources
68
+ component.get_sources(workdir)
69
+ component.get_patches(workdir)
70
+ end
71
+ end
72
+
73
+ # Collects any additional files supplied by components
74
+ #
75
+ # @return [Array] array of files installed by components of the project
76
+ def get_files
77
+ files = []
78
+ files.push @version_file if @version_file
79
+ files.push @components.map(&:files).flatten
80
+ files.flatten.uniq
81
+ end
82
+
83
+ # Collects all of the requires for both the project and its components
84
+ #
85
+ # @return [Array] array of runtime requirements for the project
86
+ def get_requires
87
+ req = []
88
+ req << @components.map(&:requires).flatten
89
+ req << @requires
90
+ req.flatten.uniq
91
+ end
92
+
93
+ # Collects all of the replacements for the project and its components
94
+ #
95
+ # @return [Array] array of package level replacements for the project
96
+ def get_replaces
97
+ replaces = []
98
+ replaces.push @replaces.flatten
99
+ replaces.push @components.map(&:replaces).flatten
100
+ replaces.flatten.uniq
101
+ end
102
+
103
+ # Collects all of the provides for the project and its components
104
+ #
105
+ # @return [Array] array of package level provides for the project
106
+ def get_provides
107
+ provides = []
108
+ provides.push @provides.flatten
109
+ provides.push @components.map(&:provides).flatten
110
+ provides.flatten.uniq
111
+ end
112
+
113
+ # Collects the pre-install actions for the project and it's components
114
+ #
115
+ # @return [Array] array of Bourne shell compatible scriptlets to execute
116
+ def get_preinstall_actions
117
+ @components.map(&:preinstall_actions).flatten
118
+ end
119
+
120
+ # Collects the post-install actions for the project and it's components
121
+ #
122
+ # @return [Array] array of Bourne shell compatible scriptlets to execute
123
+ def get_postinstall_actions
124
+ @components.map(&:postinstall_actions).flatten
125
+ end
126
+
127
+ # Collects any configfiles supplied by components
128
+ #
129
+ # @return [Array] array of configfiles installed by components of the project
130
+ def get_configfiles
131
+ @components.map(&:configfiles).flatten.uniq
132
+ end
133
+
134
+ # Collects any directories declared by the project and components
135
+ #
136
+ # @return [Array] the directories in the project and components
137
+ def get_directories
138
+ dirs = []
139
+ dirs.push @directories
140
+ dirs.push @components.map(&:directories).flatten
141
+ dirs.flatten.uniq
142
+ end
143
+
144
+ # Gets the highest level directories declared by the project
145
+ #
146
+ # @return [Array] the highest level directories that have been declared by the project
147
+ def get_root_directories
148
+ dirs = get_directories.map { |dir| dir.path.split('/') }
149
+ dirs.sort! { |dir1, dir2| dir1.length <=> dir2.length }
150
+ ret_dirs = []
151
+
152
+ dirs.each do |dir|
153
+ unless ret_dirs.include?(dir.first(dir.length - 1).join('/'))
154
+ ret_dirs << dir.join('/')
155
+ end
156
+ end
157
+ ret_dirs
158
+ end
159
+
160
+ # Get any services registered by components in the project
161
+ #
162
+ # @return [Array] the services provided by components in the project
163
+ def get_services
164
+ @components.map(&:service).flatten.compact
165
+ end
166
+
167
+ # Simple utility for determining if the components in the project declare
168
+ # any services
169
+ #
170
+ # @return [True, False] Whether or not there are services declared for this project or not
171
+ def has_services?
172
+ !get_services.empty?
173
+ end
174
+
175
+ # Generate a list of all files and directories to be included in a tarball
176
+ # for the project
177
+ #
178
+ # @return [Array] all the files and directories that should be included in the tarball
179
+ def get_tarball_files
180
+ files = ['file-list', 'bill-of-materials']
181
+ files.push get_files.map(&:path)
182
+ files.push get_configfiles.map(&:path)
183
+ end
184
+
185
+ # Generate a bill-of-materials: a listing of the components and their
186
+ # versions in the current project
187
+ #
188
+ # @return [Array] a listing of component names and versions
189
+ def generate_bill_of_materials
190
+ @components.map { |comp| "#{comp.name} #{comp.version}" }.sort
191
+ end
192
+
193
+ # Method to generate the command to create a tarball of the project
194
+ #
195
+ # @return [String] cross platform command to generate a tarball of the project
196
+ def pack_tarball_command
197
+ tar_root = "#{@name}-#{@version}"
198
+ ["mkdir -p '#{tar_root}'",
199
+ %('#{@platform.tar}' -cf - -T #{get_tarball_files.join(" ")} | ( cd '#{tar_root}/'; '#{@platform.tar}' xfp -)),
200
+ %('#{@platform.tar}' -cf - #{tar_root}/ | gzip -9c > #{tar_root}.tar.gz)].join("\n\t")
201
+ end
202
+
203
+ # Evaluates the makefile template and writes the contents to the workdir
204
+ # for use in building the project
205
+ #
206
+ # @param workdir [String] full path to the workdir to send the evaluated template
207
+ # @return [String] full path to the generated Makefile
208
+ def make_makefile(workdir)
209
+ erb_file(File.join(VANAGON_ROOT, "templates/Makefile.erb"), File.join(workdir, "Makefile"))
210
+ end
211
+
212
+ # Generates a bill-of-materials and writes the contents to the workdir for use in
213
+ # building the project
214
+ #
215
+ # @param workdir [String] full path to the workdir to send the bill-of-materials
216
+ # @return [String] full path to the generated bill-of-materials
217
+ def make_bill_of_materials(workdir)
218
+ File.open(File.join(workdir, 'bill-of-materials'), 'w') { |f| f.puts(generate_bill_of_materials.join("\n")) }
219
+ end
220
+
221
+ # Return a list of the build_dependencies that are satisfied by an internal component
222
+ #
223
+ # @param component [Vanagon::Component] component to check for already satisfied build dependencies
224
+ # @return [Array] a list of the build dependencies for the given component that are satisfied by other components in the project
225
+ def list_component_dependencies(component)
226
+ component.build_requires.select { |dep| @components.map(&:name).include?(dep) }
227
+ end
228
+
229
+ # Get the package name for the project on the current platform
230
+ #
231
+ # @return [String] package name for the current project as defined by the platform
232
+ def package_name
233
+ @platform.package_name(self)
234
+ end
235
+
236
+ # Ascertain how to build a package for the current platform
237
+ #
238
+ # @return [String, Array] commands to build a package for the current project as defined by the platform
239
+ def generate_package
240
+ @platform.generate_package(self)
241
+ end
242
+
243
+ # Generate any required files to build a package for this project on the
244
+ # current platform into the provided workdir
245
+ #
246
+ # @param workdir [String] workdir to put the packaging files into
247
+ def generate_packaging_artifacts(workdir)
248
+ @platform.generate_packaging_artifacts(workdir, @name, binding)
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,218 @@
1
+ require 'vanagon/project'
2
+ require 'vanagon/utilities'
3
+ require 'vanagon/component/source'
4
+ require 'set'
5
+
6
+ class Vanagon
7
+ class Project
8
+ class DSL
9
+ # Constructor for the DSL object
10
+ #
11
+ # @param name [String] name of the project
12
+ # @param platform [Vanagon::Platform] platform for the project to build against
13
+ # @param include_components [List] optional list restricting the loaded components
14
+ # @return [Vanagon::Project::DSL] A DSL object to describe the {Vanagon::Project}
15
+ def initialize(name, platform, include_components = [])
16
+ @name = name
17
+ @project = Vanagon::Project.new(@name, platform)
18
+ @include_components = include_components.to_set
19
+ end
20
+
21
+ # Primary way of interacting with the DSL
22
+ #
23
+ # @param name [String] name of the project
24
+ # @param block [Proc] DSL definition of the project to call
25
+ def project(name, &block)
26
+ block.call(self)
27
+ end
28
+
29
+ # Accessor for the project.
30
+ #
31
+ # @return [Vanagon::Project] the project the DSL methods will be acting against
32
+ def _project
33
+ @project
34
+ end
35
+
36
+
37
+ # Project attributes and DSL methods defined below
38
+ #
39
+ #
40
+ # All purpose getter. This object, which is passed to the project block,
41
+ # won't have easy access to the attributes of the @project, so we make a
42
+ # getter for each attribute.
43
+ #
44
+ # We only magically handle get_ methods, any other methods just get the
45
+ # standard method_missing treatment.
46
+ #
47
+ def method_missing(method, *args)
48
+ attribute_match = method.to_s.match(/get_(.*)/)
49
+ if attribute_match
50
+ attribute = attribute_match.captures.first
51
+ @project.send(attribute)
52
+ elsif @project.settings.has_key?(method)
53
+ return @project.settings[method]
54
+ else
55
+ super
56
+ end
57
+ end
58
+
59
+ # Sets a key value pair on the settings hash of the project
60
+ #
61
+ # @param name [String] name of the setting
62
+ # @param value [String] value of the setting
63
+ def setting(name, value)
64
+ @project.settings[name] = value
65
+ end
66
+
67
+ # Sets the description of the project. Mainly for use in packaging.
68
+ #
69
+ # @param descr [String] description of the project
70
+ def description(descr)
71
+ @project.description = descr
72
+ end
73
+
74
+ # Resets the name of the project. Is useful for dynamically changing the project name.
75
+ #
76
+ # @param the_name [String] name of the project
77
+ def name(the_name)
78
+ @project.name = the_name
79
+ end
80
+
81
+ # Sets the homepage for the project. Mainly for use in packaging.
82
+ #
83
+ # @param page [String] url of homepage of the project
84
+ def homepage(page)
85
+ @project.homepage = page
86
+ end
87
+
88
+ # Sets the run time requirements for the project. Mainly for use in packaging.
89
+ #
90
+ # @param req [String] of requirements of the project
91
+ def requires(req)
92
+ @project.requires << req
93
+ end
94
+
95
+ # Indicates that this component replaces a system level package. Replaces can be collected and used by the project and package.
96
+ #
97
+ # @param replacement [String] a package that is replaced with this component
98
+ # @param version [String] the version of the package that is replaced
99
+ def replaces(replacement, version = nil)
100
+ @project.replaces << OpenStruct.new(:replacement => replacement, :version => version)
101
+ end
102
+
103
+ # Indicates that this component provides a system level package. Provides can be collected and used by the project and package.
104
+ #
105
+ # @param provide [String] a package that is provided with this component
106
+ # @param version [String] the version of the package that is provided with this component
107
+ def provides(provide, version = nil)
108
+ @project.provides << OpenStruct.new(:provide => provide, :version => version)
109
+ end
110
+
111
+ # Sets the version for the project. Mainly for use in packaging.
112
+ #
113
+ # @param ver [String] version of the project
114
+ def version(ver)
115
+ @project.version = ver.gsub('-', '.')
116
+ end
117
+
118
+ # Sets the release for the project. Mainly for use in packaging.
119
+ #
120
+ # @param rel [String] release of the project
121
+ def release(rel)
122
+ @project.release = rel
123
+ end
124
+
125
+ # Sets the version for the project based on a git describe of the
126
+ # directory that holds the configs. Requires that a git tag be present
127
+ # and reachable from the current commit in that repository.
128
+ #
129
+ def version_from_git
130
+ @project.version = Vanagon::Utilities.git_version(File.expand_path("..", Vanagon::Driver.configdir)).gsub('-', '.')
131
+ end
132
+
133
+ # Sets the vendor for the project. Used in packaging artifacts.
134
+ #
135
+ # @param vend [String] vendor or author of the project
136
+ def vendor(vend)
137
+ @project.vendor = vend
138
+ end
139
+
140
+ # Adds a directory to the list of directories provided by the project, to be included in any packages of the project
141
+ #
142
+ # @param dir [String] directory to add to the project
143
+ # @param mode [String] octal mode to apply to the directory
144
+ # @param owner [String] owner of the directory
145
+ # @param group [String] group of the directory
146
+ def directory(dir, mode: nil, owner: nil, group: nil)
147
+ @project.directories << Vanagon::Common::Pathname.new(dir, mode: mode, owner: owner, group: group)
148
+ end
149
+
150
+ # Add a user to the project
151
+ #
152
+ # @param name [String] name of the user to create
153
+ # @param group [String] group of the user
154
+ # @param shell [String] login shell to set for the user
155
+ # @param is_system [true, false] if the user should be a system user
156
+ # @param homedir [String] home directory for the user
157
+ def user(name, group: nil, shell: nil, is_system: false, homedir: nil)
158
+ @project.user = Vanagon::Common::User.new(name, group, shell, is_system, homedir)
159
+ end
160
+
161
+ # Sets the license for the project. Mainly for use in packaging.
162
+ #
163
+ # @param lic [String] the license the project is released under
164
+ def license(lic)
165
+ @project.license = lic
166
+ end
167
+
168
+ # Sets the identifier for the project. Mainly for use in OSX packaging.
169
+ #
170
+ # @param ident [String] uses the reverse-domain naming convention
171
+ def identifier(ident)
172
+ @project.identifier = ident
173
+ end
174
+
175
+ # Adds a component to the project
176
+ #
177
+ # @param name [String] name of component to add. must be present in configdir/components and named $name.rb currently
178
+ def component(name)
179
+ puts "Loading #{name}"
180
+ if @include_components.empty? or @include_components.include?(name)
181
+ component = Vanagon::Component.load_component(name, File.join(Vanagon::Driver.configdir, "components"), @project.settings, @project.platform)
182
+ @project.components << component
183
+ end
184
+ end
185
+
186
+ # Adds a target repo for the project
187
+ #
188
+ # @param repo [String] name of the target repository to ship to used in laying out the packages on disk
189
+ def target_repo(repo)
190
+ @project.repo = repo
191
+ end
192
+
193
+ # Sets the project to be architecture independent, or noarch
194
+ def noarch
195
+ @project.noarch = true
196
+ end
197
+
198
+ # Sets up a rewrite rule for component sources for a given protocol
199
+ #
200
+ # @param protocol [String] a supported component source type (Http, Git, ...)
201
+ # @param rule [String, Proc] a rule used to rewrite component source urls
202
+ def register_rewrite_rule(protocol, rule)
203
+ Vanagon::Component::Source.register_rewrite_rule(protocol, rule)
204
+ end
205
+
206
+ # Toggle to apply additional cleanup during the build for space constrained systems
207
+ def cleanup_during_build
208
+ @project.cleanup = true
209
+ end
210
+
211
+ # This method will write the projects version to a designated file during package creation
212
+ # @param target [String] a full path to the version file for the project
213
+ def write_version_file(target)
214
+ @project.version_file = Vanagon::Common::Pathname.file(target)
215
+ end
216
+ end
217
+ end
218
+ end