between_meals 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +2 -2
- data/lib/between_meals/changes/change.rb +3 -3
- data/lib/between_meals/changes/cookbook.rb +8 -8
- data/lib/between_meals/changes/databag.rb +3 -3
- data/lib/between_meals/changes/role.rb +4 -4
- data/lib/between_meals/changeset.rb +3 -3
- data/lib/between_meals/cmd.rb +44 -0
- data/lib/between_meals/knife.rb +52 -13
- data/lib/between_meals/repo.rb +74 -30
- data/lib/between_meals/repo/git.rb +49 -49
- data/lib/between_meals/repo/git/cmd.rb +49 -0
- data/lib/between_meals/repo/hg.rb +214 -0
- data/lib/between_meals/repo/hg/cmd.rb +72 -0
- data/lib/between_meals/repo/svn.rb +51 -68
- data/lib/between_meals/repo/svn/cmd.rb +56 -0
- data/lib/between_meals/util.rb +3 -3
- metadata +41 -8
@@ -1,39 +1,50 @@
|
|
1
1
|
# vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
|
2
2
|
|
3
3
|
# Copyright 2013-present Facebook
|
4
|
-
#
|
4
|
+
#
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
6
|
# you may not use this file except in compliance with the License.
|
7
7
|
# You may obtain a copy of the License at
|
8
|
-
#
|
8
|
+
#
|
9
9
|
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
10
|
+
#
|
11
11
|
# Unless required by applicable law or agreed to in writing, software
|
12
12
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
13
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
14
|
# See the License for the specific language governing permissions and
|
15
15
|
# limitations under the License.
|
16
16
|
|
17
|
+
# Require openssl in order to make rugged work reliably
|
18
|
+
require 'openssl'
|
19
|
+
|
17
20
|
require 'rugged'
|
18
21
|
require 'mixlib/shellout'
|
19
22
|
require 'between_meals/changeset'
|
23
|
+
require 'between_meals/repo/git/cmd'
|
20
24
|
|
21
25
|
module BetweenMeals
|
22
|
-
# Local checkout wrapper
|
23
26
|
class Repo
|
24
|
-
# Git provider
|
25
27
|
class Git < BetweenMeals::Repo
|
26
28
|
def setup
|
27
29
|
if File.exists?(File.expand_path(@repo_path))
|
28
|
-
|
30
|
+
begin
|
31
|
+
@repo = Rugged::Repository.new(File.expand_path(@repo_path))
|
32
|
+
rescue
|
33
|
+
@repo = nil
|
34
|
+
end
|
29
35
|
else
|
30
36
|
@repo = nil
|
31
37
|
end
|
32
38
|
@bin = 'git'
|
39
|
+
@cmd = BetweenMeals::Repo::Git::Cmd.new(
|
40
|
+
:bin => @bin,
|
41
|
+
:cwd => @repo_path,
|
42
|
+
:logger => @logger,
|
43
|
+
)
|
33
44
|
end
|
34
45
|
|
35
46
|
def exists?
|
36
|
-
|
47
|
+
!@repo.nil?
|
37
48
|
end
|
38
49
|
|
39
50
|
def head_rev
|
@@ -58,34 +69,30 @@ module BetweenMeals
|
|
58
69
|
end
|
59
70
|
|
60
71
|
def head_parents
|
61
|
-
@repo.head.target.parents
|
72
|
+
@repo.head.target.parents.map do |x|
|
73
|
+
{ :rev => x.tree.oid, :time => x.time }
|
74
|
+
end
|
62
75
|
end
|
63
76
|
|
64
77
|
def checkout(url)
|
65
|
-
|
66
|
-
"#{@bin} clone #{url} #{@repo} #{@repo_path}"
|
67
|
-
).run_command
|
68
|
-
s.error!
|
78
|
+
@cmd.clone(url, @repo_path)
|
69
79
|
@repo = Rugged::Repository.new(File.expand_path(@repo_path))
|
70
80
|
end
|
71
81
|
|
72
82
|
# Return files changed between two revisions
|
73
83
|
def changes(start_ref, end_ref)
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
:cwd => File.expand_path(@repo_path)
|
78
|
-
)
|
79
|
-
s.run_command.error!
|
84
|
+
valid_ref?(start_ref)
|
85
|
+
valid_ref?(end_ref) if end_ref
|
86
|
+
stdout = @cmd.diff(start_ref, end_ref).stdout
|
80
87
|
begin
|
81
|
-
parse_status(
|
88
|
+
parse_status(stdout).compact
|
82
89
|
rescue => e
|
83
90
|
# We've seen some weird non-reproducible failures here
|
84
91
|
@logger.error(
|
85
92
|
'Something went wrong. Please please report this output.'
|
86
93
|
)
|
87
94
|
@logger.error(e)
|
88
|
-
|
95
|
+
stdout.lines.each do |line|
|
89
96
|
@logger.error(line.strip)
|
90
97
|
end
|
91
98
|
exit(1)
|
@@ -93,16 +100,7 @@ module BetweenMeals
|
|
93
100
|
end
|
94
101
|
|
95
102
|
def update
|
96
|
-
cmd
|
97
|
-
"#{@bin} pull --rebase", :cwd => File.expand_path(@repo_path)
|
98
|
-
)
|
99
|
-
cmd.run_command
|
100
|
-
if cmd.exitstatus != 0
|
101
|
-
@logger.error('Something went wrong with git!')
|
102
|
-
@logger.error(cmd.stdout)
|
103
|
-
fail
|
104
|
-
end
|
105
|
-
cmd.stdout
|
103
|
+
@cmd.pull.stdout
|
106
104
|
end
|
107
105
|
|
108
106
|
# Return all files
|
@@ -110,33 +108,35 @@ module BetweenMeals
|
|
110
108
|
@repo.index.map { |x| { :path => x[:path], :status => :created } }
|
111
109
|
end
|
112
110
|
|
113
|
-
def
|
114
|
-
cmd
|
115
|
-
|
116
|
-
:cwd => File.expand_path(@repo_path)
|
117
|
-
)
|
118
|
-
cmd.run_command
|
119
|
-
if cmd.exitstatus != 0
|
120
|
-
@logger.error('Something went wrong with git!')
|
121
|
-
@logger.error(cmd.stdout)
|
122
|
-
fail
|
111
|
+
def upstream?(rev, master = 'remotes/trunk')
|
112
|
+
if @cmd.merge_base(rev, master).stdout.strip == rev
|
113
|
+
return true
|
123
114
|
end
|
124
|
-
|
115
|
+
return false
|
116
|
+
rescue
|
117
|
+
return false
|
125
118
|
end
|
126
119
|
|
127
|
-
|
120
|
+
def status
|
121
|
+
@cmd.status.stdout.strip
|
122
|
+
end
|
123
|
+
|
124
|
+
def name
|
125
|
+
@cmd.config('user.name').stdout.strip
|
126
|
+
end
|
127
|
+
|
128
|
+
def email
|
129
|
+
@cmd.config('user.email').stdout.strip
|
130
|
+
end
|
128
131
|
|
129
|
-
def
|
130
|
-
unless @repo.exists?(
|
132
|
+
def valid_ref?(ref)
|
133
|
+
unless @repo.exists?(ref)
|
131
134
|
fail Changeset::ReferenceError
|
132
135
|
end
|
133
|
-
unless end_ref.nil?
|
134
|
-
unless @repo.exists?(end_ref)
|
135
|
-
fail Changeset::ReferenceError
|
136
|
-
end
|
137
|
-
end
|
138
136
|
end
|
139
137
|
|
138
|
+
private
|
139
|
+
|
140
140
|
def parse_status(changes)
|
141
141
|
# man git-diff-files
|
142
142
|
# Possible status letters are:
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
|
2
|
+
|
3
|
+
# Copyright 2013-present Facebook
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'between_meals/cmd'
|
18
|
+
|
19
|
+
module BetweenMeals
|
20
|
+
class Repo
|
21
|
+
class Git < BetweenMeals::Repo
|
22
|
+
class Cmd < BetweenMeals::Cmd
|
23
|
+
def config(key)
|
24
|
+
cmd("config #{key}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def clone(url, repo_path)
|
28
|
+
cmd("clone #{url} #{repo_path}", '/tmp')
|
29
|
+
end
|
30
|
+
|
31
|
+
def diff(start_ref, end_ref)
|
32
|
+
cmd("diff --name-status #{start_ref} #{end_ref}")
|
33
|
+
end
|
34
|
+
|
35
|
+
def pull
|
36
|
+
cmd('pull --rebase')
|
37
|
+
end
|
38
|
+
|
39
|
+
def merge_base(rev, master)
|
40
|
+
cmd("merge-base #{rev} #{master}")
|
41
|
+
end
|
42
|
+
|
43
|
+
def status
|
44
|
+
cmd('status --porcelain 2>&1')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
# vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
|
2
|
+
|
3
|
+
# Copyright 2013-present Facebook
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'pathname'
|
18
|
+
require 'mixlib/shellout'
|
19
|
+
require 'between_meals/changeset'
|
20
|
+
require 'between_meals/repo/hg/cmd'
|
21
|
+
|
22
|
+
module BetweenMeals
|
23
|
+
class Repo
|
24
|
+
class Hg < BetweenMeals::Repo
|
25
|
+
def setup
|
26
|
+
@bin = 'hg'
|
27
|
+
@cmd = BetweenMeals::Repo::Hg::Cmd.new(
|
28
|
+
:bin => @bin,
|
29
|
+
:cwd => @repo_path,
|
30
|
+
:logger => @logger,
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def exists?
|
35
|
+
Dir.exists?(Pathname.new(@repo_path).join('.hg'))
|
36
|
+
end
|
37
|
+
|
38
|
+
def head_rev
|
39
|
+
@cmd.log('node').stdout
|
40
|
+
end
|
41
|
+
|
42
|
+
def checkout(url)
|
43
|
+
@cmd.clone(url, @repo_path)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Return files changed between two revisions
|
47
|
+
def changes(start_ref, end_ref)
|
48
|
+
valid_ref?(start_ref)
|
49
|
+
valid_ref?(end_ref) if end_ref
|
50
|
+
stdout = @cmd.status(start_ref, end_ref).stdout
|
51
|
+
begin
|
52
|
+
parse_status(stdout).compact
|
53
|
+
rescue => e
|
54
|
+
# We've seen some weird non-reproducible failures here
|
55
|
+
@logger.error(
|
56
|
+
'Something went wrong. Please please report this output.'
|
57
|
+
)
|
58
|
+
@logger.error(e)
|
59
|
+
stdout.lines.each do |line|
|
60
|
+
@logger.error(line.strip)
|
61
|
+
end
|
62
|
+
exit(1)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def update
|
67
|
+
@cmd.pull.stdout
|
68
|
+
rescue
|
69
|
+
@logger.error('Something went wrong with hg!')
|
70
|
+
@logger.error(cmd.stdout)
|
71
|
+
raise
|
72
|
+
end
|
73
|
+
|
74
|
+
# Return all files
|
75
|
+
def files
|
76
|
+
@cmd.manifest.stdout.split("\n").map do |x|
|
77
|
+
{ :path => x, :status => :created }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def head_parents
|
82
|
+
[{
|
83
|
+
:time => Time.parse(@cmd.log('date|isodate', 'master').stdout),
|
84
|
+
:rev => @cmd.log('node', 'master').stdout,
|
85
|
+
}]
|
86
|
+
rescue
|
87
|
+
[{
|
88
|
+
:time => nil,
|
89
|
+
:rev => nil,
|
90
|
+
}]
|
91
|
+
end
|
92
|
+
|
93
|
+
def last_author
|
94
|
+
[
|
95
|
+
/^.*<(.*)>$/,
|
96
|
+
/^(.*@.*)$/,
|
97
|
+
].each do |re|
|
98
|
+
m = @cmd.log('author').stdout.match(re)
|
99
|
+
return { :email => m[1] } if m
|
100
|
+
end
|
101
|
+
return { :email => nil }
|
102
|
+
end
|
103
|
+
|
104
|
+
def last_msg
|
105
|
+
@cmd.log('desc').stdout
|
106
|
+
rescue
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
110
|
+
def last_msg=(msg)
|
111
|
+
if last_msg.strip != msg.strip
|
112
|
+
@cmd.amend(msg.strip)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def email
|
117
|
+
username[2]
|
118
|
+
rescue
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
|
122
|
+
def name
|
123
|
+
username[1]
|
124
|
+
rescue
|
125
|
+
nil
|
126
|
+
end
|
127
|
+
|
128
|
+
def status
|
129
|
+
@cmd.status.stdout
|
130
|
+
end
|
131
|
+
|
132
|
+
def upstream?(rev)
|
133
|
+
# Check if commit is an ancestor of master
|
134
|
+
# Returns the diff if common ancestor is found,
|
135
|
+
# returns nothing if not
|
136
|
+
if @cmd.rev("'ancestor(master,#{rev}) & #{rev}'").stdout.empty?
|
137
|
+
return false
|
138
|
+
else
|
139
|
+
return true
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def valid_ref?(ref)
|
144
|
+
@cmd.rev(ref)
|
145
|
+
return true
|
146
|
+
rescue
|
147
|
+
raise Changeset::ReferenceError
|
148
|
+
end
|
149
|
+
|
150
|
+
private
|
151
|
+
|
152
|
+
def username
|
153
|
+
@cmd.username.stdout.lines.first.strip.match(/^(.*?)(?:\s<(.*)>)?$/)
|
154
|
+
end
|
155
|
+
|
156
|
+
def parse_status(changes)
|
157
|
+
# The codes used to show the status of files are:
|
158
|
+
#
|
159
|
+
# M = modified
|
160
|
+
# A = added
|
161
|
+
# R = removed
|
162
|
+
# C = clean
|
163
|
+
# ! = missing (deleted by non-hg command, but still tracked)
|
164
|
+
# ? = not tracked
|
165
|
+
# I = ignored
|
166
|
+
# = origin of the previous file (with --copies)
|
167
|
+
|
168
|
+
# rubocop:disable MultilineBlockChain
|
169
|
+
changes.lines.map do |line|
|
170
|
+
case line
|
171
|
+
when /^A (\S+)$/
|
172
|
+
{
|
173
|
+
:status => :added,
|
174
|
+
:path => Regexp.last_match(1)
|
175
|
+
}
|
176
|
+
when /^C (\S+)$/
|
177
|
+
{
|
178
|
+
:status => :clean,
|
179
|
+
:path => Regexp.last_match(1)
|
180
|
+
}
|
181
|
+
when /^R (\S+)$/
|
182
|
+
{
|
183
|
+
:status => :deleted,
|
184
|
+
:path => Regexp.last_match(1)
|
185
|
+
}
|
186
|
+
when /^M (\S+)$/
|
187
|
+
{
|
188
|
+
:status => :modified,
|
189
|
+
:path => Regexp.last_match(1)
|
190
|
+
}
|
191
|
+
when /^! (\S+)$/
|
192
|
+
{
|
193
|
+
:status => :missing,
|
194
|
+
:path => Regexp.last_match(1)
|
195
|
+
}
|
196
|
+
when /^\? (\S+)$/
|
197
|
+
{
|
198
|
+
:status => :untracked,
|
199
|
+
:path => Regexp.last_match(1)
|
200
|
+
}
|
201
|
+
when /^I (\S+)$/
|
202
|
+
{
|
203
|
+
:status => :ignored,
|
204
|
+
:path => Regexp.last_match(1)
|
205
|
+
}
|
206
|
+
else
|
207
|
+
fail 'No match'
|
208
|
+
end
|
209
|
+
end
|
210
|
+
# rubocop:enable MultilineBlockChain
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# vim: syntax=ruby:expandtab:shiftwidth=2:softtabstop=2:tabstop=2
|
2
|
+
|
3
|
+
# Copyright 2013-present Facebook
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
|
17
|
+
require 'between_meals/cmd'
|
18
|
+
require 'tempfile'
|
19
|
+
|
20
|
+
module BetweenMeals
|
21
|
+
class Repo
|
22
|
+
class Hg < BetweenMeals::Repo
|
23
|
+
class Cmd < BetweenMeals::Cmd
|
24
|
+
def rev(rev)
|
25
|
+
cmd("log -r #{rev}")
|
26
|
+
end
|
27
|
+
|
28
|
+
def log(template, rev = '.')
|
29
|
+
cmd("log -r #{rev} -l 1 -T '{#{template}}'")
|
30
|
+
end
|
31
|
+
|
32
|
+
def clone(url, repo_path)
|
33
|
+
cmd("clone #{url} #{repo_path}")
|
34
|
+
end
|
35
|
+
|
36
|
+
def pull
|
37
|
+
cmd('pull --rebase')
|
38
|
+
end
|
39
|
+
|
40
|
+
def manifest
|
41
|
+
cmd('manifest')
|
42
|
+
end
|
43
|
+
|
44
|
+
def username
|
45
|
+
cmd('config ui.username')
|
46
|
+
end
|
47
|
+
|
48
|
+
def amend(msg)
|
49
|
+
f = Tempfile.new('between_meals.hg.amend')
|
50
|
+
begin
|
51
|
+
f.write(msg)
|
52
|
+
f.flush
|
53
|
+
cmd("commit --amend -l #{f.path}")
|
54
|
+
ensure
|
55
|
+
f.close
|
56
|
+
f.unlink
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def status(start_ref = nil, end_ref = nil)
|
61
|
+
if start_ref && end_ref
|
62
|
+
cmd("status --rev #{start_ref} --rev #{end_ref}")
|
63
|
+
elsif start_ref
|
64
|
+
cmd("status --rev #{start_ref}")
|
65
|
+
else
|
66
|
+
cmd('status')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|