aboutsummaryrefslogtreecommitdiffstats
path: root/lib/tasks/themes.rake
blob: cbd12fd86c11511a63af9138c08dbc87bab404bb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
require Rails.root.join('commonlib', 'rblib', 'git')

namespace :themes do

    # Alias the module so we don't need the MySociety prefix here
    Git = MySociety::Git

    def all_themes_dir
        File.join(Rails.root,"lib","themes")
    end

    def theme_dir(theme_name)
        File.join(all_themes_dir, theme_name)
    end

    def old_all_themes_dir(theme_name)
        File.join(Rails.root, "vendor", "plugins", theme_name)
    end

    def possible_theme_dirs(theme_name)
        [theme_dir(theme_name), old_all_themes_dir(theme_name)]
    end

    def installed?(theme_name)
        possible_theme_dirs(theme_name).any? { |dir| File.directory? dir }
    end

    def usage_tag(version)
        "use-with-alaveteli-#{version}"
    end

    def uninstall(theme_name, verbose=false)
        possible_theme_dirs(theme_name).each do |dir|
            if File.directory?(dir)
                run_hook(theme_name, 'uninstall', verbose)
            end
        end
    end

    def run_hook(theme_name, hook_name, verbose=false)
        directory = theme_dir(theme_name)
        hook_file = File.join(directory, "#{hook_name}.rb")
        if File.exist? hook_file
            puts "Running #{hook_name} hook in #{directory}" if verbose
            load hook_file
        end
    end

    def move_old_theme(old_theme_directory)
        puts "There was an old-style theme at #{old_theme_directory}" if verbose
        moved_directory = "#{old_theme_directory}-moved"
        begin
            File.rename old_theme_directory, moved_directory
        rescue Errno::ENOTEMPTY, Errno::EEXIST
            raise "Tried to move #{old_theme_directory} out of the way, " \
                "but #{moved_directory} already existed"
        end
    end

    def committishes_to_try
        result = []
        theme_branch = AlaveteliConfiguration::theme_branch
        result.push "origin/#{theme_branch}" if theme_branch
        result.push usage_tag(ALAVETELI_VERSION)
        hotfix_match = /^(\d+\.\d+\.\d+)(\.\d+)+/.match(ALAVETELI_VERSION)
        result.push usage_tag(hotfix_match[1]) if hotfix_match
        minor_match = /^(\d+\.\d+)(\.\d+)+/.match(ALAVETELI_VERSION)
        result.push usage_tag(minor_match[1]) if minor_match
        result
    end

    def checkout_best_option(theme_name)
        theme_directory = theme_dir theme_name
        all_failed = true
        committishes_to_try.each do |committish|
            if Git.committish_exists? theme_directory, committish
                puts "Checking out #{committish}" if verbose
                Git.checkout theme_directory, committish
                all_failed = false
                break
            else
                puts "Failed to find #{committish}; skipping..." if verbose
            end
        end
        puts "Falling to using HEAD instead" if all_failed and verbose
    end

    def install_theme(theme_url, verbose, deprecated=false)
        FileUtils.mkdir_p all_themes_dir
        deprecation_string = deprecated ? " using deprecated THEME_URL" : ""
        theme_name = theme_url_to_theme_name theme_url
        puts "Installing theme #{theme_name}#{deprecation_string} from #{theme_url}"
        # Make sure any uninstall hooks have been run:
        uninstall(theme_name, verbose) if installed?(theme_name)
        theme_directory = theme_dir theme_name
        # Is there an old-style theme directory there?  If so, move it
        # out of the way so that there's no risk that work is lost:
        if File.directory? theme_directory
            unless Git.non_bare_repository? theme_directory
                move_old_theme theme_directory
            end
        end
        # If there isn't a directory there already, clone it into place:
        unless File.directory? theme_directory
            unless system "git", "clone", theme_url, theme_directory
                raise "Cloning from #{theme_url} to #{theme_directory} failed"
            end
        end
        # Set the URL for origin in case it has changed, and fetch from there:
        Git.remote_set_url theme_directory, 'origin', theme_url
        Git.fetch theme_directory, 'origin'
        # Check that checking-out a new commit will be safe:
        unless Git.status_clean theme_directory
            raise "There were uncommitted changes in #{theme_directory}"
        end
        unless Git.is_HEAD_pushed? theme_directory
            raise "The current work in #{theme_directory} is unpushed"
        end
        # Now try to checkout various commits in order of preference:
        checkout_best_option theme_name
        # Finally run the install hooks:
        run_hook(theme_name, 'install', verbose)
        run_hook(theme_name, 'post_install', verbose)
    end

    desc "Install themes specified in the config file's THEME_URLS"
    task :install => :environment do
        verbose = true
        AlaveteliConfiguration::theme_urls.each{ |theme_url| install_theme(theme_url, verbose) }
        if ! AlaveteliConfiguration::theme_url.blank?
            # Old version of the above, for backwards compatibility
            install_theme(AlaveteliConfiguration::theme_url, verbose, deprecated=true)
        end
    end

end