squared 0.3.11 → 0.4.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/CHANGELOG.md +44 -126
- data/README.md +13 -2
- data/README.ruby.md +169 -89
- data/lib/squared/app.rb +1 -0
- data/lib/squared/common/base.rb +6 -1
- data/lib/squared/common/class.rb +1 -1
- data/lib/squared/common/format.rb +32 -22
- data/lib/squared/common/prompt.rb +3 -3
- data/lib/squared/common/shell.rb +53 -41
- data/lib/squared/common/utils.rb +55 -2
- data/lib/squared/config.rb +1 -1
- data/lib/squared/version.rb +1 -1
- data/lib/squared/workspace/application.rb +20 -17
- data/lib/squared/workspace/project/base.rb +458 -170
- data/lib/squared/workspace/project/docker.rb +572 -0
- data/lib/squared/workspace/project/git.rb +472 -235
- data/lib/squared/workspace/project/node.rb +53 -58
- data/lib/squared/workspace/project/python.rb +130 -41
- data/lib/squared/workspace/project/ruby.rb +47 -58
- data/lib/squared/workspace/project.rb +7 -1
- data/lib/squared/workspace/repo.rb +11 -4
- data/lib/squared/workspace/series.rb +1 -1
- metadata +4 -6
@@ -1,5 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'date'
|
4
|
+
require 'time'
|
5
|
+
require 'digest'
|
6
|
+
|
3
7
|
module Squared
|
4
8
|
module Workspace
|
5
9
|
module Git
|
@@ -7,29 +11,27 @@ module Squared
|
|
7
11
|
GIT_PROTO = %r{^(?:https?|ssh|git|file)://}i.freeze
|
8
12
|
private_constant :GIT_REPO, :GIT_PROTO
|
9
13
|
|
10
|
-
|
14
|
+
attr_reader :revfile
|
15
|
+
|
16
|
+
def git(name, uri = nil, base: nil, repo: [], options: {}, cache: nil)
|
11
17
|
data = {}
|
12
18
|
check = ->(proj) { proj.is_a?(Project::Git) && !proj.exclude?(Project::Git.ref) && git_clone?(proj.path) }
|
13
19
|
if uri.is_a?(Array)
|
14
20
|
base = name
|
15
|
-
uri.each
|
16
|
-
if (proj = @project[val.to_s]) && check.(proj)
|
17
|
-
repo << proj
|
18
|
-
end
|
19
|
-
end
|
21
|
+
uri.each { |val| repo << proj if (proj = @project[val.to_s]) && check.(proj) }
|
20
22
|
elsif uri
|
21
23
|
data[name.to_s] = uri
|
22
24
|
elsif name.is_a?(Enumerable)
|
23
25
|
data = name.to_h
|
24
|
-
elsif name.is_a?(String) && name
|
26
|
+
elsif name.is_a?(String) && name.match?(GIT_PROTO)
|
25
27
|
base = name
|
26
28
|
@project.each_value { |proj| repo << proj if !proj.parent && check.(proj) }
|
27
29
|
else
|
28
|
-
warn log_message(Logger::WARN, name, subject: 'git', hint: 'invalid') if warning
|
30
|
+
warn log_message(Logger::WARN, name, subject: 'git', hint: 'invalid', pass: true) if warning
|
29
31
|
return self
|
30
32
|
end
|
31
33
|
if base
|
32
|
-
base = base
|
34
|
+
base = base.match?(GIT_PROTO) ? "#{base.chomp('/')}/" : @root.join(base)
|
33
35
|
repo.each do |target|
|
34
36
|
if target.is_a?(Project::Git)
|
35
37
|
data[target.localname] = target.project
|
@@ -59,6 +61,23 @@ module Squared
|
|
59
61
|
(GIT_REPO[main] ||= {})[key] = [uri.to_s, opts]
|
60
62
|
(@kind[key] ||= []) << Project::Git
|
61
63
|
end
|
64
|
+
if cache == true
|
65
|
+
revbuild
|
66
|
+
elsif cache
|
67
|
+
revbuild(file: cache)
|
68
|
+
end
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
def revbuild(file: nil)
|
73
|
+
@revfile = @home.join(file || "#{@main}.revb")
|
74
|
+
@revdoc = JSON.parse(@revfile.read) if @revfile.exist?
|
75
|
+
rescue StandardError => e
|
76
|
+
@revfile = nil
|
77
|
+
warn log_message(Logger::WARN, e, pass: true) if @warning
|
78
|
+
self
|
79
|
+
else
|
80
|
+
@revdoc = {} unless @revdoc.is_a?(Hash)
|
62
81
|
self
|
63
82
|
end
|
64
83
|
|
@@ -66,36 +85,86 @@ module Squared
|
|
66
85
|
(ret = GIT_REPO[main]) && ret[name]
|
67
86
|
end
|
68
87
|
|
88
|
+
def rev_entry(*keys, val: nil, create: true)
|
89
|
+
return unless @revdoc
|
90
|
+
return @revdoc.dig(*keys) unless val
|
91
|
+
|
92
|
+
data = @revdoc
|
93
|
+
last = keys.pop
|
94
|
+
for key in keys
|
95
|
+
if data[key].is_a?(Hash)
|
96
|
+
data = data[key]
|
97
|
+
elsif create
|
98
|
+
data = data[key] = {}
|
99
|
+
else
|
100
|
+
return
|
101
|
+
end
|
102
|
+
end
|
103
|
+
data[last] = val
|
104
|
+
end
|
105
|
+
|
106
|
+
def rev_timeutc(*keys)
|
107
|
+
rev_entry(*keys, val: rev_timenow)
|
108
|
+
end
|
109
|
+
|
110
|
+
def rev_timesince(*keys, clock: false)
|
111
|
+
epoch = rev_timenow - rev_entry(*keys).to_i
|
112
|
+
rescue StandardError
|
113
|
+
nil
|
114
|
+
else
|
115
|
+
time_format(epoch, clock: clock)
|
116
|
+
end
|
117
|
+
|
118
|
+
def rev_clear(name)
|
119
|
+
rev_write if rev_entry(name, 'revision', val: '', create: false)
|
120
|
+
end
|
121
|
+
|
122
|
+
def rev_write(name = nil, data = nil, utc: nil)
|
123
|
+
return unless @revfile
|
124
|
+
|
125
|
+
if name
|
126
|
+
data&.each { |key, val| rev_entry(name, key, val: val) }
|
127
|
+
rev_timeutc(name, utc) if utc
|
128
|
+
end
|
129
|
+
File.write(@revfile, JSON.pretty_generate(@revdoc))
|
130
|
+
end
|
131
|
+
|
69
132
|
def git_clone?(path, name = nil)
|
70
133
|
return false if name && !git_repo(name)
|
71
134
|
|
72
135
|
!path.exist? || path.empty?
|
73
136
|
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def rev_timenow
|
141
|
+
DateTime.now.strftime('%Q').to_i + time_offset
|
142
|
+
end
|
74
143
|
end
|
75
144
|
Application.include Git
|
76
145
|
|
77
146
|
module Project
|
78
147
|
class Git < Base
|
79
|
-
include Prompt
|
80
|
-
|
81
148
|
OPT_GIT = {
|
82
|
-
|
83
|
-
|
149
|
+
common: %w[bare p|paginate P|no-pager glob-pathspecs icase-pathspecs literal-pathspecs no-optional-locks
|
150
|
+
no-replace-objects noglob-pathspecs c=q config-env=q exec-path=p namespace=p].freeze,
|
151
|
+
branch: %w[a|all create-reflog i|ignore-case q|quiet r|remotes v|verbose abbrev=i color=b column=b
|
152
|
+
contains=b format=q merged=b no-contains=b no-merged=b points-at=e u|set-upstream-to=e sort=q
|
84
153
|
t|track=b].freeze,
|
85
154
|
checkout: %w[l d|detach f|force ignore-other-worktrees ignore-skip-worktree-bits m|merge p|patch
|
86
|
-
pathspec-file-nul q
|
155
|
+
pathspec-file-nul q quiet orphan=e ours theirs conflict=b pathspec-from-file=p
|
87
156
|
t|track=b].freeze,
|
157
|
+
clean: %w[d x X f|force i|interactive n|dry-run q|quiet e|exlcude=q].freeze,
|
88
158
|
diff: {
|
89
159
|
base: %w[0 1|base 2|ours 3|theirs].freeze,
|
90
160
|
show: %w[s exit-code histogram].freeze
|
91
161
|
}.freeze,
|
92
162
|
fetch: {
|
93
|
-
base: %w[multiple progress P|prune-tags refetch stdin u|update-head-ok
|
163
|
+
base: %w[multiple progress P|prune-tags refetch stdin u|update-head-ok recurse-submodules=b
|
94
164
|
recurse-submodules-default=b].freeze,
|
95
|
-
pull: %w[4 6 n t a|append atomic dry-run f|force k|keep negotiate-only prefetch p|prune q|quiet
|
165
|
+
pull: %w[4 6 n t a|append atomic dry-run f|force k|keep n|negotiate-only prefetch p|prune q|quiet
|
96
166
|
set-upstream unshallow update-shallow v|verbose deepen=i depth=i j|jobs=i negotiation-tip=q
|
97
|
-
|
98
|
-
upload-pack=e].freeze
|
167
|
+
refmap=q o|server-option=q shallow-exclude=e shallow-since=b upload-pack=q].freeze
|
99
168
|
}.freeze,
|
100
169
|
log: {
|
101
170
|
base: %w[all all-match alternate-refs author-date-order basic-regexp bisect boundary cherry cherry-mark
|
@@ -103,47 +172,54 @@ module Squared
|
|
103
172
|
first-parent F|fixed-strings follow full-diff full-history ignore-missing invert-grep left-only
|
104
173
|
merge log-size no-max-parents no-min-parents not P|perl-regexp reflog i|regexp-ignore-case
|
105
174
|
remove-empty reverse right-only simplify-by-decoration simplify-merges single-worktree show-pulls
|
106
|
-
source sparse stdin topo-order g|walk-reflogs after=q ancestry-path=
|
175
|
+
source sparse stdin topo-order g|walk-reflogs after=q ancestry-path=b? author=q before=q
|
107
176
|
branches=q? committer=q decorate=b decorate-refs=q decorate-refs-exclude=q exclude=q
|
108
177
|
exclude-hidden=b? glob=q grep=q grep-reflog=q L=q n|max-count=i max-parents=i min-parents=i
|
109
178
|
no-walk=b? remotes=q? since=q since-as-filter=q skip=i tags=q? until=q].freeze,
|
110
179
|
format: %w[t children combined-all-paths oneline left-right no-diff-merges parents relative-date
|
111
|
-
show-signature date=q diff-merges=b encoding=b expand-tabs=i format=q notes=
|
180
|
+
show-signature date=q diff-merges=b encoding=b expand-tabs=i format=q notes=q pretty=q?
|
112
181
|
show-linear-break=q?].freeze,
|
113
182
|
diff: %w[p R u z l=i G=q O=q S=q binary check compact-summary cumulative find-copies-harder full-index
|
114
183
|
W|function-context w|ignore-all-space ignore-blank-lines ignore-cr-at-eol ignore-space-at-eol
|
115
184
|
b|ignore-space-change D|irreversible-delete graph ita-invisible-in-index minimal name-only
|
116
185
|
name-status no-color-moved-ws no-prefix no-renames numstat patch-with-raw patch-with-stat patience
|
117
|
-
pickaxe-all pickaxe-regex raw shortstat summary a|text abbrev=i? anchored=q B|break-rewrites=
|
118
|
-
color=b color-moved=b color-moved-ws=b color-words=q? diff-algorithm=b diff-filter=e? X|dirstat=
|
119
|
-
dirstat-by-file=q? dst-prefix=q C|find-copies=
|
186
|
+
pickaxe-all pickaxe-regex raw shortstat summary a|text abbrev=i? anchored=q B|break-rewrites=b?
|
187
|
+
color=b color-moved=b color-moved-ws=b color-words=q? diff-algorithm=b diff-filter=e? X|dirstat=q?
|
188
|
+
dirstat-by-file=q? dst-prefix=q C|find-copies=i? find-object=b M|find-renames=i?
|
120
189
|
I|ignore-matching-lines=q ignore-submodules=b inter-hunk-context=i line-prefix=q output=p
|
121
190
|
output-indicator-context=q output-indicator-new=q output-indicator-old=q relative=p rotate-to=p
|
122
191
|
skip-to=p src-prefix=q stat=q? stat-width=i stat-name-width=i stat-count=i submodule=b? U|unified=i
|
123
|
-
word-diff=b? word-diff-regex=q ws-error-
|
192
|
+
word-diff=b? word-diff-regex=q ws-error-highligt=q].freeze
|
124
193
|
}.freeze,
|
125
|
-
ls_files: %w[
|
126
|
-
|
194
|
+
ls_files: %w[z debug deduplicate directory eol error-unmatch exclude-standard full-name k|killed
|
195
|
+
no-empty-directory recurse-submodules sparse s|stage u|unmerged abbrev=i x|exclude=q
|
127
196
|
X|exclude-from=p exclude-per-directory=p format=q with-tree=q].freeze,
|
128
|
-
ls_remote: %w[exit-code get-url q|quiet o|server-option=
|
129
|
-
|
130
|
-
|
197
|
+
ls_remote: %w[exit-code get-url q|quiet o|server-option=q symref sort=q upload-pack=q].freeze,
|
198
|
+
mv: %w[k f|force n|dry-run v|verbose].freeze,
|
199
|
+
pull: %w[e n allow-unrelated-histories ff-only S|gpg-sign=qq log=i r|rebase=b? s|strategy=b
|
200
|
+
X|strategy-option=b].freeze,
|
201
|
+
merge: %w[e n allow-unrelated-histories ff-only m=q q|quiet v|verbose cleanup=b F|file=p S|gpg-sign=qq
|
202
|
+
into-name=e log=i s|strategy=b X|strategy-option=b].freeze,
|
131
203
|
rebase: %w[n C=i allow-empty-message apply committer-date-is-author-date edit-todo f|force-rebase ignore-date
|
132
|
-
ignore-whitespace i|interactive keep-base m
|
133
|
-
reset-author-date root show-current-patch signoff v|verbose empty=b S|gpg-sign=
|
134
|
-
s|strategy=b X|strategy-option=b whitespace=
|
204
|
+
ignore-whitespace i|interactive keep-base m merge no-ff q|quiet quit r|rebase-merges=b?
|
205
|
+
reset-author-date root show-current-patch signoff v|verbose empty=b S|gpg-sign=qq onto=e
|
206
|
+
s|strategy=b X|strategy-option=b whitespace=b].freeze,
|
135
207
|
reset: %w[N pathspec-file-nul q|quiet pathspec-from-file=p].freeze,
|
136
208
|
restore: %w[ignore-unmerged ignore-skip-worktree-bits m|merge ours p|patch pathspec-file-nul S|staged theirs
|
137
209
|
W|worktree conflict=b pathspec-from-file=p s|source=q].freeze,
|
210
|
+
revert: %w[e abort continue no-commit quit reference skip cleanup=b S|gpg-sign=qq m|mainline=i s|signoff
|
211
|
+
strategy=b X|strategy-option=b].freeze,
|
138
212
|
rev_parse: {
|
139
213
|
output: %w[absolute-git-dir all flags git-common-dir git-dir is-bare-repository is-inside-git-dir
|
140
|
-
is-inside-work-tree is-shallow-repository local-env-vars no-flags no-revs not q|quiet
|
141
|
-
shared-index-path show-cdup show-prefix show-toplevel show-superproject-working-tree
|
142
|
-
symbolic symbolic-full-name verify abbrev-ref=b? after=q before=q default=
|
143
|
-
exclude=q exclude-hidden=b glob=q git-path=p path-format=b? prefix=q branches=q?
|
144
|
-
resolve-git-dir=p short=i? show-object-format=b? since=q tags=q? until=q].freeze,
|
214
|
+
is-inside-work-tree is-shallow-repository local-env-vars no-flags no-revs not q|quiet sq
|
215
|
+
revs-only shared-index-path show-cdup show-prefix show-toplevel show-superproject-working-tree
|
216
|
+
sq-quote symbolic symbolic-full-name verify abbrev-ref=b? after=q before=q default=q
|
217
|
+
disambiguate=b exclude=q exclude-hidden=b glob=q git-path=p path-format=b? prefix=q branches=q?
|
218
|
+
remotes=q? resolve-git-dir=p short=i? show-object-format=b? since=q tags=q? until=q].freeze,
|
145
219
|
parseopt: %w[keep-dashdash stop-at-non-option stuck-long].freeze
|
146
220
|
}.freeze,
|
221
|
+
rm: %w[r cached f|force n|dry-run ignore-unmatch pathspec-file-nul q|quiet sparse v|verbose
|
222
|
+
pathspec-from-file=p].freeze,
|
147
223
|
show: %w[t combined-all-paths no-diff-merges remerge-diff show-signature diff-merges=b encoding=b
|
148
224
|
expand-tabs=i notes=q show-notes=q?].freeze,
|
149
225
|
stash: {
|
@@ -153,7 +229,8 @@ module Squared
|
|
153
229
|
pop: %w[index].freeze,
|
154
230
|
apply: %w[index].freeze
|
155
231
|
}.freeze,
|
156
|
-
|
232
|
+
status: %w[untracked-files=b? u|ignore-submodules=m? ignored=b?],
|
233
|
+
tag: %w[create-reflog column=b contains=b? format=q merged=b? n=i no-contains=b? no-merged=b? points-at=q
|
157
234
|
sort=q].freeze,
|
158
235
|
no: {
|
159
236
|
fetch: {
|
@@ -169,20 +246,26 @@ module Squared
|
|
169
246
|
tag: %w[column].freeze,
|
170
247
|
branch: %w[color-moved column color track].freeze,
|
171
248
|
checkout: %w[overwrite-ignore guess overlay progress recurse-submodules track].freeze,
|
249
|
+
merge: %w[autostash edit ff gpg-sign log progress overwrite-ignore rerere-autoupdate signoff squash stat
|
250
|
+
verify verify-signatures].freeze,
|
172
251
|
rebase: %w[autosquash autostash fork-point gpg-sign keep-empty reapply-cherry-picks reschedule-failed-exec
|
173
252
|
rerere-autoupdate stat update-refs verify].freeze,
|
174
253
|
reset: %w[refresh].freeze,
|
175
254
|
restore: %w[overlay progress recurse-submodules].freeze,
|
255
|
+
revert: %w[edit gpg-sign rerere-autoupdate].freeze,
|
176
256
|
show: %w[standard-notes].freeze
|
177
257
|
}.freeze
|
178
|
-
}
|
258
|
+
}.freeze
|
179
259
|
VAL_GIT = {
|
260
|
+
merge: {
|
261
|
+
send: %w[continue abort quit].freeze
|
262
|
+
}.freeze,
|
180
263
|
rebase: {
|
181
264
|
send: %w[continue skip abort quit].freeze,
|
182
265
|
value: %w[true false merges interactive].freeze
|
183
266
|
}.freeze,
|
184
267
|
reset: %w[soft mixed hard merge keep recurse-submodules no-recurse-submodules].freeze
|
185
|
-
}
|
268
|
+
}.freeze
|
186
269
|
private_constant :OPT_GIT, :VAL_GIT
|
187
270
|
|
188
271
|
class << self
|
@@ -214,7 +297,7 @@ module Squared
|
|
214
297
|
end
|
215
298
|
|
216
299
|
def tasks
|
217
|
-
%i[pull rebase fetch clone stash status].freeze
|
300
|
+
%i[pull rebase fetch clone stash status branch revbuild].freeze
|
218
301
|
end
|
219
302
|
|
220
303
|
def batchargs
|
@@ -232,24 +315,25 @@ module Squared
|
|
232
315
|
'branch' => %i[create set delete move copy list edit current].freeze,
|
233
316
|
'checkout' => %i[commit branch track detach path].freeze,
|
234
317
|
'commit' => %i[add all amend amend-orig].freeze,
|
235
|
-
'diff' => %i[head
|
318
|
+
'diff' => %i[head branch files view between contain].freeze,
|
236
319
|
'fetch' => %i[origin remote].freeze,
|
237
|
-
'files' => %i[cached modified deleted others].freeze,
|
320
|
+
'files' => %i[cached modified deleted others ignored].freeze,
|
321
|
+
'git' => %i[clean mv restore revert rm].freeze,
|
238
322
|
'log' => %i[view between contain].freeze,
|
323
|
+
'merge' => %i[commit no-commit send].freeze,
|
239
324
|
'pull' => %i[origin remote].freeze,
|
240
325
|
'rebase' => %i[branch onto send].freeze,
|
241
326
|
'refs' => %i[heads tags remote].freeze,
|
242
327
|
'reset' => %i[commit index patch mode].freeze,
|
243
|
-
'
|
244
|
-
'rev' => %i[commit branch output parseopt].freeze,
|
328
|
+
'rev' => %i[commit branch output parseopt build].freeze,
|
245
329
|
'show' => %i[format oneline].freeze,
|
246
|
-
'stash' => %i[push pop apply drop
|
330
|
+
'stash' => %i[push pop apply drop list].freeze,
|
247
331
|
'tag' => %i[add delete list].freeze
|
248
332
|
}.freeze
|
249
333
|
|
250
334
|
def initialize(*, **)
|
251
335
|
super
|
252
|
-
initialize_ref
|
336
|
+
initialize_ref Git.ref if gitpath.exist?
|
253
337
|
end
|
254
338
|
|
255
339
|
def ref
|
@@ -294,19 +378,6 @@ module Squared
|
|
294
378
|
commit(flag, refs: refs)
|
295
379
|
end
|
296
380
|
end
|
297
|
-
when 'restore'
|
298
|
-
if flag == :source
|
299
|
-
format_desc action, flag, 'tree,opts*,pathspec*'
|
300
|
-
task flag, [:tree] do |_, args|
|
301
|
-
tree = param_guard(action, flag, args: args, key: :tree)
|
302
|
-
restore(flag, args.extras, tree: tree)
|
303
|
-
end
|
304
|
-
else
|
305
|
-
format_desc action, flag, 'opts*,pathspec+'
|
306
|
-
task flag do |_, args|
|
307
|
-
restore flag, args.to_a
|
308
|
-
end
|
309
|
-
end
|
310
381
|
when 'tag'
|
311
382
|
case flag
|
312
383
|
when :list
|
@@ -340,9 +411,19 @@ module Squared
|
|
340
411
|
case flag
|
341
412
|
when :view, :between, :contain
|
342
413
|
if flag == :view && action == 'log'
|
343
|
-
format_desc action, flag, '(^)commit*,pathspec*,opts*'
|
414
|
+
format_desc action, flag, '(^)commit/H0*,pathspec*,opts*'
|
344
415
|
task flag do |_, args|
|
345
|
-
|
416
|
+
index = []
|
417
|
+
args.to_a.each do |val|
|
418
|
+
if val =~ /^H(\d+)$/
|
419
|
+
index << "HEAD~#{$1}"
|
420
|
+
elsif (sha = commithash(val))
|
421
|
+
index << sha
|
422
|
+
elsif val.start_with?('^') || (!%r{^[.\\/]}.match?(val) && !%r{[\\/]$}.match?(val))
|
423
|
+
index << shell_quote(val)
|
424
|
+
end
|
425
|
+
end
|
426
|
+
logx(flag, args.to_a.drop(index.size), index: index)
|
346
427
|
end
|
347
428
|
else
|
348
429
|
format_desc action, flag, 'commit1,commit2,pathspec*,opts*'
|
@@ -352,10 +433,16 @@ module Squared
|
|
352
433
|
__send__(action == 'log' ? :logx : :diff, flag, args.extras, range: [commit1, commit2])
|
353
434
|
end
|
354
435
|
end
|
355
|
-
when :head
|
356
|
-
format_desc action, flag, 'opts*,pathspec*'
|
436
|
+
when :head
|
437
|
+
format_desc action, flag, 'commit/H0*,opts*,pathspec*'
|
357
438
|
task flag do |_, args|
|
358
|
-
|
439
|
+
index = []
|
440
|
+
args.to_a.each do |val|
|
441
|
+
break unless val =~ /^H(\d+)$/ || (sha = commithash(val))
|
442
|
+
|
443
|
+
index << ($1 ? "HEAD~#{$1}" : sha)
|
444
|
+
end
|
445
|
+
diff(flag, args.to_a.drop(index.size), index: index)
|
359
446
|
end
|
360
447
|
when :branch
|
361
448
|
format_desc action, flag, 'name,opts*,pathspec*'
|
@@ -406,7 +493,7 @@ module Squared
|
|
406
493
|
format_desc action, flag, 'branch/commit,opts*'
|
407
494
|
task flag, [:commit] do |_, args|
|
408
495
|
commit = param_guard(action, flag, args: args, key: :commit)
|
409
|
-
checkout(flag,
|
496
|
+
checkout(flag, commit: commit)
|
410
497
|
end
|
411
498
|
when :detach
|
412
499
|
format_desc action, flag, 'branch/commit?'
|
@@ -500,7 +587,7 @@ module Squared
|
|
500
587
|
show args.format, args.extras
|
501
588
|
end
|
502
589
|
end
|
503
|
-
when 'rebase'
|
590
|
+
when 'rebase', 'merge'
|
504
591
|
case flag
|
505
592
|
when :branch
|
506
593
|
format_desc action, flag, 'opts*,upstream?,branch?'
|
@@ -515,11 +602,18 @@ module Squared
|
|
515
602
|
upstream = param_guard(action, flag, args: args, key: :upstream)
|
516
603
|
rebase(flag, commit: commit, upstream: upstream, branch: args.branch)
|
517
604
|
end
|
605
|
+
when :commit, :'no-commit'
|
606
|
+
format_desc action, flag, 'branch/commit+,opts*'
|
607
|
+
task flag do |_, args|
|
608
|
+
args = param_guard(action, flag, args: args.to_a)
|
609
|
+
merge flag, args
|
610
|
+
end
|
518
611
|
when :send
|
519
|
-
format_desc(action, flag, VAL_GIT[
|
612
|
+
format_desc(action, flag, VAL_GIT[action.to_sym][:send], arg: nil)
|
520
613
|
task flag, [:command] do |_, args|
|
521
|
-
command = param_guard(action, flag, args: args, key: :command
|
522
|
-
|
614
|
+
command = param_guard(action, flag, args: args, key: :command,
|
615
|
+
values: VAL_GIT[action.to_sym][:send])
|
616
|
+
__send__(action, flag, command: command)
|
523
617
|
end
|
524
618
|
end
|
525
619
|
when 'rev'
|
@@ -540,6 +634,11 @@ module Squared
|
|
540
634
|
task flag, [:ref] do |_, args|
|
541
635
|
rev_parse(flag, ref: args.ref)
|
542
636
|
end
|
637
|
+
when :build
|
638
|
+
format_desc action, flag, OPT_GIT[:status]
|
639
|
+
task flag do |_, args|
|
640
|
+
revbuild flag, args.to_a
|
641
|
+
end
|
543
642
|
else
|
544
643
|
format_desc action, flag, 'opts*,args*'
|
545
644
|
task flag do |_, args|
|
@@ -551,7 +650,7 @@ module Squared
|
|
551
650
|
format_desc action, flag, 'remote,opts*,pattern*'
|
552
651
|
task flag, [:remote] do |_, args|
|
553
652
|
remote = param_guard(action, flag, args: args, key: :remote)
|
554
|
-
ls_remote(flag, args.
|
653
|
+
ls_remote(flag, args.to_a.drop(1), remote: remote)
|
555
654
|
end
|
556
655
|
else
|
557
656
|
format_desc action, flag, 'opts*,pattern*'
|
@@ -559,6 +658,18 @@ module Squared
|
|
559
658
|
__send__(action == 'refs' ? :ls_remote : :ls_files, flag, args.to_a)
|
560
659
|
end
|
561
660
|
end
|
661
|
+
when 'git'
|
662
|
+
format_desc(action, flag, 'opts*', before: case flag
|
663
|
+
when :rm
|
664
|
+
'source+,destination'
|
665
|
+
when :revert
|
666
|
+
'commit+'
|
667
|
+
else
|
668
|
+
'pathspec*'
|
669
|
+
end)
|
670
|
+
task flag do |_, args|
|
671
|
+
git(flag, args.to_a)
|
672
|
+
end
|
562
673
|
end
|
563
674
|
end
|
564
675
|
end
|
@@ -571,12 +682,19 @@ module Squared
|
|
571
682
|
super
|
572
683
|
end
|
573
684
|
|
685
|
+
def depend(*, **)
|
686
|
+
workspace.rev_clear name
|
687
|
+
super
|
688
|
+
end
|
689
|
+
|
690
|
+
def clean(*, **)
|
691
|
+
workspace.rev_clear name
|
692
|
+
super
|
693
|
+
end
|
694
|
+
|
574
695
|
def pull(flag = nil, opts = [], sync: invoked_sync?('pull', flag), remote: nil)
|
575
|
-
cmd = git_session
|
576
|
-
if
|
577
|
-
cmd << '--rebase'
|
578
|
-
cmd << '--autostash' if option('autostash')
|
579
|
-
elsif (val = option('rebase', ignore: false))
|
696
|
+
cmd, opts = git_session('pull', flag && "--#{flag}", opts: opts)
|
697
|
+
if (val = option('rebase', ignore: false))
|
580
698
|
cmd << case val
|
581
699
|
when '0'
|
582
700
|
'--no-rebase'
|
@@ -588,8 +706,8 @@ module Squared
|
|
588
706
|
no: OPT_GIT[:no][:pull] + OPT_GIT[:no][:fetch][:pull], remote: remote, flag: flag)
|
589
707
|
source(sync: sync, sub: if verbose
|
590
708
|
[
|
591
|
-
{ pat: /^(.+)(\|\s+\d+\s+)([^-]*)(-+)(.*)$/, styles: :red, index: 4 },
|
592
|
-
{ pat: /^(.+)(\|\s+\d+\s+)(\++)(-*)(.*)$/, styles: :green, index: 3 }
|
709
|
+
{ pat: /^(.+)(\|\s+\d+\s+)([^-]*)(-+)(.*)$/, styles: color(:red), index: 4 },
|
710
|
+
{ pat: /^(.+)(\|\s+\d+\s+)(\++)(-*)(.*)$/, styles: color(:green), index: 3 }
|
593
711
|
]
|
594
712
|
end, **threadargs)
|
595
713
|
end
|
@@ -598,7 +716,7 @@ module Squared
|
|
598
716
|
command: nil)
|
599
717
|
return pull(:rebase, sync: sync) unless flag
|
600
718
|
|
601
|
-
cmd = git_session
|
719
|
+
cmd, opts = git_session('rebase', opts: opts)
|
602
720
|
case flag
|
603
721
|
when :branch
|
604
722
|
branch = option_sanitize(opts, OPT_GIT[:rebase], no: OPT_GIT[:no][:rebase]).first
|
@@ -627,7 +745,7 @@ module Squared
|
|
627
745
|
end
|
628
746
|
|
629
747
|
def fetch(flag = nil, opts = [], sync: invoked_sync?('fetch', flag), remote: nil)
|
630
|
-
cmd = git_session
|
748
|
+
cmd, opts = git_session('fetch', opts: opts)
|
631
749
|
cmd << '--all' if !remote && !opts.include?('multiple') && option('all')
|
632
750
|
cmd << '--verbose' if verbose && !opts.include?('quiet')
|
633
751
|
append_pull(opts, collect_hash(OPT_GIT[:fetch]), no: collect_hash(OPT_GIT[:no][:fetch]),
|
@@ -659,22 +777,14 @@ module Squared
|
|
659
777
|
|
660
778
|
def stash(flag = nil, opts = [], sync: invoked_sync?('stash', flag))
|
661
779
|
if flag
|
662
|
-
cmd = git_session
|
663
|
-
|
664
|
-
refs = option_sanitize(opts, list).first
|
780
|
+
cmd, opts = git_session('stash', flag, opts: opts)
|
781
|
+
refs = option_sanitize(opts, OPT_GIT[:stash][:common] + OPT_GIT[:stash].fetch(flag, [])).first
|
665
782
|
case flag
|
666
783
|
when :push
|
667
784
|
append_pathspec refs
|
668
785
|
when :pop, :apply, :drop
|
669
|
-
|
670
|
-
|
671
|
-
option_clear refs
|
672
|
-
end
|
673
|
-
when :clear
|
674
|
-
if confirm("Remove #{sub_style('all', styles: theme[:active])} the stash entries? [y/N] ", 'N')
|
675
|
-
source(stdout: true)
|
676
|
-
end
|
677
|
-
return
|
786
|
+
cmd << shell_quote(refs.pop)
|
787
|
+
option_clear refs
|
678
788
|
when :list
|
679
789
|
out, banner, from = source(io: true)
|
680
790
|
print_item banner
|
@@ -683,17 +793,16 @@ module Squared
|
|
683
793
|
return
|
684
794
|
end
|
685
795
|
else
|
686
|
-
git_session
|
796
|
+
git_session('stash', 'push', opts: opts)
|
687
797
|
append_option(%w[all keep-index include-untracked staged].freeze, no: true, ignore: false)
|
688
798
|
append_message option('message', 'm', ignore: false)
|
689
799
|
end
|
690
800
|
source(banner: !quiet?, sync: sync, **threadargs)
|
691
801
|
end
|
692
802
|
|
693
|
-
def status(
|
803
|
+
def status(*)
|
694
804
|
cmd = git_session 'status'
|
695
805
|
cmd << (option('long') ? '--long' : '--short')
|
696
|
-
cmd << '--branch' if option('branch')
|
697
806
|
if (val = option('ignore-submodules', ignore: false))
|
698
807
|
cmd << basic_option('ignore-submodules', case val
|
699
808
|
when '0', 'none'
|
@@ -708,31 +817,85 @@ module Squared
|
|
708
817
|
end
|
709
818
|
append_pathspec
|
710
819
|
out, banner, from = source(io: true)
|
711
|
-
if sync
|
712
|
-
print_item banner
|
713
|
-
banner = nil
|
714
|
-
end
|
715
820
|
ret = write_lines(out, banner: banner, sub: if verbose
|
821
|
+
r = color(:red)
|
822
|
+
g = color(:green)
|
716
823
|
[
|
717
|
-
{ pat: /^(.)([A-Z?!])(.+)$/, styles:
|
718
|
-
{ pat: /^([A-Z?!])(.+)$/, styles:
|
719
|
-
{ pat: /^(\?\?)(.+)$/, styles:
|
824
|
+
{ pat: /^(.)([A-Z?!])(.+)$/, styles: r, index: 2 },
|
825
|
+
{ pat: /^([A-Z?!])(.+)$/, styles: g },
|
826
|
+
{ pat: /^(\?\?)(.+)$/, styles: r },
|
720
827
|
{ pat: /^(## )(.+)(\.{3})(.+)$/,
|
721
|
-
styles: [nil,
|
828
|
+
styles: [nil, g, nil, r], index: -1 }
|
722
829
|
]
|
723
830
|
end)
|
724
831
|
list_result(ret, 'files', from: from, action: 'modified')
|
725
832
|
end
|
726
833
|
|
834
|
+
def revbuild(flag = nil, opts = [], sync: invoked_sync?('revbuild', flag), **kwargs)
|
835
|
+
statusargs = lambda do
|
836
|
+
{
|
837
|
+
include: relativepath(as_a(kwargs[:include]), all: true),
|
838
|
+
exclude: relativepath(as_a(kwargs[:exclude]), all: true)
|
839
|
+
}
|
840
|
+
end
|
841
|
+
unless workspace.closed
|
842
|
+
if @revbuild
|
843
|
+
statusargs.().each { |key, val| @revbuild[key] += val }
|
844
|
+
else
|
845
|
+
@revbuild = statusargs.()
|
846
|
+
end
|
847
|
+
return
|
848
|
+
end
|
849
|
+
sha = source(git_output('rev-parse --verify HEAD'), io: true, banner: false, stdout: true).first.to_s.chomp
|
850
|
+
return if sha.empty?
|
851
|
+
|
852
|
+
args = []
|
853
|
+
kwargs = kwargs.key?(:include) || kwargs.key?(:exclude) ? statusargs.() : @revbuild || {}
|
854
|
+
case flag
|
855
|
+
when :build
|
856
|
+
opts = option_sanitize(opts, OPT_GIT[:status], target: args).first
|
857
|
+
option_clear opts
|
858
|
+
else
|
859
|
+
args << basic_option('untracked-files', flag) if (flag = option('untracked-files', prefix: 'git'))
|
860
|
+
args << basic_option('ignore-submodules', flag) if (flag = option('ignore-submodules', prefix: 'git'))
|
861
|
+
args << basic_option('ignored', flag) if (flag = option('ignored', prefix: 'git'))
|
862
|
+
end
|
863
|
+
if (cur = workspace.rev_entry(name)) && cur['revision'] == sha
|
864
|
+
files = status_digest(*args, **kwargs)
|
865
|
+
if cur['files'].size == files.size && cur['files'].find { |key, val| files[key] != val }.nil?
|
866
|
+
if verbose
|
867
|
+
if (since = workspace.rev_timesince(name, 'build'))
|
868
|
+
puts log_message(Logger::INFO, name, 'no changes', subject: 'revbuild', hint: "#{since} ago")
|
869
|
+
else
|
870
|
+
workspace.rev_timeutc(name, 'build')
|
871
|
+
end
|
872
|
+
end
|
873
|
+
return
|
874
|
+
end
|
875
|
+
end
|
876
|
+
start = epochtime
|
877
|
+
build(@output, sync: sync, from: :'git:revbuild')
|
878
|
+
rescue StandardError => e
|
879
|
+
warn log_message(Logger::WARN, e, pass: true) if warning?
|
880
|
+
else
|
881
|
+
if verbose
|
882
|
+
msg = sub_style('completed', styles: theme[:active])
|
883
|
+
puts log_message(Logger::INFO, name, msg, subject: 'revbuild', hint: time_format(epochtime - start))
|
884
|
+
end
|
885
|
+
workspace.rev_write(name, { 'revision' => sha, 'files' => status_digest(*args, **kwargs) }, utc: 'build')
|
886
|
+
end
|
887
|
+
|
727
888
|
def reset(flag, opts = [], refs: nil, ref: nil, mode: nil, commit: nil)
|
728
|
-
cmd = git_session
|
889
|
+
cmd, opts = git_session('reset', opts: opts)
|
729
890
|
case flag
|
730
891
|
when :commit, :index
|
731
|
-
|
892
|
+
out = option_sanitize(opts, OPT_GIT[:reset] + VAL_GIT[:reset], no: OPT_GIT[:no][:reset]).first
|
732
893
|
if flag == :commit
|
733
|
-
append_value
|
734
|
-
option_clear
|
894
|
+
append_value(commit, delim: true)
|
895
|
+
option_clear out
|
735
896
|
ref = false
|
897
|
+
else
|
898
|
+
(refs ||= []).concat(out)
|
736
899
|
end
|
737
900
|
when :mode
|
738
901
|
return unless VAL_GIT[:reset].include?(mode)
|
@@ -748,21 +911,19 @@ module Squared
|
|
748
911
|
return
|
749
912
|
end
|
750
913
|
unless ref == false
|
751
|
-
append_commit
|
914
|
+
append_commit(ref, head: true)
|
752
915
|
append_pathspec refs if refs
|
753
916
|
end
|
754
917
|
source
|
755
918
|
end
|
756
919
|
|
757
920
|
def checkout(flag, opts = [], branch: nil, origin: nil, create: nil, commit: nil, detach: nil)
|
758
|
-
cmd = git_session
|
921
|
+
cmd, opts = git_session('checkout', opts: opts)
|
759
922
|
append_option 'force', 'merge'
|
760
923
|
case flag
|
761
924
|
when :branch
|
762
925
|
cmd << '--detach' if detach == 'd' || option('detach')
|
763
|
-
|
764
|
-
cmd << shell_option('track', val)
|
765
|
-
end
|
926
|
+
append_option('track', equals: true)
|
766
927
|
cmd << if create
|
767
928
|
shell_option(create, branch)
|
768
929
|
else
|
@@ -783,7 +944,7 @@ module Squared
|
|
783
944
|
else
|
784
945
|
out = option_sanitize(opts, OPT_GIT[:checkout], no: OPT_GIT[:no][:checkout]).first
|
785
946
|
if flag == :commit
|
786
|
-
append_value
|
947
|
+
append_value(commit, delim: true)
|
787
948
|
option_clear out
|
788
949
|
else
|
789
950
|
append_head
|
@@ -794,7 +955,7 @@ module Squared
|
|
794
955
|
end
|
795
956
|
|
796
957
|
def tag(flag, opts = [], refs: [], message: nil, commit: nil)
|
797
|
-
cmd = git_session
|
958
|
+
cmd, opts = git_session('tag', opts: opts)
|
798
959
|
case flag
|
799
960
|
when :add
|
800
961
|
if option('sign')
|
@@ -802,8 +963,8 @@ module Squared
|
|
802
963
|
elsif !session_arg?('s', 'sign', 'u', 'local-user')
|
803
964
|
cmd << '--annotate'
|
804
965
|
end
|
805
|
-
if !commit && message && (
|
806
|
-
commit =
|
966
|
+
if !commit && message && (sha = commithash(message))
|
967
|
+
commit = sha
|
807
968
|
else
|
808
969
|
append_message message
|
809
970
|
end
|
@@ -826,41 +987,27 @@ module Squared
|
|
826
987
|
source
|
827
988
|
end
|
828
989
|
|
829
|
-
def logx(flag, opts = [], range: [])
|
830
|
-
cmd = git_session
|
831
|
-
|
990
|
+
def logx(flag, opts = [], range: [], index: [])
|
991
|
+
cmd, opts = git_session('log', opts: opts)
|
992
|
+
refs = option_sanitize(opts, collect_hash(OPT_GIT[:log]), no: collect_hash(OPT_GIT[:no][:log])).first
|
832
993
|
case flag
|
833
994
|
when :between, :contain
|
834
995
|
cmd << shell_quote(range.join(flag == :between ? '..' : '...'))
|
835
996
|
else
|
836
|
-
|
837
|
-
val.start_with?('^') || (!%r{^.(?:[\\/]|$)}.match?(val) && !%r{[\\/]$}.match?(val)) || commithash(val)
|
838
|
-
end
|
839
|
-
cmd.merge(commit.map { |val| commithash(val) || shell_quote(val) }) unless commit.empty?
|
997
|
+
cmd.merge(index)
|
840
998
|
end
|
841
999
|
append_nocolor
|
842
|
-
append_pathspec
|
1000
|
+
append_pathspec refs
|
843
1001
|
source(exception: false)
|
844
1002
|
end
|
845
1003
|
|
846
|
-
def diff(flag, opts = [], refs: [], branch: nil, range: [])
|
847
|
-
cmd = git_session
|
1004
|
+
def diff(flag, opts = [], refs: [], branch: nil, range: [], index: [])
|
1005
|
+
cmd, opts = git_session('diff', opts: opts)
|
848
1006
|
files = option_sanitize(opts, collect_hash(OPT_GIT[:diff]) + OPT_GIT[:log][:diff],
|
849
1007
|
no: OPT_GIT[:no][:log][:diff]).first
|
850
1008
|
case flag
|
851
1009
|
when :files, :view, :between, :contain
|
852
1010
|
cmd.delete('--cached')
|
853
|
-
else
|
854
|
-
items = files.dup
|
855
|
-
sha = nil
|
856
|
-
files.clear
|
857
|
-
items.each do |val|
|
858
|
-
if (s = commithash(val))
|
859
|
-
(sha ||= []).push(s)
|
860
|
-
else
|
861
|
-
files << val
|
862
|
-
end
|
863
|
-
end
|
864
1011
|
end
|
865
1012
|
append_nocolor
|
866
1013
|
if flag == :files
|
@@ -875,15 +1022,14 @@ module Squared
|
|
875
1022
|
cmd.delete('--merge-base')
|
876
1023
|
cmd << shell_quote(range.join(flag == :between ? '..' : '...'))
|
877
1024
|
else
|
878
|
-
cmd << '--cached' if flag == :cached
|
879
1025
|
cmd << '--merge-base' if option('merge-base')
|
880
1026
|
cmd << shell_quote(branch) if branch
|
881
|
-
if
|
1027
|
+
if !index.empty?
|
882
1028
|
if session_arg?('cached')
|
883
|
-
raise_error(
|
884
|
-
cmd <<
|
1029
|
+
raise_error("one commit only: #{index.join(', ')}", hint: '--cached') if index.size > 1
|
1030
|
+
cmd << index.first
|
885
1031
|
else
|
886
|
-
cmd.merge(
|
1032
|
+
cmd.merge(index)
|
887
1033
|
end
|
888
1034
|
elsif (n = option('index'))
|
889
1035
|
cmd << "HEAD~#{n}"
|
@@ -900,48 +1046,61 @@ module Squared
|
|
900
1046
|
if !message && !amend
|
901
1047
|
return if pass
|
902
1048
|
|
903
|
-
raise_error('
|
1049
|
+
raise_error('missing message', hint: 'GIT_MESSAGE="description"')
|
904
1050
|
end
|
905
1051
|
pathspec = if flag == :all || (amend && refs.size == 1 && refs.first == '*')
|
906
1052
|
'--all'
|
907
1053
|
elsif (refs = projectmap(refs)).empty?
|
908
|
-
raise_error
|
1054
|
+
raise_error 'no qualified pathspec'
|
909
1055
|
else
|
910
1056
|
"-- #{refs.join(' ')}"
|
911
1057
|
end
|
912
|
-
format = '%(if)%(HEAD)%(then)%(refname:short)...%(upstream:short)...%(upstream:track)%(end)'
|
913
|
-
branch = nil
|
914
1058
|
origin = nil
|
915
|
-
|
916
|
-
|
917
|
-
source(
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
|
925
|
-
|
926
|
-
|
1059
|
+
branch = nil
|
1060
|
+
upstream = nil
|
1061
|
+
source(git_output('fetch --no-tags --quiet'), io: true, banner: false)
|
1062
|
+
source(git_output('branch -vv --list'), io: true, banner: false).first.each do |val|
|
1063
|
+
next unless (r = /^\*\s(\S+)\s+(\h+)(?:\s\[(.+?)(?=\]\s)\])?\s/.match(val))
|
1064
|
+
|
1065
|
+
branch = r[1]
|
1066
|
+
if r[3]
|
1067
|
+
origin = r[3][%r{^(.+)/#{Regexp.escape(branch)}$}, 1]
|
1068
|
+
else
|
1069
|
+
unless (origin = option('repository', prefix: 'git', ignore: false))
|
1070
|
+
out = source(git_output('log -n1 --format=%h%d'), io: true, banner: false, stdout: true).first
|
1071
|
+
if out =~ /^#{r[2]} \(HEAD -> #{Regexp.escape(branch)}, (.+?)\)$/
|
1072
|
+
split_escape($1).each do |val|
|
1073
|
+
next unless val.end_with?("/#{branch}")
|
1074
|
+
|
1075
|
+
origin = val[0, val.size - branch.size - 1]
|
1076
|
+
break
|
1077
|
+
end
|
1078
|
+
end
|
1079
|
+
end
|
1080
|
+
upstream = true if origin
|
927
1081
|
end
|
928
1082
|
break
|
929
1083
|
end
|
930
|
-
|
931
|
-
branch = "#{branch}:#{origin[i + 1..-1]}" unless origin.end_with?("/#{branch}")
|
932
|
-
origin = origin[0..i - 1]
|
1084
|
+
raise_error 'work tree is not usable' unless origin && branch
|
933
1085
|
cmd = git_session('commit', option('dry-run') && '--dry-run', options: false)
|
934
|
-
|
1086
|
+
if amend
|
1087
|
+
cmd << '--amend'
|
1088
|
+
else
|
1089
|
+
cmd.delete('--amend')
|
1090
|
+
end
|
935
1091
|
if message
|
936
1092
|
append_message message
|
937
1093
|
elsif flag == :'amend-orig' || option('no-edit')
|
938
1094
|
cmd << '--no-edit'
|
939
1095
|
end
|
940
1096
|
a = git_output 'add', '--verbose'
|
941
|
-
b = git_output 'push'
|
942
|
-
|
1097
|
+
b = git_output 'push', upstream && '--set-upstream'
|
1098
|
+
if dryrun?
|
1099
|
+
a << '--dry-run'
|
1100
|
+
b << '--dry-run'
|
1101
|
+
end
|
943
1102
|
a << pathspec
|
944
|
-
b << '--force
|
1103
|
+
b << '--force' if amend
|
945
1104
|
b << origin << branch
|
946
1105
|
puts if pass
|
947
1106
|
source a
|
@@ -949,8 +1108,24 @@ module Squared
|
|
949
1108
|
source b
|
950
1109
|
end
|
951
1110
|
|
952
|
-
def
|
953
|
-
cmd = git_session
|
1111
|
+
def merge(flag, opts = [], command: nil)
|
1112
|
+
cmd, opts = git_session('merge', opts: opts)
|
1113
|
+
case flag
|
1114
|
+
when :commit, :'no-commit'
|
1115
|
+
refs = option_sanitize(opts, OPT_GIT[:merge], no: OPT_GIT[:no][:merge]).first
|
1116
|
+
raise_error 'no branch/commit' if refs.empty?
|
1117
|
+
cmd << "--#{flag}" << '--'
|
1118
|
+
append_commit(*refs)
|
1119
|
+
else
|
1120
|
+
return unless VAL_GIT[:merge][:send].include?(command)
|
1121
|
+
|
1122
|
+
cmd << "--#{command}"
|
1123
|
+
end
|
1124
|
+
source
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
def branch(flag = nil, opts = [], refs: [], ref: nil, target: nil)
|
1128
|
+
cmd, opts = git_session('branch', opts: opts)
|
954
1129
|
stdout = false
|
955
1130
|
case flag
|
956
1131
|
when :create
|
@@ -969,7 +1144,7 @@ module Squared
|
|
969
1144
|
return unless ref
|
970
1145
|
|
971
1146
|
if ref.start_with?('^')
|
972
|
-
cmd << '--unset-upstream' << shell_escape(
|
1147
|
+
cmd << '--unset-upstream' << shell_escape(arg[1..-1])
|
973
1148
|
target = nil
|
974
1149
|
stdout = true
|
975
1150
|
else
|
@@ -977,7 +1152,7 @@ module Squared
|
|
977
1152
|
end
|
978
1153
|
ref = nil
|
979
1154
|
when :delete
|
980
|
-
force, list = refs.partition { |val| val
|
1155
|
+
force, list = refs.partition { |val| val.match?(/^[\^~]/) }
|
981
1156
|
force.each do |val|
|
982
1157
|
dr = val[0, 3]
|
983
1158
|
d = dr.include?('^') ? '-D' : '-d'
|
@@ -997,10 +1172,9 @@ module Squared
|
|
997
1172
|
cmd << '--edit-description'
|
998
1173
|
when :current
|
999
1174
|
cmd << '--show-current'
|
1000
|
-
|
1001
|
-
opts = option_sanitize(opts, OPT_GIT[:branch], no: OPT_GIT[:no][:branch]).first
|
1175
|
+
when :list
|
1002
1176
|
grep = []
|
1003
|
-
opts.each do |opt|
|
1177
|
+
option_sanitize(opts, OPT_GIT[:branch], no: OPT_GIT[:no][:branch]).first.each do |opt|
|
1004
1178
|
if opt =~ /^(v+)$/
|
1005
1179
|
cmd << "-#{$1}"
|
1006
1180
|
else
|
@@ -1012,42 +1186,46 @@ module Squared
|
|
1012
1186
|
out, banner, from = source(io: true)
|
1013
1187
|
print_item banner
|
1014
1188
|
ret = write_lines(out, sub: [
|
1015
|
-
{ pat: /^(\*\s+)(\S+)(\s*)$/, styles: :green, index: 2 },
|
1016
|
-
{ pat: %r{^(\s*)(remotes/\S+)(.*)$}, styles: :red, index: 2 }
|
1189
|
+
{ pat: /^(\*\s+)(\S+)(\s*)$/, styles: color(:green), index: 2 },
|
1190
|
+
{ pat: %r{^(\s*)(remotes/\S+)(.*)$}, styles: color(:red), index: 2 }
|
1017
1191
|
])
|
1018
1192
|
list_result(ret, 'branches', from: from)
|
1019
1193
|
return
|
1194
|
+
else
|
1195
|
+
head = source(git_output('rev-parse --abbrev-ref HEAD'), io: true, banner: false, stdout: true).first.chomp
|
1196
|
+
if head.empty?
|
1197
|
+
ret = 0
|
1198
|
+
else
|
1199
|
+
out, banner, from = source(cmd << '-vv --no-abbrev --list', io: true)
|
1200
|
+
ret = write_lines(out, grep: /^\*\s+#{Regexp.escape(head)}\s/, banner: banner, first: true) do |line|
|
1201
|
+
next line if stdin?
|
1202
|
+
|
1203
|
+
data = line.sub(/^\*\s+/, '').split(/\s+/)
|
1204
|
+
a = sub_style(data[0], styles: theme[:inline])
|
1205
|
+
b = sub_style(data[1], styles: theme[:extra])
|
1206
|
+
r = /\A(?:\[(.+?)(?=\]\s)\]\s)?(.+)\z/m.match(data[2..-1].join(' '))
|
1207
|
+
[" Branch: #{a + (r[1] ? " (#{r[1]})" : '')}", " Commit: #{b}", "Message: #{r[2]}"].compact.join("\n")
|
1208
|
+
end
|
1209
|
+
on :last, from
|
1210
|
+
end
|
1211
|
+
if ret == 0
|
1212
|
+
warn log_message(Logger::WARN, name, 'no ref found', subject: 'branch', hint: 'head', pass: true)
|
1213
|
+
end
|
1214
|
+
return
|
1020
1215
|
end
|
1021
1216
|
cmd << shell_escape(target) if target
|
1022
1217
|
cmd << shell_escape(ref) if ref
|
1023
1218
|
source(stdout: stdout)
|
1024
1219
|
end
|
1025
1220
|
|
1026
|
-
def restore(flag, opts = [], tree: nil)
|
1027
|
-
cmd = git_session 'restore'
|
1028
|
-
refs = option_sanitize(opts, OPT_GIT[:restore], no: OPT_GIT[:no][:restore]).first
|
1029
|
-
if flag == :source
|
1030
|
-
cmd << '--patch' if refs.empty?
|
1031
|
-
cmd << shell_option('source', tree)
|
1032
|
-
else
|
1033
|
-
cmd << "--#{flag}"
|
1034
|
-
end
|
1035
|
-
if session_arg?('p', 'patch')
|
1036
|
-
option_clear refs
|
1037
|
-
else
|
1038
|
-
append_pathspec(refs, expect: true)
|
1039
|
-
end
|
1040
|
-
source(sync: false, stderr: true)
|
1041
|
-
end
|
1042
|
-
|
1043
1221
|
def show(format, opts = [])
|
1044
|
-
cmd = git_session
|
1222
|
+
cmd, opts = git_session('show', opts: opts)
|
1045
1223
|
if format
|
1046
1224
|
case (val = format.downcase)
|
1047
1225
|
when 'oneline', 'short', 'medium', 'full', 'fuller', 'reference', 'email', 'raw'
|
1048
1226
|
cmd << basic_option('format', val)
|
1049
1227
|
else
|
1050
|
-
if format
|
1228
|
+
if format.match?(/^t?format:/) || format.include?('%')
|
1051
1229
|
cmd << quote_option('pretty', format)
|
1052
1230
|
else
|
1053
1231
|
opts << format
|
@@ -1065,18 +1243,19 @@ module Squared
|
|
1065
1243
|
end
|
1066
1244
|
|
1067
1245
|
def rev_parse(flag, opts = [], ref: nil, size: nil)
|
1068
|
-
cmd = git_session
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1246
|
+
cmd, opts = git_session('rev-parse', opts: opts)
|
1247
|
+
cmd << if flag == :parseopt
|
1248
|
+
'--parseopt'
|
1249
|
+
elsif opts.delete('sq-quote')
|
1250
|
+
'--sq-quote'
|
1251
|
+
end
|
1073
1252
|
case flag
|
1074
1253
|
when :commit
|
1075
1254
|
cmd << ((n = size.to_i) > 0 ? basic_option('short', [n, 5].max) : '--verify')
|
1076
|
-
append_commit
|
1255
|
+
append_commit(ref, head: true)
|
1077
1256
|
when :branch
|
1078
1257
|
cmd << '--abbrev-ref'
|
1079
|
-
append_commit
|
1258
|
+
append_commit(ref, head: true)
|
1080
1259
|
else
|
1081
1260
|
args = option_sanitize(opts, OPT_GIT[:rev_parse][flag]).first
|
1082
1261
|
append_value(args, escape: session_arg?('sq-quote'))
|
@@ -1085,7 +1264,7 @@ module Squared
|
|
1085
1264
|
end
|
1086
1265
|
|
1087
1266
|
def ls_remote(flag, opts = [], remote: nil)
|
1088
|
-
cmd = git_session
|
1267
|
+
cmd, opts = git_session('ls-remote', '--refs', opts: opts)
|
1089
1268
|
cmd << "--#{flag}" unless flag == :remote
|
1090
1269
|
grep = option_sanitize(opts, OPT_GIT[:ls_remote]).first
|
1091
1270
|
cmd << shell_quote(remote) if remote
|
@@ -1096,7 +1275,7 @@ module Squared
|
|
1096
1275
|
end
|
1097
1276
|
|
1098
1277
|
def ls_files(flag, opts = [])
|
1099
|
-
git_session
|
1278
|
+
opts = git_session('ls-files', "--#{flag}", opts: opts).last
|
1100
1279
|
grep = option_sanitize(opts, OPT_GIT[:ls_files]).first
|
1101
1280
|
out, banner, from = source(io: true)
|
1102
1281
|
print_item banner
|
@@ -1104,10 +1283,51 @@ module Squared
|
|
1104
1283
|
list_result(ret, 'files', from: from, grep: grep)
|
1105
1284
|
end
|
1106
1285
|
|
1286
|
+
def git(flag, opts = [])
|
1287
|
+
cmd, opts = git_session(flag, opts: opts)
|
1288
|
+
refs = option_sanitize(opts, OPT_GIT[flag], no: OPT_GIT[:no][flag]).first
|
1289
|
+
refs = projectmap(refs) unless flag == :revert
|
1290
|
+
sync = false
|
1291
|
+
stderr = true
|
1292
|
+
case flag
|
1293
|
+
when :clean
|
1294
|
+
unless refs.empty?
|
1295
|
+
cmd << '--'
|
1296
|
+
cmd.merge(refs)
|
1297
|
+
end
|
1298
|
+
sync = true
|
1299
|
+
stderr = false
|
1300
|
+
when :restore
|
1301
|
+
if session_arg?('p', 'patch')
|
1302
|
+
option_clear refs
|
1303
|
+
else
|
1304
|
+
append_pathspec(refs, expect: true)
|
1305
|
+
end
|
1306
|
+
when :revert
|
1307
|
+
if VAL_GIT[:rebase][:send].any? { |val| session_arg?(val) }
|
1308
|
+
option_clear refs
|
1309
|
+
elsif refs.empty?
|
1310
|
+
raise_error 'no commit given'
|
1311
|
+
else
|
1312
|
+
append_commit(*refs)
|
1313
|
+
end
|
1314
|
+
when :mv
|
1315
|
+
raise_error 'no source/destination' unless refs.size > 1
|
1316
|
+
cmd.merge(refs)
|
1317
|
+
when :rm
|
1318
|
+
append_pathspec(refs, expect: true)
|
1319
|
+
end
|
1320
|
+
source(sync: sync, stderr: stderr)
|
1321
|
+
end
|
1322
|
+
|
1107
1323
|
def clone?
|
1108
1324
|
ref?(workspace.baseref) && workspace.git_clone?(path, name) ? 1 : false
|
1109
1325
|
end
|
1110
1326
|
|
1327
|
+
def revbuild?
|
1328
|
+
build? && !!workspace.revfile
|
1329
|
+
end
|
1330
|
+
|
1111
1331
|
def enabled?(*, **kwargs)
|
1112
1332
|
super || (kwargs[:base] == false && !!clone?)
|
1113
1333
|
end
|
@@ -1120,7 +1340,7 @@ module Squared
|
|
1120
1340
|
if cmd.respond_to?(:done)
|
1121
1341
|
if io && banner == false
|
1122
1342
|
from = nil
|
1123
|
-
elsif !from && (from = cmd.drop(1).find { |val| val
|
1343
|
+
elsif !from && (from = cmd.drop(1).find { |val| val.match?(/^[a-z][a-z\-]{2,}$/) })
|
1124
1344
|
from = :"git:#{from}"
|
1125
1345
|
end
|
1126
1346
|
banner &&= cmd.temp { |val| val.start_with?('--work-tree') || val.start_with?('--git-dir') }
|
@@ -1166,13 +1386,13 @@ module Squared
|
|
1166
1386
|
ret = on(:error, from, e)
|
1167
1387
|
raise if exception && ret != true
|
1168
1388
|
|
1169
|
-
warn log_message(Logger::WARN, e) if warning?
|
1389
|
+
warn log_message(Logger::WARN, e, pass: true) if warning?
|
1170
1390
|
else
|
1171
1391
|
on :last, from
|
1172
1392
|
end
|
1173
1393
|
end
|
1174
1394
|
|
1175
|
-
def write_lines(data, banner: nil, loglevel: nil, grep: nil, sub: nil, pass: false)
|
1395
|
+
def write_lines(data, banner: nil, loglevel: nil, grep: nil, sub: nil, pass: false, first: false)
|
1176
1396
|
grep = as_a(grep).map do |val|
|
1177
1397
|
next val if val.is_a?(Regexp)
|
1178
1398
|
|
@@ -1185,6 +1405,7 @@ module Squared
|
|
1185
1405
|
data.each do |line|
|
1186
1406
|
next if grep&.none? { |pat| pat.match?(line) }
|
1187
1407
|
|
1408
|
+
line = yield line if block_given?
|
1188
1409
|
if loglevel
|
1189
1410
|
log&.add loglevel, line
|
1190
1411
|
else
|
@@ -1196,8 +1417,9 @@ module Squared
|
|
1196
1417
|
end
|
1197
1418
|
end
|
1198
1419
|
ret += 1
|
1420
|
+
break if first
|
1199
1421
|
end
|
1200
|
-
print_item banner, out if banner && (ret > 0 || !pass)
|
1422
|
+
print_item banner, out if banner && (ret > 0 || (!pass && !first))
|
1201
1423
|
ret
|
1202
1424
|
end
|
1203
1425
|
|
@@ -1206,7 +1428,7 @@ module Squared
|
|
1206
1428
|
if size > 0
|
1207
1429
|
styles = theme.fetch(:banner, []).reject { |s| s.to_s.end_with?('!') }
|
1208
1430
|
styles << :bold if styles.size <= 1
|
1209
|
-
puts print_footer("#{size} #{size == 1 ? type.sub(/
|
1431
|
+
puts print_footer("#{size} #{size == 1 ? type.sub(/e?s\z/, '') : type}",
|
1210
1432
|
sub: { pat: /\A(\d+)(.+)\z/, styles: styles })
|
1211
1433
|
else
|
1212
1434
|
puts empty_status("No #{type} were #{action}", 'grep', grep.is_a?(Array) ? case grep.size
|
@@ -1220,12 +1442,27 @@ module Squared
|
|
1220
1442
|
on :last, from
|
1221
1443
|
end
|
1222
1444
|
|
1445
|
+
def status_digest(*args, algorithm: Digest::SHA256, **kwargs)
|
1446
|
+
glob = kwargs.fetch(:include, [])
|
1447
|
+
pass = kwargs.fetch(:exclude, [])
|
1448
|
+
ret = {}
|
1449
|
+
out = source(git_output('status -s --porcelain', *args), io: true, banner: false).first
|
1450
|
+
out.each do |line|
|
1451
|
+
next unless (file = line[/^[A-Z ?!]{3}"?(.+?)"?$/, 1])
|
1452
|
+
next if !glob.empty? && glob.none? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
|
1453
|
+
next if !pass.empty? && pass.any? { |val| File.fnmatch?(val, file, File::FNM_DOTMATCH) }
|
1454
|
+
|
1455
|
+
ret[file] = algorithm.hexdigest(File.read(basepath(file)))
|
1456
|
+
end
|
1457
|
+
ret
|
1458
|
+
end
|
1459
|
+
|
1223
1460
|
def append_pull(opts, list, target: @session, no: nil, flag: nil, remote: nil)
|
1224
|
-
|
1461
|
+
cmd << '--force' if option('force')
|
1225
1462
|
rsm = append_submodules(target: target)
|
1226
1463
|
out = []
|
1227
1464
|
refspec = []
|
1228
|
-
opts, pat = option_sanitize(opts, remote ? list + ['refspec=
|
1465
|
+
opts, pat = option_sanitize(opts, remote ? list + ['refspec=b'] : list, target: target, no: no)
|
1229
1466
|
opts.each do |opt|
|
1230
1467
|
if opt =~ pat
|
1231
1468
|
case $1
|
@@ -1246,7 +1483,7 @@ module Squared
|
|
1246
1483
|
end
|
1247
1484
|
if remote
|
1248
1485
|
append_value(remote, target: target, delim: true)
|
1249
|
-
if (val = option('refspec',
|
1486
|
+
if (val = option('refspec', strict: true))
|
1250
1487
|
append_value(split_escape(val), target: target)
|
1251
1488
|
else
|
1252
1489
|
target.merge(refspec)
|
@@ -1259,23 +1496,27 @@ module Squared
|
|
1259
1496
|
option_clear(out, target: target, subject: flag.to_s) if flag
|
1260
1497
|
end
|
1261
1498
|
|
1262
|
-
def append_commit(val, target: @session)
|
1263
|
-
val
|
1264
|
-
|
1499
|
+
def append_commit(*val, target: @session, head: false)
|
1500
|
+
val.compact!
|
1501
|
+
if !val.empty?
|
1502
|
+
val.each { |ref| target << (commithash(ref) || shell_quote(ref)) }
|
1503
|
+
elsif head
|
1504
|
+
target << (append_head(target: target) || 'HEAD')
|
1505
|
+
end
|
1265
1506
|
end
|
1266
1507
|
|
1267
1508
|
def append_pathspec(files = [], target: @session, expect: false, parent: false)
|
1268
|
-
if session_arg?('pathspec-from-file'
|
1509
|
+
if session_arg?('pathspec-from-file')
|
1269
1510
|
option_clear files
|
1270
1511
|
else
|
1271
|
-
if files.empty? && (val = option('pathspec'
|
1512
|
+
if files.empty? && (val = option('pathspec'))
|
1272
1513
|
files = split_escape(val)
|
1273
1514
|
end
|
1274
1515
|
files = projectmap(files, parent: parent)
|
1275
1516
|
if !files.empty?
|
1276
|
-
target <<
|
1517
|
+
target << '--' << files.join(' ')
|
1277
1518
|
elsif expect
|
1278
|
-
raise_error(parent ? 'pathspec not present' : 'pathspec not within worktree'
|
1519
|
+
raise_error(parent ? 'pathspec not present' : 'pathspec not within worktree')
|
1279
1520
|
end
|
1280
1521
|
end
|
1281
1522
|
end
|
@@ -1291,34 +1532,32 @@ module Squared
|
|
1291
1532
|
end
|
1292
1533
|
|
1293
1534
|
def append_submodules(from = nil, target: @session)
|
1294
|
-
return unless (val = option('recurse-submodules',
|
1535
|
+
return unless (val = option('recurse-submodules', ignore: false))
|
1295
1536
|
|
1296
1537
|
if from == :clone
|
1297
|
-
|
1298
|
-
|
1299
|
-
target << '--no-recurse-submodules'
|
1300
|
-
when '1', 'true'
|
1301
|
-
target << '--recurse-submodules'
|
1302
|
-
else
|
1303
|
-
projectmap(split_escape(val)).each do |path|
|
1304
|
-
target << basic_option('recurse-submodules', path)
|
1305
|
-
end
|
1538
|
+
projectmap(split_escape(val)).each do |path|
|
1539
|
+
target << basic_option('recurse-submodules', path)
|
1306
1540
|
end
|
1541
|
+
target
|
1307
1542
|
else
|
1308
1543
|
target << case val
|
1309
1544
|
when 'no', '0'
|
1310
1545
|
'--no-recurse-submodules'
|
1311
1546
|
when 'yes', 'on-demand'
|
1312
|
-
"--recurse-submodules=#{val}"
|
1547
|
+
"--recurse-submodules#{from == :reset ? '' : "=#{val}"}"
|
1313
1548
|
else
|
1314
1549
|
'--recurse-submodules'
|
1315
1550
|
end
|
1316
1551
|
end
|
1317
1552
|
end
|
1318
1553
|
|
1319
|
-
def git_session(*cmd, worktree: true, **kwargs)
|
1554
|
+
def git_session(*cmd, opts: nil, worktree: true, **kwargs)
|
1320
1555
|
dir = worktree ? ["--work-tree=#{shell_quote(path)}", "--git-dir=#{shell_quote(gitpath)}"] : []
|
1321
|
-
session('git', *dir,
|
1556
|
+
ret = session('git', *dir, **kwargs)
|
1557
|
+
return ret.merge(cmd) unless opts
|
1558
|
+
|
1559
|
+
opts = option_sanitize(opts, OPT_GIT[:common]).first
|
1560
|
+
[ret.merge(cmd), opts]
|
1322
1561
|
end
|
1323
1562
|
|
1324
1563
|
def git_output(*cmd, **kwargs)
|
@@ -1326,9 +1565,7 @@ module Squared
|
|
1326
1565
|
end
|
1327
1566
|
|
1328
1567
|
def dryrun?(*, target: @session, **)
|
1329
|
-
|
1330
|
-
|
1331
|
-
target.include?('--dry-run')
|
1568
|
+
!!target&.include?('--dry-run')
|
1332
1569
|
end
|
1333
1570
|
|
1334
1571
|
def quiet?(target: @session)
|
@@ -1338,11 +1575,11 @@ module Squared
|
|
1338
1575
|
end
|
1339
1576
|
|
1340
1577
|
def gitpath
|
1341
|
-
basepath
|
1578
|
+
basepath '.git'
|
1342
1579
|
end
|
1343
1580
|
|
1344
1581
|
def commithash(val)
|
1345
|
-
val
|
1582
|
+
val[/^#\{(\h{5,40})\}$/, 1]
|
1346
1583
|
end
|
1347
1584
|
|
1348
1585
|
def threadargs
|