repo-mgr 0.1.1 → 0.2.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/README.md +30 -3
- data/lib/repo_mgr/backends/deb.rb +17 -2
- data/lib/repo_mgr/backends/rpm.rb +6 -0
- data/lib/repo_mgr/cli.rb +52 -6
- data/lib/repo_mgr/config.rb +20 -9
- data/lib/repo_mgr/publishers.rb +18 -0
- data/lib/repo_mgr/publishers/git.rb +30 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 134dd25e2f420da28416738476d2461cfc4e41e358b9eeefd95740b12fb32b29
|
4
|
+
data.tar.gz: 583f3afd307e6b101df5fb316619c8636882388d93937fe8cd66200d302c03e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88e36dd2757d71c32276fa7a7c02c218a0f3dcc2c497b87264388e0ef9a9cd65308b35588ae3b967073ddb823c6bdb3310be6eb47b87f18a63de75526d6b039e
|
7
|
+
data.tar.gz: 0bf223130b5aee561025db95edf42322e09071767c43d2ceddaeee77317a1a808fde24f994cf9995c1e4299424e26ecda35aa0222a047bf6ef6b7ecc0d6d883d
|
data/README.md
CHANGED
@@ -9,8 +9,12 @@ Features:
|
|
9
9
|
* Create/update deb/rpm repositories.
|
10
10
|
* Add/remove packages to these repositories and automatically sign packages using GPG.
|
11
11
|
* Repository metadata/manifest signing using GPG.
|
12
|
+
* Publish to remote via git.
|
12
13
|
|
13
|
-
To simplify things
|
14
|
+
To simplify things:
|
15
|
+
|
16
|
+
* aptly (which, kind of obviously, manages deb repositories) uses "stable" as distribution and "main" as component.
|
17
|
+
* The git publisher uses the `main` branch for `sync` only.
|
14
18
|
|
15
19
|
## Install
|
16
20
|
|
@@ -35,6 +39,7 @@ repo-mgr check-depends
|
|
35
39
|
| dpkg-sig | ✔ |
|
36
40
|
| createrepo | ✔ |
|
37
41
|
| rpm | ✔ |
|
42
|
+
| git | ✔ |
|
38
43
|
+------------+--------+
|
39
44
|
```
|
40
45
|
|
@@ -48,6 +53,12 @@ For managing rpm repositories:
|
|
48
53
|
|
49
54
|
```bash
|
50
55
|
sudo apt install createrepo rpm
|
56
|
+
```
|
57
|
+
|
58
|
+
For using the git publisher:
|
59
|
+
|
60
|
+
```bash
|
61
|
+
sudo apt install git
|
51
62
|
```
|
52
63
|
|
53
64
|
n.b `createrepo` is not normally available for Debian and derrivates (including Ubuntu). This tool
|
@@ -65,11 +76,27 @@ repo-mgr help
|
|
65
76
|
# create repo
|
66
77
|
## --path => a local directory where the repository is published - no remote support at the moment
|
67
78
|
## GPGKEYID is expected as log keyid i.e 16 hex chars
|
68
|
-
|
79
|
+
## --publisher - is optional i.e you can still manually publish a local repository
|
80
|
+
repo-mgr upsert-repo --name foo --type deb --path path/to/foo --keyid GPGKEYID --publisher git
|
69
81
|
|
70
82
|
# sign package, add to repository, and update local repo (includes sign repo release manifest)
|
71
83
|
# the local repo is exported to the path indicated in upsert-repo
|
84
|
+
# the git publisher also commits the changes as the path for upsert-repo is expected to be
|
85
|
+
# a git repository
|
72
86
|
repo-mgr add-pkg --repo foo --path path/to/bar_0.0.1_amd64.deb
|
87
|
+
|
88
|
+
# publish the repository to a remote - for git publisher this means doing git push
|
89
|
+
repo-mgr sync --repo foo
|
90
|
+
```
|
91
|
+
|
92
|
+
## Migrating from v0.1
|
93
|
+
|
94
|
+
The package list is stored into a structure that's prone to lose the list upon re-running `upsert-repo` for `v0.1.x` of this gem. For this reason, the package list data structure has been redesigned within repo-mgr's config file.
|
95
|
+
|
96
|
+
So, to migrate from this earlier version, you must run, for every repo:
|
97
|
+
|
98
|
+
```bash
|
99
|
+
repo-mgr rebuild-pkg-list --repo foo
|
73
100
|
```
|
74
101
|
|
75
|
-
|
102
|
+
This rebuilds the data structure in the new config location.
|
@@ -45,7 +45,7 @@ module RepoMgr
|
|
45
45
|
repo_publish repo
|
46
46
|
end
|
47
47
|
|
48
|
-
def check_sig(pkg, allow_fail
|
48
|
+
def check_sig(pkg, allow_fail: false)
|
49
49
|
out, status = Open3.capture2e "dpkg-sig --verify #{pkg}"
|
50
50
|
|
51
51
|
return out if status.exitstatus.zero? || allow_fail
|
@@ -55,7 +55,7 @@ module RepoMgr
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def sign_pkg(repo, pkg)
|
58
|
-
signature = check_sig pkg, true
|
58
|
+
signature = check_sig pkg, allow_fail: true
|
59
59
|
|
60
60
|
unless signature[-6, 5] == 'NOSIG'
|
61
61
|
return puts "-- dpkg-sig returned:\n#{signature.first}"
|
@@ -73,6 +73,21 @@ module RepoMgr
|
|
73
73
|
Tools.error "unable to sign #{pkg} - dpkg-sig returned:\n#{out}"
|
74
74
|
end
|
75
75
|
|
76
|
+
def rebuild_pkg_list(repo)
|
77
|
+
out, status = Open3.capture2e "aptly -config=#{@aptly_config_file} "\
|
78
|
+
"-with-packages repo show #{repo}"
|
79
|
+
|
80
|
+
unless status.exitstatus.zero?
|
81
|
+
Tools.error "aptly repo show failed with with:\n#{out}"
|
82
|
+
end
|
83
|
+
|
84
|
+
pkgs = out.split
|
85
|
+
mark = pkgs.find_index 'Packages:'
|
86
|
+
pkgs = pkgs.drop(mark + 1)
|
87
|
+
|
88
|
+
pkgs.map { |e| "#{e}.deb" }
|
89
|
+
end
|
90
|
+
|
76
91
|
private
|
77
92
|
|
78
93
|
def init_aptly_config
|
@@ -69,6 +69,12 @@ module RepoMgr
|
|
69
69
|
Tools.error "unable to sign #{pkg} - rpm --addsign returned:\n#{out}"
|
70
70
|
end
|
71
71
|
|
72
|
+
def rebuild_pkg_list(repo)
|
73
|
+
Dir["#{@config.cfg_dir}/rpms/#{repo}/**/*.rpm"].map do |e|
|
74
|
+
File.basename e
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
72
78
|
private
|
73
79
|
|
74
80
|
def extract_arch(pkg)
|
data/lib/repo_mgr/cli.rb
CHANGED
@@ -8,6 +8,7 @@ require 'terminal-table'
|
|
8
8
|
require_relative 'tools'
|
9
9
|
require_relative 'config'
|
10
10
|
require_relative 'backends'
|
11
|
+
require_relative 'publishers'
|
11
12
|
|
12
13
|
module RepoMgr
|
13
14
|
# implements CLI interface
|
@@ -20,12 +21,16 @@ module RepoMgr
|
|
20
21
|
%w[deb rpm]
|
21
22
|
end
|
22
23
|
|
24
|
+
def self.publishers
|
25
|
+
%w[git]
|
26
|
+
end
|
27
|
+
|
23
28
|
desc 'check-depends', 'Check dependencies'
|
24
29
|
|
25
30
|
def check_depends
|
26
31
|
rows = []
|
27
32
|
|
28
|
-
%w[aptly dpkg-sig createrepo rpm].each do |bin_dep|
|
33
|
+
%w[aptly dpkg-sig createrepo rpm git].each do |bin_dep|
|
29
34
|
rows << if Tools.which bin_dep
|
30
35
|
[bin_dep, '✔'.green]
|
31
36
|
else
|
@@ -45,13 +50,14 @@ module RepoMgr
|
|
45
50
|
desc: 'Directory path where to build the repository'
|
46
51
|
option :keyid, type: :string, required: true, aliases: %w[-k],
|
47
52
|
desc: 'GPG key id used to sign the repository metadata'
|
53
|
+
option :publisher, type: :string, aliases: %w[-r], enum: publishers,
|
54
|
+
desc: 'Publisher used to sync repo data to remote target'
|
48
55
|
|
49
56
|
def upsert_repo
|
50
57
|
FileUtils.mkdir_p options[:path]
|
51
58
|
|
52
59
|
config = Config.new
|
53
|
-
config.upsert_repo options
|
54
|
-
options[:keyid]
|
60
|
+
config.upsert_repo options
|
55
61
|
|
56
62
|
backend = Backends.load options[:type], config
|
57
63
|
backend.add_repo options[:name]
|
@@ -66,12 +72,14 @@ module RepoMgr
|
|
66
72
|
config = Config.new
|
67
73
|
|
68
74
|
config.cfg[:repos].each do |name, repo|
|
69
|
-
rows << [name, repo[:type], repo[:path], repo[:keyid]]
|
75
|
+
rows << [name, repo[:type], repo[:path], repo[:keyid], repo[:publisher]]
|
70
76
|
end
|
71
77
|
|
72
78
|
return puts '-- No repos have been created' if rows.count.zero?
|
73
79
|
|
74
|
-
puts Terminal::Table.new
|
80
|
+
puts Terminal::Table.new(
|
81
|
+
headings: %w[Name Type Path KeyID Publisher], rows: rows
|
82
|
+
)
|
75
83
|
end
|
76
84
|
|
77
85
|
desc 'add-pkg', 'Add package to repository'
|
@@ -85,6 +93,12 @@ module RepoMgr
|
|
85
93
|
backend.add_pkg options[:repo], options[:path]
|
86
94
|
config.add_pkg options[:repo], options[:path]
|
87
95
|
|
96
|
+
pub_type = config.cfg[:repos][options[:repo]][:publisher]
|
97
|
+
if pub_type
|
98
|
+
publisher = Publishers.load pub_type, config
|
99
|
+
publisher.save options[:repo], options[:path]
|
100
|
+
end
|
101
|
+
|
88
102
|
puts "-- Added #{File.basename(options[:path])} to "\
|
89
103
|
"#{options[:repo]} repository"
|
90
104
|
end
|
@@ -94,7 +108,7 @@ module RepoMgr
|
|
94
108
|
desc: 'The repository to list the packages from'
|
95
109
|
|
96
110
|
def list_pkgs
|
97
|
-
packages = Config.new.cfg[:
|
111
|
+
packages = Config.new.cfg[:packages][options[:repo]]
|
98
112
|
|
99
113
|
if packages.nil?
|
100
114
|
Tools.error "#{options[:repo]} repo does not have any packages"
|
@@ -130,6 +144,38 @@ module RepoMgr
|
|
130
144
|
puts backend.check_sig options[:path]
|
131
145
|
end
|
132
146
|
|
147
|
+
desc 'rebuild-pkg-list', 'Rebuild package list from local pkg cache'
|
148
|
+
option :repo, type: :string, required: true, aliases: %w[-r],
|
149
|
+
desc: 'The repository to rebuild pkg list for'
|
150
|
+
def rebuild_pkg_list
|
151
|
+
config = Config.new
|
152
|
+
backend = Backends.load config.cfg[:repos][options[:repo]][:type], config
|
153
|
+
pkgs = backend.rebuild_pkg_list options[:repo]
|
154
|
+
|
155
|
+
pkgs.each do |pkg|
|
156
|
+
config.add_pkg options[:repo], pkg
|
157
|
+
end
|
158
|
+
|
159
|
+
puts "-- Rebuilt #{options[:repo]} repo pkg list"
|
160
|
+
end
|
161
|
+
|
162
|
+
desc 'sync', 'Sync local repo to remote target using repo publisher'
|
163
|
+
option :repo, type: :string, required: true, aliases: %w[-r],
|
164
|
+
desc: 'The repository to sync to remote target via publisher'
|
165
|
+
def sync
|
166
|
+
config = Config.new
|
167
|
+
pub_type = config.cfg[:repos][options[:repo]][:publisher]
|
168
|
+
|
169
|
+
unless pub_type
|
170
|
+
Tools.error "#{options[:repo]} repo does not have a publisher"
|
171
|
+
end
|
172
|
+
|
173
|
+
publisher = Publishers.load pub_type, config
|
174
|
+
publisher.sync options[:repo]
|
175
|
+
|
176
|
+
puts "-- Synchronised #{options[:repo]} using #{pub_type} publisher"
|
177
|
+
end
|
178
|
+
|
133
179
|
private
|
134
180
|
|
135
181
|
def load_backend(path)
|
data/lib/repo_mgr/config.rb
CHANGED
@@ -15,7 +15,9 @@ module RepoMgr
|
|
15
15
|
FileUtils.mkdir_p @cfg_dir
|
16
16
|
|
17
17
|
@cfg_file = "#{@cfg_dir}/repo-mgr.yml"
|
18
|
-
|
18
|
+
unless File.exist? @cfg_file
|
19
|
+
File.write @cfg_file, { repos: {}, packages: {} }.to_yaml
|
20
|
+
end
|
19
21
|
|
20
22
|
@cfg = YAML.load_file @cfg_file
|
21
23
|
end
|
@@ -24,17 +26,24 @@ module RepoMgr
|
|
24
26
|
File.write @cfg_file, @cfg.to_yaml
|
25
27
|
end
|
26
28
|
|
27
|
-
def upsert_repo(
|
29
|
+
def upsert_repo(options)
|
30
|
+
name = options[:name]
|
31
|
+
type = options[:type]
|
32
|
+
|
28
33
|
if @cfg[:repos][name] && @cfg[:repos][name][:type] != type
|
29
34
|
Tools.error "unable to change type for #{name} repository"
|
30
35
|
end
|
31
36
|
|
32
37
|
@cfg[:repos][name] = {
|
33
38
|
type: type,
|
34
|
-
path: path,
|
35
|
-
keyid: keyid
|
39
|
+
path: options[:path],
|
40
|
+
keyid: options[:keyid]
|
36
41
|
}
|
37
42
|
|
43
|
+
if options[:publisher]
|
44
|
+
@cfg[:repos][name][:publisher] = options[:publisher]
|
45
|
+
end
|
46
|
+
|
38
47
|
save
|
39
48
|
end
|
40
49
|
|
@@ -43,14 +52,15 @@ module RepoMgr
|
|
43
52
|
Tools.error "unable to add packages to #{repo} - repo does not exist"
|
44
53
|
end
|
45
54
|
|
46
|
-
@cfg[:
|
55
|
+
@cfg[:packages] ||= {}
|
56
|
+
@cfg[:packages][repo] ||= []
|
47
57
|
pkg = File.basename path
|
48
58
|
|
49
|
-
if @cfg[:
|
59
|
+
if @cfg[:packages][repo].include?(pkg)
|
50
60
|
Tools.error "you already have #{pkg} in your #{repo} repo"
|
51
61
|
end
|
52
62
|
|
53
|
-
@cfg[:
|
63
|
+
@cfg[:packages][repo] << pkg
|
54
64
|
|
55
65
|
save
|
56
66
|
end
|
@@ -61,9 +71,10 @@ module RepoMgr
|
|
61
71
|
'- repo does not exist'
|
62
72
|
end
|
63
73
|
|
64
|
-
@cfg[:
|
74
|
+
@cfg[:packages] ||= {}
|
75
|
+
@cfg[:packages][repo] ||= []
|
65
76
|
pkg = File.basename path
|
66
|
-
@cfg[:
|
77
|
+
@cfg[:packages][repo].delete pkg
|
67
78
|
|
68
79
|
save
|
69
80
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require_relative 'publishers/git'
|
4
|
+
|
5
|
+
module RepoMgr
|
6
|
+
# factory loader for RepoMgr::Publisher::Foo objects
|
7
|
+
class Publishers
|
8
|
+
def self.load(publisher, config)
|
9
|
+
@obj ||= {}
|
10
|
+
|
11
|
+
@obj[publisher] ||= Object.const_get(
|
12
|
+
"RepoMgr::Publisher::#{publisher.capitalize}"
|
13
|
+
).new(config)
|
14
|
+
|
15
|
+
@obj[publisher]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'git'
|
4
|
+
|
5
|
+
module RepoMgr
|
6
|
+
module Publisher
|
7
|
+
# git publisher
|
8
|
+
class Git
|
9
|
+
def initialize(config)
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
# method invoked when the local deb/rpm repository is built
|
14
|
+
# for git, this requires a commit into the target git repository
|
15
|
+
# which is the target for deb/rpm repository export
|
16
|
+
def save(repo, pkg)
|
17
|
+
git = ::Git.open @config.cfg[:repos][repo][:path]
|
18
|
+
git.add(all: true)
|
19
|
+
git.commit "Add #{File.basename(pkg)}."
|
20
|
+
end
|
21
|
+
|
22
|
+
# method invoked when the local deb/rpm repository is published
|
23
|
+
# for git, this is pushing to a remote
|
24
|
+
def sync(repo)
|
25
|
+
git = ::Git.open @config.cfg[:repos][repo][:path]
|
26
|
+
git.push(git.remote('origin'), 'main')
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: repo-mgr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ștefan Rusu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-04-
|
11
|
+
date: 2021-04-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colored
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: git
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.8.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.8.1
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: gpgme
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -140,6 +154,8 @@ files:
|
|
140
154
|
- lib/repo_mgr/backends/rpm.rb
|
141
155
|
- lib/repo_mgr/cli.rb
|
142
156
|
- lib/repo_mgr/config.rb
|
157
|
+
- lib/repo_mgr/publishers.rb
|
158
|
+
- lib/repo_mgr/publishers/git.rb
|
143
159
|
- lib/repo_mgr/tools.rb
|
144
160
|
homepage: https://github.com/mr-staker/repo-mgr
|
145
161
|
licenses:
|