gitdis 0.0.1.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 +7 -0
- data/README.md +89 -0
- data/VERSION +1 -0
- data/bin/gitdis +88 -0
- data/lib/gitdis.rb +115 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cbc3764ebe71bcc03b916fb6a29b1b02daaf34dd
|
4
|
+
data.tar.gz: 3dbd971bf31a576d535e176e573023fe362d383b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6da95b9acf0be41a12e4c588169d19ab10e72d48f381f4337fe229e166263b79d414be8cb2144cef37d6a9668de6771355bdf1ca1e28be4268372db013a26421
|
7
|
+
data.tar.gz: 64f87929af5d569b59bf08d2d927855ee657508fed9bd149ab37a577852062dfc4c8d94dfb972914a40fd032243298b6f21600088effeec78273d0f478700861
|
data/README.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# gitdis
|
2
|
+
|
3
|
+
## Install
|
4
|
+
|
5
|
+
### Prerequisites
|
6
|
+
|
7
|
+
* Ruby (>= 2.0)
|
8
|
+
|
9
|
+
### Procedure
|
10
|
+
|
11
|
+
`gem install gitdis`
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
`gitdis path/to/config.yaml [options]`
|
16
|
+
|
17
|
+
## Config
|
18
|
+
|
19
|
+
### YAML Config
|
20
|
+
|
21
|
+
5 options, 1 keymap, plus environment overrides:
|
22
|
+
|
23
|
+
```
|
24
|
+
redis-host: localhost
|
25
|
+
redis-port: 6379
|
26
|
+
redis-db: 0
|
27
|
+
git-repo: ~/foo/bar/baz
|
28
|
+
git-branch: quux
|
29
|
+
keymap:
|
30
|
+
"redis:key:1": "path/to/file1"
|
31
|
+
"redis:key:2": "path/to/file2"
|
32
|
+
|
33
|
+
environments:
|
34
|
+
yours:
|
35
|
+
redis-host: localhost
|
36
|
+
git-branch: mine
|
37
|
+
mine:
|
38
|
+
redis-host: localhost
|
39
|
+
git-branch: yours
|
40
|
+
qa:
|
41
|
+
redis-host: qa.big.com
|
42
|
+
git-branch: develop
|
43
|
+
prod:
|
44
|
+
redis-host: secret.big.net
|
45
|
+
git-branch: master
|
46
|
+
```
|
47
|
+
|
48
|
+
### Command Line Options
|
49
|
+
|
50
|
+
Select your environment (optional). Add final overrides (optional).
|
51
|
+
|
52
|
+
```
|
53
|
+
Environment selection
|
54
|
+
-e, --environment select within YAML[environments]
|
55
|
+
Redis overrides
|
56
|
+
-H, --redis-host string
|
57
|
+
-p, --redis-port number
|
58
|
+
-d, --redis-db number
|
59
|
+
Git repo overrides
|
60
|
+
-r, --git-repo path/to/repo_dir
|
61
|
+
-b, --git-branch e.g. master
|
62
|
+
Other options
|
63
|
+
-D, --dump Just dump Redis contents per YAML keymap
|
64
|
+
-h, --help
|
65
|
+
```
|
66
|
+
|
67
|
+
### Basic operation
|
68
|
+
|
69
|
+
1. pull the latest changes from origin on the specified branch
|
70
|
+
2. iterate over all the expected filenames, skipping any that are missing
|
71
|
+
3. calculate md5 for all the filenames
|
72
|
+
4. compare the md5 to what is in redis
|
73
|
+
5. update redis if the md5s do not match
|
74
|
+
|
75
|
+
### Redis update
|
76
|
+
|
77
|
+
Assuming `foo:bar:baz` base key:
|
78
|
+
|
79
|
+
```
|
80
|
+
# redis.connect(redis_options)
|
81
|
+
GET foo:bar:baz:md5 # assume md5 mismatch
|
82
|
+
SET foo:bar:baz # file contents
|
83
|
+
SET foo:bar:baz:md5 # file contents md5
|
84
|
+
INCR foo:bar:baz:version
|
85
|
+
```
|
86
|
+
|
87
|
+
### Execution
|
88
|
+
|
89
|
+
This script is short-running and intended to be scheduled by e.g. `cron`
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1.1
|
data/bin/gitdis
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'slop'
|
5
|
+
require 'gitdis'
|
6
|
+
|
7
|
+
opts = Slop.parse { |o|
|
8
|
+
o.banner = "USAGE: gitdis path/to/config.yaml [options]"
|
9
|
+
o.separator ' Environment selection'
|
10
|
+
o.string '-e', '--environment', 'select within YAML[environments]'
|
11
|
+
o.separator ' Redis overrides'
|
12
|
+
o.string '-H', '--redis-host', 'string'
|
13
|
+
o.integer '-p', '--redis-port', 'number'
|
14
|
+
o.integer '-d', '--redis-db', 'number'
|
15
|
+
o.separator ' Git repo overrides'
|
16
|
+
o.string '-r', '--git-repo', 'path/to/repo_dir'
|
17
|
+
o.string '-b', '--git-branch', 'e.g. master'
|
18
|
+
o.separator ' Other options'
|
19
|
+
o.bool '-D', '--dump', 'Just dump Redis contents per YAML keymap'
|
20
|
+
o.on '-h', '--help' do
|
21
|
+
puts o
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
}
|
25
|
+
|
26
|
+
unless(yaml_file = opts.arguments.shift)
|
27
|
+
puts opts
|
28
|
+
puts "path/to/config.yaml is required"
|
29
|
+
exit 1
|
30
|
+
end
|
31
|
+
|
32
|
+
# load the default (required) config
|
33
|
+
yaml = YAML.load_file(yaml_file)
|
34
|
+
config = yaml.fetch('default')
|
35
|
+
|
36
|
+
# apply any env-specific settings
|
37
|
+
if opts[:environment]
|
38
|
+
env = opts[:environment].downcase
|
39
|
+
unless yaml.key?(env)
|
40
|
+
warn "no environment #{env} found in #{yaml_file}"
|
41
|
+
exit 1
|
42
|
+
end
|
43
|
+
config.merge!(yaml[env])
|
44
|
+
end
|
45
|
+
|
46
|
+
# make sure we have a keymap
|
47
|
+
keymap = config.fetch('keymap')
|
48
|
+
raise "keymap should be a hash/map" unless keymap.is_a?(Hash)
|
49
|
+
|
50
|
+
# update config with any settings from opts
|
51
|
+
# create redis_options
|
52
|
+
redis_options = {}
|
53
|
+
%w[git-repo git-branch redis-host redis-port redis-db].each { |item|
|
54
|
+
opt_value = opts[item.to_sym]
|
55
|
+
config[item] = opt_value if opt_value
|
56
|
+
|
57
|
+
if item.match /^redis-/ # set :host, :port, :db
|
58
|
+
cfg_value = config[item]
|
59
|
+
if cfg_value
|
60
|
+
# "redis-foo-bar" => :foo_bar
|
61
|
+
ropt = item.split('-').drop(1).join('_').to_sym
|
62
|
+
redis_options[ropt] = cfg_value
|
63
|
+
end
|
64
|
+
end
|
65
|
+
puts [item, config[item]].join(': ') if config[item]
|
66
|
+
}
|
67
|
+
puts "Redis options: #{redis_options}"
|
68
|
+
|
69
|
+
# do things'n'stuff
|
70
|
+
if opts.dump?
|
71
|
+
GitDis.dump(keymap.keys, redis_options)
|
72
|
+
else
|
73
|
+
gd = GitDis.new config.fetch('git-repo')
|
74
|
+
gd.git_pull config.fetch('git-branch')
|
75
|
+
keymap.each { |key, fileglob|
|
76
|
+
result = gd.update(key, fileglob)
|
77
|
+
case result
|
78
|
+
when nil
|
79
|
+
puts "#{fileglob} not found"
|
80
|
+
when false
|
81
|
+
puts "#{fileglob} unchanged"
|
82
|
+
else
|
83
|
+
ver, md5 = *result
|
84
|
+
puts "#{fileglob} updated:"
|
85
|
+
puts "\tVersion: #{ver} (#{md5})"
|
86
|
+
end
|
87
|
+
}
|
88
|
+
end
|
data/lib/gitdis.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'open3' # used for rudimentary git pull
|
2
|
+
require 'digest' # md5sum
|
3
|
+
require 'redis'
|
4
|
+
|
5
|
+
class GitDis
|
6
|
+
# return Process::Status, stream through STDOUT and STDERR
|
7
|
+
def self.exec(cmd, bytes=1024)
|
8
|
+
Open3.popen3(cmd) { |sin, sout, serr, thr|
|
9
|
+
sin.close_write
|
10
|
+
while !sout.eof or !serr.eof
|
11
|
+
ready = IO.select [sout, serr]
|
12
|
+
if ready
|
13
|
+
ready[0].each { |f| # ready for reading
|
14
|
+
begin
|
15
|
+
(f == sout ? $stdout : $stderr).print f.read_nonblock(bytes)
|
16
|
+
rescue EOFError => e
|
17
|
+
# ok
|
18
|
+
end
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
thr.value # Process::Status
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
# raise on nonzero exit code
|
27
|
+
def self.exec!(cmd)
|
28
|
+
status = self.exec(cmd)
|
29
|
+
raise "`#{cmd}` #{status}" unless status.exitstatus == 0
|
30
|
+
0
|
31
|
+
end
|
32
|
+
|
33
|
+
# file contents, version, md5
|
34
|
+
def self.keyset(base_key)
|
35
|
+
[base_key, [base_key, 'version'].join(':'), [base_key, 'md5'].join(':')]
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.dump(keys, redis_options)
|
39
|
+
redis = Redis.new(redis_options)
|
40
|
+
keys.each { |base_key|
|
41
|
+
self.keyset(base_key).each { |rkey|
|
42
|
+
val = redis.get(rkey)
|
43
|
+
if val and val.include?("\n")
|
44
|
+
val = "\n" << val.split("\n").map { |line| "\t#{line}" }.join("\n")
|
45
|
+
end
|
46
|
+
puts ["[#{rkey}]", val].join(' ')
|
47
|
+
}
|
48
|
+
}
|
49
|
+
redis.disconnect
|
50
|
+
end
|
51
|
+
|
52
|
+
attr_accessor :repo_dir, :redis
|
53
|
+
|
54
|
+
def initialize(repo_dir, redis_options = {})
|
55
|
+
@repo_dir = File.expand_path(repo_dir)
|
56
|
+
raise "#{@repo_dir} does not exist!" unless Dir.exist? @repo_dir
|
57
|
+
@redis = Redis.new(redis_options)
|
58
|
+
end
|
59
|
+
|
60
|
+
def git_pull(git_branch)
|
61
|
+
Dir.chdir @repo_dir do
|
62
|
+
if self.class.exec("git diff --quiet HEAD").exitstatus != 0
|
63
|
+
raise "please stash your local changes"
|
64
|
+
end
|
65
|
+
self.class.exec! "git checkout #{git_branch}"
|
66
|
+
self.class.exec! "git pull"
|
67
|
+
end
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
# quick false if calculated md5 == redis md5
|
72
|
+
# otherwise update contents and md5; increment version
|
73
|
+
def update_redis(base_key, file_contents)
|
74
|
+
md5 = Digest::MD5.hexdigest(file_contents)
|
75
|
+
fkey, vkey, mkey = self.class.keyset(base_key)
|
76
|
+
return false if @redis.get(mkey) == md5
|
77
|
+
|
78
|
+
@redis.set(fkey, file_contents)
|
79
|
+
@redis.set(mkey, md5)
|
80
|
+
ver = @redis.incr(vkey)
|
81
|
+
[ver, md5]
|
82
|
+
end
|
83
|
+
|
84
|
+
# e.g. update('foo:bar:baz', 'foo/bar/*.baz')
|
85
|
+
# return nil # path does not exist
|
86
|
+
# false # no update needed
|
87
|
+
# [ver, md5] # updated
|
88
|
+
def update(base_key, relpath)
|
89
|
+
# handle e.g. "foo/bar/*.yaml"
|
90
|
+
files = Dir.glob(File.join(@repo_dir, relpath))
|
91
|
+
case files.length
|
92
|
+
when 0 then nil
|
93
|
+
when 1 then self.update_redis(base_key, File.read(files.first))
|
94
|
+
else
|
95
|
+
puts "concatenating #{files.length} files"
|
96
|
+
result = ''
|
97
|
+
sep = "\n"
|
98
|
+
files.each { |fname|
|
99
|
+
s = File.read(fname)
|
100
|
+
if s and !s.empty?
|
101
|
+
# scan for carriage returns (Microsoft text format)
|
102
|
+
sep = "\r\n" if sep == "\n" and s.include?("\r")
|
103
|
+
s << sep if s.last != "\n"
|
104
|
+
result << s
|
105
|
+
# debugging
|
106
|
+
elsif s
|
107
|
+
puts "#{fname} is empty"
|
108
|
+
else
|
109
|
+
puts "File.read(#{fname}) returned false/nil"
|
110
|
+
end
|
111
|
+
}
|
112
|
+
self.update_redis(base_key, result.chomp(sep))
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gitdis
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rick Hull
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: slop
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '4.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '4.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redis
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: buildar
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2'
|
55
|
+
description: Should you use this? YES!
|
56
|
+
email:
|
57
|
+
executables:
|
58
|
+
- gitdis
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- README.md
|
63
|
+
- VERSION
|
64
|
+
- bin/gitdis
|
65
|
+
- lib/gitdis.rb
|
66
|
+
homepage: https://github.com/rickhull/gitdis
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '2.0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 2.4.5
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Pull from git, push to redis and beyond!
|
90
|
+
test_files: []
|