vanagon 0.5.0 → 0.5.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 +4 -4
- data/README.md +3 -0
- data/lib/vanagon/common/pathname.rb +3 -1
- data/lib/vanagon/component.rb +5 -2
- data/lib/vanagon/component/dsl.rb +10 -3
- data/lib/vanagon/component/source/git.rb +3 -3
- data/lib/vanagon/component/source/http.rb +11 -19
- data/lib/vanagon/driver.rb +1 -1
- data/lib/vanagon/engine/base.rb +4 -3
- data/lib/vanagon/engine/docker.rb +1 -0
- data/lib/vanagon/engine/hardware.rb +1 -0
- data/lib/vanagon/engine/local.rb +1 -0
- data/lib/vanagon/engine/pooler.rb +1 -0
- data/lib/vanagon/platform.rb +6 -2
- data/lib/vanagon/platform/deb.rb +1 -1
- data/lib/vanagon/platform/dsl.rb +24 -0
- data/lib/vanagon/platform/osx.rb +2 -2
- data/lib/vanagon/platform/rpm.rb +1 -1
- data/lib/vanagon/platform/solaris_10.rb +1 -1
- data/lib/vanagon/platform/solaris_11.rb +1 -1
- data/lib/vanagon/platform/windows.rb +241 -0
- data/lib/vanagon/project.rb +7 -2
- data/lib/vanagon/utilities.rb +14 -5
- data/{templates → resources}/Makefile.erb +3 -3
- data/{templates → resources}/deb/changelog.erb +0 -0
- data/{templates → resources}/deb/conffiles.erb +0 -0
- data/{templates → resources}/deb/control.erb +0 -0
- data/{templates → resources}/deb/dirs.erb +0 -0
- data/{templates → resources}/deb/docs.erb +0 -0
- data/{templates → resources}/deb/install.erb +0 -0
- data/{templates → resources}/deb/postinst.erb +0 -0
- data/{templates → resources}/deb/postrm.erb +0 -0
- data/{templates → resources}/deb/preinst.erb +0 -0
- data/{templates → resources}/deb/prerm.erb +0 -0
- data/{templates → resources}/deb/rules.erb +2 -0
- data/{templates → resources}/osx/postinstall.erb +0 -0
- data/{templates → resources}/osx/preinstall.erb +0 -0
- data/{templates → resources}/osx/project-installer.xml.erb +0 -0
- data/{templates → resources}/rpm/project.spec.erb +2 -1
- data/{templates → resources}/solaris/10/depend.erb +0 -0
- data/{templates → resources}/solaris/10/pkginfo.erb +0 -0
- data/{templates → resources}/solaris/10/postinstall.erb +0 -0
- data/{templates → resources}/solaris/10/preinstall.erb +0 -0
- data/{templates → resources}/solaris/10/preremove.erb +0 -0
- data/{templates → resources}/solaris/10/proto.erb +0 -0
- data/{templates → resources}/solaris/11/p5m.erb +0 -0
- data/resources/windows/nuget/chocolateyInstall.ps1 +28 -0
- data/resources/windows/nuget/chocolateyUninstall.ps1 +24 -0
- data/resources/windows/nuget/project.nuspec.erb +31 -0
- data/resources/windows/wix/service.component.wxs.erb +55 -0
- data/spec/lib/vanagon/component/dsl_spec.rb +31 -1
- data/spec/lib/vanagon/component/source/git_spec.rb +14 -0
- data/spec/lib/vanagon/component/source/http_spec.rb +10 -1
- data/spec/lib/vanagon/engine/pooler_spec.rb +1 -1
- data/spec/lib/vanagon/platform/windows_spec.rb +43 -0
- data/spec/lib/vanagon/utilities_spec.rb +7 -0
- metadata +32 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6faf9b7a2f17d4a0d10d3e9a050d066ba92ab7a0
|
4
|
+
data.tar.gz: 112f2f90afafb386461ec92ed67238fefddcf76d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8edf1722f845927b0ba7858b077bd3c57908f7395beee779aa068552ea7c5e46d7a827416b201b275fb90c947438162f1a0f42004a85662b1716a8e9f264161f
|
7
|
+
data.tar.gz: 85a5e28c1954033d3120d3e4ee72582f413982762ba430d3e1ebaa0e38127cfb994d3edfdaf921392a76fd7737ff5a6176469b006ff0a63905da653ed37a2607
|
data/README.md
CHANGED
@@ -106,6 +106,9 @@ A full path on disk for a private ssh key to be used in ssh and rsync
|
|
106
106
|
communications. This will be used instead of whatever defaults are configured
|
107
107
|
in .ssh/config.
|
108
108
|
|
109
|
+
##### VANAGON\_SSH\_AGENT
|
110
|
+
When set, Vanagon will forward the ssh authentication agent connection.
|
111
|
+
|
109
112
|
##### VMPOOLER\_TOKEN
|
110
113
|
Used in conjunction with the pooler engine, this is a token to pass to the
|
111
114
|
vmpooler to access the API. Without this token, the default lifetime of vms
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
1
3
|
class Vanagon
|
2
4
|
class Common
|
3
5
|
class Pathname
|
@@ -28,7 +30,7 @@ class Vanagon
|
|
28
30
|
# and exposed through the {#configfile?} method.
|
29
31
|
# @return [Vanagon::Common::Pathname] Returns a new Pathname instance.
|
30
32
|
def initialize(path, mode: nil, owner: nil, group: nil, config: false)
|
31
|
-
@path =
|
33
|
+
@path = ::Pathname.new(path).cleanpath.to_s
|
32
34
|
@mode ||= mode
|
33
35
|
@owner ||= owner
|
34
36
|
@group ||= group
|
data/lib/vanagon/component.rb
CHANGED
@@ -10,7 +10,7 @@ class Vanagon
|
|
10
10
|
attr_accessor :name, :version, :source, :url, :configure, :build, :check, :install
|
11
11
|
attr_accessor :environment, :extract_with, :dirname, :build_requires, :build_dir
|
12
12
|
attr_accessor :settings, :platform, :patches, :requires, :service, :options
|
13
|
-
attr_accessor :directories, :replaces, :provides, :cleanup_source
|
13
|
+
attr_accessor :directories, :replaces, :provides, :cleanup_source
|
14
14
|
attr_accessor :sources, :preinstall_actions, :postinstall_actions
|
15
15
|
attr_accessor :preremove_actions, :postremove_actions
|
16
16
|
|
@@ -109,7 +109,7 @@ class Vanagon
|
|
109
109
|
@source = Vanagon::Component::Source.source(@url, @options, workdir)
|
110
110
|
@source.fetch
|
111
111
|
@source.verify
|
112
|
-
@extract_with = @source.extract(@platform.tar)
|
112
|
+
@extract_with = @source.respond_to?(:extract) ? @source.extract(@platform.tar) : ':'
|
113
113
|
@cleanup_source = @source.cleanup if @source.respond_to?(:cleanup)
|
114
114
|
@dirname = @source.dirname
|
115
115
|
|
@@ -120,6 +120,9 @@ class Vanagon
|
|
120
120
|
|
121
121
|
# If there is no source, we don't want to try to change directories, so we just change to the current directory.
|
122
122
|
@dirname = './'
|
123
|
+
|
124
|
+
# If there is no source, there is nothing to do to extract
|
125
|
+
@extract_with = ':'
|
123
126
|
end
|
124
127
|
end
|
125
128
|
|
@@ -158,7 +158,8 @@ class Vanagon
|
|
158
158
|
# @param default_file [String] path to the default file relative to the source
|
159
159
|
# @param service_name [String] name of the service
|
160
160
|
# @param service_type [String] type of the service (network, application, system, etc)
|
161
|
-
|
161
|
+
# @param service_hash [Hash] hash of options to parse for the service
|
162
|
+
def install_service(service_file, default_file = nil, service_name = @component.name, service_type: nil, service_hash: nil)
|
162
163
|
case @component.platform.servicetype
|
163
164
|
when "sysv"
|
164
165
|
target_service_file = File.join(@component.platform.servicedir, service_name)
|
@@ -183,6 +184,9 @@ class Vanagon
|
|
183
184
|
@component.service = OpenStruct.new(:name => service_name, :service_command => File.read(service_file).chomp)
|
184
185
|
# Return here because there is no file to install, just a string read in
|
185
186
|
return
|
187
|
+
when "windows"
|
188
|
+
@component.service = OpenStruct.new(name: service_name, options: service_hash)
|
189
|
+
return
|
186
190
|
else
|
187
191
|
fail "Don't know how to install the #{@component.platform.servicetype}. Please teach #install_service how to do this."
|
188
192
|
end
|
@@ -207,7 +211,7 @@ class Vanagon
|
|
207
211
|
# @param group [String] group owner of the file
|
208
212
|
def install_file(source, target, mode: '0644', owner: nil, group: nil)
|
209
213
|
@component.install << "#{@component.platform.install} -d '#{File.dirname(target)}'"
|
210
|
-
@component.install << "
|
214
|
+
@component.install << "#{@component.platform.copy} -p '#{source}' '#{target}'"
|
211
215
|
@component.add_file Vanagon::Common::Pathname.file(target, mode: mode, owner: owner, group: group)
|
212
216
|
end
|
213
217
|
|
@@ -241,7 +245,10 @@ class Vanagon
|
|
241
245
|
# @param target [String] path to the desired symlink
|
242
246
|
def link(source, target)
|
243
247
|
@component.install << "#{@component.platform.install} -d '#{File.dirname(target)}'"
|
244
|
-
|
248
|
+
# Use a bash conditional to only create the link if it doesn't already point to the correct source.
|
249
|
+
# This allows rerunning the install step to be idempotent, rather than failing because the link
|
250
|
+
# already exists.
|
251
|
+
@component.install << "([[ '#{target}' -ef '#{source}' ]] || ln -s '#{source}' '#{target}')"
|
245
252
|
@component.add_file Vanagon::Common::Pathname.file(target)
|
246
253
|
end
|
247
254
|
|
@@ -27,10 +27,10 @@ class Vanagon
|
|
27
27
|
def fetch
|
28
28
|
puts "Cloning ref '#{@ref}' from url '#{@url}'"
|
29
29
|
Dir.chdir(@workdir) do
|
30
|
-
git(
|
30
|
+
git("clone #{@url}", true)
|
31
31
|
Dir.chdir(dirname) do
|
32
|
-
git(
|
33
|
-
git(
|
32
|
+
git("checkout #{@ref}", true)
|
33
|
+
git("submodule update --init --recursive", true)
|
34
34
|
@version = git_version
|
35
35
|
end
|
36
36
|
end
|
@@ -12,9 +12,6 @@ class Vanagon
|
|
12
12
|
# Extensions for files we intend to unpack during the build
|
13
13
|
ARCHIVE_EXTENSIONS = '.tar.gz', '.tgz', '.zip'
|
14
14
|
|
15
|
-
# Extensions for files we aren't going to unpack during the build
|
16
|
-
NON_ARCHIVE_EXTENSIONS = '.gem', '.ru', '.txt', '.conf', '.ini', '.gpg', '.rb', '.sh', '.csh', '.xml', '.vim', '.json', '.service'
|
17
|
-
|
18
15
|
# Constructor for the Http source type
|
19
16
|
#
|
20
17
|
# @param url [String] url of the http source to fetch
|
@@ -106,11 +103,9 @@ class Vanagon
|
|
106
103
|
when ".zip"
|
107
104
|
return "unzip '#{@file}'"
|
108
105
|
end
|
109
|
-
elsif NON_ARCHIVE_EXTENSIONS.include?(@extension)
|
110
|
-
# Don't need to unpack gems, ru, txt, conf, ini, gpg
|
111
|
-
return nil
|
112
106
|
else
|
113
|
-
|
107
|
+
# Extension does not appear to be an archive
|
108
|
+
return ':'
|
114
109
|
end
|
115
110
|
end
|
116
111
|
|
@@ -121,24 +116,25 @@ class Vanagon
|
|
121
116
|
def cleanup
|
122
117
|
if ARCHIVE_EXTENSIONS.include?(@extension)
|
123
118
|
return "rm #{@file}; rm -r #{dirname}"
|
124
|
-
|
119
|
+
else
|
125
120
|
# Because dirname will be ./ here, we don't want to try to nuke it
|
126
121
|
return "rm #{@file}"
|
127
|
-
else
|
128
|
-
fail "Don't know how to cleanup for '#{@file}' with extension: '#{@extension}'. Please teach me."
|
129
122
|
end
|
130
123
|
end
|
131
124
|
|
132
125
|
# Returns the extension for @file
|
133
126
|
#
|
134
127
|
# @return [String] the extension of @file
|
135
|
-
# @raise [RuntimeError] an exception is raised if the extension isn't in the current list
|
136
128
|
def get_extension
|
137
|
-
extension_match = @file.match(/.*(#{Regexp.union(ARCHIVE_EXTENSIONS
|
129
|
+
extension_match = @file.match(/.*(#{Regexp.union(ARCHIVE_EXTENSIONS)})/)
|
138
130
|
unless extension_match
|
139
|
-
|
131
|
+
if @file.split('.').last.include?('.')
|
132
|
+
return '.' + @file.split('.').last
|
133
|
+
else
|
134
|
+
# This is the case where the file has no extension
|
135
|
+
return @file
|
136
|
+
end
|
140
137
|
end
|
141
|
-
|
142
138
|
extension_match[1]
|
143
139
|
end
|
144
140
|
|
@@ -149,12 +145,8 @@ class Vanagon
|
|
149
145
|
def dirname
|
150
146
|
if ARCHIVE_EXTENSIONS.include?(@extension)
|
151
147
|
return @file.chomp(@extension)
|
152
|
-
elsif NON_ARCHIVE_EXTENSIONS.include?(@extension)
|
153
|
-
# Because we cd into the source dir, using ./ here avoids special casing single file
|
154
|
-
# sources in the Makefile
|
155
|
-
return './'
|
156
148
|
else
|
157
|
-
|
149
|
+
return './'
|
158
150
|
end
|
159
151
|
end
|
160
152
|
end
|
data/lib/vanagon/driver.rb
CHANGED
data/lib/vanagon/engine/base.rb
CHANGED
@@ -4,13 +4,14 @@ require 'vanagon/errors'
|
|
4
4
|
class Vanagon
|
5
5
|
class Engine
|
6
6
|
class Base
|
7
|
-
attr_accessor :target, :remote_workdir
|
7
|
+
attr_accessor :target, :remote_workdir, :name
|
8
8
|
|
9
9
|
def initialize(platform, target = nil)
|
10
10
|
@platform = platform
|
11
11
|
@required_attributes = ["ssh_port"]
|
12
12
|
@target = target if target
|
13
|
-
@target_user =
|
13
|
+
@target_user = @platform.target_user
|
14
|
+
@name = 'base'
|
14
15
|
end
|
15
16
|
|
16
17
|
# This method is used to obtain a vm to build upon
|
@@ -57,7 +58,7 @@ class Vanagon
|
|
57
58
|
|
58
59
|
def retrieve_built_artifact
|
59
60
|
FileUtils.mkdir_p("output")
|
60
|
-
Vanagon::Utilities.rsync_from("#{@remote_workdir}/output/*", "#{@target_user}@#{@target}", "output", @platform.ssh_port)
|
61
|
+
Vanagon::Utilities.rsync_from("#{@remote_workdir}/output/*", "#{@target_user}@#{@target}", "output/", @platform.ssh_port)
|
61
62
|
end
|
62
63
|
|
63
64
|
# Ensures that the platform defines the attributes that the engine needs to function.
|
@@ -52,6 +52,7 @@ class Vanagon
|
|
52
52
|
|
53
53
|
def initialize(platform, target)
|
54
54
|
Vanagon::Driver.logger.debug "Hardware engine invoked."
|
55
|
+
@name = 'hardware'
|
55
56
|
@platform = platform
|
56
57
|
@build_hosts = platform.build_hosts
|
57
58
|
# Redis is the only backend supported in lock_manager currently
|
data/lib/vanagon/engine/local.rb
CHANGED
data/lib/vanagon/platform.rb
CHANGED
@@ -6,7 +6,7 @@ class Vanagon
|
|
6
6
|
attr_accessor :build_dependencies, :name, :vmpooler_template, :cflags, :ldflags, :settings
|
7
7
|
attr_accessor :servicetype, :patch, :architecture, :codename, :os_name, :os_version
|
8
8
|
attr_accessor :docker_image, :ssh_port, :rpmbuild, :install, :platform_triple
|
9
|
-
attr_accessor :package_type, :build_hosts
|
9
|
+
attr_accessor :target_user, :package_type, :find, :sort, :build_hosts, :copy
|
10
10
|
|
11
11
|
# Platform names currently contain some information about the platform. Fields
|
12
12
|
# within the name are delimited by the '-' character, and this regex can be used to
|
@@ -101,6 +101,10 @@ class Vanagon
|
|
101
101
|
@ssh_port = 22
|
102
102
|
@provisioning = []
|
103
103
|
@install ||= "install"
|
104
|
+
@target_user ||= "root"
|
105
|
+
@find ||= "find"
|
106
|
+
@sort ||= "sort"
|
107
|
+
@copy ||= "cp"
|
104
108
|
end
|
105
109
|
|
106
110
|
# This allows instance variables to be accessed using the hash lookup syntax
|
@@ -226,7 +230,7 @@ class Vanagon
|
|
226
230
|
#
|
227
231
|
# @return [true, false] true if it is a windows variety, false otherwise
|
228
232
|
def is_windows?
|
229
|
-
return !!@name.match(/^
|
233
|
+
return !!@name.match(/^windows-.*$/)
|
230
234
|
end
|
231
235
|
|
232
236
|
# Utility matcher to determine is the platform is a linux variety
|
data/lib/vanagon/platform/deb.rb
CHANGED
@@ -29,7 +29,7 @@ class Vanagon
|
|
29
29
|
|
30
30
|
# Lots of templates here
|
31
31
|
["changelog", "conffiles", "control", "docs", "dirs", "install", "preinst", "postinst", "postrm", "prerm", "rules"].each do |deb_file|
|
32
|
-
erb_file(File.join(VANAGON_ROOT, "
|
32
|
+
erb_file(File.join(VANAGON_ROOT, "resources/deb/#{deb_file}.erb"), File.join(deb_dir, deb_file), false, { :binding => binding })
|
33
33
|
end
|
34
34
|
|
35
35
|
# These could be templates, but their content is static, so that seems weird.
|
data/lib/vanagon/platform/dsl.rb
CHANGED
@@ -7,6 +7,7 @@ require 'vanagon/platform/rpm/eos'
|
|
7
7
|
require 'vanagon/platform/osx'
|
8
8
|
require 'vanagon/platform/solaris_10'
|
9
9
|
require 'vanagon/platform/solaris_11'
|
10
|
+
require 'vanagon/platform/windows'
|
10
11
|
require 'securerandom'
|
11
12
|
require 'uri'
|
12
13
|
|
@@ -43,6 +44,8 @@ class Vanagon
|
|
43
44
|
Vanagon::Platform::Solaris10.new(@name)
|
44
45
|
when /^solaris-11/
|
45
46
|
Vanagon::Platform::Solaris11.new(@name)
|
47
|
+
when /^windows-/
|
48
|
+
Vanagon::Platform::Windows.new(@name)
|
46
49
|
else
|
47
50
|
fail "Platform not implemented for '#{@name}' yet. Please go do so..."
|
48
51
|
end
|
@@ -97,6 +100,27 @@ class Vanagon
|
|
97
100
|
@platform.package_type = pkg_type
|
98
101
|
end
|
99
102
|
|
103
|
+
# Set the path to find for the platform
|
104
|
+
#
|
105
|
+
# @param find_cmd [String] Full path to the find command for the platform
|
106
|
+
def find(find_cmd)
|
107
|
+
@platform.find = find_cmd
|
108
|
+
end
|
109
|
+
|
110
|
+
# Set the path to sort for the platform
|
111
|
+
#
|
112
|
+
# @param sort_cmd [String] Full path to the sort command for the platform
|
113
|
+
def sort(sort_cmd)
|
114
|
+
@platform.sort = sort_cmd
|
115
|
+
end
|
116
|
+
|
117
|
+
# Set the path to copy for the platform
|
118
|
+
#
|
119
|
+
# @param copy_cmd [String] Full path to the copy command for the platform
|
120
|
+
def copy(copy_cmd)
|
121
|
+
@platform.copy = copy_cmd
|
122
|
+
end
|
123
|
+
|
100
124
|
# Set the path to rpmbuild for the platform
|
101
125
|
#
|
102
126
|
# @param rpmbuild_cmd [String] Full path to rpmbuild with arguments to be used by default
|
data/lib/vanagon/platform/osx.rb
CHANGED
@@ -66,10 +66,10 @@ class Vanagon
|
|
66
66
|
script_dir = File.join(workdir, "scripts")
|
67
67
|
FileUtils.mkdir_p(script_dir)
|
68
68
|
|
69
|
-
erb_file(File.join(VANAGON_ROOT, "
|
69
|
+
erb_file(File.join(VANAGON_ROOT, "resources/osx/project-installer.xml.erb"), File.join(workdir, "#{name}-installer.xml"), false, { :binding => binding })
|
70
70
|
|
71
71
|
["postinstall", "preinstall"].each do |script_file|
|
72
|
-
erb_file(File.join(VANAGON_ROOT, "
|
72
|
+
erb_file(File.join(VANAGON_ROOT, "resources/osx/#{script_file}.erb"), File.join(script_dir, script_file), false, { :binding => binding })
|
73
73
|
FileUtils.chmod 0755, File.join(script_dir, script_file)
|
74
74
|
end
|
75
75
|
|
data/lib/vanagon/platform/rpm.rb
CHANGED
@@ -25,7 +25,7 @@ class Vanagon
|
|
25
25
|
# @param name [String] name of the project
|
26
26
|
# @param binding [Binding] binding to use in evaluating the packaging templates
|
27
27
|
def generate_packaging_artifacts(workdir, name, binding)
|
28
|
-
erb_file(File.join(VANAGON_ROOT, "
|
28
|
+
erb_file(File.join(VANAGON_ROOT, "resources/rpm/project.spec.erb"), File.join(workdir, "#{name}.spec"), false, { :binding => binding })
|
29
29
|
end
|
30
30
|
|
31
31
|
# Method to derive the package name for the project
|
@@ -83,7 +83,7 @@ class Vanagon
|
|
83
83
|
["pkginfo", "depend", "preinstall", "preremove", "postinstall", "proto"].each do |template|
|
84
84
|
target_dir = File.join(workdir, 'packaging')
|
85
85
|
FileUtils.mkdir_p(target_dir)
|
86
|
-
erb_file(File.join(VANAGON_ROOT, "
|
86
|
+
erb_file(File.join(VANAGON_ROOT, "resources/solaris/10/#{template}.erb"), File.join(target_dir, template), false, { :binding => binding })
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
@@ -43,7 +43,7 @@ class Vanagon
|
|
43
43
|
def generate_packaging_artifacts(workdir, name, binding)
|
44
44
|
target_dir = File.join(workdir, 'packaging')
|
45
45
|
FileUtils.mkdir_p(target_dir)
|
46
|
-
erb_file(File.join(VANAGON_ROOT, "
|
46
|
+
erb_file(File.join(VANAGON_ROOT, "resources/solaris/11/p5m.erb"), File.join(target_dir, "#{name}.p5m"), false, { :binding => binding })
|
47
47
|
end
|
48
48
|
|
49
49
|
# Generate the scripts required to add a group to the package generated.
|
@@ -0,0 +1,241 @@
|
|
1
|
+
class Vanagon
|
2
|
+
class Platform
|
3
|
+
class Windows < Vanagon::Platform
|
4
|
+
# The specific bits used to generate a windows package for a given project
|
5
|
+
#
|
6
|
+
# @param project [Vanagon::Project] project to build a windows package of
|
7
|
+
# @return [Array] list of commands required to build a windows package for the given project from a tarball
|
8
|
+
def generate_package(project)
|
9
|
+
case project.platform.package_type
|
10
|
+
when "msi"
|
11
|
+
return generate_msi_package(project)
|
12
|
+
when "nuget"
|
13
|
+
return generate_nuget_package(project)
|
14
|
+
else
|
15
|
+
raise Vanagon::Error, "I don't know how to build package type '#{project.platform.package_type}' for Windows. Teach me?"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Method to derive the package name for the project
|
20
|
+
#
|
21
|
+
# @param project [Vanagon::Project] project to name
|
22
|
+
# @return [String] name of the windows package for this project
|
23
|
+
def package_name(project)
|
24
|
+
case project.platform.package_type
|
25
|
+
when "msi"
|
26
|
+
return msi_package_name(project)
|
27
|
+
when "nuget"
|
28
|
+
return nuget_package_name(project)
|
29
|
+
else
|
30
|
+
raise Vanagon::Error, "I don't know how to name package type '#{project.platform.package_type}' for Windows. Teach me?"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Method to generate the files required to build a windows package for the project
|
35
|
+
#
|
36
|
+
# @param workdir [String] working directory to stage the evaluated templates in
|
37
|
+
# @param name [String] name of the project
|
38
|
+
# @param binding [Binding] binding to use in evaluating the packaging templates
|
39
|
+
def generate_packaging_artifacts(workdir, name, binding)
|
40
|
+
case @package_type
|
41
|
+
when "msi"
|
42
|
+
return generate_msi_packaging_artifacts(workdir, name, binding)
|
43
|
+
when "nuget"
|
44
|
+
return generate_nuget_packaging_artifacts(workdir, name, binding)
|
45
|
+
else
|
46
|
+
raise Vanagon::Error, "I don't know how create packaging artifacts for package type '#{project.platform.package_type}' for Windows. Teach me?"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Method to generate the files required to build an MSI package for the project
|
51
|
+
#
|
52
|
+
# @param workdir [String] working directory to stage the evaluated templates in
|
53
|
+
# @param name [String] name of the project
|
54
|
+
# @param binding [Binding] binding to use in evaluating the packaging templates
|
55
|
+
def generate_msi_packaging_artifacts(workdir, name, binding)
|
56
|
+
FileUtils.mkdir_p(File.join(workdir, "wix"))
|
57
|
+
erb_file(File.join(VANAGON_ROOT, "resources/windows/wix/service.component.wxs.erb"), File.join(workdir, "wix", "service.#{name}.wxs"), false, { :binding => binding })
|
58
|
+
end
|
59
|
+
|
60
|
+
# Method to generate the files required to build a nuget package for the project
|
61
|
+
#
|
62
|
+
# @param workdir [String] working directory to stage the evaluated templates in
|
63
|
+
# @param name [String] name of the project
|
64
|
+
# @param binding [Binding] binding to use in evaluating the packaging templates
|
65
|
+
def generate_nuget_packaging_artifacts(workdir, name, binding)
|
66
|
+
# nuget templates that do require a name change
|
67
|
+
erb_file(File.join(VANAGON_ROOT, "resources/windows/nuget/project.nuspec.erb"), File.join(workdir, "#{name}.nuspec"), false, { :binding => binding })
|
68
|
+
|
69
|
+
# nuget static resources to be copied into place
|
70
|
+
["chocolateyInstall.ps1", "chocolateyUninstall.ps1"].each do |win_file|
|
71
|
+
FileUtils.copy(File.join(VANAGON_ROOT, "resources/windows/nuget/#{win_file}"), File.join(workdir, win_file))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# The specific bits used to generate a windows nuget package for a given project
|
76
|
+
# Nexus expects packages to be named #{name}-#{version}.nupkg. However, chocolatey
|
77
|
+
# will generate them to be #{name}.#{version}.nupkg. So, we have to rename the
|
78
|
+
# package after we build it.
|
79
|
+
#
|
80
|
+
# @param project [Vanagon::Project] project to build a nuget package of
|
81
|
+
# @return [Array] list of commands required to build a nuget package for
|
82
|
+
# the given project from a tarball
|
83
|
+
def generate_nuget_package(project)
|
84
|
+
target_dir = project.repo ? output_dir(project.repo) : output_dir
|
85
|
+
["mkdir -p output/#{target_dir}",
|
86
|
+
"mkdir -p $(tempdir)/#{project.name}/tools",
|
87
|
+
"#{@copy} #{project.name}.nuspec $(tempdir)/#{project.name}/",
|
88
|
+
"#{@copy} chocolateyInstall.ps1 chocolateyUninstall.ps1 $(tempdir)/#{project.name}/tools/",
|
89
|
+
"#{@copy} file-list $(tempdir)/#{project.name}/tools/file-list.txt",
|
90
|
+
"gunzip -c #{project.name}-#{project.version}.tar.gz | '#{@tar}' -C '$(tempdir)/#{project.name}/tools' --strip-components 1 -xf -",
|
91
|
+
"(cd $(tempdir)/#{project.name} ; C:/ProgramData/chocolatey/bin/choco.exe pack #{project.name}.nuspec)",
|
92
|
+
"#{@copy} $(tempdir)/#{project.name}/#{project.name}-#{@architecture}.#{nuget_package_version(project.version, project.release)}.nupkg ./output/#{target_dir}/#{nuget_package_name(project)}"]
|
93
|
+
end
|
94
|
+
|
95
|
+
# The specific bits used to generate a windows msi package for a given project
|
96
|
+
# Have changed this to reflect the overall commands we need to generate the package.
|
97
|
+
# Question - should we break this down into some simpler Make tasks ?
|
98
|
+
# 1. Heat the directory tree to produce the file list
|
99
|
+
# 2. Compile (candle) all the wxs files into wixobj files
|
100
|
+
# 3. Run light to produce the final MSI
|
101
|
+
#
|
102
|
+
# @param project [Vanagon::Project] project to build a msi package of
|
103
|
+
# @return [Array] list of commands required to build an msi package for the given project from a tarball
|
104
|
+
def generate_msi_package(project)
|
105
|
+
target_dir = project.repo ? output_dir(project.repo) : output_dir
|
106
|
+
cg_name = "compfiles"
|
107
|
+
dir_ref = "INSTALLDIR"
|
108
|
+
# Actual array of commands to be written to the Makefile
|
109
|
+
["mkdir -p output/#{target_dir}",
|
110
|
+
"mkdir -p $(tempdir)/staging",
|
111
|
+
"gunzip -c #{project.name}-#{project.version}.tar.gz | '#{@tar}' -C '$(tempdir)/staging' --strip-components 1 -xf -",
|
112
|
+
# Run the Heat command in a single pass
|
113
|
+
# Heat command documentation at: http://wixtoolset.org/documentation/manual/v3/overview/heat.html
|
114
|
+
# dir <directory> - Traverse directory to find all sub-files and directories.
|
115
|
+
# -ke - Keep Empty directories
|
116
|
+
# -cg - Component Group Name
|
117
|
+
# -gg - Generate GUIDS now
|
118
|
+
# -dr - Directory reference to root directories (cannot contains spaces e.g. -dr MyAppDirRef)
|
119
|
+
# -sreg - Suppress registry harvesting.
|
120
|
+
# -var <variable> - Substitute File/@Source="SourceDir" with a preprocessor or a wix variable
|
121
|
+
"cd $(tempdir); \"$$WIX/bin/heat.exe\" dir staging -v -ke -indent 2 -cg #{cg_name} -gg -dr #{dir_ref} -sreg -var var.StageDir -out wix/#{project.name}-harvest.wxs",
|
122
|
+
]
|
123
|
+
end
|
124
|
+
|
125
|
+
# Method to derive the msi (Windows Installer) package name for the project.
|
126
|
+
#
|
127
|
+
# @param project [Vanagon::Project] project to name
|
128
|
+
# @return [String] name of the windows package for this project
|
129
|
+
def msi_package_name(project)
|
130
|
+
# Decided to use native project version in hope msi versioning doesn't have same resrictions as nuget
|
131
|
+
"#{project.name}-#{project.version}.#{project.release}-#{@architecture}.msi"
|
132
|
+
end
|
133
|
+
|
134
|
+
# Method to derive the package name for the project.
|
135
|
+
# Neither chocolatey nor nexus know how to deal with architecture, so
|
136
|
+
# we are just pretending it's part of the package name.
|
137
|
+
#
|
138
|
+
# @param project [Vanagon::Project] project to name
|
139
|
+
# @return [String] name of the windows package for this project
|
140
|
+
def nuget_package_name(project)
|
141
|
+
"#{project.name}-#{@architecture}-#{nuget_package_version(project.version, project.release)}.nupkg"
|
142
|
+
end
|
143
|
+
|
144
|
+
# Nuget versioning is awesome!
|
145
|
+
#
|
146
|
+
# Nuget and chocolatey have some expectations about version numbers.
|
147
|
+
#
|
148
|
+
# First, if this is a final package (built from a tag), the version must
|
149
|
+
# only contain digits with each element of the version separated by
|
150
|
+
# periods.
|
151
|
+
#
|
152
|
+
# If we are creating the version for a prerelease package (built from a
|
153
|
+
# commit that does not have a corresponding tag), we have the
|
154
|
+
# option to append a string to the version. The string must start with a
|
155
|
+
# letter, be separated from the rest of the version with a dash, and
|
156
|
+
# contain no punctuation.
|
157
|
+
#
|
158
|
+
# We assume we are working from a semver tag as the base of our version.
|
159
|
+
# If this is a final release, we only have to worry about that tag. We
|
160
|
+
# can also include the release number in the package version. If this is
|
161
|
+
# a prerelease package, then we assume we have a semver compliant tag,
|
162
|
+
# followed by the number of commits beyond the tag and the short sha of
|
163
|
+
# the latest change. Because we are working with git, if the version
|
164
|
+
# contains a short sha, it will begin with 'g'. We check for this to
|
165
|
+
# determine what version type to deliver.
|
166
|
+
#
|
167
|
+
# Examples of final versions:
|
168
|
+
# 1.2.3
|
169
|
+
# 1.5.3.1
|
170
|
+
#
|
171
|
+
# Examples of prerelease versions:
|
172
|
+
# 1.2.3.1234-g124dm9302
|
173
|
+
# 3.2.5.23-gd329nd
|
174
|
+
#
|
175
|
+
# @param project [Vanagon::Project] project to version
|
176
|
+
# @return [String] the version of the nuget package for this project
|
177
|
+
def nuget_package_version(version, release)
|
178
|
+
version_elements = version.split('.')
|
179
|
+
if version_elements.last.start_with?('g')
|
180
|
+
# Version for the prerelease package
|
181
|
+
"#{version_elements[0..-2].join('.').gsub(/[a-zA-Z]/, '')}-#{version_elements[-1]}"
|
182
|
+
else
|
183
|
+
"#{version}.#{release}".gsub(/[a-zA-Z]/, '')
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Add a repository (or install Chocolatey)
|
188
|
+
# Note - this only prepares the list of commands to be executed once the Platform
|
189
|
+
# has been setup
|
190
|
+
#
|
191
|
+
# @param definition [String] Definition for adding repo, can be a Repo URL (including file:)
|
192
|
+
# If file suffix is 'ps1' it is downloaded and executed to install chocolatey
|
193
|
+
# @return [Array] Commands to executed after platform startup
|
194
|
+
def add_repository(definition)
|
195
|
+
definition = URI.parse(definition)
|
196
|
+
commands = []
|
197
|
+
|
198
|
+
if definition.scheme =~ /^(http|ftp|file)/
|
199
|
+
if File.extname(definition.path) == '.ps1'
|
200
|
+
commands << %(powershell.exe -NoProfile -ExecutionPolicy Bypass -Command 'iex ((new-object net.webclient).DownloadString(\"#{definition}\"))')
|
201
|
+
else
|
202
|
+
commands << %(C:/ProgramData/chocolatey/bin/choco.exe source add -n #{definition.host}-#{definition.path.gsub('/', '-')} -s "#{definition}" --debug || echo "Oops, it seems that you don't have chocolatey installed on this system. Please ensure it's there by adding something like 'plat.add_repository 'https://chocolatey.org/install.ps1'' to your platform definition.")
|
203
|
+
end
|
204
|
+
else
|
205
|
+
raise Vanagon::Error, "Invalid repo specification #{definition}"
|
206
|
+
end
|
207
|
+
|
208
|
+
commands
|
209
|
+
end
|
210
|
+
|
211
|
+
# Get the expected output dir for the windows packages. This allows us to
|
212
|
+
# use some standard tools to ship internally.
|
213
|
+
#
|
214
|
+
# @param target_repo [String] optional repo target for built packages defined
|
215
|
+
# at the project level
|
216
|
+
# @return [String] relative path to where windows packages should be staged
|
217
|
+
def output_dir(target_repo = "")
|
218
|
+
File.join("windows", target_repo, @architecture)
|
219
|
+
end
|
220
|
+
|
221
|
+
# Constructor. Sets up some defaults for the windows platform and calls the parent constructor
|
222
|
+
#
|
223
|
+
# Mingw varies on where it is installed based on architecture. We want to use which ever is on the system.
|
224
|
+
#
|
225
|
+
# @param name [String] name of the platform
|
226
|
+
# @return [Vanagon::Platform::Windows] the win derived platform with the given name
|
227
|
+
def initialize(name)
|
228
|
+
@target_user = "Administrator"
|
229
|
+
@make = "/usr/bin/make"
|
230
|
+
@tar = "/usr/bin/tar"
|
231
|
+
@find = "/usr/bin/find"
|
232
|
+
@sort = "/usr/bin/sort"
|
233
|
+
@num_cores = "/usr/bin/nproc"
|
234
|
+
@install = "/usr/bin/install"
|
235
|
+
@copy = "/usr/bin/cp"
|
236
|
+
@package_type = "msi"
|
237
|
+
super(name)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|