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