lib/raykit/console.rb



require 'optparse'
require 'slop'
require_relative('./logging.rb')

module Raykit
    # The implementation for the raykit console application

    class Console
        attr_accessor :opts
        def initialize
            @opts = Slop.parse do |o|
                o.string '-t','--task','rake task', default: 'default'
                o.bool '-v','--verbose','print detailed output', default: false
                o.bool '-q','--quiet','minimal output', default: false
                o.bool '-s','--stop','stop on error', default: true
            end

            if(opts.verbose?)
                puts "options: " + Rainbow(@opts.to_hash).yellow.bright
                puts "arguments:" + Rainbow(@opts.arguments).yellow.bright
            end
        end

        def run
            verb = "usage"
            verb = @opts.arguments[0] if(@opts.arguments.length > 0)
            case verb
            when "usage"
                usage
            when "add"
                add
            when "remove"
                remove
            when "show"
                show
            when "work"
                work
            when "import"
                import
            when "clean"
                clean
            when "sync_version"
                sync_version
            when "copy"
                copy
            when "pull"
                pull
            else
                puts 'unrecognized command ' + verb
                return 1
            end
        end

        def verb_descriptions
            { "add"=> "add a git url",
            "remove" => "remove one or more git urls",
            "show" => "show git urls matching a specific pattern",
            "work" => "clone and rake a git repository",
            "import" => "import git urls matching a specific pattern",
            "clean" => "clean one or more working directories",
            "pull" => "preform git pull on one or more working directories",
            "sync_version" => "synchronize the version number between two files",
            "copy" => "copy a file"
        }
        end
        def verb_usage
            { "add" => "add GIT_URL",
                "remove" => "remove URL_PATTERN",
                "show" => "show URL_PATTERN",
                "work" => "work URL_PATTERN [--task RAKE_TASK]",
                "import" => "import URL_PATTERN",
                "clean" => "clean URL_PATTERN",
                "pull" => "pull URL_PATTERN",
                "sync_version" => "sync_version SOURCE_FILENAME DESTINATION_FILENAME",
                "copy" => "copy SOURCE DESTINATION"}
        end

        def usage

            puts "Usage: raykit VERB [GIT_URL|PATTERN] [OPTIONS]"
            verb_descriptions.each{|k,v|
                puts k.ljust(15,' ') + " - " + v
            }
            #puts @opts

            #puts "verbs: " + verbs.to_s

            0
        end

        def add
            if(@opts.arguments.length < 2)
                puts 'add requires a url'
                return 1
            end
            url=@opts.arguments[1] 
            if(REPOSITORIES.include?(url))
                puts 'url ' + url + ' already exists.'
            else
                REPOSITORIES << url
                REPOSITORIES.save(REPOSITORIES.filename)
                puts 'url ' + url + ' added.'
            end
        end

        def remove
            if(@opts.arguments.length < 2)
                puts 'remove requires a url or pattern'
                return 1
            end
            pattern=''
            pattern=@opts.arguments[1] if(@opts.arguments.length > 1)
            remove_urls = REPOSITORIES.matches(pattern)
            if(remove_urls.length == 0)
                puts 'no matching urls found.'
            
            else
                remove_urls.each{|url|
                REPOSITORIES.delete(url)
                puts 'url ' + url + ' removed.'
                }
                REPOSITORIES.save(REPOSITORIES.filename)
            end
        end

        def show
            pattern=''
            pattern=@opts.arguments[1] if(@opts.arguments.length > 1)
            REPOSITORIES.matches(pattern).each{|url|
                puts url
            }
        end

        def work
            pattern=''
            pattern=@opts.arguments[1] if(@opts.arguments.length > 1)

            work_repositories = REPOSITORIES.matches(pattern)
            errors=Array.new()
            puts 'work: found ' + work_repositories.length.to_s + ' matching urls'
            work_repositories.each{|url|
                exitstatus = work_url(url)
                puts ' ' if(@opts.verbose?)
                return exitstatus if(@opts[:stop] && exitstatus != 0)
            }
            0
        end

        def work_url(url)
            return 0 if(url == "https://gitlab.com/lou-parslow/raykit.git")
            puts Rainbow(url).yellow.bright if(@opts.verbose?)
            repo=Raykit::Git::Repository.new(url)
            work=Raykit::Git::Directory.new(repo.get_dev_dir('work'))
            if(!Dir.exist?(work.directory))
                clone = Command.new("git clone #{url} #{work.directory} --recursive")
                puts clone.summary if(!@opts.quiet?)
                if(clone.exitstatus != 0)
                    clone.details
                    return clone.exitstatus
                end
            end
            if(Dir.exist?(work.directory))
                Dir.chdir(work.directory) do
                    if(File.exist?('rakefile.rb'))
                        rake = Raykit::Command.new("rake #{@opts[:task]}")
                        rake.summary(true) if(!@opts.quiet?) || rake.exitstatus != 0
                        if(rake.exitstatus != 0)
                            rake.details
                            rake.summary true
                            return rake.exitstatus
                        end
                    else
                        puts('rakefile.rb not found in ' + work.directory) if(@opts.verbose?)
                        return 0
                    end
                end
            end
            return 0
        end

        def pull
            pattern=''
            pattern=@opts.arguments[1] if(@opts.arguments.length > 1)
            REPOSITORIES.matches(pattern).each{|url|
                begin
                    repo=Raykit::Git::Repository.new(url)
                    work=Raykit::Git::Directory.new(repo.get_dev_dir('work'))
                    if(Dir.exist?(work.directory) && !work.directory=='.git')
                        Dir.chdir(work.directory) do
                            diff=`git diff`.strip
                            status=`git status`.strip
                            if(diff.length == 0 && status.include?('nothing to commit'))
                                cmd = Command.new('git pull')
                                cmd.summary if(@opts.verbose?)

                                if(cmd.exitstatus != 0)
                                    cmd.details
                                    if(@opts.quit?)
                                        abort Rainbow(cmd.summary).blue.bright
                                    end
                                end
                            end
                        end
                    end
                rescue => error
                    issue = 'error occurred for pull of ' + url +' ' + error.to_s
                    if(@opts.quit?)
                        abort Rainbow(issue).blue.bright
                    else
                        puts Rainbow(issue).blue.bright
                    end
                end
            }
        end

        def import
            pattern=''
            pattern=@opts.arguments[1] if(@opts.arguments.length > 1)
            puts 'scanning...'
            count=REPOSITORIES.length
            REPOSITORIES.import(pattern)
            new_count=REPOSITORIES.length-count
            puts "imported #{new_count} git repositories"
        end

        def clean
            pattern=''
            pattern=@opts.arguments[1] if(@opts.arguments.length > 1)
            REPOSITORIES.matches(pattern).each{|url|
                repo=Raykit::Git::Repository.new(url)
                work=Raykit::Git::Directory.new(repo.get_dev_dir('work'))
                if(Dir.exist?(work.directory))
                    puts 'removing ' + work.directory
                    begin
                        FileUtils.rm_rf(work.directory,secure:true)
                    rescue
                        puts 'error removing ' + work.directory
                    end
                end
            }
        end

        #def sync_version

        #    if(@opts.arguments.length < 3)

        #        puts 'source and destination arguments are required for sync_version'

        #        return 1

        #    end

        #    source = @opts.arguments[1]

        #    dest = @opts.arguments[2]

        #    Raykit::Version::sync_file_versions(source,dest)

        #    version = Raykit::Version::detect(source,false)

        #    puts "version #{version} detected in #{source}, updating #{dest} to match."

        #end


        def copy
            if(@opts.arguments.length < 3)
                puts 'source and destination arguments are required for copy'
                return 1
            end
            source = @opts.arguments[1]
            dest = @opts.arguments[2]
            FileUtils.cp(source,dest)
            puts "copied #{source} to #{dest}"
        end

        def rake(hash)
            REPOSITORIES.each{|remote|
                if(remote.include?(hash[:pattern]))
                    begin
                        puts "remote: #{remote}"
                        cmd = Raykit::Rake::run(remote,'master')
                        elapsed_str = Timer.get_elapsed_str(cmd.elapsed)
                        if(cmd.exitstatus == 0)
                            puts elapsed_str + " " +  Rainbow(SECRETS.hide(cmd.command)).yellow.bright + " (#{cmd.directory})"
                        else
                            puts "\r\n" + cmd.command + "\r\n"
                            puts "\r\n" + cmd.output + "\r\n"
                            puts "\r\n" + cmd.error + "\r\n"
                            puts ''
                            puts Rainbow(elapsed_str).red.bright + " " +  Rainbow(cmd.command).white
                        end
                    rescue
                        puts 'rescued...'
                    end
                end
            }
        end

        
    end
end

#CONSOLE=Raykit::Console.new