cartage 1.2 → 2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Cartage.yml.rdoc +51 -215
- data/Contributing.md +71 -0
- data/Extending.md +520 -0
- data/History.md +106 -0
- data/{Licence.rdoc → Licence.md} +5 -5
- data/Manifest.txt +19 -12
- data/README.rdoc +64 -109
- data/Rakefile +37 -32
- data/bin/cartage +2 -2
- data/cartage-cli.md +137 -0
- data/cartage.yml.sample +43 -153
- data/lib/cartage.rb +296 -366
- data/lib/cartage/backport.rb +66 -0
- data/lib/cartage/cli.rb +234 -0
- data/lib/cartage/commands/echo.rb +23 -0
- data/lib/cartage/commands/info.rb +57 -0
- data/lib/cartage/commands/manifest.rb +88 -0
- data/lib/cartage/commands/pack.rb +18 -0
- data/lib/cartage/config.rb +118 -125
- data/lib/cartage/core.rb +112 -0
- data/lib/cartage/gli_ext.rb +58 -0
- data/lib/cartage/minitest.rb +140 -0
- data/lib/cartage/plugin.rb +137 -25
- data/lib/cartage/plugins/build_tarball.rb +40 -0
- data/lib/cartage/{manifest.rb → plugins/manifest.rb} +47 -35
- data/test/minitest_config.rb +3 -65
- data/test/test_cartage.rb +253 -109
- data/test/test_cartage_build_tarball.rb +57 -0
- data/test/test_cartage_config.rb +100 -28
- data/test/test_cartage_core.rb +172 -0
- data/test/test_cartage_manifest.rb +234 -13
- data/test/test_cartage_plugin.rb +85 -0
- metadata +63 -79
- data/.autotest +0 -8
- data/.gemtest +0 -1
- data/.minitest.rb +0 -2
- data/.travis.yml +0 -36
- data/Contributing.rdoc +0 -66
- data/Gemfile +0 -9
- data/History.rdoc +0 -43
- data/lib/cartage/command.rb +0 -59
- data/lib/cartage/manifest/commands.rb +0 -106
- data/lib/cartage/pack_command.rb +0 -14
data/bin/cartage
CHANGED
data/cartage-cli.md
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
# cartage - Manage releaseable packages
|
2
|
+
|
3
|
+
Cartage provides a repeatable means to create a package for a server-side
|
4
|
+
application that can be used in deployment with a configuration tool like
|
5
|
+
Ansible, Chef, Puppet, or Salt.
|
6
|
+
|
7
|
+
## Global Options
|
8
|
+
|
9
|
+
__`-C`, `--config-file FILE`__
|
10
|
+
|
11
|
+
Use the specified Cartage configuration file.
|
12
|
+
|
13
|
+
Use the specified configuration file. If not specified, the configuration is
|
14
|
+
found relative to the current working directory (assumed to be the project
|
15
|
+
root) at one of the following locations:
|
16
|
+
|
17
|
+
1. config/cartage.yml
|
18
|
+
2. cartage.yml
|
19
|
+
3. .cartage.yml
|
20
|
+
|
21
|
+
__`--dependency-cache-path PATH`__
|
22
|
+
|
23
|
+
The path where vendored dependencies will be cached between builds.
|
24
|
+
|
25
|
+
Dependencies for deployable packages are vendored. To reduce network calls and
|
26
|
+
build time, Cartage will cache the vendored dependencies in a tarball
|
27
|
+
(dependency-cache.tar.bz2) in this path.
|
28
|
+
|
29
|
+
__`-n`, `--name NAME`__
|
30
|
+
|
31
|
+
The name of the package.
|
32
|
+
|
33
|
+
The name of the package is used with the timestamp to create the final package
|
34
|
+
name. Defaults to the last part of the repo URL.
|
35
|
+
|
36
|
+
__`-r`, `--root-path PATH`__
|
37
|
+
|
38
|
+
The package source root path.
|
39
|
+
|
40
|
+
Where the package is built from. Defaults to the root of the repository.
|
41
|
+
|
42
|
+
__`-t`, `--target PATH`__
|
43
|
+
|
44
|
+
The destination of the created package.
|
45
|
+
|
46
|
+
Where the final package will be written. Defaults to 'tmp'.
|
47
|
+
|
48
|
+
__`--timestamp TIMESTAMP`__
|
49
|
+
|
50
|
+
The timestamp used for building the package.
|
51
|
+
|
52
|
+
The timestamp is used with the name of the package is used to create the final
|
53
|
+
package name.
|
54
|
+
|
55
|
+
__`-T`, `--trace`__
|
56
|
+
|
57
|
+
Show the backtrace when an error occurs.
|
58
|
+
|
59
|
+
__`--disable-dependency-cache`__
|
60
|
+
|
61
|
+
Disable the use of vendor dependency caching.
|
62
|
+
|
63
|
+
__`-q`, `--[no-]quiet`__
|
64
|
+
|
65
|
+
Silence normal output.
|
66
|
+
|
67
|
+
__`-v`, `--[no-]verbose`__
|
68
|
+
|
69
|
+
Show verbose output.
|
70
|
+
|
71
|
+
__`--version`__
|
72
|
+
|
73
|
+
Display the program version.
|
74
|
+
|
75
|
+
## Commands
|
76
|
+
|
77
|
+
### `help COMMAND`
|
78
|
+
|
79
|
+
Shows a list of commands or help for one command.
|
80
|
+
|
81
|
+
Gets help for the application or its commands. Can also list the commands in a
|
82
|
+
way helpful to creating a bash-style completion function.
|
83
|
+
|
84
|
+
*__Options__*
|
85
|
+
|
86
|
+
__`-c`__
|
87
|
+
|
88
|
+
List commands one per line, to assist with shell completion.
|
89
|
+
|
90
|
+
### `manifest`
|
91
|
+
|
92
|
+
Work with the Manifest.txt file
|
93
|
+
|
94
|
+
#### `manifest` Subcommands
|
95
|
+
|
96
|
+
##### `manifest cartignore`
|
97
|
+
|
98
|
+
Install or update the .cartignore file
|
99
|
+
|
100
|
+
*__Options__*
|
101
|
+
|
102
|
+
__`--mode MODE`__
|
103
|
+
|
104
|
+
Overwrite or merge an existing .cartignore. If specified, must be one of
|
105
|
+
`overwrite` or `merge`.
|
106
|
+
|
107
|
+
__`-f`, `--force`, `--overwrite`__
|
108
|
+
|
109
|
+
Overwrite an existing .cartignore (the same as `--mode overwrite`).
|
110
|
+
|
111
|
+
__`-m`, `--merge`__
|
112
|
+
|
113
|
+
Merge an existing .cartignore (the same as `--mode merge`).
|
114
|
+
|
115
|
+
##### `manifest check`
|
116
|
+
|
117
|
+
Check the Manifest.txt file against the current repository. If no command is
|
118
|
+
provided, this will run.
|
119
|
+
|
120
|
+
##### `manifest generate`, `manifest update`
|
121
|
+
|
122
|
+
Generate or update the Manifest.txt file.
|
123
|
+
|
124
|
+
##### `manifest show`
|
125
|
+
|
126
|
+
Show the files that will be included in the package.
|
127
|
+
|
128
|
+
### `pack`, `build`
|
129
|
+
|
130
|
+
Create a package with Cartage based on the Manifest.
|
131
|
+
|
132
|
+
*__Options__*
|
133
|
+
|
134
|
+
__`--skip-check`__
|
135
|
+
|
136
|
+
Skip checking the status of the Manifest before attempting to build the
|
137
|
+
package.
|
data/cartage.yml.sample
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
# The name of the application. Optional, defaults to the basename of the origin
|
3
|
-
#
|
3
|
+
# repo URL. Overridden with <tt>cartage --name NAME</tt>.
|
4
4
|
# ---
|
5
5
|
# name: my-application
|
6
6
|
|
7
|
-
# The target path for the Cartage package. Optional
|
7
|
+
# The target path for the Cartage package. Optional, defaults to
|
8
8
|
# <tt>./tmp</tt>. Overridden with <tt>cartage --target PATH</tt>.
|
9
9
|
# ---
|
10
10
|
# target: tmp/cartage
|
11
11
|
|
12
|
-
# The root path of the application. Optional, defaults to the top of the
|
12
|
+
# The root path of the application. Optional, defaults to the top of the
|
13
13
|
# repository (<tt>git rev-parse --show-cdup</tt>). Overridden with <tt>cartage
|
14
14
|
# --root-path ROOT_PATH</tt>.
|
15
15
|
# ---
|
@@ -22,162 +22,52 @@
|
|
22
22
|
# ---
|
23
23
|
# timestamp: not-a-timestamp
|
24
24
|
|
25
|
-
# The
|
26
|
-
#
|
27
|
-
#
|
25
|
+
# The type of compression to be used. Optional, defaults to 'bzip2'. Must be
|
26
|
+
# one of 'bzip2', 'gzip', or 'none'. Overridden with <tt>cartage --compression
|
27
|
+
# TYPE</tt>.
|
28
|
+
#
|
29
|
+
# This affects the compression of both the final package and the dependency
|
30
|
+
# cache.
|
28
31
|
# ---
|
29
|
-
#
|
32
|
+
# compression: gzip
|
30
33
|
|
31
|
-
#
|
32
|
-
#
|
33
|
-
# group1,group2</tt>.
|
34
|
+
# Silence normal output. Optional, defaults false. Overridden with <tt>cartage
|
35
|
+
# --quiet</tt>.
|
34
36
|
# ---
|
35
|
-
#
|
36
|
-
# - development
|
37
|
-
# - test
|
38
|
-
# - other
|
37
|
+
# quiet: true
|
39
38
|
|
40
|
-
#
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
# The path to the cartage S3 bucket or directory (for another service that
|
45
|
-
# Fog::Storage supports). This has no default and is overridden with
|
46
|
-
# <tt>cartage s3 --path PATH</tt>.
|
47
|
-
# ---
|
48
|
-
# path: cartage-bucket
|
49
|
-
|
50
|
-
# The credentials dictionary passed to Fog::Storage for uploads. Each
|
51
|
-
# provider has different keys. If present, this will dictionary be used in
|
52
|
-
# preference to <tt>cartage s3</tt> flags <tt>--key-id</tt>,
|
53
|
-
# <tt>--secret-key</tt>, and <tt>--region</tt> as those work *only* with
|
54
|
-
# Amazon AWS S3.
|
55
|
-
credentials:
|
56
|
-
# The name of the provider.
|
57
|
-
# ---
|
58
|
-
# provider: AWS
|
59
|
-
# provider: Rackspace
|
60
|
-
# provider: Google
|
61
|
-
|
62
|
-
# The name of the access user. The name of this key varies per provider.
|
63
|
-
# ---
|
64
|
-
# aws_access_key_id: YOUR_AWS_ACCESS_KEY_ID
|
65
|
-
# rackspace_username: RACKSPACE_USERNAME
|
66
|
-
# google_storage_access_key_id: YOUR_SECRET_ACCESS_KEY_ID
|
67
|
-
|
68
|
-
# The authentication key. The name of this key varies per provider.
|
69
|
-
# ---
|
70
|
-
# aws_secret_access_key: YOUR_AWS_SECRET_ACCESS_KEY
|
71
|
-
# rackspace_api_key: RACKSPACE_API_KEY
|
72
|
-
# google_storage_secret_access_key: YOUR_SECRET_ACCESS_KEY
|
73
|
-
|
74
|
-
# Other keys can be provided as needed for the provider. AWS generally
|
75
|
-
# wants to know the +region+, and Rackspace needs to know if you are
|
76
|
-
# using its European datacentre.
|
77
|
-
# ---
|
78
|
-
# region: us-west-2
|
79
|
-
# rackspace_auth_url: lon.auth.api.rackspacecloud.com
|
80
|
-
|
81
|
-
# This section is for cartage-remote. cartage-remote will not work without a
|
82
|
-
# configuration section at this point because remote build scripts tend to be
|
83
|
-
# heavily customized. This may change in the future.
|
84
|
-
remote:
|
85
|
-
# The name of the build server. This field is required and can show up in
|
86
|
-
# two different formats.
|
87
|
-
# ---
|
88
|
-
# server: build@my-build-machine:2222
|
89
|
-
# server:
|
90
|
-
# user: build
|
91
|
-
# host: my-build-machine
|
92
|
-
# port: 2222
|
93
|
-
|
94
|
-
# The SSH key(s) used to connect to the server. Optional, and
|
95
|
-
# cartage-remote will use <tt>~/.ssh/*id_[rd]sa</tt> to find keys if this
|
96
|
-
# is not provided. Three formats are available.
|
97
|
-
#
|
98
|
-
# As a dictionary (first form), the private keys are embedded directly in
|
99
|
-
# the configuration file. As a string or an array, provides glob patterns
|
100
|
-
# to find key files on disk.
|
101
|
-
# ---
|
102
|
-
# keys:
|
103
|
-
# custom: |
|
104
|
-
# -----BEGIN RSA PRIVATE KEY-----
|
105
|
-
# ...
|
106
|
-
# -----END RSA PRIVATE KEY-----
|
107
|
-
# keys:
|
108
|
-
# - "config/secrets/*id_[rd]sa"
|
109
|
-
# - "~/.ssh/*id_[rd]sa"
|
110
|
-
# keys: "config/secrets/*id_[rd]sa"
|
39
|
+
# Show verbose output. Optional, defaults false. Overridden with <tt>cartage
|
40
|
+
# --verbose</tt>.
|
41
|
+
# ---
|
42
|
+
# verbose: true
|
111
43
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
# fi
|
126
|
-
# ---
|
127
|
-
# build: |
|
128
|
-
# #!/bin/bash
|
129
|
-
# set -e
|
130
|
-
# if [ -f Gemfile ]; then
|
131
|
-
# bundle install --path %<remote_bundle>s
|
132
|
-
# bundle exec cartage s3 \
|
133
|
-
# --config-file %<config_file>s \
|
134
|
-
# --target %<project_path>s \
|
135
|
-
# --verbose
|
136
|
-
# else
|
137
|
-
# cartage build \
|
138
|
-
# --config-file %<config_file>s \
|
139
|
-
# --target %<project_path>s \
|
140
|
-
# --verbose
|
141
|
-
# fi
|
44
|
+
# Disable dependency caching. Optional, defaults false.
|
45
|
+
# ---
|
46
|
+
# disable_dependency_cache: true
|
47
|
+
|
48
|
+
# The path where the dependency cache will be written
|
49
|
+
# (<tt>dependency-cache.tar.*</tt>) for use in successive builds. Optional,
|
50
|
+
# defaults to <tt>./tmp</tt>. Overridden with <tt>cartage
|
51
|
+
# --dependency-cache-path PATH</tt>.
|
52
|
+
#
|
53
|
+
# On a CI system, this should be written somewhere that the CI system uses for
|
54
|
+
# build caching.
|
55
|
+
# ---
|
56
|
+
# dependency_cache_path: <%= ENV['SEMAPHORE_CACHE'] %>
|
142
57
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
# prebuild: |
|
150
|
-
# #!/bin/bash
|
151
|
-
# ssh-keyscan -H %<remote_host>s >> ~/.ssh/known_hosts
|
152
|
-
# echo 'Prebuild complete'
|
58
|
+
# This dictionary is for command-specific configuration. As of this writing,
|
59
|
+
# none of the commands provided by default or in existing plug-ins have
|
60
|
+
# command-specific configuration. The keys are freeform and should be based on
|
61
|
+
# the *primary* name of the command (so the <tt>cartage pack</tt> command
|
62
|
+
# should use the key <tt>pack</tt>.)
|
63
|
+
commands: {}
|
153
64
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
# finished). If the build was interrupted with an error, the error
|
160
|
-
# message will be passed as $2.
|
161
|
-
# ---
|
162
|
-
# postbuild: |
|
163
|
-
# #!/bin/bash
|
164
|
-
# case ${1:-undefined} in
|
165
|
-
# finished)
|
166
|
-
# t="token=SLACK_TOKEN"
|
167
|
-
# c="channel=%23ci"
|
168
|
-
# d=MYDOMAIN
|
169
|
-
# u="https://${d}.slack.com/services/hooks/slackbot?${t}&${c}"
|
170
|
-
# curl --data "Build %<name>s-%<timestamp>s complete." ${u}
|
171
|
-
# ;;
|
172
|
-
# *)
|
173
|
-
# : # ${1} is the stage, ${2} is the error message
|
174
|
-
# ;;
|
175
|
-
# esac
|
65
|
+
# This dictionary is for plug-in-specific configuration. See each plug-in for
|
66
|
+
# configuration options. The keys to the plug-ins are based on the plug-in
|
67
|
+
# name. cartage-bundler is available as Cartage::Bundler; the transformed
|
68
|
+
# plug-in name will be <tt>bundler</tt>.
|
69
|
+
plugins: {}
|
176
70
|
|
177
71
|
# This must not be indented for it to work.
|
178
|
-
|
179
|
-
<%=
|
180
|
-
<% end %>
|
181
|
-
<% if File.exist?('config/local/cartage.yml') %>
|
182
|
-
<%= File.read('config/local/cartage.yml') %>
|
183
|
-
<% end %>
|
72
|
+
<%= Cartage::Config.import 'config/ansible/cartage.yml' %>
|
73
|
+
<%= Cartage::Config.import 'config/local/cartage.yml' %>
|
data/lib/cartage.rb
CHANGED
@@ -1,31 +1,22 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
VERSION = '1.2' #:nodoc:
|
6
|
-
|
7
|
-
# Plug-in commands that want to return a specific exit code should use
|
8
|
-
# Cartage::StatusError to wrap the error.
|
9
|
-
class StatusError < StandardError
|
10
|
-
# Initialize the exception with +exitstatus+ and the exception to wrap.
|
11
|
-
def initialize(exitstatus, exception_or_message)
|
12
|
-
super(exception_or_message) if exception_or_message
|
13
|
-
@exitstatus = exitstatus
|
14
|
-
end
|
3
|
+
require 'pathname'
|
4
|
+
require 'json'
|
15
5
|
|
16
|
-
|
17
|
-
|
18
|
-
|
6
|
+
require 'cartage/core'
|
7
|
+
require 'cartage/plugin'
|
8
|
+
require 'cartage/config'
|
19
9
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
def initialize(exitstatus)
|
25
|
-
super(exitstatus, nil)
|
26
|
-
end
|
10
|
+
##
|
11
|
+
# Cartage, a reliable package builder.
|
12
|
+
class Cartage
|
13
|
+
VERSION = '2.0.rc1' #:nodoc:
|
27
14
|
|
28
|
-
|
15
|
+
# Creates a new Cartage instance. If provided a Cartage::Config object in
|
16
|
+
# +config+, sets the configuration and resolves it. If +config+ is not
|
17
|
+
# provided, the default configuration will be loaded.
|
18
|
+
def initialize(config = nil)
|
19
|
+
self.config = config || Cartage::Config.load(:default)
|
29
20
|
end
|
30
21
|
|
31
22
|
##
|
@@ -39,6 +30,8 @@ class Cartage
|
|
39
30
|
# The default name of the package to be created, derived from the
|
40
31
|
# repository's Git URL.
|
41
32
|
|
33
|
+
attr_accessor_with_default :name, default: -> { File.basename(repo_url, '.git') }
|
34
|
+
|
42
35
|
##
|
43
36
|
# :attr_accessor: root_path
|
44
37
|
#
|
@@ -50,6 +43,16 @@ class Cartage
|
|
50
43
|
# The default root path of the package, the top-level path of the Git
|
51
44
|
# repository.
|
52
45
|
|
46
|
+
attr_reader_with_default :root_path do
|
47
|
+
Pathname(%x(git rev-parse --show-cdup).chomp).expand_path
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
def root_path=(v) #:nodoc:
|
52
|
+
reset_computed_values
|
53
|
+
@root_path = Pathname(v).expand_path
|
54
|
+
end
|
55
|
+
|
53
56
|
##
|
54
57
|
# :attr_accessor: target
|
55
58
|
#
|
@@ -60,6 +63,10 @@ class Cartage
|
|
60
63
|
#
|
61
64
|
# The default target of the package, './tmp'.
|
62
65
|
|
66
|
+
attr_accessor_with_default :target,
|
67
|
+
transform: ->(v) { Pathname(v) },
|
68
|
+
default: -> { Pathname('tmp') }
|
69
|
+
|
63
70
|
##
|
64
71
|
# :attr_accessor: timestamp
|
65
72
|
#
|
@@ -70,169 +77,265 @@ class Cartage
|
|
70
77
|
#
|
71
78
|
# The default timestamp.
|
72
79
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
# The environments to exclude from a bundle install.
|
80
|
+
attr_accessor_with_default :timestamp, default: -> {
|
81
|
+
Time.now.utc.strftime('%Y%m%d%H%M%S')
|
82
|
+
}
|
77
83
|
|
78
84
|
##
|
79
|
-
# :
|
85
|
+
# :attr_accessor: compression
|
80
86
|
#
|
81
|
-
# The
|
82
|
-
#
|
87
|
+
# The compression to be applied to any tarballs created (either the final
|
88
|
+
# tarball or the dependency cache tarball).
|
83
89
|
|
84
|
-
|
85
|
-
|
90
|
+
##
|
91
|
+
def compression
|
92
|
+
unless defined?(@compression)
|
93
|
+
@compression = :bzip2
|
94
|
+
reset_computed_values
|
95
|
+
end
|
96
|
+
@compression
|
97
|
+
end
|
86
98
|
|
87
|
-
|
88
|
-
|
99
|
+
##
|
100
|
+
def compression=(value) #:nodoc:
|
101
|
+
case value
|
102
|
+
when :bzip2, :none, :gzip, 'bzip2', 'none', 'gzip'
|
103
|
+
@compression = value
|
104
|
+
reset_computed_values
|
105
|
+
else
|
106
|
+
fail ArgumentError, "Invalid compression type #{value.inspect}"
|
107
|
+
end
|
108
|
+
end
|
89
109
|
|
90
|
-
#
|
91
|
-
|
92
|
-
# environment partitions, but if they do, use this to select the environment
|
93
|
-
# partition.
|
94
|
-
attr_accessor :environment
|
110
|
+
# If +true+, dependencies will not be cached.
|
111
|
+
attr_accessor :disable_dependency_cache
|
95
112
|
|
96
|
-
|
97
|
-
#
|
98
|
-
# #environment will be returned. If +with_environment+ is +false+, the full
|
99
|
-
# configuration will be returned.
|
113
|
+
##
|
114
|
+
# :attr_reader: dependency_cache
|
100
115
|
#
|
101
|
-
#
|
102
|
-
# plug-in will be returned.
|
116
|
+
# The path to the tarball of vendored dependencies in the working path.
|
103
117
|
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
# # => base_config[:plugins][:s3]
|
113
|
-
def config(with_environment: true, for_plugin: nil)
|
114
|
-
env = environment.to_sym if with_environment && environment
|
115
|
-
plug = for_plugin.to_sym if for_plugin
|
116
|
-
|
117
|
-
cfg = if env
|
118
|
-
base_config[env]
|
119
|
-
else
|
120
|
-
base_config
|
121
|
-
end
|
122
|
-
|
123
|
-
cfg = cfg.plugins[plug] if plug && cfg.plugins
|
124
|
-
cfg
|
125
|
-
end
|
126
|
-
|
127
|
-
# The configuration file to read. This should not be used by clients.
|
128
|
-
attr_writer :load_config #:nodoc:
|
129
|
-
|
130
|
-
# The base config file. This should not be used by clients.
|
131
|
-
attr_accessor :base_config #:nodoc:
|
132
|
-
|
133
|
-
def initialize #:nodoc:
|
134
|
-
@load_config = :default
|
135
|
-
end
|
136
|
-
|
137
|
-
# Create the package.
|
138
|
-
def pack
|
139
|
-
timestamp # Force the timestamp to be set now.
|
140
|
-
prepare_work_area
|
141
|
-
save_release_hashref
|
142
|
-
fetch_bundler
|
143
|
-
install_vendor_bundle
|
144
|
-
restore_modified_files
|
145
|
-
build_final_tarball
|
118
|
+
# Vendored dependencies vary by build system. With Ruby and Bundler, this
|
119
|
+
# would be the <tt>vendor/bundle</tt> path; with npm, this would be the
|
120
|
+
# <tt>node_modules</tt> path.
|
121
|
+
|
122
|
+
##
|
123
|
+
def dependency_cache
|
124
|
+
self.dependency_cache_path = tmp_path unless defined?(@dependency_cache)
|
125
|
+
@dependency_cache
|
146
126
|
end
|
147
127
|
|
148
|
-
|
149
|
-
#
|
128
|
+
##
|
129
|
+
# :attr_accessor: dependency_cache_path
|
150
130
|
#
|
151
|
-
#
|
152
|
-
#
|
153
|
-
# the bundle has been installed. In this way, bundle installation works
|
154
|
-
# almost the same way as Capistrano’s shared bundle concept as long as the
|
155
|
-
# path to the bundle_cache has been set to a stable location.
|
131
|
+
# Reads or sets the vendored dependency cache path. This is where the tarball
|
132
|
+
# of vendored dependencies in the working path will reside.
|
156
133
|
#
|
157
|
-
# On
|
134
|
+
# On a CI system, this should be written somewhere that the CI system uses
|
135
|
+
# for build caching. On Semaphore CI, this would be
|
158
136
|
# <tt>$SEMAPHORE_CACHE</tt>.
|
159
|
-
|
160
|
-
|
161
|
-
def
|
162
|
-
|
163
|
-
|
164
|
-
|
137
|
+
|
138
|
+
##
|
139
|
+
def dependency_cache_path
|
140
|
+
self.dependency_cache_path = tmp_path unless defined?(@dependency_cache_path)
|
141
|
+
@dependency_cache_path
|
142
|
+
end
|
143
|
+
|
144
|
+
##
|
145
|
+
def dependency_cache_path=(path) #:nodoc:
|
146
|
+
@dependency_cache_path = Pathname(path || tmp_path).expand_path
|
147
|
+
@dependency_cache = @dependency_cache_path.
|
148
|
+
join("dependency-cache.tar#{tar_compression_extension}")
|
149
|
+
end
|
150
|
+
|
151
|
+
# Commands that normally output data will have that output suppressed.
|
152
|
+
attr_accessor :quiet
|
153
|
+
|
154
|
+
# Commands will be run with extra information.
|
155
|
+
attr_accessor :verbose
|
156
|
+
|
157
|
+
# The cartage configuration object, implemented as a recursive OpenStruct.
|
158
|
+
# This can return just the subset of configuration for a command or plug-in
|
159
|
+
# by providing the +for_plugin+ or +for_command+ parameters.
|
160
|
+
def config(for_plugin: nil, for_command: nil)
|
161
|
+
if for_plugin && for_command
|
162
|
+
fail ArgumentError, 'Cannot get config for plug-in and command together'
|
163
|
+
elsif for_plugin
|
164
|
+
@config.dig(:plugins, for_plugin.to_sym) || OpenStruct.new
|
165
|
+
elsif for_command
|
166
|
+
@config.dig(:commands, for_command.to_sym) || OpenStruct.new
|
167
|
+
else
|
168
|
+
@config
|
165
169
|
end
|
166
|
-
@bundle_cache
|
167
170
|
end
|
168
171
|
|
169
|
-
#
|
170
|
-
|
171
|
-
|
172
|
+
# The config file. This should not be used by clients.
|
173
|
+
def config=(cfg) # :nodoc:
|
174
|
+
fail ArgumentError, 'No config provided' unless cfg
|
175
|
+
@plugins = Plugins.new
|
176
|
+
@config = cfg
|
177
|
+
resolve_config!
|
178
|
+
end
|
179
|
+
|
180
|
+
# The release metadata that will be written for the package.
|
181
|
+
def release_metadata
|
182
|
+
@release_metadata ||= {
|
183
|
+
package: {
|
184
|
+
name: name,
|
185
|
+
repo: {
|
186
|
+
type: 'git', # Hardcoded until we have other support
|
187
|
+
url: repo_url
|
188
|
+
},
|
189
|
+
hashref: release_hashref,
|
190
|
+
timestamp: timestamp
|
191
|
+
}
|
192
|
+
}
|
193
|
+
end
|
194
|
+
|
195
|
+
# Return the release hashref.
|
196
|
+
def release_hashref
|
172
197
|
@release_hashref ||= %x(git rev-parse HEAD).chomp
|
173
|
-
File.open(save_to, 'w') { |f| f.write @release_hashref } if save_to
|
174
|
-
@release_hashref
|
175
198
|
end
|
176
199
|
|
177
200
|
# The repository URL.
|
178
201
|
def repo_url
|
179
202
|
unless defined? @repo_url
|
180
|
-
|
181
|
-
|
182
|
-
@repo_url = match[:fetch]
|
203
|
+
@repo_url = %x(git remote show -n origin).
|
204
|
+
match(/\n\s+Fetch URL: (?<fetch>[^\n]+)/)[:fetch]
|
183
205
|
end
|
184
206
|
@repo_url
|
185
207
|
end
|
186
208
|
|
187
|
-
# The path
|
188
|
-
def
|
189
|
-
@
|
209
|
+
# The temporary path.
|
210
|
+
def tmp_path
|
211
|
+
@tmp_path ||= root_path.join('tmp')
|
212
|
+
end
|
213
|
+
|
214
|
+
# The working path for the job, in #tmp_path.
|
215
|
+
def work_path
|
216
|
+
@work_path ||= tmp_path.join(name)
|
190
217
|
end
|
191
218
|
|
192
|
-
# The
|
193
|
-
def
|
194
|
-
@
|
195
|
-
Pathname("#{final_name}-release-hashref.txt")
|
219
|
+
# The final name
|
220
|
+
def final_name
|
221
|
+
@final_name ||= tmp_path.join("#{name}-#{timestamp}")
|
196
222
|
end
|
197
223
|
|
198
|
-
#
|
199
|
-
|
200
|
-
|
224
|
+
# The path to the resulting release-metadata.json file.
|
225
|
+
def final_release_metadata_json
|
226
|
+
@final_release_metadata_json ||= Pathname("#{final_name}-release-metadata.json")
|
227
|
+
end
|
228
|
+
|
229
|
+
# A utility method for Cartage plug-ins to display a +message+ only if
|
230
|
+
# verbose is on. Unless the command implemented by the plug-in is output
|
231
|
+
# only, this should be used.
|
201
232
|
def display(message)
|
202
233
|
__display(message)
|
203
234
|
end
|
204
235
|
|
236
|
+
# A utility method for Cartage plug-ins to run a +command+ in the shell. Uses
|
237
|
+
# IO.popen.
|
238
|
+
def run(command)
|
239
|
+
display command.join(' ')
|
240
|
+
|
241
|
+
IO.popen(command + [ err: %i(child out) ]) do |io|
|
242
|
+
__display(io.read(128), partial: true, verbose: true) until io.eof?
|
243
|
+
end
|
244
|
+
|
245
|
+
fail StandardError, "Error running '#{command.join(' ')}'" unless $?.success?
|
246
|
+
end
|
247
|
+
|
248
|
+
# Returns the registered plug-ins, once configuration has been resolved.
|
249
|
+
def plugins
|
250
|
+
@plugins ||= Plugins.new
|
251
|
+
end
|
252
|
+
|
253
|
+
# Create the release package(s).
|
254
|
+
#
|
255
|
+
# Requests:
|
256
|
+
# * +:vendor_dependencies+ (#vendor_dependencies, #path)
|
257
|
+
# * +:pre_build_package+
|
258
|
+
# * +:build_package+
|
259
|
+
# * +:post_build_package+
|
260
|
+
def build_package
|
261
|
+
# Force timestamp to be initialized before anything else. This gives us a
|
262
|
+
# stable timestamp for the process.
|
263
|
+
timestamp
|
264
|
+
# Prepare the work area: copy files from root_path to work_path based on
|
265
|
+
# the resolved Manifest.txt.
|
266
|
+
prepare_work_area
|
267
|
+
# Anything that has been modified locally needs to be reset.
|
268
|
+
restore_modified_files
|
269
|
+
# Save both the final release metadata and the in-package release metadata.
|
270
|
+
save_release_metadata
|
271
|
+
# Vendor the dependencies for the package.
|
272
|
+
vendor_dependencies
|
273
|
+
# Request that supporting plug-ins build the package.
|
274
|
+
request_build_package
|
275
|
+
end
|
276
|
+
|
277
|
+
# Returns the flag to use with +tar+ given the value of +compression+.
|
278
|
+
def tar_compression_flag
|
279
|
+
case compression
|
280
|
+
when :bzip2, 'bzip2', nil
|
281
|
+
'j'
|
282
|
+
when :gzip, 'gzip'
|
283
|
+
'z'
|
284
|
+
when :none, 'none'
|
285
|
+
''
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
# Returns the extension to use with +tar+ given the value of +compression+.
|
290
|
+
def tar_compression_extension
|
291
|
+
case compression
|
292
|
+
when :bzip2, 'bzip2', nil
|
293
|
+
'.bz2'
|
294
|
+
when :gzip, 'gzip'
|
295
|
+
'.gz'
|
296
|
+
when :none, 'none'
|
297
|
+
''
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
205
301
|
private
|
206
|
-
def resolve_config!(*with_plugins)
|
207
|
-
return unless @load_config
|
208
|
-
@base_config = Cartage::Config.load(@load_config)
|
209
302
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
303
|
+
attr_writer :release_hashref
|
304
|
+
|
305
|
+
def resolve_config!
|
306
|
+
fail 'No configuration' unless config
|
307
|
+
|
308
|
+
Cartage::Plugin.load_for(singleton_class)
|
216
309
|
|
217
|
-
|
218
|
-
|
310
|
+
self.disable_dependency_cache = config.disable_dependency_cache
|
311
|
+
self.quiet = config.quiet
|
312
|
+
self.verbose = config.verbose
|
219
313
|
|
220
|
-
|
221
|
-
|
222
|
-
|
314
|
+
maybe_assign :name, config.name
|
315
|
+
maybe_assign :target, config.target
|
316
|
+
maybe_assign :root_path, config.root_path
|
317
|
+
maybe_assign :timestamp, config.timestamp
|
318
|
+
maybe_assign :dependency_cache_path, config.dependency_cache_path
|
319
|
+
maybe_assign :release_hashref, config.release_hashref
|
223
320
|
|
224
|
-
|
321
|
+
Cartage::Plugin.each do |name|
|
322
|
+
next unless respond_to?(name)
|
323
|
+
plugin = send(name) or next
|
225
324
|
plugin.send(:resolve_config!, config(for_plugin: name))
|
325
|
+
|
326
|
+
plugins.add plugin
|
226
327
|
end
|
328
|
+
|
329
|
+
plugins.freeze
|
227
330
|
end
|
228
331
|
|
229
332
|
def maybe_assign(name, value)
|
230
|
-
return if value.nil? || value.empty? ||
|
231
|
-
|
333
|
+
return if value.nil? || (value.respond_to?(:empty?) && value.empty?) ||
|
334
|
+
instance_variable_defined?(:"@#{name}")
|
232
335
|
send(:"#{name}=", value)
|
233
336
|
end
|
234
337
|
|
235
|
-
def __display(message, partial: false, verbose: verbose
|
338
|
+
def __display(message, partial: false, verbose: self.verbose)
|
236
339
|
return unless verbose && !quiet
|
237
340
|
|
238
341
|
if partial
|
@@ -242,26 +345,21 @@ class Cartage
|
|
242
345
|
end
|
243
346
|
end
|
244
347
|
|
245
|
-
def
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
unless $?.success?
|
253
|
-
raise StandardError, "Error running '#{command.join(' ')}'"
|
254
|
-
end
|
348
|
+
def reset_computed_values
|
349
|
+
instance_variable_set(:@tmp_path, nil)
|
350
|
+
instance_variable_set(:@final_name, nil)
|
351
|
+
instance_variable_set(:@final_release_metadata_json, nil)
|
352
|
+
instance_variable_set(:@release_metadata, nil)
|
353
|
+
instance_variable_set(:@work_path, nil)
|
354
|
+
self.dependency_cache_path = dependency_cache_path
|
255
355
|
end
|
256
356
|
|
257
357
|
def prepare_work_area
|
258
|
-
display
|
358
|
+
display 'Preparing cartage work area...'
|
259
359
|
|
260
360
|
work_path.rmtree if work_path.exist?
|
261
361
|
work_path.mkpath
|
262
362
|
|
263
|
-
xf_status = cf_status = nil
|
264
|
-
|
265
363
|
manifest.resolve(root_path) do |file_list|
|
266
364
|
tar_cf_cmd = [
|
267
365
|
'tar', 'cf', '-', '-C', parent, '-h', '-T', file_list
|
@@ -276,74 +374,29 @@ class Cartage
|
|
276
374
|
xf.write cf.read
|
277
375
|
end
|
278
376
|
|
279
|
-
unless $?.success?
|
280
|
-
raise StandardError, "Error running #{tar_xf_cmd.join(' ')}"
|
281
|
-
end
|
377
|
+
fail StandardError, "Error running #{tar_xf_cmd.join(' ')}" unless $?.success?
|
282
378
|
end
|
283
379
|
|
284
|
-
unless $?.success?
|
285
|
-
raise StandardError, "Error running #{tar_cf_cmd.join(' ')}"
|
286
|
-
end
|
380
|
+
fail StandardError, "Error running #{tar_cf_cmd.join(' ')}" unless $?.success?
|
287
381
|
end
|
288
382
|
end
|
289
383
|
|
290
|
-
def
|
291
|
-
display 'Saving release
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
def extract_bundle_cache
|
297
|
-
run %W(tar xfj #{bundle_cache} -C #{work_path}) if bundle_cache.exist?
|
298
|
-
end
|
299
|
-
|
300
|
-
def create_bundle_cache
|
301
|
-
run %W(tar cfj #{bundle_cache} -C #{work_path} vendor/bundle)
|
302
|
-
end
|
303
|
-
|
304
|
-
def install_vendor_bundle
|
305
|
-
extract_bundle_cache
|
306
|
-
|
307
|
-
Bundler.with_clean_env do
|
308
|
-
Dir.chdir(work_path) do
|
309
|
-
run %w(bundle install --jobs=4 --deployment --clean --without) +
|
310
|
-
without_groups
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
create_bundle_cache
|
384
|
+
def save_release_metadata
|
385
|
+
display 'Saving release metadata...'
|
386
|
+
json = JSON.generate(release_metadata)
|
387
|
+
work_path.join('release-metadata.json').write(json)
|
388
|
+
final_release_metadata_json.write(json)
|
315
389
|
end
|
316
390
|
|
317
391
|
def restore_modified_files
|
318
|
-
%x(git status -s).
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
end
|
327
|
-
end
|
328
|
-
|
329
|
-
def build_final_tarball
|
330
|
-
run %W(tar cfj #{final_tarball} -C #{tmp_path} #{name})
|
331
|
-
end
|
332
|
-
|
333
|
-
def work_path
|
334
|
-
@work_path ||= tmp_path.join(name)
|
335
|
-
end
|
336
|
-
|
337
|
-
def clean
|
338
|
-
[ work_path ] + final
|
339
|
-
end
|
340
|
-
|
341
|
-
def final
|
342
|
-
[ final_tarball, final_release_hashref ]
|
343
|
-
end
|
344
|
-
|
345
|
-
def parent
|
346
|
-
@parent ||= root_path.parent
|
392
|
+
%x(git status -s).
|
393
|
+
split($/).
|
394
|
+
map(&:split).
|
395
|
+
select { |s, _f| s !~ /\?/ }.
|
396
|
+
map(&:last).
|
397
|
+
each { |file|
|
398
|
+
restore_modified_file file
|
399
|
+
}
|
347
400
|
end
|
348
401
|
|
349
402
|
def restore_modified_file(filename)
|
@@ -354,175 +407,52 @@ class Cartage
|
|
354
407
|
IO.popen(command) do |show|
|
355
408
|
work_path.join(filename).open('w') { |f|
|
356
409
|
f.puts show.read
|
357
|
-
f.puts timestamp
|
358
410
|
}
|
359
411
|
end
|
360
412
|
end
|
361
413
|
|
362
|
-
def
|
363
|
-
|
364
|
-
end
|
365
|
-
|
366
|
-
def final_name
|
367
|
-
@final_name ||= tmp_path.join("#{name}-#{timestamp}")
|
368
|
-
end
|
369
|
-
|
370
|
-
class << self
|
371
|
-
private
|
414
|
+
def vendor_dependencies
|
415
|
+
extract_dependency_cache
|
372
416
|
|
373
|
-
|
374
|
-
ivar = :"@#{sym}"
|
375
|
-
wsym = :"#{sym}="
|
376
|
-
dsym = :"default_#{sym}"
|
377
|
-
|
378
|
-
if default.nil? && block.nil?
|
379
|
-
raise ArgumentError, "No default provided."
|
380
|
-
end
|
381
|
-
|
382
|
-
if setter && !setter.respond_to?(:call)
|
383
|
-
raise ArgumentError, "setter must be callable"
|
384
|
-
end
|
385
|
-
|
386
|
-
setter ||= ->(v) { v }
|
387
|
-
|
388
|
-
dblk = if default.respond_to?(:call)
|
389
|
-
default
|
390
|
-
elsif default.nil?
|
391
|
-
block
|
392
|
-
else
|
393
|
-
-> { default }
|
394
|
-
end
|
395
|
-
|
396
|
-
define_method(sym) do
|
397
|
-
instance_variable_get(ivar) || send(dsym)
|
398
|
-
end
|
399
|
-
|
400
|
-
define_method(wsym) do |value|
|
401
|
-
instance_variable_set(ivar, setter.call(value || send(dsym)))
|
402
|
-
end
|
417
|
+
plugins.request(:vendor_dependencies)
|
403
418
|
|
404
|
-
|
405
|
-
|
419
|
+
create_dependency_cache(
|
420
|
+
plugins.request_map(:vendor_dependencies, :path).compact.flatten
|
421
|
+
)
|
406
422
|
end
|
407
423
|
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
default: -> { Pathname('tmp') }
|
413
|
-
lazy_accessor :timestamp, default: -> {
|
414
|
-
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
415
|
-
}
|
416
|
-
lazy_accessor :without_groups, setter: ->(v) { Array(v) },
|
417
|
-
default: -> { %w(development test) }
|
418
|
-
lazy_accessor :base_config, default: -> { OpenStruct.new }
|
419
|
-
end
|
420
|
-
|
421
|
-
class << Cartage
|
422
|
-
# Run the Cartage command-line program.
|
423
|
-
def run(args) #:nodoc:
|
424
|
-
require_relative 'cartage/plugin'
|
425
|
-
Cartage::Plugin.load
|
426
|
-
Cartage::Plugin.decorate(Cartage)
|
427
|
-
|
428
|
-
cartage = Cartage.new
|
429
|
-
|
430
|
-
cli = CmdParse::CommandParser.new(handle_exceptions: true)
|
431
|
-
cli.main_options.program_name = 'cartage'
|
432
|
-
cli.main_options.version = Cartage::VERSION.split(/\./)
|
433
|
-
cli.main_options.banner = 'Manage releaseable packages.'
|
434
|
-
|
435
|
-
cli.global_options do |opts|
|
436
|
-
# opts.on('--[no-]quiet', 'Silence normal command output.') { |q|
|
437
|
-
# cartage.quiet = !!q
|
438
|
-
# }
|
439
|
-
opts.on('--[no-]verbose', 'Show verbose output.') { |v|
|
440
|
-
cartage.verbose = !!v
|
441
|
-
}
|
442
|
-
opts.on(
|
443
|
-
'-E', '--environment [ENVIRONMENT]', <<-desc
|
444
|
-
Set the environment to be used when necessary. If an environment name is not
|
445
|
-
provided, it will check the values of $RAILS_ENV and RACK_ENV. If neither is
|
446
|
-
set, this option is ignored.
|
447
|
-
desc
|
448
|
-
) { |e| cartage.environment = e || ENV['RAILS_ENV'] || ENV['RACK_ENV'] }
|
449
|
-
opts.on(
|
450
|
-
'-C', '--[no-]config-file load_config', <<-desc
|
451
|
-
Configure Cartage from a default configuration file or a specified
|
452
|
-
configuration file.
|
453
|
-
desc
|
454
|
-
) { |c| cartage.load_config = c }
|
455
|
-
end
|
456
|
-
|
457
|
-
cli.add_command(CmdParse::HelpCommand.new)
|
458
|
-
cli.add_command(CmdParse::VersionCommand.new)
|
459
|
-
cli.add_command(Cartage::PackCommand.new(cartage))
|
460
|
-
|
461
|
-
Cartage::Plugin.registered.each do |plugin|
|
462
|
-
if plugin.respond_to?(:commands)
|
463
|
-
Array(plugin.commands).flatten.each do |command|
|
464
|
-
registered_commands << command
|
465
|
-
end
|
466
|
-
end
|
467
|
-
end
|
424
|
+
def extract_dependency_cache
|
425
|
+
return if disable_dependency_cache || !dependency_cache.exist?
|
426
|
+
run %W(tar xf#{tar_compression_flag} #{dependency_cache} -C #{work_path})
|
427
|
+
end
|
468
428
|
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
def common_build_options(opts, cartage)
|
480
|
-
opts.on(
|
481
|
-
'-t', '--target PATH',
|
482
|
-
'The build package will be placed in PATH, which defaults to \'tmp\'.'
|
483
|
-
) { |t| cartage.target = t }
|
484
|
-
opts.on(
|
485
|
-
'-n', '--name NAME',
|
486
|
-
"Set the package name. Defaults to '#{cartage.default_name}'."
|
487
|
-
) { |n| cartage.name = n }
|
488
|
-
opts.on(
|
489
|
-
'-r', '--root-path PATH',
|
490
|
-
'Set the root path. Defaults to the repository root.'
|
491
|
-
) { |r| cartage.root_path = r }
|
492
|
-
opts.on(
|
493
|
-
'--timestamp TIMESTAMP',
|
494
|
-
'The timestamp used for the final package.'
|
495
|
-
) { |t| cartage.timestamp = t }
|
496
|
-
opts.on(
|
497
|
-
'--bundle-cache PATH',
|
498
|
-
'Set the bundle cache path.'
|
499
|
-
) { |b| cartage.bundle_cache(b) }
|
500
|
-
opts.on(
|
501
|
-
'--without GROUP1,GROUP2', Array,
|
502
|
-
'Set the groups to be excluded from bundle installation.',
|
503
|
-
) { |w| cartage.without_environments = w }
|
429
|
+
def create_dependency_cache(paths = [])
|
430
|
+
return if disable_dependency_cache || paths.empty?
|
431
|
+
run [
|
432
|
+
'tar',
|
433
|
+
"cf#{tar_compression_flag}",
|
434
|
+
dependency_cache,
|
435
|
+
'-C',
|
436
|
+
work_path,
|
437
|
+
*paths
|
438
|
+
].map(&:to_s)
|
504
439
|
end
|
505
440
|
|
506
|
-
|
507
|
-
|
508
|
-
@registered_commands ||= []
|
441
|
+
def parent
|
442
|
+
@parent ||= root_path.parent
|
509
443
|
end
|
510
444
|
|
511
|
-
def
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
end
|
445
|
+
def realize!
|
446
|
+
repo_url
|
447
|
+
root_path
|
448
|
+
release_hashref
|
449
|
+
timestamp
|
517
450
|
end
|
518
451
|
|
519
|
-
def
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
$stderr.puts exception.backtrace.join("\n")
|
524
|
-
end
|
525
|
-
end
|
452
|
+
def request_build_package
|
453
|
+
plugins.request(:pre_build_package)
|
454
|
+
plugins.request(:build_package)
|
455
|
+
plugins.request(:post_build_package)
|
526
456
|
end
|
527
457
|
end
|
528
458
|
|