Search code examples
rubyrake

How do I copy .htaccess files using Rake?


I am in the process of creating some build scripts, using Rake, that will be used as part of the overall process of deploying our web services to the cloud via Docker containers. In order to accomplish this we combine resources from several repos using Rake to "assemble" the directory/file layout. This all work well save for one item, .htaccess files.

Here is the copy function that I've created:

require 'fileutils'

EXT_ALLOWED = ["html", "css", "js", "svg", "otf", "eot", "ttf", "woff", "jpeg", "map", "ico", "map", "png", "db", "php", "conf"]

def copy_to(dest, src, trim="")

    files = FileList.new()
    EXT_ALLOWED.each {|ext| files.include "#{src}/**/*.#{ext}"}
    files.each do |file|
        dir = File.dirname(file)
        filename = File.basename(file)
        trimming = "/shared/" + trim + "(.*)"
        path = dir.match(trimming)
        if path == nil || dest == path[1] + '/'
            bin = dest
        else
            bin = File.join(dest, path[1] + '/')
        end
        puts "copying #{file} to #{bin}"
        FileUtils.mkdir_p(bin)
        FileUtils.cp file, bin
    end

end

The usage for this would be:

desc 'copies from shared/admin to the base server directory'
task :admin do
    # Copy admin over
    dest = 'www-server/'
    src = '../shared/admin'
    trim = "admin/"
    copy_to dest, src, trim
end

The trim variable is there to make sure files are copied to the appropriate directories. In this case files in admin are copied directly to www-server without an admin subdirectory.

I, naively, tried adding "htaccess" to the EXT_ALLOWED array, but that failed.

I have also followed some items online, but most have to do with Octopress which does not solve the problem.

The .htaccess file is in ../shared/admin and needs to end up in www-server/, can I make that happen within this function? Or do I need to write something specifically for file names beginning with dots?


Solution

  • In this case, looking for a quick and dirty (yes...I feel dirty doing it this way!) option, I wrote a function which specifically looks for the .htaccess file in a particular directory:

    def copy_htaccess(src, dest)
        files = Dir.glob("#{src}/.*")
        files.each do |file|
            filename = File.basename(file)
            if filename == ".htaccess"
                puts "copying #{file} to #{dest}"
                FileUtils.mkdir_p(dest)
                FileUtils.cp file, dest
            end
        end
    end
    

    With the usage being performed this way:

    desc 'copies the .htaccess file from one root to the web root'
    task :htaccess do
        src = '../shared/admin'
        dest = 'www-server/'
        copy_htaccess src, dest
    end
    

    Here I am able to use Dir.glob() to list all files starting with a ., then test for the .htaccess file and perform the copying.

    I will be looking into ways to modifying the single copy function to make this cleaner, if possible. Perhaps this can be done by globbing the directory and adding the files starting with . to the files array.

    EDIT: Rather than creating an additional function I found that I could just push the .htaccess file's information onto the end of the files array in the original copying function, after first checking if it exists in the source directory:

    if File.file?("#{src}/.htaccess")
        files.push("#{src}/.htaccess")
    end
    

    Making the whole function as shown below:

    def copy_to(dest, src, trim="")
    
        files = FileList.new()
        EXT_ALLOWED.each {|ext| files.include "#{src}/**/*.#{ext}"}
        if File.file?("#{src}/.htaccess")
            files.push("#{src}/.htaccess")
        end
        files.each do |file|
            dir = File.dirname(file)
            filename = File.basename(file)
            trimming = "/shared/" + trim + "(.*)"
            path = dir.match(trimming)
            if path == nil || dest == path[1] + '/'
                bin = dest
            else
                bin = File.join(dest, path[1] + '/')
            end
            puts "copying #{file} to #{bin}"
            FileUtils.mkdir_p(bin)
            FileUtils.cp file, bin
        end
    
    end
    

    Note that I am using .file? to test for an actual file where .exists? can return a directories truthiness. In the end you can use either method depending on your situation.