mirrorfile 0.1.1 → 1.0.1
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/lib/mirrorfile/cli.rb +53 -14
- data/lib/mirrorfile/cli_legacy.rb +74 -0
- data/lib/mirrorfile/entry.rb +21 -4
- data/lib/mirrorfile/mirror.rb +42 -31
- data/lib/mirrorfile/version.rb +1 -1
- data/lib/mirrorfile.rb +9 -8
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d8ab3635e4795e7250a284a158d0122062460a19db75d4eb00cd8754e0cedbb5
|
|
4
|
+
data.tar.gz: aec727ba372fea9a0cf78fcb38e321db66845f6e8d6e63618a62b6d2ba6c780b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8deb4362ac6f4d89ba6dc3d8c7f5d2dc3887bf1e433ca2dba9151ffcd0905edfaddf62757f3600fae74f6eb53982c7f1ba7b35a4e8e55e1e62bb03d84f54e43c
|
|
7
|
+
data.tar.gz: 3c190b0887928dfedd7cd5cfae45fa1858f248417461e7e05411a63c93cd827844a18ef3c0462e1b3fe7120ad3487b9e0c77ab7fc61fa9bfb2fb37ea0f39654b
|
data/lib/mirrorfile/cli.rb
CHANGED
|
@@ -21,12 +21,7 @@ module Mirrorfile
|
|
|
21
21
|
class CLI
|
|
22
22
|
# Available CLI commands
|
|
23
23
|
# @return [Array<String>] list of valid commands
|
|
24
|
-
COMMANDS = %w[init install update list migrate-to-v1 help].freeze
|
|
25
|
-
|
|
26
|
-
# Deprecation warning shown on every command except migrate-to-v1
|
|
27
|
-
DEPRECATION_WARNING = <<~WARN.freeze
|
|
28
|
-
[mirrorfile] WARNING: v#{VERSION} is deprecated. Run `mirror migrate-to-v1` to upgrade to v1.0.
|
|
29
|
-
WARN
|
|
24
|
+
COMMANDS = %w[init install update list git migrate-to-v1 help].freeze
|
|
30
25
|
|
|
31
26
|
# Creates a new CLI instance.
|
|
32
27
|
#
|
|
@@ -53,16 +48,32 @@ module Mirrorfile
|
|
|
53
48
|
def call(args)
|
|
54
49
|
command = args.first
|
|
55
50
|
|
|
56
|
-
|
|
51
|
+
if legacy_command?(command) && Mirror.new.legacy?
|
|
52
|
+
return CLILegacy.new(stdout: @stdout, stderr: @stderr).call(args)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
dispatch(args)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Dispatches args to the appropriate command method.
|
|
59
|
+
#
|
|
60
|
+
# Separated from {#call} so that {CLILegacy} can dispatch
|
|
61
|
+
# without re-checking legacy state.
|
|
62
|
+
#
|
|
63
|
+
# @param args [Array<String>] command-line arguments
|
|
64
|
+
# @return [Integer] exit status code
|
|
65
|
+
def dispatch(args)
|
|
66
|
+
command = args.first
|
|
57
67
|
|
|
58
68
|
case command
|
|
59
|
-
when 'init'
|
|
60
|
-
when 'install'
|
|
61
|
-
when 'update'
|
|
62
|
-
when 'list'
|
|
69
|
+
when 'init' then init
|
|
70
|
+
when 'install' then install
|
|
71
|
+
when 'update' then update
|
|
72
|
+
when 'list' then list
|
|
73
|
+
when 'git' then git(args.drop(1))
|
|
63
74
|
when 'migrate-to-v1' then migrate_to_v1
|
|
64
75
|
when 'help' then help
|
|
65
|
-
when '-h', '--help'
|
|
76
|
+
when '-h', '--help' then help
|
|
66
77
|
when '-v', '--version' then version
|
|
67
78
|
else usage
|
|
68
79
|
end
|
|
@@ -79,6 +90,19 @@ module Mirrorfile
|
|
|
79
90
|
|
|
80
91
|
private
|
|
81
92
|
|
|
93
|
+
# Returns whether the given command should use legacy mode
|
|
94
|
+
# when legacy mirrors are detected.
|
|
95
|
+
#
|
|
96
|
+
# Commands like init, help, and version flags are not affected
|
|
97
|
+
# by legacy state and always use the standard CLI.
|
|
98
|
+
#
|
|
99
|
+
# @param command [String, nil] the command name
|
|
100
|
+
# @return [Boolean]
|
|
101
|
+
# @api private
|
|
102
|
+
def legacy_command?(command)
|
|
103
|
+
%w[install update list git].include?(command)
|
|
104
|
+
end
|
|
105
|
+
|
|
82
106
|
# Executes the init command.
|
|
83
107
|
#
|
|
84
108
|
# @return [void]
|
|
@@ -117,6 +141,18 @@ module Mirrorfile
|
|
|
117
141
|
entries.empty? ? @stdout.puts('No mirrors defined.') : entries.each { @stdout.puts _1 }
|
|
118
142
|
end
|
|
119
143
|
|
|
144
|
+
# Executes a git command against a .git.mirror directory.
|
|
145
|
+
#
|
|
146
|
+
# Runs git with --git-dir=.git.mirror in the current working
|
|
147
|
+
# directory, passing through all additional arguments.
|
|
148
|
+
#
|
|
149
|
+
# @param args [Array<String>] arguments to pass to git
|
|
150
|
+
# @return [void]
|
|
151
|
+
# @api private
|
|
152
|
+
def git(args)
|
|
153
|
+
system('git', '--git-dir=.git.mirror', *args)
|
|
154
|
+
end
|
|
155
|
+
|
|
120
156
|
# Executes the migrate-to-v1 command.
|
|
121
157
|
#
|
|
122
158
|
# @return [void]
|
|
@@ -141,7 +177,8 @@ module Mirrorfile
|
|
|
141
177
|
install Clone repositories that don't exist locally
|
|
142
178
|
update Pull latest changes for existing repositories
|
|
143
179
|
list Show all defined mirrors
|
|
144
|
-
|
|
180
|
+
git Run git commands against a .git.mirror directory
|
|
181
|
+
migrate-to-v1 Upgrade legacy mirrors to v1.0 format
|
|
145
182
|
help Show this help message
|
|
146
183
|
|
|
147
184
|
Options:
|
|
@@ -152,6 +189,7 @@ module Mirrorfile
|
|
|
152
189
|
$ mirror init
|
|
153
190
|
$ mirror install
|
|
154
191
|
$ mirror update
|
|
192
|
+
$ cd mirrors/rails && mirror git log --oneline
|
|
155
193
|
|
|
156
194
|
Mirrorfile syntax:
|
|
157
195
|
source "https://github.com"
|
|
@@ -188,7 +226,8 @@ module Mirrorfile
|
|
|
188
226
|
install Clone repositories that don't exist locally
|
|
189
227
|
update Pull latest changes for existing repositories
|
|
190
228
|
list Show all defined mirrors
|
|
191
|
-
|
|
229
|
+
git Run git commands against a .git.mirror directory
|
|
230
|
+
migrate-to-v1 Upgrade legacy mirrors to v1.0 format
|
|
192
231
|
help Show detailed help
|
|
193
232
|
|
|
194
233
|
Run 'mirror help' for more information.
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mirrorfile
|
|
4
|
+
# Legacy CLI for projects with old-style .git directories.
|
|
5
|
+
#
|
|
6
|
+
# This CLI is used automatically when mirrorfile detects that the
|
|
7
|
+
# mirrors directory contains repositories with .git instead of
|
|
8
|
+
# .git.mirror. It prints a deprecation warning and operates using
|
|
9
|
+
# the legacy .git directory name.
|
|
10
|
+
#
|
|
11
|
+
# @see CLI
|
|
12
|
+
# @since 1.0.0
|
|
13
|
+
class CLILegacy < CLI
|
|
14
|
+
LEGACY_WARNING = <<~WARN
|
|
15
|
+
[mirrorfile] WARNING: Your mirrors use legacy .git directories.
|
|
16
|
+
Upgrade with mirrorfile v0.1.1 (`mirror migrate-to-v1`), or remove
|
|
17
|
+
the mirrors/ directory and re-run `mirror install`.
|
|
18
|
+
WARN
|
|
19
|
+
|
|
20
|
+
# Overrides CLI#call to skip legacy detection and dispatch directly.
|
|
21
|
+
#
|
|
22
|
+
# @param args [Array<String>] command-line arguments
|
|
23
|
+
# @return [Integer] exit status code
|
|
24
|
+
def call(args)
|
|
25
|
+
dispatch(args)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
# Executes the install command in legacy mode.
|
|
31
|
+
#
|
|
32
|
+
# @return [void]
|
|
33
|
+
# @api private
|
|
34
|
+
def install
|
|
35
|
+
@stderr.puts LEGACY_WARNING
|
|
36
|
+
@stdout.puts 'Installing mirrors (legacy mode)...'
|
|
37
|
+
Mirror.new.install(legacy: true)
|
|
38
|
+
@stdout.puts 'Done.'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Executes the update command in legacy mode.
|
|
42
|
+
#
|
|
43
|
+
# @return [void]
|
|
44
|
+
# @api private
|
|
45
|
+
def update
|
|
46
|
+
@stderr.puts LEGACY_WARNING
|
|
47
|
+
@stdout.puts 'Updating mirrors (legacy mode)...'
|
|
48
|
+
Mirror.new.update(legacy: true)
|
|
49
|
+
@stdout.puts 'Done.'
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Executes the list command with a legacy warning.
|
|
53
|
+
#
|
|
54
|
+
# @return [void]
|
|
55
|
+
# @api private
|
|
56
|
+
def list
|
|
57
|
+
@stderr.puts LEGACY_WARNING
|
|
58
|
+
super
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Executes a git command using the default .git directory.
|
|
62
|
+
#
|
|
63
|
+
# In legacy mode, mirrors have .git (not .git.mirror), so
|
|
64
|
+
# no --git-dir flag is needed.
|
|
65
|
+
#
|
|
66
|
+
# @param args [Array<String>] arguments to pass to git
|
|
67
|
+
# @return [void]
|
|
68
|
+
# @api private
|
|
69
|
+
def git(args)
|
|
70
|
+
@stderr.puts LEGACY_WARNING
|
|
71
|
+
system('git', *args)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
data/lib/mirrorfile/entry.rb
CHANGED
|
@@ -41,7 +41,13 @@ module Mirrorfile
|
|
|
41
41
|
# clone the repository once. If the local directory already exists,
|
|
42
42
|
# no action is taken.
|
|
43
43
|
#
|
|
44
|
+
# After cloning, the .git directory is renamed to the configured
|
|
45
|
+
# git_dir name (default: .git.mirror) so that the host project's
|
|
46
|
+
# git does not treat it as a nested repository.
|
|
47
|
+
#
|
|
44
48
|
# @param base_dir [Pathname] the base directory to clone into
|
|
49
|
+
# @param git_dir [String] the git directory name to use
|
|
50
|
+
# (default: ".git.mirror", use ".git" for legacy mode)
|
|
45
51
|
# @return [Boolean, nil] true if clone succeeded, false if failed,
|
|
46
52
|
# nil if already exists
|
|
47
53
|
#
|
|
@@ -49,9 +55,15 @@ module Mirrorfile
|
|
|
49
55
|
# entry.install(Pathname.new("mirrors"))
|
|
50
56
|
#
|
|
51
57
|
# @see #update
|
|
52
|
-
def install(base_dir)
|
|
58
|
+
def install(base_dir, git_dir: '.git.mirror')
|
|
53
59
|
dir = local_path(base_dir)
|
|
54
|
-
|
|
60
|
+
return if dir.exist?
|
|
61
|
+
|
|
62
|
+
return unless system('git', 'clone', url, dir.to_s)
|
|
63
|
+
|
|
64
|
+
return unless git_dir != '.git'
|
|
65
|
+
|
|
66
|
+
File.rename(dir.join('.git').to_s, dir.join(git_dir).to_s)
|
|
55
67
|
end
|
|
56
68
|
|
|
57
69
|
# Updates an existing repository by pulling the latest changes.
|
|
@@ -60,6 +72,8 @@ module Mirrorfile
|
|
|
60
72
|
# If the local directory doesn't exist, no action is taken.
|
|
61
73
|
#
|
|
62
74
|
# @param base_dir [Pathname] the base directory containing the clone
|
|
75
|
+
# @param git_dir [String] the git directory name to use
|
|
76
|
+
# (default: ".git.mirror", use ".git" for legacy mode)
|
|
63
77
|
# @return [Boolean, nil] true if pull succeeded, false if failed,
|
|
64
78
|
# nil if directory doesn't exist
|
|
65
79
|
#
|
|
@@ -67,9 +81,12 @@ module Mirrorfile
|
|
|
67
81
|
# entry.update(Pathname.new("mirrors"))
|
|
68
82
|
#
|
|
69
83
|
# @see #install
|
|
70
|
-
def update(base_dir)
|
|
84
|
+
def update(base_dir, git_dir: '.git.mirror')
|
|
71
85
|
dir = local_path(base_dir)
|
|
72
|
-
|
|
86
|
+
return unless dir.exist?
|
|
87
|
+
|
|
88
|
+
system('git', '--git-dir', dir.join(git_dir).to_s,
|
|
89
|
+
'--work-tree', dir.to_s, 'pull', '--ff-only')
|
|
73
90
|
end
|
|
74
91
|
|
|
75
92
|
# Returns a human-readable representation of the entry.
|
data/lib/mirrorfile/mirror.rb
CHANGED
|
@@ -68,10 +68,11 @@ module Mirrorfile
|
|
|
68
68
|
# mirror.install
|
|
69
69
|
#
|
|
70
70
|
# @see Entry#install
|
|
71
|
-
def install
|
|
71
|
+
def install(legacy: false)
|
|
72
72
|
ensure_mirrorfile!
|
|
73
73
|
mirrors_dir.mkpath
|
|
74
|
-
|
|
74
|
+
git_dir = legacy ? '.git' : '.git.mirror'
|
|
75
|
+
@mirrorfile.entries.each { _1.install(mirrors_dir, git_dir: git_dir) }
|
|
75
76
|
end
|
|
76
77
|
|
|
77
78
|
# Updates all existing local repositories.
|
|
@@ -88,9 +89,10 @@ module Mirrorfile
|
|
|
88
89
|
# mirror.update
|
|
89
90
|
#
|
|
90
91
|
# @see Entry#update
|
|
91
|
-
def update
|
|
92
|
+
def update(legacy: false)
|
|
92
93
|
ensure_mirrorfile!
|
|
93
|
-
|
|
94
|
+
git_dir = legacy ? '.git' : '.git.mirror'
|
|
95
|
+
@mirrorfile.entries.each { _1.update(mirrors_dir, git_dir: git_dir) }
|
|
94
96
|
end
|
|
95
97
|
|
|
96
98
|
# Initializes a new project with mirror support.
|
|
@@ -117,6 +119,7 @@ module Mirrorfile
|
|
|
117
119
|
def init
|
|
118
120
|
create_mirrorfile
|
|
119
121
|
setup_gitignore
|
|
122
|
+
setup_templates
|
|
120
123
|
setup_zeitwerk
|
|
121
124
|
puts "Initialized mirrors in #{root}"
|
|
122
125
|
end
|
|
@@ -145,11 +148,25 @@ module Mirrorfile
|
|
|
145
148
|
def migrate_to_v1
|
|
146
149
|
update_gemfile
|
|
147
150
|
update_system_gem
|
|
148
|
-
|
|
151
|
+
setup_templates
|
|
149
152
|
rename_git_dirs
|
|
150
153
|
puts 'Migration to v1.0 complete.'
|
|
151
154
|
end
|
|
152
155
|
|
|
156
|
+
# Returns whether any mirrors use legacy .git directories.
|
|
157
|
+
#
|
|
158
|
+
# A project is considered legacy if any subdirectory of mirrors/
|
|
159
|
+
# contains a .git directory without a .git.mirror sibling.
|
|
160
|
+
#
|
|
161
|
+
# @return [Boolean] true if legacy mirrors are detected
|
|
162
|
+
def legacy?
|
|
163
|
+
return false unless mirrors_dir.exist?
|
|
164
|
+
|
|
165
|
+
mirrors_dir.children.select(&:directory?).any? do |path|
|
|
166
|
+
path.join('.git').exist? && !path.join('.git.mirror').exist?
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
153
170
|
private
|
|
154
171
|
|
|
155
172
|
# Loads and parses the Mirrorfile.
|
|
@@ -253,6 +270,26 @@ module Mirrorfile
|
|
|
253
270
|
RUBY
|
|
254
271
|
end
|
|
255
272
|
|
|
273
|
+
# Copies template files into the mirrors directory.
|
|
274
|
+
#
|
|
275
|
+
# Creates the mirrors directory if it doesn't exist, then copies
|
|
276
|
+
# envrc.template and README.md.template from the gem's
|
|
277
|
+
# templates directory. Existing files are not overwritten.
|
|
278
|
+
#
|
|
279
|
+
# @return [void]
|
|
280
|
+
# @api private
|
|
281
|
+
def setup_templates
|
|
282
|
+
mirrors_dir.mkpath
|
|
283
|
+
|
|
284
|
+
templates_dir = Pathname.new(__dir__).join('../../templates')
|
|
285
|
+
|
|
286
|
+
envrc_dest = mirrors_dir.join('.envrc')
|
|
287
|
+
envrc_dest.exist? || FileUtils.cp(templates_dir.join('envrc.template'), envrc_dest)
|
|
288
|
+
|
|
289
|
+
readme_dest = mirrors_dir.join('README.md')
|
|
290
|
+
readme_dest.exist? || FileUtils.cp(templates_dir.join('README.md.template'), readme_dest)
|
|
291
|
+
end
|
|
292
|
+
|
|
256
293
|
# Updates the Gemfile to use mirrorfile ~> 1.0.
|
|
257
294
|
#
|
|
258
295
|
# Replaces any existing mirrorfile gem declaration with one
|
|
@@ -289,32 +326,6 @@ module Mirrorfile
|
|
|
289
326
|
system('gem', 'update', 'mirrorfile')
|
|
290
327
|
end
|
|
291
328
|
|
|
292
|
-
# Copies template files into the mirrors directory.
|
|
293
|
-
#
|
|
294
|
-
# Creates the mirrors directory if needed, then copies
|
|
295
|
-
# envrc.template and README.md.template. Existing files
|
|
296
|
-
# are not overwritten.
|
|
297
|
-
#
|
|
298
|
-
# @return [void]
|
|
299
|
-
# @api private
|
|
300
|
-
def install_templates
|
|
301
|
-
mirrors_dir.mkpath
|
|
302
|
-
|
|
303
|
-
templates_dir = Pathname.new(__dir__).join('../../templates')
|
|
304
|
-
|
|
305
|
-
envrc_dest = mirrors_dir.join('.envrc')
|
|
306
|
-
unless envrc_dest.exist?
|
|
307
|
-
FileUtils.cp(templates_dir.join('envrc.template'), envrc_dest)
|
|
308
|
-
puts 'Created mirrors/.envrc'
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
readme_dest = mirrors_dir.join('README.md')
|
|
312
|
-
return if readme_dest.exist?
|
|
313
|
-
|
|
314
|
-
FileUtils.cp(templates_dir.join('README.md.template'), readme_dest)
|
|
315
|
-
puts 'Created mirrors/README.md'
|
|
316
|
-
end
|
|
317
|
-
|
|
318
329
|
# Renames .git directories to .git.mirror in existing mirrors.
|
|
319
330
|
#
|
|
320
331
|
# Scans all subdirectories of mirrors/ for .git directories
|
data/lib/mirrorfile/version.rb
CHANGED
data/lib/mirrorfile.rb
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
3
|
+
require 'pathname'
|
|
4
4
|
|
|
5
|
-
require_relative
|
|
6
|
-
require_relative
|
|
7
|
-
require_relative
|
|
8
|
-
require_relative
|
|
9
|
-
require_relative
|
|
5
|
+
require_relative 'mirrorfile/version'
|
|
6
|
+
require_relative 'mirrorfile/entry'
|
|
7
|
+
require_relative 'mirrorfile/mirrorfile'
|
|
8
|
+
require_relative 'mirrorfile/mirror'
|
|
9
|
+
require_relative 'mirrorfile/cli'
|
|
10
|
+
require_relative 'mirrorfile/cli_legacy'
|
|
10
11
|
|
|
11
12
|
# Mirrorfile is a gem for managing local mirrors of git repositories.
|
|
12
13
|
#
|
|
@@ -49,14 +50,14 @@ module Mirrorfile
|
|
|
49
50
|
#
|
|
50
51
|
# @return [Pathname] path to the mirrors directory
|
|
51
52
|
def mirrors_dir
|
|
52
|
-
root.join(
|
|
53
|
+
root.join('mirrors')
|
|
53
54
|
end
|
|
54
55
|
|
|
55
56
|
# Returns the path to the Mirrorfile
|
|
56
57
|
#
|
|
57
58
|
# @return [Pathname] path to the Mirrorfile
|
|
58
59
|
def mirrorfile_path
|
|
59
|
-
root.join(
|
|
60
|
+
root.join('Mirrorfile')
|
|
60
61
|
end
|
|
61
62
|
end
|
|
62
63
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mirrorfile
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nathan Kidd
|
|
@@ -88,6 +88,7 @@ files:
|
|
|
88
88
|
- flake.nix
|
|
89
89
|
- lib/mirrorfile.rb
|
|
90
90
|
- lib/mirrorfile/cli.rb
|
|
91
|
+
- lib/mirrorfile/cli_legacy.rb
|
|
91
92
|
- lib/mirrorfile/entry.rb
|
|
92
93
|
- lib/mirrorfile/mirror.rb
|
|
93
94
|
- lib/mirrorfile/mirrorfile.rb
|