confctl 1.0.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 +7 -0
- data/.editorconfig +11 -0
- data/.gitignore +8 -0
- data/.overcommit.yml +6 -0
- data/.rubocop.yml +67 -0
- data/.rubocop_todo.yml +5 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +2 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +674 -0
- data/README.md +522 -0
- data/Rakefile +40 -0
- data/bin/confctl +4 -0
- data/confctl.gemspec +33 -0
- data/example/.gitignore +2 -0
- data/example/README.md +38 -0
- data/example/cluster/cluster.nix +7 -0
- data/example/cluster/module-list.nix +3 -0
- data/example/cluster/nixos-machine/config.nix +15 -0
- data/example/cluster/nixos-machine/hardware.nix +4 -0
- data/example/cluster/nixos-machine/module.nix +8 -0
- data/example/cluster/vpsadminos-container/config.nix +22 -0
- data/example/cluster/vpsadminos-container/module.nix +8 -0
- data/example/cluster/vpsadminos-machine/config.nix +22 -0
- data/example/cluster/vpsadminos-machine/hardware.nix +4 -0
- data/example/cluster/vpsadminos-machine/module.nix +8 -0
- data/example/cluster/vpsfreecz-vps/config.nix +25 -0
- data/example/cluster/vpsfreecz-vps/module.nix +8 -0
- data/example/configs/confctl.nix +10 -0
- data/example/configs/swpins.nix +28 -0
- data/example/data/default.nix +5 -0
- data/example/data/ssh-keys.nix +7 -0
- data/example/environments/base.nix +13 -0
- data/example/modules/module-list.nix +13 -0
- data/example/shell.nix +11 -0
- data/example/swpins/channels/nixos-unstable.json +35 -0
- data/example/swpins/channels/vpsadminos-staging.json +35 -0
- data/lib/confctl/cli/app.rb +551 -0
- data/lib/confctl/cli/attr_filters.rb +51 -0
- data/lib/confctl/cli/cluster.rb +1248 -0
- data/lib/confctl/cli/command.rb +206 -0
- data/lib/confctl/cli/configuration.rb +296 -0
- data/lib/confctl/cli/gen_data.rb +97 -0
- data/lib/confctl/cli/generation.rb +335 -0
- data/lib/confctl/cli/log_view.rb +267 -0
- data/lib/confctl/cli/output_formatter.rb +288 -0
- data/lib/confctl/cli/swpins/base.rb +40 -0
- data/lib/confctl/cli/swpins/channel.rb +73 -0
- data/lib/confctl/cli/swpins/cluster.rb +80 -0
- data/lib/confctl/cli/swpins/core.rb +86 -0
- data/lib/confctl/cli/swpins/utils.rb +55 -0
- data/lib/confctl/cli/swpins.rb +5 -0
- data/lib/confctl/cli/tag_filters.rb +30 -0
- data/lib/confctl/cli.rb +5 -0
- data/lib/confctl/conf_cache.rb +105 -0
- data/lib/confctl/conf_dir.rb +88 -0
- data/lib/confctl/erb_template.rb +37 -0
- data/lib/confctl/exceptions.rb +3 -0
- data/lib/confctl/gcroot.rb +30 -0
- data/lib/confctl/generation/build.rb +145 -0
- data/lib/confctl/generation/build_list.rb +106 -0
- data/lib/confctl/generation/host.rb +35 -0
- data/lib/confctl/generation/host_list.rb +81 -0
- data/lib/confctl/generation/unified.rb +117 -0
- data/lib/confctl/generation/unified_list.rb +63 -0
- data/lib/confctl/git_repo_mirror.rb +79 -0
- data/lib/confctl/health_checks/base.rb +66 -0
- data/lib/confctl/health_checks/run_command.rb +179 -0
- data/lib/confctl/health_checks/systemd/properties.rb +84 -0
- data/lib/confctl/health_checks/systemd/property_check.rb +31 -0
- data/lib/confctl/health_checks/systemd/property_list.rb +20 -0
- data/lib/confctl/health_checks.rb +5 -0
- data/lib/confctl/hook.rb +35 -0
- data/lib/confctl/line_buffer.rb +53 -0
- data/lib/confctl/logger.rb +151 -0
- data/lib/confctl/machine.rb +107 -0
- data/lib/confctl/machine_control.rb +172 -0
- data/lib/confctl/machine_list.rb +108 -0
- data/lib/confctl/machine_status.rb +135 -0
- data/lib/confctl/module_options.rb +95 -0
- data/lib/confctl/nix.rb +382 -0
- data/lib/confctl/nix_build.rb +108 -0
- data/lib/confctl/nix_collect_garbage.rb +64 -0
- data/lib/confctl/nix_copy.rb +49 -0
- data/lib/confctl/nix_format.rb +124 -0
- data/lib/confctl/nix_literal_expression.rb +15 -0
- data/lib/confctl/parallel_executor.rb +43 -0
- data/lib/confctl/pattern.rb +9 -0
- data/lib/confctl/settings.rb +50 -0
- data/lib/confctl/std_line_buffer.rb +40 -0
- data/lib/confctl/swpins/change_set.rb +151 -0
- data/lib/confctl/swpins/channel.rb +62 -0
- data/lib/confctl/swpins/channel_list.rb +47 -0
- data/lib/confctl/swpins/cluster_name.rb +94 -0
- data/lib/confctl/swpins/cluster_name_list.rb +15 -0
- data/lib/confctl/swpins/core.rb +137 -0
- data/lib/confctl/swpins/deployed_info.rb +23 -0
- data/lib/confctl/swpins/spec.rb +20 -0
- data/lib/confctl/swpins/specs/base.rb +184 -0
- data/lib/confctl/swpins/specs/directory.rb +51 -0
- data/lib/confctl/swpins/specs/git.rb +135 -0
- data/lib/confctl/swpins/specs/git_rev.rb +24 -0
- data/lib/confctl/swpins.rb +17 -0
- data/lib/confctl/system_command.rb +10 -0
- data/lib/confctl/user_script.rb +13 -0
- data/lib/confctl/user_scripts.rb +41 -0
- data/lib/confctl/utils/file.rb +21 -0
- data/lib/confctl/version.rb +3 -0
- data/lib/confctl.rb +43 -0
- data/man/man8/confctl-options.nix.8 +1334 -0
- data/man/man8/confctl-options.nix.8.md +1340 -0
- data/man/man8/confctl.8 +660 -0
- data/man/man8/confctl.8.md +654 -0
- data/nix/evaluator.nix +160 -0
- data/nix/lib/default.nix +83 -0
- data/nix/lib/machine/default.nix +74 -0
- data/nix/lib/machine/info.nix +5 -0
- data/nix/lib/swpins/eval.nix +71 -0
- data/nix/lib/swpins/options.nix +94 -0
- data/nix/machines.nix +31 -0
- data/nix/modules/cluster/default.nix +459 -0
- data/nix/modules/confctl/cli.nix +21 -0
- data/nix/modules/confctl/generations.nix +84 -0
- data/nix/modules/confctl/nix.nix +28 -0
- data/nix/modules/confctl/swpins.nix +55 -0
- data/nix/modules/module-list.nix +19 -0
- data/shell.nix +42 -0
- data/template/confctl-options.nix/main.erb +45 -0
- data/template/confctl-options.nix/options.erb +15 -0
- metadata +353 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
module ConfCtl
|
|
5
|
+
class Swpins::Core
|
|
6
|
+
# @return [Swpins::Core]
|
|
7
|
+
def self.get
|
|
8
|
+
return @instance if @instance
|
|
9
|
+
|
|
10
|
+
@instance = new
|
|
11
|
+
@instance.parse
|
|
12
|
+
@instance
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
include Utils::File
|
|
16
|
+
|
|
17
|
+
# @return [String]
|
|
18
|
+
attr_reader :name
|
|
19
|
+
|
|
20
|
+
# @return [String]
|
|
21
|
+
attr_reader :path
|
|
22
|
+
|
|
23
|
+
# @return [Hash<String, Swpins::Specs::Base>]
|
|
24
|
+
attr_reader :specs
|
|
25
|
+
|
|
26
|
+
# @return [Array<Swpins::Channel>]
|
|
27
|
+
attr_reader :channels
|
|
28
|
+
|
|
29
|
+
def initialize
|
|
30
|
+
@name = 'core'
|
|
31
|
+
@path = File.join(ConfCtl::Swpins.core_dir, 'core.json')
|
|
32
|
+
|
|
33
|
+
settings = ConfCtl::Settings.instance
|
|
34
|
+
|
|
35
|
+
@channels = Swpins::ChannelList.get.select do |c|
|
|
36
|
+
settings.core_swpin_channels.include?(c.name)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
@nix_specs = settings.core_swpin_pins
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def parse
|
|
43
|
+
@specs = {}
|
|
44
|
+
|
|
45
|
+
# Add specs from channels
|
|
46
|
+
channels.each do |chan|
|
|
47
|
+
chan.specs.each do |name, chan_spec|
|
|
48
|
+
s = chan_spec.clone
|
|
49
|
+
s.channel = chan.name
|
|
50
|
+
specs[name] = s
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Add core-specific specs
|
|
55
|
+
@json_specs = if File.exist?(path)
|
|
56
|
+
JSON.parse(File.read(path))
|
|
57
|
+
else
|
|
58
|
+
{}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
nix_specs.each do |name, nix_opts|
|
|
62
|
+
specs[name] = Swpins::Spec.for(nix_opts['type'].to_sym).new(
|
|
63
|
+
name,
|
|
64
|
+
nix_opts[nix_opts['type']],
|
|
65
|
+
json_specs[name]
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def valid?
|
|
71
|
+
specs.values.all?(&:valid?)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def save
|
|
75
|
+
custom = {}
|
|
76
|
+
|
|
77
|
+
specs.each do |name, s|
|
|
78
|
+
custom[name] = s unless s.from_channel?
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if custom.empty?
|
|
82
|
+
begin
|
|
83
|
+
File.unlink(path)
|
|
84
|
+
rescue Errno::ENOENT
|
|
85
|
+
# ignore
|
|
86
|
+
end
|
|
87
|
+
else
|
|
88
|
+
tmp = "#{path}.new"
|
|
89
|
+
|
|
90
|
+
FileUtils.mkdir_p(ConfCtl::Swpins.core_dir)
|
|
91
|
+
|
|
92
|
+
File.open(tmp, 'w') do |f|
|
|
93
|
+
f.puts(JSON.pretty_generate(custom))
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
File.rename(tmp, path)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def pre_evaluate
|
|
101
|
+
nix = ConfCtl::Nix.new
|
|
102
|
+
paths = nix.eval_core_swpins
|
|
103
|
+
|
|
104
|
+
FileUtils.mkdir_p(cache_dir)
|
|
105
|
+
|
|
106
|
+
paths.each do |pin, path|
|
|
107
|
+
name = "core-swpin.#{pin}"
|
|
108
|
+
link = File.join(cache_dir, name)
|
|
109
|
+
replace_symlink(link, path)
|
|
110
|
+
ConfCtl::GCRoot.add(name, link) unless ConfCtl::GCRoot.exist?(name)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def pre_evaluated_store_paths
|
|
115
|
+
swpins_path = File.join(cache_dir, 'core.swpins')
|
|
116
|
+
return unless File.exist?(swpins_path)
|
|
117
|
+
|
|
118
|
+
swpins = JSON.parse(File.read(swpins_path))
|
|
119
|
+
|
|
120
|
+
missing_path = swpins.each_value.detect do |path|
|
|
121
|
+
!Dir.exist?(path)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
return if missing_path
|
|
125
|
+
|
|
126
|
+
swpins
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
protected
|
|
130
|
+
|
|
131
|
+
attr_reader :nix_specs, :json_specs
|
|
132
|
+
|
|
133
|
+
def cache_dir
|
|
134
|
+
File.join(ConfDir.cache_dir, 'build')
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
module ConfCtl
|
|
4
|
+
class Swpins::DeployedInfo
|
|
5
|
+
# @param json [String]
|
|
6
|
+
def self.parse!(json)
|
|
7
|
+
new(JSON.parse(json))
|
|
8
|
+
rescue JSON::ParserError => e
|
|
9
|
+
raise Error, "unable to parse swpins info: #{e.message}"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @return [Hash]
|
|
13
|
+
attr_reader :swpins
|
|
14
|
+
|
|
15
|
+
def initialize(hash)
|
|
16
|
+
@swpins = hash
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def [](swpin)
|
|
20
|
+
swpins[swpin]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module ConfCtl
|
|
2
|
+
module Swpins::Spec
|
|
3
|
+
# @param name [Symbol]
|
|
4
|
+
# @param klass [Class]
|
|
5
|
+
def self.register(name, klass)
|
|
6
|
+
@specs ||= {}
|
|
7
|
+
@specs[name] = klass
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @param name [Symbol]
|
|
11
|
+
# @return [Class]
|
|
12
|
+
def self.for(name)
|
|
13
|
+
@specs[name]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
module Swpins::Specs; end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
require_rel 'specs'
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
module ConfCtl
|
|
2
|
+
class Swpins::Specs::Base
|
|
3
|
+
class << self
|
|
4
|
+
attr_reader :type
|
|
5
|
+
|
|
6
|
+
# @param name [Symbol]
|
|
7
|
+
def handle(name)
|
|
8
|
+
@type = name
|
|
9
|
+
Swpins::Spec.register(name, self)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# @return [String]
|
|
14
|
+
attr_reader :name
|
|
15
|
+
|
|
16
|
+
# @param [String]
|
|
17
|
+
# @return [String, nil]
|
|
18
|
+
attr_accessor :channel
|
|
19
|
+
|
|
20
|
+
# @return [Array]
|
|
21
|
+
attr_reader :errors
|
|
22
|
+
|
|
23
|
+
# @return [Hash]
|
|
24
|
+
attr_reader :info
|
|
25
|
+
|
|
26
|
+
# @param name [String]
|
|
27
|
+
# @param nix_opts [Hash] options from the user's nix configuration
|
|
28
|
+
# @param json_opts [Hash] options from generated json file
|
|
29
|
+
def initialize(name, nix_opts, json_opts)
|
|
30
|
+
@name = name
|
|
31
|
+
@nix_opts = nix_opts
|
|
32
|
+
@json_opts = json_opts
|
|
33
|
+
@state = nil
|
|
34
|
+
@info = nil
|
|
35
|
+
@fetcher = nil
|
|
36
|
+
@fetcher_opts = nil
|
|
37
|
+
@errors = []
|
|
38
|
+
parse
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def type
|
|
42
|
+
self.class.type
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Check that current nix options match those that generated json options
|
|
46
|
+
# @return [Boolean]
|
|
47
|
+
def check_opts
|
|
48
|
+
raise NotImplementedError
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def valid?
|
|
52
|
+
errors.empty?
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def can_update?
|
|
56
|
+
nix_opts['update']['ref'] ? true : false
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def auto_update?
|
|
60
|
+
can_update? && nix_opts['update']['auto']
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def from_channel?
|
|
64
|
+
!channel.nil?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def status
|
|
68
|
+
valid? ? version : 'update'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def version
|
|
72
|
+
raise NotImplementedError
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def prefetch_set(args)
|
|
76
|
+
raise NotImplementedError
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def prefetch_update
|
|
80
|
+
raise NotImplementedError
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Check that `other_info` corresponds to this spec
|
|
84
|
+
# @param other_info [Hash]
|
|
85
|
+
# @return [Boolean]
|
|
86
|
+
def check_info(other_info)
|
|
87
|
+
raise NotImplementedError
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Return version based on the info hash
|
|
91
|
+
# @param other_info [Hash]
|
|
92
|
+
# @return [String]
|
|
93
|
+
def version_info(other_info)
|
|
94
|
+
raise NotImplementedError
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Generate changelog between revisions
|
|
98
|
+
# @param type [:upgrade, :downgrade]
|
|
99
|
+
# @param other_info [any] version reference
|
|
100
|
+
# @param opts [Hash] options
|
|
101
|
+
# @option opts [Boolean] :color
|
|
102
|
+
# @option opts [Boolean] :verbose
|
|
103
|
+
# @option opts [Boolean] :patch
|
|
104
|
+
# @return [String, nil]
|
|
105
|
+
def string_changelog_info(type, other_info, **opts)
|
|
106
|
+
raise NotImplementedError
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# Generate diff between revisions
|
|
110
|
+
# @param type [:upgrade, :downgrade]
|
|
111
|
+
# @param other_info [any] version reference
|
|
112
|
+
# @param opts [Hash] options
|
|
113
|
+
# @option opts [Boolean] :color
|
|
114
|
+
# @return [String, nil]
|
|
115
|
+
def string_diff_info(type, other_info, **opts)
|
|
116
|
+
raise NotImplementedError
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def as_json
|
|
120
|
+
ret = {}
|
|
121
|
+
ret['type'] = type.to_s
|
|
122
|
+
ret['nix_options'] = nix_opts
|
|
123
|
+
ret['state'] = state
|
|
124
|
+
ret['info'] = info
|
|
125
|
+
ret['fetcher'] = fetcher && {
|
|
126
|
+
'type' => fetcher,
|
|
127
|
+
'options' => fetcher_opts
|
|
128
|
+
}
|
|
129
|
+
ret
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def to_json(*args)
|
|
133
|
+
as_json.to_json(*args)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
protected
|
|
137
|
+
|
|
138
|
+
# @return [Hash]
|
|
139
|
+
attr_reader :nix_opts
|
|
140
|
+
|
|
141
|
+
# @return [Hash]
|
|
142
|
+
attr_reader :json_opts
|
|
143
|
+
|
|
144
|
+
# @return [Hash]
|
|
145
|
+
attr_accessor :state
|
|
146
|
+
|
|
147
|
+
attr_writer :info
|
|
148
|
+
|
|
149
|
+
# @return [String]
|
|
150
|
+
attr_reader :fetcher
|
|
151
|
+
|
|
152
|
+
# @return [Hash]
|
|
153
|
+
attr_reader :fetcher_opts
|
|
154
|
+
|
|
155
|
+
def parse
|
|
156
|
+
errors.clear
|
|
157
|
+
|
|
158
|
+
if json_opts.nil?
|
|
159
|
+
errors << 'needs prefetch'
|
|
160
|
+
elsif type.to_s != json_opts['type']
|
|
161
|
+
errors << 'invalid type, needs update'
|
|
162
|
+
elsif !json_opts['nix_options'] || !check_opts
|
|
163
|
+
errors << 'outdated options, needs update'
|
|
164
|
+
elsif json_opts['fetcher'].nil?
|
|
165
|
+
errors << 'no fetcher, needs update'
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
return if errors.any?
|
|
169
|
+
|
|
170
|
+
@state = json_opts['state']
|
|
171
|
+
@info = json_opts['info']
|
|
172
|
+
|
|
173
|
+
return unless json_opts['fetcher']
|
|
174
|
+
|
|
175
|
+
@fetcher = json_opts['fetcher']['type']
|
|
176
|
+
@fetcher_opts = json_opts['fetcher']['options']
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def set_fetcher(name, opts)
|
|
180
|
+
@fetcher = name
|
|
181
|
+
@fetcher_opts = opts
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require_relative 'base'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
module ConfCtl
|
|
6
|
+
class Swpins::Specs::Directory < Swpins::Specs::Base
|
|
7
|
+
handle :directory
|
|
8
|
+
|
|
9
|
+
def check_opts
|
|
10
|
+
nix_opts['path'] === json_opts['nix_options']['path']
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def version
|
|
14
|
+
'directory'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def can_update?
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def auto_update?
|
|
22
|
+
true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def prefetch_set(args)
|
|
26
|
+
raise "spec #{name} does not accept any arguments" if args.any?
|
|
27
|
+
|
|
28
|
+
set_fetcher(:directory, { path: nix_opts['path'] })
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def prefetch_update
|
|
32
|
+
set_fetcher(:directory, { path: nix_opts['path'] })
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def check_info(_other_info)
|
|
36
|
+
false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def version_info(_other_info)
|
|
40
|
+
'directory'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def string_changelog_info(_type, _other_info, verbose: false, patch: false, color: false)
|
|
44
|
+
nil
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def string_diff_info(_type, _other_info, _opts = {})
|
|
48
|
+
nil
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
require_relative 'base'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
module ConfCtl
|
|
6
|
+
class Swpins::Specs::Git < Swpins::Specs::Base
|
|
7
|
+
handle :git
|
|
8
|
+
|
|
9
|
+
def check_opts
|
|
10
|
+
nix_opts['url'] === json_opts['nix_options']['url'] \
|
|
11
|
+
&& nix_opts['fetchSubmodules'] === json_opts['nix_options']['fetchSubmodules']
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def version
|
|
15
|
+
state['rev'][0..8]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def auto_update?
|
|
19
|
+
super && (
|
|
20
|
+
state['date'].nil? \
|
|
21
|
+
|| (Time.iso8601(state['date']) + nix_opts['update']['interval'] < Time.now)
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def prefetch_set(args)
|
|
26
|
+
ref = args[0]
|
|
27
|
+
|
|
28
|
+
if %r{^https://github\.com/} =~ nix_opts['url'] && !nix_opts['fetchSubmodules']
|
|
29
|
+
set_fetcher('zip', prefetch_github(ref))
|
|
30
|
+
else
|
|
31
|
+
set_fetcher('git', prefetch_git(ref))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def prefetch_update
|
|
36
|
+
prefetch_set([nix_opts['update']['ref']])
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def check_info(other_info)
|
|
40
|
+
return false if !other_info.is_a?(Hash) || !info.is_a?(Hash)
|
|
41
|
+
|
|
42
|
+
other_info['rev'] == info['rev'] && other_info['sha256'] == info['sha256']
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def version_info(other_info)
|
|
46
|
+
return false if !other_info.is_a?(Hash) || !info.is_a?(Hash)
|
|
47
|
+
|
|
48
|
+
other_info['rev'] && other_info['rev'][0..8]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def string_changelog_info(type, other_info, verbose: false, patch: false, color: false)
|
|
52
|
+
opts = []
|
|
53
|
+
opts << '--color=always' if color
|
|
54
|
+
opts << '--oneline' unless verbose
|
|
55
|
+
opts << '-p' if patch
|
|
56
|
+
|
|
57
|
+
args =
|
|
58
|
+
if type == :upgrade
|
|
59
|
+
[other_info['rev'], state['rev']]
|
|
60
|
+
else
|
|
61
|
+
[state['rev'], other_info['rev']]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
git_mirror_with_info(other_info) do |mirror|
|
|
65
|
+
mirror.log(*args, opts:)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def string_diff_info(type, other_info, color: false, **_opts)
|
|
70
|
+
gitopts = []
|
|
71
|
+
gitopts << '--color=always' if color
|
|
72
|
+
|
|
73
|
+
args =
|
|
74
|
+
if type == :upgrade
|
|
75
|
+
[other_info['rev'], state['rev']]
|
|
76
|
+
else
|
|
77
|
+
[state['rev'], other_info['rev']]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
git_mirror_with_info(other_info) do |mirror|
|
|
81
|
+
mirror.diff(*args, opts: gitopts)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
protected
|
|
86
|
+
|
|
87
|
+
def prefetch_git(ref)
|
|
88
|
+
json = `nix-prefetch-git --quiet #{nix_opts['url']} #{ref}`
|
|
89
|
+
|
|
90
|
+
raise "nix-prefetch-git failed with status #{$?.exitstatus}" if $?.exitstatus != 0
|
|
91
|
+
|
|
92
|
+
ret = JSON.parse(json.strip)
|
|
93
|
+
self.state = {
|
|
94
|
+
'rev' => ret['rev'],
|
|
95
|
+
'date' => Time.now.iso8601
|
|
96
|
+
}
|
|
97
|
+
self.info = {
|
|
98
|
+
'rev' => ret['rev'],
|
|
99
|
+
'sha256' => ret['sha256']
|
|
100
|
+
}
|
|
101
|
+
ret
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def prefetch_github(ref)
|
|
105
|
+
mirror = GitRepoMirror.new(nix_opts['url'])
|
|
106
|
+
mirror.setup
|
|
107
|
+
|
|
108
|
+
rev = mirror.revision_parse(ref)
|
|
109
|
+
url = File.join(nix_opts['url'], 'archive', "#{rev}.tar.gz")
|
|
110
|
+
hash = `nix-prefetch-url --unpack "#{url}" 2> /dev/null`.strip
|
|
111
|
+
|
|
112
|
+
raise "nix-prefetch-url failed with status #{$?.exitstatus}" if $?.exitstatus != 0
|
|
113
|
+
|
|
114
|
+
self.state = {
|
|
115
|
+
'rev' => rev,
|
|
116
|
+
'date' => Time.now.iso8601
|
|
117
|
+
}
|
|
118
|
+
self.info = {
|
|
119
|
+
'rev' => rev,
|
|
120
|
+
'sha256' => hash
|
|
121
|
+
}
|
|
122
|
+
{ 'url' => url, 'sha256' => hash }
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def git_mirror_with_info(other_info)
|
|
126
|
+
raise ConfCtl::Error, 'swpin not configured' if info.nil?
|
|
127
|
+
|
|
128
|
+
return if state['rev'] == other_info['rev']
|
|
129
|
+
|
|
130
|
+
mirror = GitRepoMirror.new(nix_opts['url'], quiet: true)
|
|
131
|
+
mirror.setup
|
|
132
|
+
yield(mirror)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require_relative 'git'
|
|
2
|
+
|
|
3
|
+
module ConfCtl
|
|
4
|
+
class Swpins::Specs::GitRev < Swpins::Specs::Git
|
|
5
|
+
handle :'git-rev'
|
|
6
|
+
|
|
7
|
+
def prefetch_set(args)
|
|
8
|
+
super(args)
|
|
9
|
+
wrap_fetcher
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
protected
|
|
13
|
+
|
|
14
|
+
def wrap_fetcher
|
|
15
|
+
set_fetcher('git-rev', {
|
|
16
|
+
'rev' => state['rev'],
|
|
17
|
+
'wrapped_fetcher' => {
|
|
18
|
+
'type' => fetcher,
|
|
19
|
+
'options' => fetcher_opts
|
|
20
|
+
}
|
|
21
|
+
})
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module ConfCtl
|
|
2
|
+
module Swpins
|
|
3
|
+
def self.core_dir
|
|
4
|
+
File.join(ConfDir.path, 'swpins')
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.channel_dir
|
|
8
|
+
File.join(ConfDir.path, 'swpins/channels')
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.cluster_dir
|
|
12
|
+
File.join(ConfDir.path, 'swpins/cluster')
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
require_rel 'swpins'
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module ConfCtl
|
|
2
|
+
module UserScripts
|
|
3
|
+
def self.load_scripts
|
|
4
|
+
dir = ConfDir.user_script_dir
|
|
5
|
+
|
|
6
|
+
begin
|
|
7
|
+
files = Dir.entries(dir)
|
|
8
|
+
rescue Errno::ENOENT
|
|
9
|
+
return
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
files.each do |f|
|
|
13
|
+
abs_path = File.join(dir, f)
|
|
14
|
+
next unless File.file?(abs_path)
|
|
15
|
+
|
|
16
|
+
load(abs_path)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.register(klass)
|
|
21
|
+
@scripts ||= []
|
|
22
|
+
@scripts << klass.new
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.setup_all
|
|
26
|
+
each do |script|
|
|
27
|
+
script.setup_hooks(Hook)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @return [Array<UserScript>]
|
|
32
|
+
def self.get
|
|
33
|
+
@scripts || []
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# @yieldparam [UserScript]
|
|
37
|
+
def self.each(&)
|
|
38
|
+
get.each(&)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module ConfCtl
|
|
2
|
+
module Utils::File
|
|
3
|
+
# Atomically replace or create symlink
|
|
4
|
+
# @param path [String] symlink path
|
|
5
|
+
# @param dst [String] destination
|
|
6
|
+
def replace_symlink(path, dst)
|
|
7
|
+
replacement = "#{path}.new-#{SecureRandom.hex(3)}"
|
|
8
|
+
File.symlink(dst, replacement)
|
|
9
|
+
File.rename(replacement, path)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Unlink file if it exists
|
|
13
|
+
# @param path [String]
|
|
14
|
+
def unlink_if_exists(path)
|
|
15
|
+
File.unlink(path)
|
|
16
|
+
true
|
|
17
|
+
rescue Errno::ENOENT
|
|
18
|
+
false
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|