git_tree 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a42706ad381181c5b6d7ed6de426de01c514892770437155a1ede09e3c5ccf3d
4
- data.tar.gz: fc98272834fd37f68c547ba23b22b68d5097c5ab69984d291f188132a16a03cc
3
+ metadata.gz: 45ac579ee8e240d6c78bd782b40b1ca473ffd5e7f1d87a1fb81b53012516465c
4
+ data.tar.gz: 32b342b9e45b35a64beca464cf9a0e3af514ea5867cd864916ff551425f3dcd7
5
5
  SHA512:
6
- metadata.gz: 63fad3a8431607be61d06607b88ca532242dea7c0a8b244194b282aa824cf790fe8c7c21ae91d0bd7f18c38871ccb64c102f31b247136e76ac1b463a3452aa9c
7
- data.tar.gz: a3ebe92f5e7a5ed5d2b688cbb38e3c6fd40a63e470db644bfd09db3bcbbded254e8d004bc9731d789cd4269151bb116e0a4b80962aad6a6b7760c794137ea9fa
6
+ metadata.gz: 7ecfa103809f6cd8d63bbd76b69cbbf5d7af5c746b16a7d533d7bfc9a269687413413b98b7fa5aab27028f37a7d8e2ef4df40decd49a07828549cedfb072c47a
7
+ data.tar.gz: 1dc61521613c96dbb776de98b02b269a3dc0d0aa2605e534fdc19d4facf103c8e4a9fa6dddef143720b841e672b9fc5072c74b81b643cc1fd6ea4ba502a1a821
data/.rubocop.yml CHANGED
@@ -66,6 +66,9 @@ Naming/FileName:
66
66
  RSpec/ExampleLength:
67
67
  Max: 20
68
68
 
69
+ RSpec/FilePath:
70
+ Enabled: false
71
+
69
72
  RSpec/MultipleExpectations:
70
73
  Max: 15
71
74
 
@@ -88,8 +91,7 @@ Style/RegexpLiteral:
88
91
  Enabled: false
89
92
 
90
93
  Style/StringConcatenation:
91
- Exclude:
92
- - spec/**/*
94
+ Enabled: false
93
95
 
94
96
  Style/StringLiterals:
95
97
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,5 @@
1
+ ## 0.2.2 / 2023-05-23
2
+ * `git_tree_evars` now checks for previous definitions and issues warnings.
1
3
  ## 0.2.1 / 2023-05-03
2
4
  * Removed the here document wrapper from the output of `git_tree_evars`.
3
5
 
data/README.md CHANGED
@@ -15,12 +15,9 @@ Directories containing a file called `.ignore` are ignored.
15
15
 
16
16
 
17
17
  ## Usage
18
- Both commands requires only one parameter:
19
- the name of the top-level directory to scan.
20
-
21
- You must pass an environment variable to both commands.
22
- Enclosing the name of the env var in single quotes,
23
- which will prevent the shell from expanding it before invoking either command.
18
+ Both commands require one environment variable reference to be passed to them.
19
+ Enclose the name of the environment variable within single quotes,
20
+ which will prevent the shell from expanding it before invoking the command.
24
21
 
25
22
 
26
23
  ## `Git_tree_replicate` Usage
@@ -31,8 +28,8 @@ $ git_tree_replicate '$work' > work.sh
31
28
  ```
32
29
 
33
30
  The generated environment variables will all be relative to the
34
- env var you provided.
35
- You will understand what this means once you try it and look at the generated script.
31
+ path pointed to by the expanded environment variable that you provided.
32
+ You will understand what this means once you look at the generated script.
36
33
 
37
34
  When `git_tree_replicate` completes,
38
35
  edit the generated script to suit, then
@@ -108,7 +105,7 @@ $ cd $my_project
108
105
  ## Installation
109
106
  Type the following at a shell prompt:
110
107
 
111
- ```ruby
108
+ ```shell
112
109
  $ gem install git_tree
113
110
  ```
114
111
 
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
  task default: :spec
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'git_tree'
3
+ require 'git_tree_evars'
4
4
 
5
5
  GitTree.command_evars
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'git_tree'
3
+ require 'git_tree_replicate'
4
4
 
5
5
  GitTree.command_replicate
data/git_tree.gemspec CHANGED
@@ -41,5 +41,6 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
41
41
  spec.summary = 'Installs two commands that scan a git directory tree and write out scripts for replication.'
42
42
  spec.version = GitUrlsVersion::VERSION
43
43
 
44
+ spec.add_dependency 'rainbow'
44
45
  spec.add_dependency 'rugged'
45
46
  end
@@ -1,3 +1,3 @@
1
1
  module GitUrlsVersion
2
- VERSION = '0.2.1'.freeze
2
+ VERSION = '0.2.2'.freeze
3
3
  end
data/lib/git_tree.rb CHANGED
@@ -1,38 +1,19 @@
1
- module GitTree
2
- require 'find'
3
- require 'rugged'
4
- require_relative 'util'
5
-
6
- # @param root might be "$envar" or a fully qualified directory name ("/a/b/c")
7
- def self.command_evars(root = ARGV[0])
8
- abort "Error: Argument must start with a dollar sign ($)" unless root.start_with? '$'
9
-
10
- base = MslinnUtil.expand_env root
11
- dirs = directories_to_process base
12
-
13
- # puts "# root=#{root}, base=#{base}"
14
- puts make_env_vars root, base, dirs
15
- end
16
-
17
- # @param root might be "$envar" or a fully qualified directory name ("/a/b/c")
18
- def self.command_replicate(root = ARGV[0])
19
- abort "Error: Argument must start with a dollar sign ($)" unless root.start_with? '$'
1
+ require 'find'
2
+ require 'rainbow/refinement'
3
+ require 'rugged'
4
+ require_relative 'util'
20
5
 
21
- base = MslinnUtil.expand_env root
22
- dirs = directories_to_process base
23
-
24
- # puts "# root=#{root}, base=#{base}"
25
- puts make_replicate_script root, base, dirs
26
- end
6
+ module GitTree
7
+ using Rainbow
27
8
 
28
9
  # @return array containing directory names to process
29
10
  # Each directory name ends with a slash, to ensure symlinks are dereferences
30
11
  def self.directories_to_process(root)
31
12
  root_fq = File.expand_path root
32
- abort "Error: #{root_fq} is a file, instead of a directory. Cannot recurse." if File.file? root_fq
13
+ abort "Error: #{root_fq} is a file, instead of a directory. Cannot recurse.".red if File.file? root_fq
33
14
 
34
15
  root_fq = MslinnUtil.deref_symlink(root_fq).to_s
35
- abort "Error: #{root_fq} does not exist. Halting." unless Dir.exist? root_fq
16
+ abort "Error: #{root_fq} does not exist. Halting.".red unless Dir.exist? root_fq
36
17
 
37
18
  result = []
38
19
  Find.find(root_fq) do |path|
@@ -47,78 +28,4 @@ module GitTree
47
28
  end
48
29
  result.map { |x| x.delete_prefix("#{root_fq}/") }
49
30
  end
50
-
51
- def self.env_var_name(path)
52
- name = path.include?('/') ? File.basename(path) : path
53
- name.tr(' ', '_').tr('-', '_')
54
- end
55
-
56
- def self.help(msg = nil)
57
- puts msg if msg
58
- puts <<~END_HELP
59
- Replicates tree of git repos and writes a bash script to STDOUT that clones the repos in the tree.
60
- Adds upstream remotes as required.
61
-
62
- Directories containing a file called .ignore are ignored.
63
- END_HELP
64
- exit 1
65
- end
66
-
67
- def self.make_env_var(name, value)
68
- "export #{env_var_name(name)}=#{value}"
69
- end
70
-
71
- # @param root should be an "$envar" that points to the root of a directory tree containing git repos.
72
- # @param base a fully qualified directory name ("/a/b/c")
73
- # @param dirs directory list to process
74
- def self.make_env_vars(root, base, dirs)
75
- result = []
76
- result << make_env_var(env_var_name(base), MslinnUtil.deref_symlink(base))
77
- dirs.each do |dir|
78
- result << make_env_var(env_var_name(dir), "#{root}/#{dir}")
79
- end
80
- result.join("\n") + "\n" # rubocop:disable Style/StringConcatenation
81
- end
82
-
83
- # @param root should be an "$envar" that points to the root of a directory tree containing git repos.
84
- # @param base a fully qualified directory name ("/a/b/c")
85
- # @param dirs directory list to process
86
- def self.make_replicate_script(root, base, dirs)
87
- help "Error: Please specify the subdirectory to traverse.\n\n" if root.to_s.empty?
88
-
89
- Dir.chdir(base) do
90
- result = dirs.map { |dir| replicate_one(dir) }
91
- result.join "\n"
92
- end
93
- end
94
-
95
- def self.replicate_one(dir)
96
- output = []
97
- project_dir = File.basename dir
98
- parent_dir = File.dirname dir
99
- repo = Rugged::Repository.new dir
100
- origin_url = repo.config['remote.origin.url']
101
-
102
- output << "if [ ! -d \"#{dir}/.git\" ]; then"
103
- output << " mkdir -p '#{parent_dir}'"
104
- output << " pushd '#{parent_dir}' > /dev/null"
105
- output << " git clone #{origin_url}"
106
-
107
- repo.remotes.each do |remote|
108
- next if remote.name == 'origin' || remote.url == 'no_push'
109
-
110
- output << " git remote add #{remote.name} '#{remote.url}'"
111
- end
112
-
113
- output << ' popd > /dev/null'
114
-
115
- # git_dir_name = File.basename Dir.pwd
116
- # if git_dir_name != project_dir
117
- # output << ' # Git project directory was renamed, renaming this copy to match original directory structure'
118
- # output << " mv #{git_dir_name} #{project_dir}"
119
- # end
120
- output << "fi"
121
- output << ''
122
- output
123
- end
124
31
  end
@@ -0,0 +1,65 @@
1
+ require 'shellwords'
2
+ require_relative 'git_tree'
3
+
4
+ module GitTree
5
+ using Rainbow
6
+
7
+ # @param root might be "$envar" or a fully qualified directory name ("/a/b/c")
8
+ def self.command_evars(root = ARGV[0])
9
+ abort "Error: Argument must start with a dollar sign ($)".red unless root.start_with? '$'
10
+
11
+ base = MslinnUtil.expand_env root
12
+ dirs = directories_to_process base
13
+
14
+ # puts "# root=#{root}, base=#{base}"
15
+ puts make_env_vars root, base, dirs
16
+ end
17
+
18
+ def self.env_var_name(path)
19
+ name = path.include?('/') ? File.basename(path) : path
20
+ name.tr(' ', '_').tr('-', '_')
21
+ end
22
+
23
+ def self.help_evars(msg = nil)
24
+ puts msg if msg
25
+ puts <<~END_HELP
26
+ Examines a tree of git repos and writes a bash script to STDOUT that defines environment variables that point to the repos in the tree.
27
+ Does not redefine existing environment variables.
28
+
29
+ Directories containing a file called .ignore are ignored.
30
+ END_HELP
31
+ exit 1
32
+ end
33
+
34
+ def self.make_env_var(name, value)
35
+ "export #{env_var_name(name)}=#{value}"
36
+ end
37
+
38
+ # @param root should be an "$envar" that points to the root of a directory tree containing git repos.
39
+ # @param base a fully qualified directory name ("/a/b/c")
40
+ # @param dirs directory list to process
41
+ def self.make_env_vars(root, base, dirs)
42
+ help_evars "Error: Please specify the subdirectory to traverse.\n\n" if root.to_s.empty?
43
+
44
+ result = []
45
+ result << make_env_var(env_var_name(base), MslinnUtil.deref_symlink(base))
46
+ dirs.each do |dir|
47
+ ename = env_var_name dir
48
+ ename_value = MslinnUtil.expand_env "$#{ename}"
49
+ ename_value = ename_value.shellescape.delete_prefix('\\') unless ename_value.empty?
50
+ if ename_value.to_s.empty?
51
+ result << make_env_var(ename, "#{root}/#{dir}")
52
+ else
53
+ msg = "$#{ename} was previously defined as #{ename_value}"
54
+ dir = MslinnUtil.expand_env(ename_value)
55
+ if Dir.exist? dir
56
+ warn msg.cyan
57
+ else
58
+ msg += ", but that directory does not exist, so redefining #{ename}."
59
+ warn msg.green
60
+ end
61
+ end
62
+ end
63
+ result.map { |x| "#{x}\n" }.join
64
+ end
65
+ end
@@ -0,0 +1,68 @@
1
+ require_relative 'git_tree'
2
+
3
+ module GitTree
4
+ # @param root might be "$envar" or a fully qualified directory name ("/a/b/c")
5
+ def self.command_replicate(root = ARGV[0])
6
+ abort "Error: No directories were specified" if root.to_s.empty?
7
+ abort "Error: Argument must start with a dollar sign ($)" unless root.start_with? '$'
8
+
9
+ base = MslinnUtil.expand_env root
10
+ dirs = directories_to_process base
11
+
12
+ # puts "# root=#{root}, base=#{base}"
13
+ puts make_replicate_script root, base, dirs
14
+ end
15
+
16
+ def self.help_replicate(msg = nil)
17
+ puts msg if msg
18
+ puts <<~END_HELP
19
+ Replicates tree of git repos and writes a bash script to STDOUT that clones the repos in the tree.
20
+ Adds upstream remotes as required.
21
+
22
+ Directories containing a file called .ignore are ignored.
23
+ END_HELP
24
+ exit 1
25
+ end
26
+
27
+ # @param root should be an "$envar" that points to the root of a directory tree containing git repos.
28
+ # @param base a fully qualified directory name ("/a/b/c")
29
+ # @param dirs directory list to process
30
+ def self.make_replicate_script(root, base, dirs)
31
+ help_replicate "Error: Please specify the subdirectory to traverse.\n\n" if root.to_s.empty?
32
+
33
+ Dir.chdir(base) do
34
+ result = dirs.map { |dir| replicate_one(dir) }
35
+ result.join "\n"
36
+ end
37
+ end
38
+
39
+ def self.replicate_one(dir)
40
+ output = []
41
+ project_dir = File.basename dir
42
+ parent_dir = File.dirname dir
43
+ repo = Rugged::Repository.new dir
44
+ origin_url = repo.config['remote.origin.url']
45
+
46
+ output << "if [ ! -d \"#{dir}/.git\" ]; then"
47
+ output << " mkdir -p '#{parent_dir}'"
48
+ output << " pushd '#{parent_dir}' > /dev/null"
49
+ output << " git clone #{origin_url}"
50
+
51
+ repo.remotes.each do |remote|
52
+ next if remote.name == 'origin' || remote.url == 'no_push'
53
+
54
+ output << " git remote add #{remote.name} '#{remote.url}'"
55
+ end
56
+
57
+ output << ' popd > /dev/null'
58
+
59
+ # git_dir_name = File.basename Dir.pwd
60
+ # if git_dir_name != project_dir
61
+ # output << ' # Git project directory was renamed, renaming this copy to match original directory structure'
62
+ # output << " mv #{git_dir_name} #{project_dir}"
63
+ # end
64
+ output << "fi"
65
+ output << ''
66
+ output
67
+ end
68
+ end
data/lib/util.rb CHANGED
@@ -1,4 +1,66 @@
1
1
  module MslinnUtil
2
+ # @param paths [Array[String]] all start with a leading '/' (they are assumed to be absolute paths).
3
+ # @return [String] the longest path prefix that is a prefix of all paths in array.
4
+ # If array is empty, return ''.
5
+ # If only the leading slash matches, and allow_root_match is true, return '/', else return ''.
6
+ def self.common_prefix(paths, allow_root_match: false)
7
+ return '' if paths.empty?
8
+
9
+ relative_paths = paths.reject { |x| x.start_with? '/' }
10
+ abort "Error: common_prefix received relative paths:" + relative_paths.map { |x| " #{x}\n" } \
11
+ unless relative_paths.empty?
12
+
13
+ if paths.length == 1
14
+ result = paths.first.split('/').slice(0...-1).join('/')
15
+ return result.empty? && allow_root_match ? '/' : result
16
+ end
17
+
18
+ arr = paths.sort
19
+ first = arr.first.split('/')
20
+ last = arr.last.split('/')
21
+ i = 0
22
+ i += 1 while first[i] == last[i] && i <= first.length
23
+ result = first.slice(0, i).join('/')
24
+
25
+ result.empty? && allow_root_match ? '/' : result
26
+ end
27
+
28
+ # @param paths [Array[String]] absolute paths to examine
29
+ # @param level [Int] minimum # of leading directory names in result, origin 1
30
+ def self.roots(paths, level, allow_root_match: false)
31
+ abort "Error: level must be positive, but it is #{level}." unless level.positive?
32
+ return allow_root_match ? '/' : '' if paths.empty?
33
+
34
+ abort("Error: level parameter must be positive, #{level} was supplied instead.") if level <= 0
35
+
36
+ if paths.length == 1
37
+ root = File.dirname(paths.first)
38
+ return allow_root_match ? '/' : '' if root == '/'
39
+
40
+ return root
41
+ end
42
+
43
+ loop do
44
+ paths = trim_to_level(paths, level) # does this change paths in the caller?
45
+ return paths.first if paths.length == 1
46
+
47
+ level -= 1
48
+ break if level.zero?
49
+ end
50
+
51
+ allow_root_match ? '/' : ''
52
+ end
53
+
54
+ # @param paths [Array[String]] absolute paths to examine
55
+ # @param level is origin 1
56
+ def self.trim_to_level(paths, level)
57
+ result = paths.map do |x|
58
+ elements = x.split('/').reject(&:empty?)
59
+ '/' + elements[0..level - 1].join('/')
60
+ end
61
+ result.sort.uniq
62
+ end
63
+
2
64
  # @return Path to symlink
3
65
  def self.deref_symlink(symlink)
4
66
  require 'pathname'
@@ -15,5 +77,4 @@ module MslinnUtil
15
77
  ENV.fetch(Regexp.last_match(1), nil)
16
78
  end
17
79
  end
18
-
19
80
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: git_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Slinn
8
8
  autorequire:
9
9
  bindir: bindir
10
10
  cert_chain: []
11
- date: 2023-05-03 00:00:00.000000000 Z
11
+ date: 2023-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rainbow
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rugged
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -48,6 +62,8 @@ files:
48
62
  - git_tree.gemspec
49
63
  - lib/git_tree.rb
50
64
  - lib/git_tree/version.rb
65
+ - lib/git_tree_evars.rb
66
+ - lib/git_tree_replicate.rb
51
67
  - lib/util.rb
52
68
  homepage: https://www.mslinn.com/git/1100-git-tree.html
53
69
  licenses: