lib/raykit/project.rb



require 'rake/clean'
require 'digest'
RAKE_DIRECTORY=Rake.application.original_dir
module Raykit
    class Project
        attr_accessor :name
        attr_accessor :timer
        attr_accessor :verbose
        @directory
        @version
        @remote
        @repository
        @git_directory
        attr_accessor :target
        #@log

        #@commit_message_filename


        def initialize()
            @verbose=false
            @timer=Raykit::Timer.new
            @remote=''
            @commit_message_filename="commit_message.tmp"
            if(Dir.exist?(RAKE_DIRECTORY))
                @directory=RAKE_DIRECTORY
                if(Dir.exist?("#{RAKE_DIRECTORY}/.git") && Dir.exist?(@directory))
                    @git_directory=Raykit::Git::Directory.new(@directory)
                    @remote=@git_directory.remote
                end
            else
                @directory=''
            end

            #@log=Log.new("#{RAKE_DIRECTORY}/tmp/raykit.log")


            if(defined?(NAME))
                @name=NAME 
            else
                slns = Dir.glob("*.sln")
                if(slns.length == 1)
                    @name=slns[0].gsub('.sln','')
                else
                    remote_parts = @remote.split('/')
                    if(remote_parts.length > 0)
                        @name=remote_parts[-1].gsub('.git','')
                    end
                end
            end
            @repository=Raykit::Git::Repository.new(@remote)
        end

        def get_dev_dir(subdir)
            Raykit::Environment::get_dev_dir(subdir)
        end

        def log
            @log
        end

        #def target

        #    @target

        #end

        def target_md5
            if(!target.nil? && File.exist?(target))
                return Digest::MD5.file(target).to_s.strip
            end
            ''
        end

        def directory
            @directory
        end
        def branch
            @git_directory.branch
        end

        # latest local commit

        def latest_commit
            Dir.chdir(@directory) do
                text=`git log -n 1`
                scan=text.scan(/commit ([\w]+)\s/)
                return scan[0][0].to_s 
            end
        end

        def outstanding_commit?
            Dir.chdir(@directory) do
                return true if(!`git status`.include?('nothing to commit'))
            end
            false
        end 

        def outstanding_tag?
            #puts `git log -n 1`

            #!latest_tag_commit.eql?(latest_commit)

            #commit 2e4cb6d6c0721e16cd06afee85b7cdc27354921b (HEAD -> master, tag: 0.0.180, origin/master, origin/HEAD)

            outstanding_commit? || !`git log -n 1`.include?('tag:')
        end

        def has_diff?(filename)
            Dir.chdir(@directory) do
                text=`git diff #{filename}`.strip
                return true if(text.length > 0) 
            end    
        end

        def version
            if(@version.nil?)
                #Dir.chdir(@directory) do

                #    if(Dir.glob("*.gemspec").length > 0)

                #        @version=`bump current`.gsub('Current version:','').strip

                #    else

                #        @version=Raykit::VersionHelper.detect(@name,@verbose)

                #    end

                @version=Raykit::Version.detect(@name,@verbose)
                #end

            end
            @version
        end

        #def update_version

        #    @version=Raykit::Version.detect(@name,@verbose)

        #end


        def latest_tag
            `git describe  --abbrev=0`.strip
        end

        def latest_tag_commit
            `git show-ref -s #{latest_tag}`.strip
        end

        def latest_tag_md5
            text=`git tag #{latest_tag} -n3`
            scan = text.scan(/md5=(\w{32})/)
            if(scan.length > 0 && scan[0].length > 0)
                return scan[0][0].to_s.strip
            end 
            ''
        end

        def remote
            @remote
        end

        def last_modified_filename
            Dir.chdir(@directory) do
                Dir.glob("**/*.*").select{|f| File.file?(f)}.max_by {|f| File.mtime(f)}
            end
        end

        def size 
            Dir.chdir(@directory) do
                text =`git count-objects -v -H`
                if matches = text.match(/size: ([. \w]+)$/)
                    matches[1]
                else
                    text
                end
            end
        end

        def size_pack
            Dir.chdir(@directory) do
                text =`git count-objects -v -H`
                if matches = text.match(/size-pack: ([. \w]+)$/)
                    matches[1]
                else
                    text
                end
            end
        end

        def elapsed
            elapsed=@timer.elapsed
            if(elapsed < 1.0)
                "%.1f" % (@timer.elapsed) + "s"
            else
                "%.0f" % (@timer.elapsed) + "s"
            end
        end

        def info
            ljust=35
            puts ''
            puts "PROJECT.name".ljust(ljust) + Rainbow(PROJECT.name).yellow.bright
            puts "PROJECT.version".ljust(ljust) + Rainbow(PROJECT.version).yellow.bright
            puts "PROJECT.remote".ljust(ljust) + Rainbow(PROJECT.remote).yellow.bright
            puts "PROJECT.branch".ljust(ljust) + Rainbow(PROJECT.branch).yellow.bright
            #puts "PROJECT.target".ljust(ljust) + Rainbow(PROJECT.target).yellow.bright

            #puts "PROJECT.target_md5".ljust(ljust) + Rainbow(PROJECT.target_md5).yellow.bright

            puts "PROJECT.latest_tag".ljust(ljust) + Rainbow(PROJECT.latest_tag).yellow.bright
            puts "PROJECT.latest_tag_commit".ljust(ljust) + Rainbow(PROJECT.latest_tag_commit).yellow.bright
            puts "PROJECT.latest_tag_md5".ljust(ljust) + Rainbow(PROJECT.latest_tag_md5).yellow.bright
            puts "PROJECT.latest_commit".ljust(ljust) + Rainbow(PROJECT.latest_commit).yellow.bright
            puts "PROJECT.last_modified_filename".ljust(ljust) + Rainbow(PROJECT.last_modified_filename).yellow.bright
            #puts "PROJECT.elapsed".ljust(ljust) + Rainbow(PROJECT.elapsed).yellow.bright

            puts "PROJECT.size".ljust(ljust) + Rainbow(PROJECT.size).yellow.bright
            puts "PROJECT.size_pack".ljust(ljust) + Rainbow(PROJECT.size_pack).yellow.bright
            puts "PROJECT.outstanding_commit?".ljust(ljust) + Rainbow(PROJECT.outstanding_commit?).yellow.bright
            puts "PROJECT.outstanding_tag?".ljust(ljust) + Rainbow(PROJECT.outstanding_tag?).yellow.bright
            puts ''
            self
        end

        def summary
            info if(@verbose)
            
            puts "[" + elapsed + "] " + Rainbow(@name).yellow.bright + " " + Rainbow(version).yellow.bright
        end

        def commit_message_filename
            warn "[DEPRECATION] 'commit_message_filename' is deprectated."
            @commit_message_filename
        end

        def commit(commit_message)
            warn "[DEPRECATION] 'commit_message_filename' is deprectated. Use a run command for better transparency."
            Dir.chdir(@directory) do
                if(File.exist?('.gitignore'))
                    status=`git status`
                    if(status.include?('Changes not staged for commit:'))
                        run("git add --all")
                        if(GIT_DIRECTORY.outstanding_commit?)
                            if(File.exist?(@commit_message_filename))
                                run("git commit --file #{@commit_message_filename}")
                                File.delete(@commit_message_filename)
                            else
                                run("git commit -m'#{commit_message}'")
                            end
                        end  
                    end
                else
                    puts "warning: .gitignore not found."
                end
            end
            self
        end

        def push
            Dir.chdir(@directory) do
                status=`git status`
                if(status.include?('use "git push"'))
                    run('git push')
                    
                    #run('git push --tags')

                end
            end
            self
        end

        def pull
            Dir.chdir(@directory) do
                run('git pull')
            end
            self
        end

        def tag
            warn "[DEPRECATION] 'tag' is deprecated. Use run command(s) for better transparency."
            Dir.chdir(@directory) do
                specific_tag=`git tag -l #{@version}`.strip
                puts Rainbow("git tag - #{@version}").green if(@verbose)
                puts `git tag -l #{@version}` if(@verbose)
                if(specific_tag.length == 0)
                    puts "tag #{@version} not detected." if(@verbose)
                    tag = `git describe --abbrev=0 --tags`.strip
                    if(@version != tag)
                        puts "latest tag #{@tag}" if(@verbose)
                        run("git tag #{@version} -m'#{@version}'")
                        run("git push origin #{@version}")
                        #push

                    end
                else
                    puts "already has tag #{specific_tag}" if(@verbose)
                end
            end
            self
        end

        def run(command,quit_on_failure=true) 
            #log.update_command_time(command,DateTime.now)

            if(command.kind_of?(Array))
                command.each{|subcommand| run(subcommand,quit_on_failure)}
            else
                cmd = Command.new(command)
                cmd.summary
                elapsed_str = Timer.get_elapsed_str(cmd.elapsed,0)
                if(cmd.exitstatus == 0)
                    #puts elapsed_str + " " +  Rainbow(cmd.command).yellow.bright

                    #return elapsed_str + " " + cmd.command

                else
                    # display error details

                    puts cmd.output
                    puts cmd.error
                    puts
                    if(quit_on_failure)
                        abort Rainbow(elapsed_str).red.bright + " " +  Rainbow(cmd.command).white
                    end
                end
                cmd
            end
        end 
    end 
end