require 'pathname' module EY module Serverside class Paths module LegacyHelpers def self.legacy_path_helper(name, new_name) define_method(name) do |*a| paths.send(new_name, *a).to_s end end legacy_path_helper :deploy_to, :deploy_root legacy_path_helper :release_dir, :releases legacy_path_helper :failed_release_dir, :releases_failed legacy_path_helper :release_path, :active_release legacy_path_helper :previous_release, :previous_release legacy_path_helper :latest_release, :latest_release legacy_path_helper :current_path, :current legacy_path_helper :shared_path, :shared legacy_path_helper :maintenance_page_enabled_path, :enabled_maintenance_page legacy_path_helper :repository_cache, :repository_cache legacy_path_helper :bundled_gems_path, :bundled_gems legacy_path_helper :ruby_version_file, :ruby_version legacy_path_helper :system_version_file, :system_version legacy_path_helper :binstubs_path, :binstubs legacy_path_helper :gemfile_path, :gemfile legacy_path_helper :ssh_identity_file, :deploy_key def all_releases EY::Serverside.deprecation_warning("config.all_releases is deprecated. Please use 'config.paths.all_releases' which returns Pathname objects.") paths.all_releases.map {|path| path.to_s } end end # Maintenance page candidates in order of search preference. MAINTENANCE_CANDIDATES = [ "public/maintenance.html.custom", "public/maintenance.html.tmp", "public/maintenance.html", "public/system/maintenance.html.default", ] # This one is guaranteed to exist. DEFAULT_MAINTENANCE_PAGE = Pathname.new("default_maintenance_page.html").expand_path(File.dirname(__FILE__)) # Define methods that get us paths def self.def_path(name, parts) define_method(name.to_sym) { path(*parts) } end # Load a path given a root and more parts # Pathname#join is extremely inefficient. # This implementation uses much less memory and way fewer objects. def path(root, *parts) Pathname.new(File.join(send(root).to_s, *parts)) end attr_reader :home, :deploy_root def_path :internal_key, [:home, '.ssh', 'internal'] def_path :current, [:deploy_root, 'current'] def_path :releases, [:deploy_root, 'releases'] def_path :releases_failed, [:deploy_root, 'releases_failed'] def_path :shared, [:deploy_root, 'shared'] def_path :shared_log, [:shared, 'log'] def_path :shared_tmp, [:shared, 'tmp'] def_path :shared_config, [:shared, 'config'] def_path :shared_hooks, [:shared, 'hooks'] def_path :shared_node_modules, [:shared, 'node_modules'] def_path :shared_system, [:shared, 'system'] def_path :default_repository_cache, [:shared, 'cached-copy'] def_path :enabled_maintenance_page, [:shared_system, 'maintenance.html'] def_path :shared_assets, [:shared, 'assets'] def_path :bundled_gems, [:shared, 'bundled_gems'] def_path :shared_services_yml, [:shared_config, 'ey_services_config_deploy.yml'] def_path :ruby_version, [:bundled_gems, 'RUBY_VERSION'] def_path :system_version, [:bundled_gems, 'SYSTEM_VERSION'] def_path :latest_revision, [:latest_release, 'REVISION'] def_path :active_revision, [:active_release, 'REVISION'] def_path :binstubs, [:active_release, 'ey_bundler_binstubs'] def_path :gemfile, [:active_release, 'Gemfile'] def_path :gemfile_lock, [:active_release, 'Gemfile.lock'] def_path :public, [:active_release, 'public'] def_path :deploy_hooks, [:active_release, 'deploy'] def_path :public_assets, [:public, 'assets'] def_path :public_system, [:public, 'system'] def_path :package_json, [:active_release, 'package.json'] def_path :composer_json, [:active_release, 'composer.json'] def_path :composer_lock, [:active_release, 'composer.lock'] def_path :active_release_config, [:active_release, 'config'] def_path :active_log, [:active_release, 'log'] def_path :active_node_modules, [:active_release, 'node_modules'] def_path :active_tmp, [:active_release, 'tmp'] def initialize(opts) @opts = opts @home = Pathname.new(@opts[:home] || ENV['HOME']) @app_name = @opts[:app_name] @active_release = Pathname.new(@opts[:active_release]) if @opts[:active_release] @repository_cache = Pathname.new(@opts[:repository_cache]) if @opts[:repository_cache] @deploy_root = Pathname.new(@opts[:deploy_root] || "/data/#{@app_name}") end def release_dirname Time.now.utc.strftime("%Y%m%d%H%M%S") end # if active_release is already set, it's set because we're operating on # an existing release. This happens during integrate def new_release! @active_release ||= path(:releases, release_dirname) end # If no active release is defined, use current def active_release @active_release || latest_release end def deploy_key path(:home, '.ssh', "#{@app_name}-deploy-key") end def ssh_wrapper path(:shared_config, "#{@app_name}-ssh-wrapper") end def deploy_hook(hook_name) path(:deploy_hooks, "#{hook_name}.rb") end def service_hook(service_name, hook_name) path(:shared_hooks, service_name, "#{hook_name}.rb") end def executable_deploy_hook(hook_name) path(:deploy_hooks, "#{hook_name}") end def executable_service_hook(service_name, hook_name) path(:shared_hooks, service_name, "#{hook_name}") end def repository_cache @repository_cache ||= default_repository_cache end def all_releases @all_releases ||= Pathname.glob(path(:releases,'*')).sort end # deploy_root/releases/ def previous_release(from_release=latest_release) index = all_releases.index(from_release) if index && index > 0 all_releases[index-1] else nil end end def previous_revision rel = previous_release(active_release) rel && rel.join('REVISION') end # deploy_root/releases/ def latest_release all_releases.last end def deployed? !!latest_release end def maintenance_page_candidates if latest_release candidates = MAINTENANCE_CANDIDATES.map do |file| path(:latest_release, file) end else candidates = [] end candidates << DEFAULT_MAINTENANCE_PAGE candidates end def rollback if deployed? && previous_release self.class.new(@opts.dup.merge(:active_release => previous_release)) else nil end end end end end