Skip to content

Instantly share code, notes, and snippets.

@rye
Last active August 29, 2015 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rye/82ca4c494d705a8644c7 to your computer and use it in GitHub Desktop.
Save rye/82ca4c494d705a8644c7 to your computer and use it in GitHub Desktop.
My data synchronization system.
#!/usr/bin/env ruby
require "json"
module DataSync
EXAMPLE_CONFIGURATION_FILE_NAME = "z_datasync-configuration.sample.json"
CONFIGURATION_FILE_NAME = "configuration.json"
OutputProperties = {
cronMode: false,
debugMode: true
}
class Configuration
attr_accessor :hash
def load(filename)
if File.exists?(File.join(File.dirname(__FILE__), filename))
configurationFilename = File.join(File.dirname(__FILE__), filename)
else
configurationFilename = File.join(File.dirname(__FILE__), EXAMPLE_CONFIGURATION_FILE_NAME)
end
@hash = JSON.parse(IO.read(configurationFilename))
return @hash
end
end
class GenericAction
attr_accessor :command, :path, :output, :progressCharacter
def to_proc
commandString = "cd #{self.path}; #{command} 2>&1"
return Proc.new { `#{commandString}` }
end
def to_fiber
commandString = "cd #{@command}; #{command} 2>&1"
return Fiber.new { `#{commandString}` }
end
end
class FetchAction < GenericAction
def initialize(command, path, progressCharacter)
raise ArgumentError, "Command not correct class!" unless command.class == String
raise ArgumentError, "Path not correct class!" unless path.class == String
raise ArgumentError, "ProgressCharacter not correct class!" unless progressCharacter.class == String
@command = command
@path = path
@progressCharacter = progressCharacter
end
end
end
def generateActions(configurationHash)
actionPile = []
if configurationHash["defaults"]
defaults = configurationHash["defaults"]
else
defaults = {
"git" => {
"fetch" => {
"command" => "git fetch",
"recurse" => false,
"progress-character" => "."
}
}
}
end
if configurationHash["git"]
if configurationHash["git"]["fetch"]
configurationHash["git"]["fetch"].each do |directory|
directoryPath = nil
# Extract the directory's path.
if directory["directory"]
# Complain about types and stuff if they aren't all right.
raise TypeError, "directory[\"directory\"] property needs to be a string" unless
directory["directory"].class == String
directoryPath = directory["directory"]
end
recursive = nil
# Ascertain as to whether or not to recurse through the directory's first-level
# subdirectories
if directory["recurse"]
# If we have a value in our directory["recurse"] property (i.e. the property is set explicitly for the directory), then store it.
recursive = directory["recurse"]
else
# If we don't,
if directory["recurse"] == nil
# Use the default (if we have one)
recursive = defaults["git"]["fetch"]["recurse"]
end
end
gitFetchCommand = nil
# Determine which command to call in each repository.
if directory["command"]
# If we have an explicit value, use it as the command.
gitFetchCommand = directory["command"]
else
# If we don't,
if directory["command"] == nil
# Use the default (if we have one)
gitFetchCommand = defaults["git"]["fetch"]["command"]
end
end
# Complain under non-ideal circumstances
raise "No directory specified for directory (#{directory.inspect}) (defaults not allowed)!" unless directoryPath != nil
raise "Recursion setting not specified, nor a default (#{directory.inspect})!" if recursive == nil
raise "Command setting not specified, nor a default (#{directory.inspect})!" if gitFetchCommand == nil
# If we're operating recursively on the current directory
if recursive
# Then make a Action pile for the directory
directoryPile = []
# Go through the array of subdirectory paths
Dir.glob(File.join(File.expand_path("#{directoryPath}"), "*/")).each do |subdirectoryPath|
# And generate a action on the directory's Action pile.
directoryPile << DataSync::FetchAction.new(gitFetchCommand, subdirectoryPath, "NOPE")
end
# Push that directory Pile onto the main action Pile
actionPile << directoryPile
else # If we're NOT operating recursively on the current directory
# Then just generate a Action for the directory (no need to recurse)
actionPile << DataSync::FetchAction.new(gitFetchCommand, directoryPath, "NOPE")
end
end
end
end
# Flatten out the Action pile and return it.
return actionPile.flatten
end
# If a configuration file exists named "configuration.json", load that, but else load
# "configuration.sample.json"
configurationHash = DataSync::Configuration.new.load(DataSync::CONFIGURATION_FILE_NAME)
# Generate an array of Actions to call.
actions = generateActions(configurationHash)
# Iterate through the array and call each one.
actions.each do |action|
print action.progressCharacter unless DataSync::OutputProperties[:cronMode]
action.output = action.to_proc.call
end
print "\n" unless DataSync::OutputProperties[:cronMode]
actions.each do |action|
puts "Action (#{action.command}<#{action.path}>):\n#{action.output.gsub(/^/, " ")}\n" if action.output.gsub(/\s+/, "").length > 0 unless DataSync::OutputProperties[:cronMode]
end
{
"defaults": {
"git": {
"fetch": {
"command": "git fetch",
"recurse": true,
"progress-character": "."
}
}
},
"git": {
"fetch": [
{
"command": "git fetch",
"directory": "~/git/github/kryestofer",
"recurse": true
},
{
"command": "git fetch",
"directory": "~/git/github/kotct",
"recurse": true
},
{
"command": "git fetch",
"directory": "~/git/github/team461wbi",
"recurse": true
},
{
"command": "git fetch",
"directory": "~/git/github/wlcsc",
"recurse": true
},
{
"command": "git fetch",
"directory": "~/git/github/promyloph",
"recurse": true
},
{
"command": "git fetch",
"directory": "~/git/github/cantino",
"recurse": true
}
]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment