update_repo 0.5.0 → 0.6.0

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
  SHA1:
3
- metadata.gz: 216483b2ac26f98ccf9b4b7712059f8876de2d9d
4
- data.tar.gz: 5fd33a763737cfb1ad7410bf7703b7650e27ddd7
3
+ metadata.gz: 4b02b9ed1895164abe441378e107c240e0d0884a
4
+ data.tar.gz: 4b78e9cb4620576e1cca044ee2c617b0e25bb9b9
5
5
  SHA512:
6
- metadata.gz: 0d4698880b1584aeab7f6f7fd9400fdfe41953cfa1446a2bafcd70f912b73d66dc5ba598fd1671770a509614ed26b794b12300107ed369a10ac36e7546a1d518
7
- data.tar.gz: 03fadd911508d1b51dbd3ffa5b8adf5fd6b3bd25d6fc1309c7d69ff55d2105d536d4df6ec636440cd4a74b9f8bc1ac6309f6d627baf7f646dda470094ae9b4ff
6
+ metadata.gz: 9f2fc8b75b84ff8db5c18949150b3a209d6341fbfda3e07a4fc6ca3900453297425479d8d1d10bb50057579e07a35ef7eec438bc78b24d2cdbf80126a6e8abb7
7
+ data.tar.gz: 270140f7a98ba431a88a87e1c93ec191f0206ca157e058b52cfbd8a669e3ea42c444bb791c59e0273c7ba2d04e807ef144d572d04bd6400a0979f74bcce2a981
data/.reek CHANGED
@@ -4,3 +4,6 @@ TooManyStatements:
4
4
 
5
5
  UtilityFunction:
6
6
  public_methods_only: true
7
+
8
+ RepeatedConditional:
9
+ max_ifs: 3
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ AllCops:
2
+ DisplayCopNames: true
data/.travis.yml CHANGED
@@ -3,5 +3,5 @@ rvm:
3
3
  - 1.9.3
4
4
  - 2.1
5
5
  - 2.2.4
6
- - 2.3.0
7
- before_install: gem install bundler -v 1.11.2
6
+ - 2.3.1
7
+ before_install: gem install bundler -v 1.12.5
data/README.md CHANGED
@@ -38,7 +38,22 @@ $ update_repo
38
38
 
39
39
  ## Configuration
40
40
  #### Configuration file
41
- To be added.
41
+ The configuration file defaults to `~/.updaterepo` and is a standard [YAML](http://yaml.org/)-formatted text file. The first line must contain the YAML frontmatter of 3 dashes (`---`). After that, the following sections can follow in any order. Only the `location:` section is compulsory, and that must contain at least one entry.
42
+
43
+ `location:` - at least one directory which contains the locally cloned repository(s) to update. There is no limit on how many directories can be listed :
44
+ ```yaml
45
+ ---
46
+ location:
47
+ - /media/myuser/git-repos
48
+ - /data/RepoDir
49
+ ```
50
+
51
+ `exceptions:` - an (optional) list of repositories that will NOT be updated automatically. Use this for repositories that need special handling, or should only be manually updated. Note that the name specified is that of the __directory__ holding the repository (has the `.git` directory inside)
52
+ ```yaml
53
+ exceptions:
54
+ - ubuntu-trusty
55
+ - update_repo
56
+ ```
42
57
 
43
58
  #### Command line switches
44
59
  Options are not required. If none are specified then the program will read from the standard configuration file (~/.updaterepo) and automatically update the specified Repositories.
@@ -47,6 +62,11 @@ Enter `update_repo --help` at the command prompt to get a list of available opti
47
62
  ```
48
63
  Options:
49
64
  -c, --color, --no-color Use colored output (default: true)
65
+ -d, --dump Dump a list of Directories and Git URL's to STDOUT in CSV format
66
+ -p, --prune=<i> Number of directory levels to remove from the --dump output.
67
+ Only valid when --dump or -d specified (Default: 0)
68
+ -i, --import Import a previous dump of directories and Git repository URL's,
69
+ (created using --dump) then proceed to clone them locally.
50
70
  -v, --version Print version and exit
51
71
  -h, --help Show this message
52
72
  ```
@@ -57,11 +77,13 @@ Not in any specific order :
57
77
  - Improve error-checking and recovery while parsing the configuration file
58
78
  * Ignore and report invalid or missing directories
59
79
  - Either add an option 'variants' or similar to allow non-standard git pull commands (eg Ubuntu kernel), or update the 'exceptions' option to do same.
60
- - Error checking and reporting for the git processes - retry for connection issues etc (config setting).
80
+ - Error checking and reporting for the git processes `[IN PROGRESS]`
81
+ * Add more failure cases, not all git errors fail with "fatal:"
82
+ - retry for connection issues etc (config setting).
61
83
  - Add extra (optional) stats / info at end-of-job :
62
- * list of changed repos
63
- * errors or connection problems
64
- * _more..._
84
+ * list of changed repos
85
+ * errors or connection problems `[IN PROGRESS]`
86
+ * _more..._
65
87
  - Add command line options to override configuration, and even specify an alternate config file. Any options so specified will have precedence over settings specified in the configuration file.
66
88
  - Add command line options for verbose or quiet, with same options in config file.
67
89
  - Add ability to specify a new directory (containing Git repos) to search from the command line, and optionally save this to the standard configuration.
@@ -69,7 +91,7 @@ Not in any specific order :
69
91
  - Add flag for 'default' repo directory (or another specific directory - if it does not already exist it will be created and added to the standard list) which will be used for new additions.
70
92
  - Option to save log file for each run.
71
93
  - Add option to only display a (text) tree of the discovered git repositories, not updating them; Similar option to just dump a list of the remote git locations.
72
- - Add ability to export a text dump of each repo location and then re-import this on a different machine or after reinstall
94
+ - Add ability to export a text dump of each repo location `[DONE]` and then re-import this on a different machine or after reinstall `[TODO]`
73
95
  - Document configuration file format and options.
74
96
  - Add testing!
75
97
 
data/Rakefile CHANGED
@@ -1,20 +1,28 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
- require 'rubocop/rake_task'
4
3
  require 'inch/rake'
5
4
 
6
5
  RSpec::Core::RakeTask.new(:spec)
7
6
 
8
- RuboCop::RakeTask.new do |task|
9
- task.options << 'lib' << 'exe'
7
+ # rubocop is not compatible with Ruby < 2.0
8
+ if RUBY_VERSION >= '2.0'
9
+ require 'rubocop/rake_task'
10
+ RuboCop::RakeTask.new do |task|
11
+ task.options << 'lib' << 'exe'
12
+ task.fail_on_error = false
13
+ end
14
+ else
15
+ task :rubocop do
16
+ # Empty task
17
+ end
10
18
  end
11
19
 
12
20
  Inch::Rake::Suggest.new do |suggest|
13
21
  suggest.args << '--pedantic'
14
22
  end
15
23
 
16
- # reek is not compatible with Ruby < 2.0]
17
- if RUBY_VERSION > '2.0'
24
+ # reek is not compatible with Ruby < 2.0
25
+ if RUBY_VERSION >= '2.0'
18
26
  require 'reek/rake/task'
19
27
  Reek::Rake::Task.new do |t|
20
28
  t.fail_on_error = false
@@ -0,0 +1,50 @@
1
+ # Module 'Helpers' containing assorted helper functions required elsewhere
2
+ module Helpers
3
+ # will remove the FIRST 'how_many' root levels from a directory path 'dir'..
4
+ # @param dir [string] Path to be truncated
5
+ # @param how_many [integer] How many levels to be dropped from path.
6
+ # @return [string] the properly truncated path
7
+ def trunc_dir(dir, how_many)
8
+ # make sure we don't lose any root slash if '--prune' is NOT specified
9
+ return dir if how_many.zero?
10
+ # convert to array then lose the first 'how_many' parts
11
+ path_array = Pathname(dir).each_filename.to_a
12
+ path_array = path_array.drop(how_many)
13
+ # join it all back up again and return it
14
+ File.join(path_array)
15
+ end
16
+
17
+ # mark these as private simply so that 'reek' wont flag as utility function.
18
+ private
19
+
20
+ # true if we are dumping the file structure and git urls instead of updating.
21
+ def dumping?
22
+ param_set('dump')
23
+ end
24
+
25
+ # true if we are importing a previously dumped list of Git repos.
26
+ def importing?
27
+ param_set('import')
28
+ end
29
+
30
+ def gitdir?(dirpath)
31
+ gitpath = dirpath + '/.git'
32
+ File.exist?(gitpath) && File.directory?(gitpath)
33
+ end
34
+
35
+ def show_time(duration)
36
+ time_taken = Time.at(duration).utc
37
+ time_taken.strftime('%-H hours, %-M Minutes and %-S seconds.')
38
+ end
39
+
40
+ # we cant use --dump and --import on the same command line
41
+ def no_import_export
42
+ Trollop.die 'update_repo : Cannot specify both --dump and --import'
43
+ end
44
+
45
+ # print the specified summary metric, called from the footer.
46
+ def summary(which, color, event)
47
+ output = "#{which} #{event}"
48
+ print ' / ', output.send(color.to_sym) unless which.zero?
49
+ end
50
+ end
@@ -1,4 +1,4 @@
1
1
  module UpdateRepo
2
2
  # constant, current version of this Gem
3
- VERSION = '0.5.0'.freeze
3
+ VERSION = '0.6.0'.freeze
4
4
  end
data/lib/update_repo.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  require 'update_repo/version'
2
+ require 'update_repo/helpers'
2
3
  require 'yaml'
3
4
  require 'colorize'
4
5
  require 'confoog'
5
6
  require 'trollop'
7
+ require 'open3'
6
8
 
7
9
  # Overall module with classes performing the functionality
8
10
  # Contains Class UpdateRepo::WalkRepo
@@ -14,15 +16,11 @@ module UpdateRepo
14
16
  # repositories found therein.
15
17
  # rubocop:disable Metrics/ClassLength
16
18
  class WalkRepo
19
+ include Helpers
17
20
  # Class constructor. No parameters required.
18
21
  # @return [void]
19
22
  def initialize
20
- # @counter - this will be incremented with each repo updated.
21
- @counter = 0
22
- # @skip_counter - will count all repos deliberately skipped
23
- @skip_count = 0
24
- # @ start_time - will be used to get elapsed time
25
- @start_time = 0
23
+ @metrics = { count: 0, skipped: 0, failed: 0, updated: 0, start_time: 0 }
26
24
  # read the options from Trollop and store in temp variable.
27
25
  # we do it this way around otherwise if configuration file is missing it
28
26
  # gives the error messages even on '--help' and '--version'
@@ -43,10 +41,15 @@ module UpdateRepo
43
41
  # walk_repo = UpdateRepo::WalkRepo.new
44
42
  # walk_repo.start
45
43
  def start
46
- String.disable_colorization = true unless @config['cmd'][:color]
47
- show_header(@config['exceptions'])
48
- @config['location'].each do |loc|
49
- recurse_dir(loc)
44
+ String.disable_colorization = true unless param_set('color')
45
+ no_import_export if dumping? && importing?
46
+ show_header
47
+ if importing?
48
+
49
+ else
50
+ @config['location'].each do |loc|
51
+ recurse_dir(loc)
52
+ end
50
53
  end
51
54
  # print out an informative footer...
52
55
  footer
@@ -54,6 +57,12 @@ module UpdateRepo
54
57
 
55
58
  private
56
59
 
60
+ # Determine options from the command line and configuration file. Command
61
+ # line takes precedence
62
+ def param_set(option)
63
+ @config['cmd'][option.to_sym] || @config[option]
64
+ end
65
+
57
66
  def config_error
58
67
  if @config.status[:errors] == Status::ERR_CANT_LOAD
59
68
  print 'Note that the the default configuration file was '.red,
@@ -63,6 +72,7 @@ module UpdateRepo
63
72
  end
64
73
 
65
74
  # rubocop:disable Metrics/MethodLength
75
+ # rubocop:disable Metrics/LineLength
66
76
  def set_options
67
77
  Trollop.options do
68
78
  version "update_repo version #{VERSION} (C)2016 G. Ramsay\n"
@@ -80,12 +90,16 @@ specified Repositories.
80
90
  Options:
81
91
  EOS
82
92
  opt :color, 'Use colored output', default: true
93
+ opt :dump, 'Dump a list of Directories and Git URL\'s to STDOUT in CSV format', default: false
94
+ opt :prune, "Number of directory levels to remove from the --dump output.\nOnly valid when --dump or -d specified", default: 0
95
+ opt :import, "Import a previous dump of directories and Git repository URL's,\n(created using --dump) then proceed to clone them locally.", default: false
83
96
  # opt :quiet, 'Only minimal output to the terminal', default: false
84
97
  # opt :silent, 'Completely silent, no output to terminal at all.',
85
98
  # default: false
86
99
  end
87
100
  end
88
101
  # rubocop:enable Metrics/MethodLength
102
+ # rubocop:enable Metrics/LineLength
89
103
 
90
104
  # take each directory contained in the Repo directory, if it is detected as
91
105
  # a Git repository then update it (or as directed by command line)
@@ -93,7 +107,14 @@ EOS
93
107
  def recurse_dir(dirname)
94
108
  Dir.chdir(dirname) do
95
109
  Dir['**/'].each do |dir|
96
- notexception?(dir) ? update_repo(dir) : skip_repo(dir) if gitdir?(dir)
110
+ next unless gitdir?(dir)
111
+ if dumping?
112
+ dump_repo(File.join(dirname, dir))
113
+ elsif importing?
114
+ # placeholder
115
+ else
116
+ notexception?(dir) ? update_repo(dir) : skip_repo(dir)
117
+ end
97
118
  end
98
119
  end
99
120
  end
@@ -107,31 +128,45 @@ EOS
107
128
 
108
129
  # Display a simple header to the console
109
130
  # @example
110
- # show_header(exceptions)
131
+ # show_header
111
132
  # @return [void]
112
- def show_header(exceptions)
133
+ def show_header
113
134
  # print an informative header before starting
135
+ # unless we are dumping the repo information
136
+ return if dumping?
114
137
  print "\nGit Repo update utility (v", VERSION, ')',
115
138
  " \u00A9 Grant Ramsay <seapagan@gmail.com>\n"
116
139
  print "Using Configuration from '#{@config.config_path}'\n"
140
+ print "Command line is : #{@config['cmd']}\n"
141
+ # list out the locations that will be searched
117
142
  list_locations
118
- if exceptions
119
- print "\nExclusions:".underline, ' ',
120
- exceptions.join(', ').yellow, "\n"
121
- end
143
+ # list any exceptions that we have from the config file
144
+ list_exceptions
122
145
  # save the start time for later display in the footer...
123
- @start_time = Time.now
146
+ @metrics[:start_time] = Time.now
124
147
  print "\n" # blank line before processing starts
125
148
  end
126
149
 
127
150
  # print out a brief footer. This will be expanded later.
128
151
  # @return [void]
129
152
  def footer
130
- duration = Time.now - @start_time
131
- print "\nUpdates completed : ", @counter.to_s.green,
132
- ' repositories processed'
133
- print ' / ', @skip_count.to_s.yellow, ' skipped' unless @skip_count == 0
134
- print ' in ', show_time(duration), "\n\n"
153
+ # no footer if we are dumping the repo information
154
+ return if dumping?
155
+ duration = Time.now - @metrics[:start_time]
156
+ print "\nUpdates completed : ", @metrics[:count].to_s.green,
157
+ ' repositories processed'.green
158
+ summary(@metrics[:updated], 'cyan', 'updated')
159
+ summary(@metrics[:skipped], 'yellow', 'skipped')
160
+ summary(@metrics[:failed], 'red', 'failed')
161
+ print ' in ', show_time(duration).cyan, "\n\n"
162
+ end
163
+
164
+ def list_exceptions
165
+ exceptions = @config['exceptions']
166
+ if exceptions
167
+ print "\nExclusions:".underline, ' ',
168
+ exceptions.join(', ').yellow, "\n"
169
+ end
135
170
  end
136
171
 
137
172
  def list_locations
@@ -145,27 +180,43 @@ EOS
145
180
  Dir.chdir(dirpath.chomp!('/')) do
146
181
  repo_url = `git config remote.origin.url`.chomp
147
182
  print '* Skipping ', Dir.pwd.yellow, " (#{repo_url})\n"
148
- @skip_count += 1
183
+ @metrics[:skipped] += 1
149
184
  end
150
185
  end
151
186
 
152
187
  def update_repo(dirname)
153
188
  Dir.chdir(dirname.chomp!('/')) do
154
189
  repo_url = `git config remote.origin.url`.chomp
155
- print '* Checking ', Dir.pwd.green, " (#{repo_url})\n", ' -> '
156
- system 'git pull'
157
- @counter += 1
190
+ do_update(repo_url)
191
+ @metrics[:count] += 1
158
192
  end
159
193
  end
160
194
 
161
- def gitdir?(dirpath)
162
- gitpath = dirpath + '/.git'
163
- File.exist?(gitpath) && File.directory?(gitpath)
195
+ def do_update(repo_url)
196
+ print '* Checking ', Dir.pwd.green, " (#{repo_url})\n"
197
+ Open3.popen3('git pull') do |_stdin, stdout, stderr, thread|
198
+ { out: stdout, err: stderr }.each do |key, stream|
199
+ Thread.new do
200
+ until (line = stream.gets).nil?
201
+ if key == :err && line =~ /^fatal:/
202
+ print ' ', line.red
203
+ @metrics[:failed] += 1
204
+ else
205
+ print ' ', line.cyan
206
+ @metrics[:updated] += 1 if line =~ /files?\schanged/
207
+ end
208
+ end
209
+ end
210
+ end
211
+ thread.join
212
+ end
164
213
  end
165
214
 
166
- def show_time(duration)
167
- time_taken = Time.at(duration).utc
168
- time_taken.strftime('%-H hours, %-M Minutes and %-S seconds.').cyan
215
+ def dump_repo(dir)
216
+ Dir.chdir(dir.chomp!('/')) do
217
+ repo_url = `git config remote.origin.url`.chomp
218
+ print "#{trunc_dir(dir, @config['cmd'][:prune])},#{repo_url}\n"
219
+ end
169
220
  end
170
221
  end
171
222
  end
data/update_repo.gemspec CHANGED
@@ -25,8 +25,8 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency 'rspec', '~> 3.0'
26
26
  spec.add_development_dependency 'pry'
27
27
  spec.add_development_dependency 'fakefs'
28
+ spec.add_development_dependency 'json', '= 1.8.3'
28
29
  spec.add_development_dependency 'coveralls'
29
- spec.add_development_dependency 'rubocop'
30
30
  spec.add_development_dependency 'inch'
31
31
  spec.add_development_dependency 'simplecov', '~> 0.10'
32
32
  spec.add_development_dependency 'pullreview-coverage'
@@ -38,5 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.add_dependency 'trollop'
39
39
 
40
40
  # Depends on Ruby version if we can use 'Reek'
41
- spec.add_development_dependency 'reek', '~> 3.3' if RUBY_VERSION > '2.0'
41
+ spec.add_development_dependency 'reek', '~> 3.3' if RUBY_VERSION >= '2.0'
42
+ # Depends on Ruby version if we can use 'rubocop'
43
+ spec.add_development_dependency 'rubocop' if RUBY_VERSION >= '2.0'
42
44
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: update_repo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Grant Ramsay
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-03-18 00:00:00.000000000 Z
11
+ date: 2016-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -81,21 +81,21 @@ dependencies:
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  - !ruby/object:Gem::Dependency
84
- name: coveralls
84
+ name: json
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - '='
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: 1.8.3
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - '='
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: 1.8.3
97
97
  - !ruby/object:Gem::Dependency
98
- name: rubocop
98
+ name: coveralls
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - ">="
@@ -234,6 +234,20 @@ dependencies:
234
234
  - - "~>"
235
235
  - !ruby/object:Gem::Version
236
236
  version: '3.3'
237
+ - !ruby/object:Gem::Dependency
238
+ name: rubocop
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ type: :development
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '0'
237
251
  description:
238
252
  email:
239
253
  - seapagan@gmail.com
@@ -246,6 +260,7 @@ files:
246
260
  - ".pullreview.yml"
247
261
  - ".reek"
248
262
  - ".rspec"
263
+ - ".rubocop.yml"
249
264
  - ".travis.yml"
250
265
  - Gemfile
251
266
  - LICENSE.txt
@@ -256,6 +271,7 @@ files:
256
271
  - bin/update_repo
257
272
  - exe/update_repo
258
273
  - lib/update_repo.rb
274
+ - lib/update_repo/helpers.rb
259
275
  - lib/update_repo/version.rb
260
276
  - update_repo.gemspec
261
277
  homepage: http://opensource.seapagan.net
@@ -278,9 +294,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
278
294
  version: '0'
279
295
  requirements: []
280
296
  rubyforge_project:
281
- rubygems_version: 2.6.2
297
+ rubygems_version: 2.6.6
282
298
  signing_key:
283
299
  specification_version: 4
284
300
  summary: A Simple Gem to keep multiple locally-cloned Git Repositories up to date
285
301
  test_files: []
286
- has_rdoc: