gitdis 0.0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|