vanagon 0.7.1 → 0.8.0
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/lib/git/basic_submodules.rb +53 -0
- data/lib/vanagon/component.rb +19 -13
- data/lib/vanagon/component/dsl.rb +6 -5
- data/lib/vanagon/component/source.rb +80 -53
- data/lib/vanagon/component/source/git.rb +129 -20
- data/lib/vanagon/component/source/http.rb +41 -73
- data/lib/vanagon/component/source/local.rb +105 -62
- data/lib/vanagon/platform/deb.rb +8 -0
- data/lib/vanagon/platform/rpm.rb +4 -0
- data/lib/vanagon/project/dsl.rb +3 -1
- data/lib/vanagon/utilities.rb +11 -54
- data/spec/fixtures/files/fake_file_ext.7z +0 -0
- data/spec/fixtures/files/fake_file_ext.bz +0 -0
- data/spec/fixtures/files/fake_file_ext.bz2 +0 -0
- data/spec/fixtures/files/fake_file_ext.cpio +0 -0
- data/spec/fixtures/files/fake_file_ext.gz +0 -0
- data/spec/fixtures/files/fake_file_ext.rar +0 -0
- data/spec/fixtures/files/fake_file_ext.tar +0 -0
- data/spec/fixtures/files/fake_file_ext.tar.bz2 +0 -0
- data/spec/fixtures/files/fake_file_ext.tar.xz +0 -0
- data/spec/fixtures/files/fake_file_ext.tbz +0 -0
- data/spec/fixtures/files/fake_file_ext.tbz2 +0 -0
- data/spec/fixtures/files/fake_file_ext.txz +0 -0
- data/spec/fixtures/files/fake_file_ext.xz +0 -0
- data/spec/fixtures/files/fake_file_ext.z +0 -0
- data/spec/lib/vanagon/component/source/git_spec.rb +25 -17
- data/spec/lib/vanagon/component/source/http_spec.rb +2 -24
- data/spec/lib/vanagon/component/source/{localsource_spec.rb → local_spec.rb} +8 -8
- data/spec/lib/vanagon/component/source_spec.rb +150 -67
- data/spec/lib/vanagon/platform_spec.rb +40 -21
- data/spec/lib/vanagon/project/dsl_spec.rb +28 -3
- data/spec/lib/vanagon/utilities_spec.rb +0 -44
- metadata +28 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b41f01dda75f8d40767ea3c7e290cf11462ff94
|
4
|
+
data.tar.gz: 7c9b7ce98ff34e60371dbf087366cb0fd488c53d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5dda1a3fde0dfb600e38da84061bfd3f006b4f8a199e04900d067a4a96408affb102e916622d88b8fa0e04f6773f686bf5e2ef13aef108c5560d2c42e009df54
|
7
|
+
data.tar.gz: 4263fedb95452fefc118f7a199d70756455cb02c0fadd1c36b9ad630cdfd8d67d647c7a358c683295ca5cc0d2c53f2eca1a5a1ee4efde71b9d91f02a864118f5
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'git'
|
2
|
+
|
3
|
+
module BasicSubmodulePrimitives
|
4
|
+
# Extend Git::Lib to support shotgunning submodules. This command
|
5
|
+
# is not smart, and it has very poor support for submodule options.
|
6
|
+
# For example, you can't pass any arguments to the handful of submodule
|
7
|
+
# options that accept them (like --depth). We may extend it later,
|
8
|
+
# but for rev. 0001, simply initializing them will suffice
|
9
|
+
def update_submodules(**options)
|
10
|
+
arr_opts = ['update']
|
11
|
+
options.each_pair do |k, v|
|
12
|
+
arr_opts << "--#{k}" if v
|
13
|
+
end
|
14
|
+
Dir.chdir(@git_work_dir) do
|
15
|
+
command('submodule', arr_opts)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module BasicSubmodules
|
21
|
+
# @example Initialize all git submodules
|
22
|
+
# >> repo = Git.clone("git@github.com:puppetlabs/facter.git", "facter", path: Dir.mktmpdir)
|
23
|
+
# => <Git::Base>
|
24
|
+
# >> repo.checkout "3.1.3
|
25
|
+
# => <String>
|
26
|
+
# >> repo.update_submodules(init: true)
|
27
|
+
# => <String>
|
28
|
+
# @param [Hash] options any options to pass to `git submodule update`
|
29
|
+
# @option options [Boolean] :init whether to initialize submodules when updating them
|
30
|
+
# @option options [Boolean] :use the submodule's remote-tracking branch instead of superproject's SHA1 sum
|
31
|
+
# @option options [Boolean] :no-fetch don't fetch new objects from the remote site.
|
32
|
+
# @option options [Boolean] :force remove submodule's working tree even if modified
|
33
|
+
# @option options [Boolean] :checkout checkout submodules in detached HEAD state
|
34
|
+
# @option options [Boolean] :merge merge recorded commit for submodule into the current branch of the submodule
|
35
|
+
# @option options [Boolean] :rebase rebase current branch of submodule onto the commit recorded in the superproject
|
36
|
+
# @option options [Boolean] :recursive recurse into nested submodules
|
37
|
+
# @return options [String] any output produced by `git` when submodules are initialized
|
38
|
+
def update_submodules(**options)
|
39
|
+
self.lib.update_submodules(options)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Git
|
44
|
+
class Lib
|
45
|
+
include BasicSubmodulePrimitives
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module Git
|
50
|
+
class Base
|
51
|
+
include BasicSubmodules
|
52
|
+
end
|
53
|
+
end
|
data/lib/vanagon/component.rb
CHANGED
@@ -105,17 +105,20 @@ class Vanagon
|
|
105
105
|
# makefile template
|
106
106
|
#
|
107
107
|
# @param workdir [String] working directory to put the source into
|
108
|
-
def get_source(workdir)
|
109
|
-
|
110
|
-
|
111
|
-
@source.
|
112
|
-
|
113
|
-
|
114
|
-
@
|
115
|
-
@
|
108
|
+
def get_source(workdir) # rubocop:disable Metrics/AbcSize
|
109
|
+
opts = options.merge({ workdir: workdir })
|
110
|
+
if url
|
111
|
+
@source = Vanagon::Component::Source.source(url, opts)
|
112
|
+
source.fetch
|
113
|
+
source.verify
|
114
|
+
@extract_with = source.respond_to?(:extract) ? source.extract(platform.tar) : ':'
|
115
|
+
@cleanup_source = source.cleanup if source.respond_to?(:cleanup)
|
116
|
+
@dirname = source.dirname
|
116
117
|
|
117
118
|
# Git based sources probably won't set the version, so we load it if it hasn't been already set
|
118
|
-
|
119
|
+
if source.respond_to?(:version)
|
120
|
+
@version ||= source.version
|
121
|
+
end
|
119
122
|
else
|
120
123
|
warn "No source given for component '#{@name}'"
|
121
124
|
|
@@ -140,10 +143,13 @@ class Vanagon
|
|
140
143
|
#
|
141
144
|
# @param workdir [String] working directory to put the source into
|
142
145
|
def get_sources(workdir)
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
146
|
+
sources.each do |source|
|
147
|
+
src = Vanagon::Component::Source.source source.url,
|
148
|
+
workdir: workdir,
|
149
|
+
ref: source.ref,
|
150
|
+
sum: source.sum
|
151
|
+
src.fetch
|
152
|
+
src.verify
|
147
153
|
end
|
148
154
|
end
|
149
155
|
|
@@ -310,11 +310,12 @@ class Vanagon
|
|
310
310
|
|
311
311
|
# This will add a source to the project and put it in the workdir alongside the other sources
|
312
312
|
#
|
313
|
-
# @param
|
314
|
-
# @param
|
315
|
-
#
|
316
|
-
|
317
|
-
|
313
|
+
# @param uri [String] uri of the source
|
314
|
+
# @param [Hash] options optional keyword arguments used to instatiate a new source
|
315
|
+
# @option opts [String] :sum
|
316
|
+
# @option opts [String] :ref
|
317
|
+
def add_source(uri, **options)
|
318
|
+
@component.sources << OpenStruct.new(options.merge({ url: uri }))
|
318
319
|
end
|
319
320
|
|
320
321
|
# Adds a directory to the list of directories provided by the project, to be included in any packages of the project
|
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'fustigit'
|
1
2
|
require 'vanagon/component/source/http'
|
2
3
|
require 'vanagon/component/source/git'
|
3
4
|
require 'vanagon/component/source/local'
|
@@ -5,74 +6,100 @@ require 'vanagon/component/source/local'
|
|
5
6
|
class Vanagon
|
6
7
|
class Component
|
7
8
|
class Source
|
8
|
-
SUPPORTED_PROTOCOLS =
|
9
|
-
|
9
|
+
SUPPORTED_PROTOCOLS = %w(file http https git).freeze
|
10
|
+
@rewrite_rules = {}
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
class << self
|
13
|
+
attr_reader :rewrite_rules
|
14
|
+
|
15
|
+
def register_rewrite_rule(protocol, rule)
|
16
|
+
if rule.is_a?(String) || rule.is_a?(Proc)
|
17
|
+
if SUPPORTED_PROTOCOLS.include?(protocol)
|
18
|
+
@rewrite_rules[protocol] = rule
|
19
|
+
else
|
20
|
+
raise Vanagon::Error, "#{protocol} is not a supported protocol for rewriting"
|
21
|
+
end
|
15
22
|
else
|
16
|
-
raise Vanagon::Error, "
|
23
|
+
raise Vanagon::Error, "String or Proc is required as a rewrite_rule."
|
17
24
|
end
|
18
|
-
else
|
19
|
-
raise Vanagon::Error, "String or Proc is required as a rewrite_rule."
|
20
25
|
end
|
21
|
-
end
|
22
26
|
|
23
|
-
|
24
|
-
|
27
|
+
def rewrite(url, protocol)
|
28
|
+
# Vanagon did not originally distinguish between http and https
|
29
|
+
# when looking up rewrite rules; this is no longer true, but it
|
30
|
+
# means that we should try to preserve old, dumb behavior until
|
31
|
+
# the rewrite engine is removed.
|
32
|
+
return rewrite(url, "http") if protocol == "https"
|
25
33
|
|
26
|
-
|
27
|
-
if rule
|
28
|
-
|
29
|
-
|
30
|
-
|
34
|
+
rule = @rewrite_rules[protocol]
|
35
|
+
if rule
|
36
|
+
if rule.is_a?(Proc)
|
37
|
+
return proc_rewrite(rule, url)
|
38
|
+
elsif rule.is_a?(String)
|
39
|
+
return string_rewrite(rule, url)
|
40
|
+
end
|
31
41
|
end
|
42
|
+
|
43
|
+
return url
|
32
44
|
end
|
33
45
|
|
34
|
-
|
35
|
-
|
46
|
+
def proc_rewrite(rule, url)
|
47
|
+
if rule.arity == 1
|
48
|
+
rule.call(url)
|
49
|
+
else
|
50
|
+
raise Vanagon::Error, "Unable to use provided rewrite rule. Expected Proc with one argument, Proc has #{rule.arity} arguments"
|
51
|
+
end
|
52
|
+
end
|
36
53
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
54
|
+
def string_rewrite(rule, original_url)
|
55
|
+
url = original_url.to_s
|
56
|
+
target_match = url.match(/.*\/([^\/]*)$/)
|
57
|
+
if target_match
|
58
|
+
target = target_match[1]
|
59
|
+
return File.join(rule, target)
|
60
|
+
else
|
61
|
+
raise Vanagon::Error, "Unable to apply url rewrite to '#{url}', expected to find at least one '/' in the url."
|
62
|
+
end
|
42
63
|
end
|
43
|
-
end
|
44
64
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
return File.join(rule, target)
|
50
|
-
else
|
51
|
-
raise Vanagon::Error, "Unable to apply url rewrite to '#{url}', expected to find at least one '/' in the url."
|
65
|
+
def parse_and_rewrite(uri)
|
66
|
+
url = URI.parse(uri)
|
67
|
+
return url unless url.scheme
|
68
|
+
rewrite(url.to_s, url.scheme)
|
52
69
|
end
|
53
|
-
end
|
54
70
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
71
|
+
# Basic factory to hand back the correct {Vanagon::Component::Source} subtype to the component
|
72
|
+
#
|
73
|
+
# @param url [String] URI of the source file (includes git@... style links)
|
74
|
+
# @param options [Hash] hash of the options needed for the subtype
|
75
|
+
# @param workdir [String] working directory to fetch the source into
|
76
|
+
# @return [Vanagon::Component::Source] the correct subtype for the given source
|
77
|
+
def source(uri, **options) # rubocop:disable Metrics/AbcSize
|
78
|
+
# First we try git
|
79
|
+
if Vanagon::Component::Source::Git.valid_remote?(parse_and_rewrite(uri))
|
80
|
+
return Vanagon::Component::Source::Git.new parse_and_rewrite(uri),
|
81
|
+
sum: options[:sum],
|
82
|
+
ref: options[:ref],
|
83
|
+
workdir: options[:workdir]
|
84
|
+
end
|
85
|
+
|
86
|
+
# Then we try HTTP
|
87
|
+
if Vanagon::Component::Source::Http.valid_url?(parse_and_rewrite(uri))
|
88
|
+
return Vanagon::Component::Source::Http.new parse_and_rewrite(uri),
|
89
|
+
sum: options[:sum],
|
90
|
+
workdir: options[:workdir]
|
91
|
+
end
|
92
|
+
|
93
|
+
# Then we try local
|
94
|
+
if Vanagon::Component::Source::Local.valid_file?(uri)
|
95
|
+
return Vanagon::Component::Source::Local.new uri,
|
96
|
+
workdir: options[:workdir]
|
97
|
+
end
|
74
98
|
|
75
|
-
|
99
|
+
# Failing all of that, we give up
|
100
|
+
raise Vanagon::Error,
|
101
|
+
"Unknown file type: '#{uri}'; cannot continue"
|
102
|
+
end
|
76
103
|
end
|
77
104
|
end
|
78
105
|
end
|
@@ -1,39 +1,69 @@
|
|
1
1
|
require 'vanagon/utilities'
|
2
|
+
require 'vanagon/errors'
|
3
|
+
# This stupid library requires a capital 'E' in its name
|
4
|
+
# but it provides a wealth of useful constants
|
5
|
+
require 'English'
|
6
|
+
require 'fustigit'
|
7
|
+
require 'git/basic_submodules'
|
8
|
+
require 'logger'
|
2
9
|
|
3
10
|
class Vanagon
|
4
11
|
class Component
|
5
12
|
class Source
|
6
13
|
class Git
|
7
|
-
|
8
|
-
|
14
|
+
attr_accessor :url, :ref, :workdir
|
15
|
+
attr_reader :version, :default_options, :repo
|
16
|
+
|
17
|
+
class << self
|
18
|
+
# Attempt to connect to whatever URL is provided and
|
19
|
+
# return True or False depending on whether or not
|
20
|
+
# `git` thinks it's a valid Git repo.
|
21
|
+
#
|
22
|
+
# @return [Boolean] whether #url is a valid Git repo or not
|
23
|
+
def valid_remote?(url)
|
24
|
+
!!::Git.ls_remote(url)
|
25
|
+
rescue ::Git::GitExecuteError
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Default options used when cloning; this may expand
|
31
|
+
# or change over time.
|
32
|
+
def default_options
|
33
|
+
@default_options ||= { ref: "refs/heads/master" }
|
34
|
+
end
|
35
|
+
private :default_options
|
9
36
|
|
10
37
|
# Constructor for the Git source type
|
11
38
|
#
|
12
39
|
# @param url [String] url of git repo to use as source
|
13
40
|
# @param ref [String] ref to checkout from git repo
|
14
41
|
# @param workdir [String] working directory to clone into
|
15
|
-
def initialize(url,
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
@url = url
|
20
|
-
@ref = ref
|
42
|
+
def initialize(url, workdir:, **options)
|
43
|
+
opts = default_options.merge(options)
|
44
|
+
|
45
|
+
# Ensure that #url returns a URI object
|
46
|
+
@url = URI.parse(url.to_s)
|
47
|
+
@ref = opts[:ref]
|
21
48
|
@workdir = workdir
|
49
|
+
@ref_name, @ref_type, = @ref.split('/', 3).reverse
|
50
|
+
|
51
|
+
# We can test for Repo existence without cloning
|
52
|
+
raise Vanagon::InvalidRepo, "#{url} not a valid Git repo" unless valid_remote?
|
22
53
|
end
|
23
54
|
|
24
55
|
# Fetch the source. In this case, clone the repository into the workdir
|
25
56
|
# and check out the ref. Also sets the version if there is a git tag as
|
26
57
|
# a side effect.
|
27
58
|
def fetch
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
end
|
59
|
+
clone!
|
60
|
+
checkout!
|
61
|
+
version
|
62
|
+
update_submodules
|
63
|
+
end
|
64
|
+
|
65
|
+
def ref
|
66
|
+
@ref_name || @ref
|
37
67
|
end
|
38
68
|
|
39
69
|
# Return the correct incantation to cleanup the source directory for a given source
|
@@ -43,18 +73,97 @@ class Vanagon
|
|
43
73
|
"rm -rf #{dirname}"
|
44
74
|
end
|
45
75
|
|
46
|
-
# There is no md5 to manually verify here, so
|
76
|
+
# There is no md5 to manually verify here, so this is a noop.
|
47
77
|
def verify
|
48
|
-
# nothing to do here, so just return
|
78
|
+
# nothing to do here, so just tell users that and return
|
79
|
+
puts "Nothing to verify for '#{dirname}' (using Git reference '#{ref}')"
|
49
80
|
end
|
50
81
|
|
51
82
|
# The dirname to reference when building from the repo
|
52
83
|
#
|
53
84
|
# @return [String] the directory where the repo was cloned
|
54
85
|
def dirname
|
55
|
-
File.basename(
|
86
|
+
File.basename(url.path, ".git")
|
87
|
+
end
|
88
|
+
|
89
|
+
# Use `git describe` to lazy-load a version for this component
|
90
|
+
def version
|
91
|
+
@version ||= describe
|
92
|
+
end
|
93
|
+
|
94
|
+
# Perform a git clone of @url as a lazy-loaded
|
95
|
+
# accessor for @clone
|
96
|
+
def clone
|
97
|
+
@clone ||= ::Git.clone(url, dirname, path: workdir)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Attempt to connect to whatever URL is provided and
|
101
|
+
# return True or False depending on whether or not
|
102
|
+
# `git` thinks it's a valid Git repo.
|
103
|
+
#
|
104
|
+
# @return [Boolean] whether #url is a valid Git repo or not
|
105
|
+
def valid_remote?
|
106
|
+
self.class.valid_remote? url
|
107
|
+
end
|
108
|
+
private :valid_remote?
|
109
|
+
|
110
|
+
# Provide a list of remote refs (branches and tags)
|
111
|
+
def remote_refs
|
112
|
+
(remote['tags'].keys + remote['branches'].keys).uniq
|
113
|
+
end
|
114
|
+
private :remote_refs
|
115
|
+
|
116
|
+
# Provide a list of local refs (branches and tags)
|
117
|
+
def refs
|
118
|
+
(clone.tags.map(&:name) + clone.branches.map(&:name)).uniq
|
119
|
+
end
|
120
|
+
private :refs
|
121
|
+
|
122
|
+
# Clone a remote repo, make noise about it, and fail entirely
|
123
|
+
# if we're unable to retrieve the remote repo
|
124
|
+
def clone!
|
125
|
+
puts "Cloning Git repo '#{url}'"
|
126
|
+
puts "Successfully cloned '#{dirname}'" if clone
|
127
|
+
rescue Git::GitExecuteError
|
128
|
+
raise Vanagon::InvalidRepo, "Unable to clone from '#{url}'"
|
56
129
|
end
|
130
|
+
private :clone!
|
131
|
+
|
132
|
+
# Checkout desired ref/sha, make noise about it, and fail
|
133
|
+
# entirely if we're unable to checkout that given ref/sha
|
134
|
+
def checkout!
|
135
|
+
puts "Checking out '#{ref}'' from Git repo '#{dirname}'"
|
136
|
+
clone.checkout(ref)
|
137
|
+
rescue ::Git::GitExecuteError
|
138
|
+
raise Vanagon::CheckoutFailed, "unable to checkout #{ref} from '#{url}'"
|
139
|
+
end
|
140
|
+
private :checkout!
|
141
|
+
|
142
|
+
# Attempt to update submodules, and do not panic
|
143
|
+
# if there are no submodules to initialize
|
144
|
+
def update_submodules
|
145
|
+
puts "Attempting to update submodules for repo '#{dirname}'"
|
146
|
+
clone.update_submodules(init: true)
|
147
|
+
end
|
148
|
+
private :update_submodules
|
149
|
+
|
150
|
+
# Determines a version for the given directory based on the git describe
|
151
|
+
# for the repository
|
152
|
+
#
|
153
|
+
# @return [String] The version of the directory according to git describe
|
154
|
+
def describe
|
155
|
+
clone.describe(ref, tags: true)
|
156
|
+
rescue ::Git::GitExecuteError
|
157
|
+
warn "Directory '#{dirname}' cannot be versioned by Git. Maybe it hasn't been tagged yet?"
|
158
|
+
end
|
159
|
+
private :describe
|
57
160
|
end
|
58
161
|
end
|
59
162
|
end
|
163
|
+
|
164
|
+
class GitError < Error; end
|
165
|
+
# Raised when a URI is not a valid Source Control repo
|
166
|
+
class InvalidRepo < GitError; end
|
167
|
+
# Raised when checking out a given ref from a Git Repo fails
|
168
|
+
class CheckoutFailed < GitError; end
|
60
169
|
end
|