vanagon 0.3.18

Sign up to get free protection for your applications and to get access to all the features.
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