vcpkg_pipeline 0.1.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.
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'claide'
4
+
5
+ module VPL
6
+ # VPL::Command
7
+ class Command < CLAide::Command
8
+ require 'vcpkg_pipeline/command/new'
9
+ require 'vcpkg_pipeline/command/scan'
10
+ require 'vcpkg_pipeline/command/update'
11
+ require 'vcpkg_pipeline/command/publish'
12
+
13
+ self.abstract_command = true
14
+ self.command = 'vpl'
15
+ self.description = 'vcpkg-Pipeline 是 vcpkg 的流水线工具'
16
+
17
+ def self.options
18
+ [
19
+ ['--help', '展示改命令的介绍面板']
20
+ ]
21
+ end
22
+
23
+ def self.options_extension
24
+ options = []
25
+ options_extension_hash.each do |key, options_extension|
26
+ options_extension.each do |option_extension|
27
+ options << [option_extension.first.gsub(/(--)(.*)/, "\\1#{key}-\\2"), option_extension.last]
28
+ end
29
+ end
30
+ options
31
+ end
32
+
33
+ def self.options_extension_hash
34
+ Hash[]
35
+ end
36
+
37
+ def self.run(argv)
38
+ ensure_not_root_or_allowed! argv
39
+ verify_minimum_git_version!
40
+ verify_xcode_license_approved!
41
+
42
+ super(argv)
43
+ end
44
+
45
+ #
46
+ # 确保root用户
47
+ #
48
+ # @return [void]
49
+ #
50
+ def self.ensure_not_root_or_allowed!(argv, uid = Process.uid, is_windows = Gem.win_platform?)
51
+ root_allowed = argv.include?('--allow-root')
52
+ help! 'You cannot run vcpkg-Pipeline as root' unless root_allowed || uid != 0 || is_windows
53
+ end
54
+
55
+ # 读取Git版本号, 返回一个新的 {Gem::Version} 实例
56
+ #
57
+ # @return [Gem::Version]
58
+ #
59
+ def self.git_version
60
+ raw_version = `git version`
61
+ unless (match = raw_version.scan(/\d+\.\d+\.\d+/).first)
62
+ raise "Failed to extract git version from `git --version` (#{raw_version.inspect})"
63
+ end
64
+
65
+ Gem::Version.new(match)
66
+ end
67
+
68
+ # 检查Git版本号是否低于 1.8.5
69
+ #
70
+ # @raise Git版本号低于 1.8.5
71
+ #
72
+ # @return [void]
73
+ #
74
+ def self.verify_minimum_git_version!
75
+ return unless git_version < Gem::Version.new('1.8.5')
76
+
77
+ raise 'You need at least git version 1.8.5 to use vcpkg-Pipeline'
78
+ end
79
+
80
+ #
81
+ # 检查xcode许可是否被批准
82
+ #
83
+ # @return [void]
84
+ #
85
+ def self.verify_xcode_license_approved!
86
+ return unless `/usr/bin/xcrun clang 2>&1` =~ /license/ && !$?.success?
87
+
88
+ raise 'You have not agreed to the Xcode license, which ' \
89
+ 'you must do to use vcpkg. Agree to the license by running: ' \
90
+ '`xcodebuild -license`'
91
+ end
92
+
93
+ def initialize(argv)
94
+ @argv_extension = {}
95
+ self.class.options_extension_hash.each_key do |key|
96
+ @argv_extension[key] = []
97
+ self.class.options.each do |option|
98
+ name = option.first
99
+ next unless name.include?(key)
100
+
101
+ is_option = name.include? '='
102
+ if is_option
103
+ option = name.gsub(/(--)(.*)(=.*)/, '\\2')
104
+ value = argv.option(option, '')
105
+ unless value.empty?
106
+ @argv_extension[key] << name.gsub(/(--.*=)(.*)/, "\\1#{value}").gsub("#{key}-",
107
+ '')
108
+ end
109
+ else
110
+ flag = name.gsub(/(--)(.*)/, '\\2')
111
+ value = argv.flag?(flag)
112
+ @argv_extension[key] << name.gsub("#{key}-", '') if value
113
+ end
114
+ end
115
+ end
116
+
117
+ super
118
+ end
119
+
120
+ attr_reader :argv_extension
121
+ end
122
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # VPL
4
+ module VPL
5
+ def self.attribute_str(msg, type)
6
+ "\n\033[#{type}m#{msg}\033[0m\n"
7
+ end
8
+
9
+ def self.title(msg)
10
+ puts attribute_str("-- #{msg} --", 44)
11
+ end
12
+
13
+ def self.info(msg)
14
+ puts attribute_str(msg, 46)
15
+ end
16
+
17
+ def self.error(msg)
18
+ raise attribute_str("Error: #{msg}!", 41)
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'git'
4
+
5
+ require 'vcpkg_pipeline/extension/cmake_vpl'
6
+ require 'vcpkg_pipeline/extension/vcport_vpl'
7
+ require 'vcpkg_pipeline/extension/vcpkg_vpl'
8
+ require 'vcpkg_pipeline/extension/git_vpl'
9
+
10
+ require 'vcpkg_pipeline/core/spec'
11
+
12
+ module VPL
13
+ # VPL::Scanner
14
+ class Scanner
15
+ attr_accessor :path, :spec, :git, :cmake, :vcport
16
+
17
+ def initialize(path)
18
+ @path = path
19
+ @spec = Spec.load(path)
20
+ @cmake = CMake.open(path)
21
+ @vcport = VCPort.open(path)
22
+ @git = Git.open(path)
23
+ end
24
+
25
+ def scan_spec
26
+ @spec = Spec.load(path)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vcpkg_pipeline/extension/vcpkg_vpl'
4
+
5
+ require 'vcpkg_pipeline/core/log'
6
+
7
+ module VPL
8
+ # VPL::Spec
9
+ class Spec
10
+ # spec file
11
+ attr_accessor :path, :content_path, :content
12
+
13
+ # port info
14
+ attr_accessor :name, :version, :user, :homepage, :description, :dependencies
15
+
16
+ # dist info
17
+ attr_accessor :sources, :disturl
18
+
19
+ def self.eval_vplspec(content, content_path)
20
+ instance_eval(content)
21
+ rescue RescueException => e
22
+ VPL.error("Invalid `#{content_path.basename}` file: #{e.message}")
23
+ end
24
+
25
+ def self.load(path)
26
+ content_path_list = Dir["#{path}/*.vplspec"]
27
+ VPL.error('未找到或存在多个 *.vplspec 文件') if content_path_list.empty? || content_path_list.count > 1
28
+ content_path = content_path_list.first
29
+ content = File.read(content_path)
30
+
31
+ spec = eval_vplspec(content, content_path)
32
+ spec.path = path
33
+ spec.content_path = content_path
34
+ spec.content = content
35
+ spec
36
+ end
37
+
38
+ def initialize
39
+ yield self if block_given?
40
+ end
41
+
42
+ def distfile_name
43
+ "#{name}-#{version}.zip"
44
+ end
45
+
46
+ def distfile_package(output_path = nil)
47
+ output_path ||= '.'
48
+ distfile_path = "#{output_path}/#{distfile_name}"
49
+ `zip #{distfile_path} #{sources.join(' ')}`
50
+ if File.exist? distfile_path
51
+ VPL.info("Dist包 打包成功: #{distfile_path}")
52
+ else
53
+ VPL.error("Dist包 打包失败: #{distfile_path}")
54
+ end
55
+ VCPkg.hash(distfile_path)
56
+ end
57
+
58
+ def write(property, value)
59
+ VPL.info("写入 #{File.basename(@content_path)} : #{property} = #{value}")
60
+
61
+ new_content = @content.gsub!(/(.*.#{property}.*=.*)('.*')/, "\\1'#{value}'")
62
+ File.write(@content_path, new_content)
63
+ end
64
+
65
+ def version_increased
66
+ versions = @version.split('.')
67
+
68
+ new_version_last = (versions.last.to_i + 1).to_s
69
+ versions.pop
70
+ versions.push(new_version_last)
71
+
72
+ versions.join('.')
73
+ end
74
+
75
+ def version_update(new_version = nil)
76
+ new_version ||= version_increased
77
+ write('version', new_version)
78
+ end
79
+
80
+ def to_s
81
+ "#{@name} (#{@version})\
82
+ \nuser: #{@user}\
83
+ \nhomepage: #{@homepage}\
84
+ \ndescription: #{@description}\
85
+ \nsources: #{@sources}\
86
+ \ndependencies: #{@dependencies}"
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vcpkg_pipeline/extension/vcpkg_vpl'
4
+
5
+ require 'vcpkg_pipeline/core/scanner'
6
+
7
+ module VPL
8
+ # VPL::Updater
9
+ class Updater
10
+ attr_accessor :path, :scanner
11
+
12
+ def initialize(path)
13
+ @path = path
14
+ @scanner = Scanner.new(path)
15
+ end
16
+
17
+ def update_spec(version = nil)
18
+ @scanner.spec.version_update(version)
19
+ @scanner.scan_spec
20
+ end
21
+
22
+ def update_cmake
23
+ @scanner.cmake.version_update(
24
+ @scanner.spec.version
25
+ )
26
+ end
27
+
28
+ def update_vcport_vcpkg
29
+ vcpkg = @scanner.vcport.vcpkg
30
+ vcpkg.version_update(@scanner.spec.version)
31
+ VCPkg.format(vcpkg.content_path)
32
+ end
33
+
34
+ def update_vcport_portfile(output_path = nil)
35
+ distfile_hash = @scanner.spec.distfile_package(output_path)
36
+ @scanner.vcport.portfile.download_distfile_update(
37
+ @scanner.spec.disturl,
38
+ @scanner.spec.distfile_name,
39
+ distfile_hash
40
+ )
41
+ end
42
+
43
+ def update_vcport(output_path = nil)
44
+ update_vcport_vcpkg
45
+ update_vcport_portfile(output_path)
46
+ end
47
+
48
+ def update_git
49
+ @scanner.git.quick_push(
50
+ @scanner.spec.version
51
+ )
52
+ end
53
+
54
+ def update_all(version = nil, output_path = nil)
55
+ @scanner.git.reset
56
+
57
+ update_spec(version)
58
+ @scanner.git.add('*.vplspec')
59
+ update_cmake
60
+ @scanner.git.add('CMakeLists.txt')
61
+ update_vcport(output_path)
62
+ @scanner.git.add('vcport')
63
+
64
+ @scanner.git.commit(@scanner.cmake.version)
65
+
66
+ update_git
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vcpkg_pipeline/extension/string_vpl'
4
+ require 'vcpkg_pipeline/extension/dir_vpl'
5
+
6
+ require 'vcpkg_pipeline/core/log'
7
+
8
+ # CMake
9
+ module CMake
10
+ def self.open(path)
11
+ CMake::Base.new(path)
12
+ end
13
+
14
+ # CMake::Base
15
+ class Base
16
+ attr_accessor :path, :content_path, :content, :project, :name, :version
17
+
18
+ def initialize(path)
19
+ @path = path
20
+ @content_path = "#{path}/CMakeLists.txt"
21
+
22
+ VPL.error("#{@content_path} Not Found") unless File.exist? @content_path
23
+ @content = File.read(@content_path)
24
+
25
+ parse_content(@content)
26
+ end
27
+
28
+ def parse_content(content)
29
+ content.each_line(')') { |piece| parse_project(piece) }
30
+ end
31
+
32
+ def parse_project(piece)
33
+ return unless piece.include? 'project'
34
+
35
+ @project = piece
36
+
37
+ clean_project = piece.clean
38
+ parse_project_name(clean_project)
39
+ parse_project_version(clean_project)
40
+ end
41
+
42
+ def parse_project_name(clean_project)
43
+ regex_name = /project \( ([^ ]*) /
44
+ regex_name.match(clean_project)
45
+ @name = Regexp.last_match(1)
46
+ end
47
+
48
+ def parse_project_version(clean_project)
49
+ regex_version = /VERSION ([^ ]*) /
50
+ regex_version.match(clean_project)
51
+ @version = Regexp.last_match(1)
52
+ end
53
+
54
+ def version_increased
55
+ regex_version = /([^.]*)\.([^.]*)\.([^.]*)\.*([^.]*)/
56
+ regex_version.match(@version)
57
+
58
+ new_patch = Regexp.last_match(3).to_i + 1
59
+ "#{Regexp.last_match(1)}.#{Regexp.last_match(2)}.#{new_patch}#{Regexp.last_match(4)}"
60
+ end
61
+
62
+ def version_update(new_version = nil)
63
+ new_version ||= version_increased
64
+
65
+ new_project = @project.sub(@version, new_version)
66
+ new_content = @content.sub(@project, new_project)
67
+ File.write(@content_path, new_content)
68
+
69
+ @content = new_content
70
+ @project = new_project
71
+ @version = new_version
72
+ end
73
+
74
+ def to_s
75
+ "#{name}-#{version}"
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Dir
4
+ class Dir
5
+ def reset(path)
6
+ return unless File.directory? path
7
+
8
+ `rm -fr #{path}`
9
+ `mkdir #{path}`
10
+ end
11
+
12
+ def self.replace_content(path, replacements)
13
+ content = File.read(path)
14
+ replacements.each do |find, replace|
15
+ content = content.gsub(find, replace)
16
+ end
17
+ File.write(path, content)
18
+ end
19
+
20
+ def self.replace_all(path, replacements)
21
+ Dir["#{path}/*"].each do |subpath|
22
+ subpath_rpl = subpath
23
+ replacements.each { |find, replace| subpath_rpl = subpath_rpl.gsub(find, replace)}
24
+ File.rename(subpath, subpath_rpl)
25
+
26
+ if File.directory? subpath_rpl
27
+ replace_all(subpath_rpl, replacements)
28
+ else
29
+ replace_content(subpath_rpl, replacements)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'git'
4
+
5
+ require 'vcpkg_pipeline/core/log'
6
+
7
+ module Git
8
+ # Git::Base
9
+ class Base
10
+ def current_branch
11
+ branches.current.first
12
+ end
13
+
14
+ def quick_push_tag(has_tag)
15
+ push(remote, current_branch, has_tag)
16
+ VPL.info("Git上传 #{remote} #{current_branch} #{new_version}")
17
+ end
18
+
19
+ def quick_push(new_tag = nil)
20
+ return unless ENV['Release']
21
+
22
+ has_tag = !new_tag.empty?
23
+ if has_tag
24
+ tags.each { |tag| VPL.error("当前版本 #{new_tag} 已发布, 请尝试其他版本号") if tag.name.eql? new_tag }
25
+
26
+ add_tag(new_tag)
27
+ VPL.info("Git提交Tag: #{new_tag}")
28
+ end
29
+ quick_push_tag(has_tag)
30
+ end
31
+
32
+ def to_s
33
+ "#{remote}-#{branches.current.first}"
34
+ end
35
+ end
36
+
37
+ # Git::Branches
38
+ class Branches
39
+ def current
40
+ local.select { :current }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # String
4
+ class String
5
+ def clean
6
+ gsub(/\#.*/, '').gsub(/\(/, ' ( ').gsub(/\)/, ' ) ').gsub(/\n/, ' ').gsub(/\ +/, ' ')
7
+ end
8
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vcpkg_pipeline/extension/vcport_vpl'
4
+
5
+ require 'vcpkg_pipeline/core/log'
6
+
7
+ # VCPkg
8
+ module VCPkg
9
+ def self.root
10
+ `echo $VCPKG_ROOT`
11
+ end
12
+
13
+ def self.ports
14
+ "#{root}/ports"
15
+ end
16
+
17
+ def self.hash(zip_path)
18
+ `vcpkg hash #{zip_path}`.sub(/\n/, '')
19
+ end
20
+
21
+ def self.format(vcpkg_json_path)
22
+ `vcpkg format-manifest #{vcpkg_json_path}`
23
+ end
24
+
25
+ def self.publish(vcport)
26
+ name = vcport.vcpkg.name
27
+ version = vcport.vcpkg.version
28
+
29
+ git_vcpkg = Git.open(root)
30
+ git_vcpkg.stashes.all
31
+
32
+ port_exist = File.directory? "#{VCPkg.root}/ports/#{name}"
33
+
34
+ `cp -fr #{vcport.port_path} #{ports}`
35
+ `vcpkg x-add-version #{name}`
36
+
37
+ git_vcpkg.add('.')
38
+ git_vcpkg.commit("[#{name}] #{port_exist ? 'Update' : 'Add'} #{version}")
39
+ git_vcpkg.quick_push
40
+ end
41
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ require 'vcpkg_pipeline/extension/string_vpl'
6
+
7
+ require 'vcpkg_pipeline/core/log'
8
+
9
+ # VCPort
10
+ module VCPort
11
+ def self.open(path)
12
+ VCPort::Base.new(path)
13
+ end
14
+
15
+ # VCPort::Base
16
+ class Base
17
+ attr_accessor :path, :port_path, :vcpkg, :portfile
18
+
19
+ def initialize(path)
20
+ @path = path
21
+ @port_path = "#{path}/vcport"
22
+ VPL.error("#{@port_path} Not Found") unless File.directory? @port_path
23
+
24
+ @vcpkg = VCPkg.new(@port_path)
25
+ @portfile = Portfile.new(@port_path)
26
+ end
27
+
28
+ def to_s
29
+ "#{vcpkg}\n#{portfile}"
30
+ end
31
+
32
+ # VCPort::Base::VCPkg
33
+ class VCPkg
34
+ attr_accessor :path, :content_path, :content, :json, :name, :version
35
+
36
+ def initialize(path)
37
+ @path = path
38
+ @content_path = "#{path}/vcpkg.json"
39
+
40
+ VPL.error("#{@content_path} Not Found") unless File.exist? @content_path
41
+ @content = File.read(@content_path)
42
+
43
+ parse_content(@content)
44
+ end
45
+
46
+ def parse_content(content)
47
+ @json = JSON.parse(content)
48
+ @name = @json['name']
49
+ @version = @json['version']
50
+ end
51
+
52
+ def version_update(new_version)
53
+ @json['version'] = new_version
54
+ File.write(@content_path, JSON.dump(@json))
55
+ VPL.info("Port 版本号更新: #{@version} -> #{new_version}")
56
+ end
57
+
58
+ def to_s
59
+ "#{json['name']}-#{json['version']}"
60
+ end
61
+ end
62
+
63
+ # VCPort::Base::Portfile
64
+ class Portfile
65
+ attr_accessor :path, :content_path, :content, :download_distfile, :url, :filename, :hash
66
+
67
+ def initialize(path)
68
+ @path = path
69
+ @content_path = "#{path}/portfile.cmake"
70
+
71
+ VPL.error("#{@content_path} Not Found") unless File.exist? @content_path
72
+ @content = File.read(@content_path)
73
+
74
+ parse_content(@content)
75
+ end
76
+
77
+ def parse_content(content)
78
+ content.each_line(')') { |piece| parse_download_distfile(piece) }
79
+ end
80
+
81
+ def parse_download_distfile(piece)
82
+ return unless piece.include? 'vcpkg_download_distfile'
83
+
84
+ @download_distfile = piece
85
+
86
+ clean_download_distfile = piece.clean
87
+ parse_download_distfile_url(clean_download_distfile)
88
+ parse_download_distfile_filename(clean_download_distfile)
89
+ parse_download_distfile_hash(clean_download_distfile)
90
+ end
91
+
92
+ def parse_download_distfile_url(clean_download_distfile)
93
+ regex_url = /URLS "([^ ]*)" /
94
+ regex_url.match(clean_download_distfile)
95
+ @url = Regexp.last_match(1)
96
+ end
97
+
98
+ def parse_download_distfile_filename(clean_download_distfile)
99
+ regex_filename = /FILENAME "([^ ]*)" /
100
+ regex_filename.match(clean_download_distfile)
101
+ @filename = Regexp.last_match(1)
102
+ end
103
+
104
+ def parse_download_distfile_hash(clean_download_distfile)
105
+ regex_hash = /SHA512 ([^ ]*) /
106
+ regex_hash.match(clean_download_distfile)
107
+ @hash = Regexp.last_match(1)
108
+ end
109
+
110
+ def download_distfile_update(new_url, new_filename, new_hash)
111
+ new_download_distfile = @download_distfile
112
+ new_download_distfile = new_download_distfile.sub("URLS \"#{@url}\"", "URLS \"#{new_url}\"")
113
+ new_download_distfile = new_download_distfile.sub("FILENAME \"#{@filename}\"", "FILENAME \"#{new_filename}\"")
114
+ new_download_distfile = new_download_distfile.sub("SHA512 #{@hash}", "SHA512 #{new_hash}")
115
+ File.write(@content_path, @content.sub(@download_distfile, new_download_distfile))
116
+ VPL.info("Port 下载文件信息更新: \
117
+ \n URLS #{@url} -> #{new_url}\
118
+ \n FILENAME #{@filename} -> #{new_filename}\
119
+ \n SHA512 #{@hash} -> #{new_hash}\
120
+ ")
121
+ end
122
+
123
+ def to_s
124
+ "#{@url} -> #{@filename}"
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ # VPL
4
+ module VPL
5
+ autoload :Command, 'vcpkg_pipeline/command'
6
+ end