git-thin 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +11 -0
- data/Rakefile +13 -0
- data/bin/git-thin +10 -0
- data/bin/thin +10 -0
- data/git-thin.gemspec +26 -0
- data/lib/git-thin.rb +5 -0
- data/lib/git-thin/command.rb +40 -0
- data/lib/git-thin/command/action.rb +117 -0
- data/lib/git-thin/command/checkout.rb +17 -0
- data/lib/git-thin/command/clone.rb +30 -0
- data/lib/git-thin/command/detect.rb +192 -0
- data/lib/git-thin/command/expire.rb +125 -0
- data/lib/git-thin/command/export.rb +256 -0
- data/lib/git-thin/command/fetch.rb +17 -0
- data/lib/git-thin/command/hook.rb +357 -0
- data/lib/git-thin/command/pull.rb +18 -0
- data/lib/git-thin/command/thin_config.rb +326 -0
- data/lib/git-thin/gem_version.rb +3 -0
- data/lib/git-thin/utils/utils.rb +133 -0
- data/spec/command/thin_spec.rb +12 -0
- data/spec/spec_helper.rb +50 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7a4e45cb46a635b4c56aa504c385a4e42161901d42a21bfd989deed914dc226b
|
4
|
+
data.tar.gz: b5047867a96ecae699129eb58a4310489b11a0f94c8e5e43bdb8a849858ce78d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c40d556d671ed2ee39ec1f97bbf07e2b85b6da44cbd09d9d6c120db6e126b3b1b11c2caf043eefa942324a7451d051b220da8c38294df12435c9e6bbd2fe73de
|
7
|
+
data.tar.gz: d89fa88459a9b3b1c1ae295e5b6fe9013165d8e736b869cbeabe2d1bf225fc9748996d7a017b7090a898c0b528b52c17a04bfed903f2d6f635376b374854e809
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2021 kyle.zhou <kyle.zhou@bytedance.com>
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
data/bin/git-thin
ADDED
data/bin/thin
ADDED
data/git-thin.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'git-thin/gem_version.rb'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'git-thin'
|
8
|
+
spec.version = GitThin::VERSION
|
9
|
+
spec.authors = ['kyle.zhou']
|
10
|
+
spec.email = ['kyle.zhou@bytedance.com']
|
11
|
+
spec.description = %q{A short description of git-thin.}
|
12
|
+
spec.summary = %q{A longer description of git-thin.}
|
13
|
+
spec.homepage = 'https://github.com/EXAMPLE/git-thin'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
#spec.files = ["thin".freeze, "bin/git-thin".freeze]
|
18
|
+
#spec.executables = ["bin/thin".freeze, "bin/git-thin".freeze]
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
# spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ['lib']
|
22
|
+
|
23
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
|
+
spec.add_development_dependency 'claide'
|
26
|
+
end
|
data/lib/git-thin.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'claide'
|
2
|
+
module GitThin
|
3
|
+
class Thin < CLAide::Command
|
4
|
+
require 'git-thin/command/thin_config'
|
5
|
+
require 'git-thin/command/export'
|
6
|
+
require 'git-thin/command/detect'
|
7
|
+
require 'git-thin/command/expire'
|
8
|
+
require 'git-thin/command/pull'
|
9
|
+
require 'git-thin/command/fetch'
|
10
|
+
require 'git-thin/command/checkout'
|
11
|
+
require 'git-thin/command/hook'
|
12
|
+
|
13
|
+
self.abstract_command = true
|
14
|
+
self.command = 'thin'
|
15
|
+
self.version = VERSION
|
16
|
+
self.summary = 'git-thin, the git thin tools.'
|
17
|
+
# self.plugin_prefixes = %w(claide cocoapods)
|
18
|
+
|
19
|
+
self.description = <<-DESC
|
20
|
+
git-thin, the git thin tools..
|
21
|
+
DESC
|
22
|
+
|
23
|
+
# self.arguments = 'NAME'
|
24
|
+
|
25
|
+
def initialize(argv)
|
26
|
+
super
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.run(argv)
|
31
|
+
# begin
|
32
|
+
super(argv)
|
33
|
+
|
34
|
+
# rescue Exception => e
|
35
|
+
# puts e.message
|
36
|
+
# puts e.backtrace.inspect
|
37
|
+
# end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'claide'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module GitThin
|
5
|
+
|
6
|
+
module Action
|
7
|
+
include GitThinUtils
|
8
|
+
def self.description(action)
|
9
|
+
'Consider thin strategy when performing a '+action+' action '
|
10
|
+
end
|
11
|
+
def self.arguments
|
12
|
+
[
|
13
|
+
CLAide::Argument.new('TYPE', false )
|
14
|
+
]
|
15
|
+
end
|
16
|
+
def self.summary(action)
|
17
|
+
'Consider thin strategy when performing a '+action+' action '
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.options
|
21
|
+
[
|
22
|
+
['--source_root', 'Specify the warehouse address manually if necessary.'],
|
23
|
+
].concat(super)
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup(argv,action)
|
28
|
+
@pwd = Dir.pwd
|
29
|
+
@action = action
|
30
|
+
@types = []
|
31
|
+
@configs = {}
|
32
|
+
@source_root = argv.option('source_root')
|
33
|
+
@verbose = argv.flag?('verbose',false )
|
34
|
+
if @verbose
|
35
|
+
@verbose = LOGC|LOGN
|
36
|
+
end
|
37
|
+
if not @source_root
|
38
|
+
run_shell 'git rev-parse --show-toplevel',false ,LOGNone do |out,err,status|
|
39
|
+
if status == 0 && out.length > 0
|
40
|
+
@source_root = out[0].strip
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
if !@source_root || !File.exist?(@source_root+'/.git')
|
45
|
+
logE "git repository not found"
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
else
|
49
|
+
if @source_root[-1] == '/'
|
50
|
+
@source_root = @source_root[0..-2 ]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
if !@source_root || !Dir.exist?(@source_root)
|
54
|
+
@source_root = nil
|
55
|
+
return
|
56
|
+
end
|
57
|
+
if FileTest.exist? @source_root+'/.thinconfig'
|
58
|
+
run_shell "git config -lf #{@source_root}/.thinconfig",true ,LOGNone do |out,err,status|
|
59
|
+
@configs = ThinConfig.prase_config out
|
60
|
+
end
|
61
|
+
end
|
62
|
+
@types =ThinConfig.prase_type_config argv,@configs,@source_root,@pwd
|
63
|
+
@argv_remainder = argv.remainder!
|
64
|
+
end
|
65
|
+
def source_root
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate!
|
70
|
+
super
|
71
|
+
help! 'validate SOURCE_ROOT is required' unless @source_root
|
72
|
+
end
|
73
|
+
|
74
|
+
def run_config
|
75
|
+
values=[]
|
76
|
+
for type in @types
|
77
|
+
config = @configs[type]
|
78
|
+
if type == ThinConfig::DEFAULT && !config
|
79
|
+
run_shell 'git config -l',true ,true do |outs,errs,status|
|
80
|
+
g_configs = ThinConfig.prase_config outs
|
81
|
+
config = g_configs[ThinConfig::DEFAULT]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
if config
|
85
|
+
value = config.getValue('lfs')
|
86
|
+
values.push value
|
87
|
+
logN "[thin] platform:#{type} lfs:#{value}\n\n",false
|
88
|
+
end
|
89
|
+
end
|
90
|
+
run_shell 'git config lfs.fetchinclude '+values.join(',') ,true ,true
|
91
|
+
return values
|
92
|
+
end
|
93
|
+
|
94
|
+
def run
|
95
|
+
old_config = ''
|
96
|
+
run_shell "git -C #{@source_root} config --get lfs.fetchinclude",true ,!@verbose do|outs,errs,status|
|
97
|
+
if status == 0 && outs.length > 0
|
98
|
+
old_config = outs[0].strip
|
99
|
+
end
|
100
|
+
end
|
101
|
+
run_config
|
102
|
+
shell_ret = 0
|
103
|
+
run_shell "git -C #{@source_root} #{@action} "+@argv_remainder.join(' '),true ,LOGPRUNE|LOGC do |outs,errs,status|
|
104
|
+
shell_ret = status
|
105
|
+
end
|
106
|
+
if old_config.strip == ''
|
107
|
+
run_shell 'git config --unset lfs.fetchinclude' ,true ,true
|
108
|
+
|
109
|
+
else
|
110
|
+
run_shell 'git config lfs.fetchinclude '+old_config ,true ,true
|
111
|
+
end
|
112
|
+
if shell_ret != 0
|
113
|
+
exit(shell_ret+100)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'claide'
|
2
|
+
require 'json'
|
3
|
+
require 'git-thin/command/action'
|
4
|
+
module GitThin
|
5
|
+
|
6
|
+
class Checkout < Thin
|
7
|
+
include Action
|
8
|
+
self.arguments = Action.arguments
|
9
|
+
self.summary = Action.summary 'checkout'
|
10
|
+
self.description = Action.description 'checkout'
|
11
|
+
|
12
|
+
def initialize(argv)
|
13
|
+
super
|
14
|
+
setup(argv,'checkout')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'claide'
|
2
|
+
require 'json'
|
3
|
+
require 'git-thin/command/action'
|
4
|
+
module GitThin
|
5
|
+
|
6
|
+
class Fetch < Thin
|
7
|
+
include Action
|
8
|
+
self.arguments = Action.arguments
|
9
|
+
self.summary = Action.summary 'clone'
|
10
|
+
self.description = Action.description 'clone'
|
11
|
+
|
12
|
+
def initialize(argv)
|
13
|
+
super
|
14
|
+
if @verbose
|
15
|
+
@verbose = LOGC|LOGN
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
|
21
|
+
shell_ret = 0
|
22
|
+
run_shell "git -C #{@source_root} clone --filter=blob:none --sparse "+@argv_remainder.join(' '),false ,LOGPRUNE|LOGC do |outs,errs,status|
|
23
|
+
shell_ret = status
|
24
|
+
end
|
25
|
+
if shell_ret != 0
|
26
|
+
exit(shell_ret+100)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require 'claide'
|
2
|
+
require 'json'
|
3
|
+
require "time"
|
4
|
+
module GitThin
|
5
|
+
|
6
|
+
class Detect < Thin
|
7
|
+
include GitThinUtils
|
8
|
+
self.summary = 'Detect expired branch'
|
9
|
+
# self.plugin_prefixes = %w(claide cocoapods)
|
10
|
+
self.arguments = [
|
11
|
+
CLAide::Argument.new('master', false ),
|
12
|
+
]
|
13
|
+
|
14
|
+
self.description = <<-DESC
|
15
|
+
Reference to master, take the update time greater than expired_time as the expired branch
|
16
|
+
DESC
|
17
|
+
|
18
|
+
def self.options
|
19
|
+
[
|
20
|
+
['--expired_time', 'in sec. (defalut:5184000)'],
|
21
|
+
['--source_root', 'git repository root.'],
|
22
|
+
['--exclude', 'exclude branch.'],
|
23
|
+
['--include', 'include branch.'],
|
24
|
+
['--output_type', 'output type. json|txt'],
|
25
|
+
].concat(super)
|
26
|
+
|
27
|
+
end
|
28
|
+
def initialize(argv)
|
29
|
+
super
|
30
|
+
@expired_time = argv.option('expired_time','5184000').to_i
|
31
|
+
@output_type = argv.option('output_type','txt')
|
32
|
+
|
33
|
+
@excludes = argv.option('exclude','').split(',').map do |item|
|
34
|
+
Regexp.new item.strip
|
35
|
+
end
|
36
|
+
@includes = argv.option('include','').split(',').map do |item|
|
37
|
+
Regexp.new item.strip
|
38
|
+
end
|
39
|
+
@source_root = argv.option('source_root')
|
40
|
+
if @source_root
|
41
|
+
Dir.chdir @source_root
|
42
|
+
end
|
43
|
+
@master = argv.shift_argument
|
44
|
+
if not @master
|
45
|
+
# @master = 'master'
|
46
|
+
return
|
47
|
+
end
|
48
|
+
run_shell 'git rev-parse --show-toplevel',false ,LOGNone do |out,err,status|
|
49
|
+
if status == 0
|
50
|
+
@source_root = out[0].strip
|
51
|
+
end
|
52
|
+
end
|
53
|
+
if not Dir.exist? @source_root
|
54
|
+
@source_root = nil
|
55
|
+
return
|
56
|
+
end
|
57
|
+
run_shell 'git branch -r',false ,true do |out,err,status|
|
58
|
+
if status == 0
|
59
|
+
@branchs = out.map { |line| line = line.strip }
|
60
|
+
@branchs.delete_if do |item|
|
61
|
+
ret = false
|
62
|
+
if item.include? '->'
|
63
|
+
ret = true
|
64
|
+
end
|
65
|
+
ret
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
run_shell "git log --pretty=format:%H origin/#{@master}",false ,true do |out,err,status|
|
71
|
+
if status == 0
|
72
|
+
@master_commits = out.map { |line|
|
73
|
+
line.strip
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
run_shell "git log -1 --pretty=format:%ad origin/#{@master}" do |out,err,status|
|
78
|
+
if status == 0 && out.length > 0
|
79
|
+
commit_time = out[0].strip
|
80
|
+
@master_time = Time.parse commit_time
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
def validate!
|
87
|
+
super
|
88
|
+
help! 'validate SOURCE_ROOT is required.' unless @source_root
|
89
|
+
help! 'master branch is required.' unless @master
|
90
|
+
end
|
91
|
+
|
92
|
+
def export_expired
|
93
|
+
Dir.chdir(@source_root)
|
94
|
+
run_shell 'git remote update',true ,true
|
95
|
+
expired_branch = []
|
96
|
+
error_branch = []
|
97
|
+
match_black = []
|
98
|
+
@branchs.each_index do |index|
|
99
|
+
branch = @branchs[index]
|
100
|
+
logN 'check branch:'+branch
|
101
|
+
include = true
|
102
|
+
if @includes.length > 0
|
103
|
+
include = false
|
104
|
+
for inc in @includes
|
105
|
+
if inc =~ branch
|
106
|
+
include = true
|
107
|
+
break
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
if include
|
112
|
+
exclude = false
|
113
|
+
for exd in @excludes
|
114
|
+
if exd =~ branch
|
115
|
+
exclude = true
|
116
|
+
match_black.push[branch]
|
117
|
+
break
|
118
|
+
end
|
119
|
+
end
|
120
|
+
if not exclude
|
121
|
+
run_shell "git log -1 --pretty=format:\"%H|%ad|%ce\" #{branch}",true ,false do |out,err,status|
|
122
|
+
if status == 0 && out.length > 0
|
123
|
+
items = out[0].split '|'
|
124
|
+
commit = items[0].strip
|
125
|
+
commit_time = items[1].strip
|
126
|
+
time = Time.parse commit_time
|
127
|
+
delay = @master_time.to_i - time.to_i
|
128
|
+
if delay > @expired_time.to_i
|
129
|
+
email = items[2]
|
130
|
+
if not email
|
131
|
+
email = ''
|
132
|
+
end
|
133
|
+
detached_count = 0
|
134
|
+
run_shell "git log --pretty=%ae #{@master}..#{branch}",true ,true do |out,stderr|
|
135
|
+
detached_count = out.length
|
136
|
+
end
|
137
|
+
expired_branch.push ({ "email"=>email,"branch"=>branch,"commit"=>commit,"detached_count"=>detached_count,"delay"=>delay/(60*60*24) })
|
138
|
+
logW 'find expired branch:' +branch
|
139
|
+
end
|
140
|
+
|
141
|
+
else
|
142
|
+
error_branch.push branch
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
expired_branch.sort! do |a,b|
|
150
|
+
a["email"] <=> b["email"]
|
151
|
+
end
|
152
|
+
if expired_branch.length > 0
|
153
|
+
if @output_type == "txt"
|
154
|
+
output_txt expired_branch
|
155
|
+
elsif @output_type == "json"
|
156
|
+
output_json expired_branch
|
157
|
+
else
|
158
|
+
output_json expired_branch
|
159
|
+
output_txt expired_branch
|
160
|
+
end
|
161
|
+
|
162
|
+
else
|
163
|
+
logW 'not match branch'
|
164
|
+
end
|
165
|
+
|
166
|
+
for branch in error_branch
|
167
|
+
logE "Error fetch branch:#{branch},please check manually"
|
168
|
+
end
|
169
|
+
for branch in match_black
|
170
|
+
logE "branch #{branch} match exclude"
|
171
|
+
end
|
172
|
+
end
|
173
|
+
def output_json(expired_branch)
|
174
|
+
File.open("expired.json", "w+") do |aFile|
|
175
|
+
aFile.syswrite(expired_branch.to_json)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def output_txt(expired_branch)
|
180
|
+
File.open("expired.text", "w+") do |aFile|
|
181
|
+
aFile.syswrite(expired_branch[0].keys.join("\t")+"\n")
|
182
|
+
expired_branch.each { |item|
|
183
|
+
aFile.syswrite(item.values.join("\t")+"\n")
|
184
|
+
}
|
185
|
+
end
|
186
|
+
end
|
187
|
+
def run
|
188
|
+
export_expired
|
189
|
+
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|