diff --git a/CHANGELOG.md b/CHANGELOG.md index c7d184b2..4d98f761 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,6 @@ - Move gem dependencies from Gemfile to tmuxinator.gemspec - Add tmux 2.2 and 2.3 the TravisCI test matrix - Fix typos -- Support user-specified and XDG Base Dirs configuration directories ## 0.9.0 ### Misc diff --git a/lib/tmuxinator.rb b/lib/tmuxinator.rb index 21fb2c68..f3829d9b 100644 --- a/lib/tmuxinator.rb +++ b/lib/tmuxinator.rb @@ -1,10 +1,8 @@ +require "yaml" require "erubis" -require "fileutils" require "shellwords" require "thor" require "thor/version" -require "xdg" -require "yaml" require "tmuxinator/util" require "tmuxinator/deprecations" diff --git a/lib/tmuxinator/cli.rb b/lib/tmuxinator/cli.rb index 75f3aa37..56e3325a 100644 --- a/lib/tmuxinator/cli.rb +++ b/lib/tmuxinator/cli.rb @@ -231,9 +231,7 @@ def delete(*projects) def implode if yes?("Are you sure you want to delete all tmuxinator configs?", :red) - Tmuxinator::Config.directories.each do |directory| - FileUtils.remove_dir(directory) - end + FileUtils.remove_dir(Tmuxinator::Config.root) say "Deleted all tmuxinator projects." end end diff --git a/lib/tmuxinator/config.rb b/lib/tmuxinator/config.rb index ea436913..e71e7e82 100644 --- a/lib/tmuxinator/config.rb +++ b/lib/tmuxinator/config.rb @@ -4,30 +4,10 @@ class Config NO_LOCAL_FILE_MSG = "Project file at ./.tmuxinator.yml doesn't exist." class << self - # The directory (created if needed) in which to store new projects - def directory - if !environment.nil? && !environment.empty? - FileUtils::mkpath(environment) unless File.directory?(environment) - return environment - end - return xdg if File.directory?(xdg) - return home if File.directory?(home) - # No project directory specified or existant, default to XDG: - FileUtils::mkpath(xdg) - xdg - end - - def home - ENV["HOME"] + "/.tmuxinator" - end - - # Is ~/.config/tmuxinator unless $XDG_CONFIG_DIR is set - def xdg - XDG["CONFIG"].to_s + "/tmuxinator" - end - - def environment - ENV["TMUXINATOR_CONFIG"] + def root + root_dir = File.expand_path("#{ENV['HOME']}/.tmuxinator") + Dir.mkdir(root_dir) unless File.directory?(root_dir) + root_dir end def sample @@ -35,7 +15,7 @@ def sample end def default - "#{directory}/default.yml" + "#{ENV['HOME']}/.tmuxinator/default.yml" end def default? @@ -66,28 +46,25 @@ def exists?(name) File.exist?(project(name)) end - def local? - local_project + def project_in_root(name) + projects = Dir.glob("#{root}/**/*.yml") + projects.detect { |project| File.basename(project, ".yml") == name } end - # Pathname of given project searching only global directories - def global_project(name) - project_in(environment, name) || - project_in(xdg, name) || - project_in(home, name) + def local? + project_in_local end - def local_project + def project_in_local [LOCAL_DEFAULT].detect { |f| File.exist?(f) } end def default_project(name) - "#{directory}/#{name}.yml" + "#{root}/#{name}.yml" end - # Pathname of the given project def project(name) - global_project(name) || local_project || default_project(name) + project_in_root(name) || project_in_local || default_project(name) end def template @@ -98,23 +75,9 @@ def wemux_template asset_path "wemux_template.erb" end - # Sorted list of all .yml files, including duplicates def configs - directories.map do |directory| - Dir["#{directory}/**/*.yml"].map do |path| - path.gsub("#{directory}/", "").gsub(".yml", "") - end - end.flatten.sort - end - - # Existant directories which may contain project files - # Listed in search order - # Used by `implode` and `list` commands - def directories - if !environment.nil? && !environment.empty? - [environment] - else - [xdg, home].select { |d| File.directory? d } + Dir["#{Tmuxinator::Config.root}/**/*.yml"].sort.map do |path| + path.gsub("#{Tmuxinator::Config.root}/", "").gsub(".yml", "") end end @@ -126,7 +89,7 @@ def validate(options = {}) project_file = if name.nil? raise NO_LOCAL_FILE_MSG \ unless Tmuxinator::Config.local? - local_project + project_in_local else raise "Project #{name} doesn't exist." \ unless Tmuxinator::Config.exists?(name) @@ -135,24 +98,11 @@ def validate(options = {}) Tmuxinator::Project.load(project_file, options).validate! end - # Deprecated methods: ignore the 1st, use the 2nd - alias :root :directory - alias :project_in_root :global_project - alias :project_in_local :local_project - private def asset_path(asset) "#{File.dirname(__FILE__)}/assets/#{asset}" end - - # The first pathname of the project named 'name' found while - # recursively searching 'directory' - def project_in(directory, name) - return nil if String(directory).empty? - projects = Dir.glob("#{directory}/**/*.yml") - projects.detect { |project| File.basename(project, ".yml") == name } - end end end end diff --git a/spec/fixtures/TMUXINATOR_CONFIG/TMUXINATOR_CONFIG.yml b/spec/fixtures/TMUXINATOR_CONFIG/TMUXINATOR_CONFIG.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/fixtures/dot-tmuxinator/both.yml b/spec/fixtures/dot-tmuxinator/both.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/fixtures/dot-tmuxinator/dup/local-dup.yml b/spec/fixtures/dot-tmuxinator/dup/local-dup.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/fixtures/dot-tmuxinator/home.yml b/spec/fixtures/dot-tmuxinator/home.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/fixtures/dot-tmuxinator/local-dup.yml b/spec/fixtures/dot-tmuxinator/local-dup.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/fixtures/xdg-tmuxinator/both.yml b/spec/fixtures/xdg-tmuxinator/both.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/fixtures/xdg-tmuxinator/xdg.yml b/spec/fixtures/xdg-tmuxinator/xdg.yml deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/lib/tmuxinator/cli_spec.rb b/spec/lib/tmuxinator/cli_spec.rb index 441b5862..9fc5e9b9 100644 --- a/spec/lib/tmuxinator/cli_spec.rb +++ b/spec/lib/tmuxinator/cli_spec.rb @@ -1,5 +1,4 @@ require "spec_helper" - describe Tmuxinator::Cli do let(:cli) { Tmuxinator::Cli } @@ -232,16 +231,16 @@ end end - context "file exists" do - let(:project_path) { "#{Tmuxinator::Config.project(name)}" } + context "files exists" do + let(:root_path) { "#{ENV['HOME']}\/\.tmuxinator\/#{name}\.yml" } before do allow(File).to receive(:exist?).with(anything).and_return(false) - expect(File).to receive(:exist?).with(project_path).and_return(true) + expect(File).to receive(:exist?).with(root_path).and_return(true) end it "just opens the file" do - expect(Kernel).to receive(:system).with(%r{#{project_path}}) + expect(Kernel).to receive(:system).with(%r{#{root_path}}) capture_io { cli.start } end end @@ -265,7 +264,7 @@ end end - context "file exists" do + context "files exists" do let(:path) { Tmuxinator::Config::LOCAL_DEFAULT } before do expect(File).to receive(:exist?).with(path) { true } @@ -445,27 +444,10 @@ capture_io { cli.start } end - it "deletes the configuration directory(s)" do - allow(Tmuxinator::Config).to receive(:directories) \ - { [Tmuxinator::Config.xdg, Tmuxinator::Config.home] } - expect(FileUtils).to receive(:remove_dir).once. - with(Tmuxinator::Config.xdg) - expect(FileUtils).to receive(:remove_dir).once. - with(Tmuxinator::Config.home) - expect(FileUtils).to receive(:remove_dir).never + it "deletes all projects" do + expect(FileUtils).to receive(:remove_dir) capture_io { cli.start } end - - context "$TMUXINATOR_CONFIG specified" do - it "only deletes projects in that directory" do - allow(ENV).to receive(:[]).and_call_original - allow(ENV).to receive(:[]).with("TMUXINATOR_CONFIG").and_return "dir" - allow(File).to receive(:directory?).with("dir").and_return true - expect(FileUtils).to receive(:remove_dir).once.with("dir") - expect(FileUtils).to receive(:remove_dir).never - capture_io { cli.start } - end - end end describe "#list" do @@ -589,7 +571,7 @@ subject { described_class.new.create_project(params) } before do - allow(Tmuxinator::Config).to receive_messages(directory: path) + allow(Tmuxinator::Config).to receive_messages(root: path) end it_should_behave_like :a_proper_project diff --git a/spec/lib/tmuxinator/config_spec.rb b/spec/lib/tmuxinator/config_spec.rb index 8f8c6f8a..4be892d0 100644 --- a/spec/lib/tmuxinator/config_spec.rb +++ b/spec/lib/tmuxinator/config_spec.rb @@ -1,98 +1,9 @@ require "spec_helper" describe Tmuxinator::Config do - let(:fixtures_dir) { File.expand_path("../../../fixtures/", __FILE__) } - let(:xdg_config_dir) { "#{fixtures_dir}/xdg-tmuxinator" } - let(:home_config_dir) { "#{fixtures_dir}/dot-tmuxinator" } - - describe "#directory" do - context "environment variable $TMUXINATOR_CONFIG set" do - it "is $TMUXINATOR_CONFIG" do - allow(ENV).to receive(:[]).with("TMUXINATOR_CONFIG"). - and_return "expected" - allow(File).to receive(:directory?).and_return true - expect(Tmuxinator::Config.directory).to eq "expected" - end - end - - context "only ~/.tmuxinator exists" do - it "is ~/.tmuxinator" do - allow(File).to receive(:directory?).with(Tmuxinator::Config.xdg). - and_return false - allow(File).to receive(:directory?).with(Tmuxinator::Config.home). - and_return true - expect(Tmuxinator::Config.directory).to eq Tmuxinator::Config.home - end - end - - context "only $XDG_CONFIG_HOME/tmuxinator exists" do - it "is #xdg" do - allow(File).to receive(:directory?).with(Tmuxinator::Config.xdg). - and_return true - allow(File).to receive(:directory?).with(Tmuxinator::Config.home). - and_return false - expect(Tmuxinator::Config.directory).to eq Tmuxinator::Config.xdg - end - end - - context "both $XDG_CONFIG_HOME/tmuxinator and ~/.tmuxinator exist" do - it "is #xdg" do - allow(File).to receive(:directory?).with(Tmuxinator::Config.xdg). - and_return true - allow(File).to receive(:directory?).with(Tmuxinator::Config.home). - and_return true - expect(Tmuxinator::Config.directory).to eq Tmuxinator::Config.xdg - end - end - - context "parent directory(s) do not exist" do - it "creates parent directories if required" do - allow(File).to receive(:directory?).and_call_original - allow(File).to receive(:directory?).with(Tmuxinator::Config.home). - and_return false - Dir.mktmpdir do |dir| - config_parent = "#{dir}/non_existant_parent/s" - allow(XDG).to receive(:[]).with("CONFIG").and_return config_parent - expect(Tmuxinator::Config.directory). - to eq "#{config_parent}/tmuxinator" - expect(File.directory? "#{config_parent}/tmuxinator").to be true - end - end - end - end - - describe "#directories" do - it "is empty if no configuration directories exist" do - allow(File).to receive(:directory?).and_return false - expect(Tmuxinator::Config.directories).to eq [] - end - - it "is only [$TMUXINATOR_CONFIG] if set" do - allow(ENV).to receive(:[]).with("TMUXINATOR_CONFIG"). - and_return "expected" - allow(File).to receive(:directory?).and_return true - expect(Tmuxinator::Config.directories).to eq ["expected"] - end - - it "contains #xdg before #home" do - allow(File).to receive(:directory?).with(Tmuxinator::Config.xdg). - and_return true - allow(File).to receive(:directory?).with(Tmuxinator::Config.home). - and_return true - expect(Tmuxinator::Config.directories).to eq \ - [Tmuxinator::Config.xdg, Tmuxinator::Config.home] - end - end - - describe "#home" do + describe "#root" do it "is ~/.tmuxinator" do - expect(Tmuxinator::Config.home).to eq "#{ENV['HOME']}/.tmuxinator" - end - end - - describe "#xdg" do - it "is $XDG_CONFIG_HOME/tmuxinator" do - expect(Tmuxinator::Config.xdg).to eq "#{XDG['CONFIG_HOME']}/tmuxinator" + expect(Tmuxinator::Config.root).to eq "#{ENV['HOME']}/.tmuxinator" end end @@ -131,7 +42,7 @@ end describe "#default?" do - let(:directory) { Tmuxinator::Config.directory } + let(:root) { Tmuxinator::Config.root } let(:local_default) { Tmuxinator::Config::LOCAL_DEFAULT } let(:proj_default) { Tmuxinator::Config.default } @@ -160,19 +71,11 @@ describe "#configs" do before do - allow(Tmuxinator::Config).to receive_messages(xdg: xdg_config_dir) - allow(Tmuxinator::Config).to receive_messages(home: home_config_dir) - end - - it "gets a sorted list of all projects" do - expect(Tmuxinator::Config.configs). - to eq ["both", "both", "dup/local-dup", "home", "local-dup", "xdg"] + allow(Dir).to receive_messages(:[] => ["test.yml"]) end - it "lists only projects in $TMUXINATOR_CONFIG when set" do - allow(ENV).to receive(:[]).with("TMUXINATOR_CONFIG"). - and_return "#{fixtures_dir}/TMUXINATOR_CONFIG" - expect(Tmuxinator::Config.configs).to eq ["TMUXINATOR_CONFIG"] + it "gets a list of all projects" do + expect(Tmuxinator::Config.configs).to include("test") end end @@ -253,31 +156,24 @@ end end - describe "#global_project" do - let(:directory) { Tmuxinator::Config.directory } - let(:base) { "#{directory}/sample.yml" } - let(:first_dup) { "#{home_config_dir}/dup/local-dup.yml" } + describe "#project_in_root" do + let(:root) { Tmuxinator::Config.root } + let(:base) { "#{root}/sample.yml" } before do - allow(Tmuxinator::Config).to receive_messages(xdg: fixtures_dir) - allow(Tmuxinator::Config).to receive_messages(home: fixtures_dir) + path = File.expand_path("../../../fixtures/", __FILE__) + allow(Tmuxinator::Config).to receive_messages(root: path) end context "with project yml" do it "gets the project as path to the yml file" do - expect(Tmuxinator::Config.global_project("sample")).to eq base + expect(Tmuxinator::Config.project_in_root("sample")).to eq base end end context "without project yml" do it "gets the project as path to the yml file" do - expect(Tmuxinator::Config.global_project("new-project")).to be_nil - end - end - - context "with duplicate project files" do - it "is the first .yml file found" do - expect(Tmuxinator::Config.global_project("local-dup")).to eq first_dup + expect(Tmuxinator::Config.project_in_root("new-project")).to be_nil end end end @@ -290,39 +186,39 @@ end end - describe "#local_project" do + describe "#project_in_local" do let(:default) { Tmuxinator::Config::LOCAL_DEFAULT } context "with a project yml" do it "gets the project as path to the yml file" do expect(File).to receive(:exist?).with(default) { true } - expect(Tmuxinator::Config.local_project).to eq default + expect(Tmuxinator::Config.project_in_local).to eq default end end context "without project yml" do it "gets the project as path to the yml file" do - expect(Tmuxinator::Config.local_project).to be_nil + expect(Tmuxinator::Config.project_in_local).to be_nil end end end describe "#project" do - let(:directory) { Tmuxinator::Config.directory } + let(:root) { Tmuxinator::Config.root } + let(:path) { File.expand_path("../../../fixtures/", __FILE__) } let(:default) { Tmuxinator::Config::LOCAL_DEFAULT } - context "with an non-local project yml" do + context "with project yml in the root directory" do before do - allow(Tmuxinator::Config).to receive_messages(directory: fixtures_dir) + allow(Tmuxinator::Config).to receive_messages(root: path) end it "gets the project as path to the yml file" do - expect(Tmuxinator::Config.project("sample")). - to eq "#{directory}/sample.yml" + expect(Tmuxinator::Config.project("sample")).to eq "#{root}/sample.yml" end end - context "with a local project, but no global project" do + context "with a local project, but no project in root" do it "gets the project as path to the yml file" do expect(File).to receive(:exist?).with(default) { true } expect(Tmuxinator::Config.project("sample")).to eq "./.tmuxinator.yml" @@ -330,7 +226,7 @@ end context "without project yml" do - let(:expected) { "#{directory}/new-project.yml" } + let(:expected) { "#{root}/new-project.yml" } it "gets the project as path to the yml file" do expect(Tmuxinator::Config.project("new-project")).to eq expected end @@ -338,6 +234,7 @@ end describe "#validate" do + let(:path) { File.expand_path("../../../fixtures", __FILE__) } let(:default) { Tmuxinator::Config::LOCAL_DEFAULT } context "when a project name is provided" do @@ -348,7 +245,7 @@ end it "should load and validate the project" do - expect(Tmuxinator::Config).to receive_messages(directory: fixtures_dir) + expect(Tmuxinator::Config).to receive_messages(root: path) expect(Tmuxinator::Config.validate(name: "sample")).to \ be_a Tmuxinator::Project end @@ -363,7 +260,7 @@ end it "should load and validate the project" do - content = File.read(File.join(fixtures_dir, "sample.yml")) + content = File.read(File.join(path, "sample.yml")) expect(File).to receive(:exist?).with(default).at_least(:once) { true } expect(File).to receive(:read).with(default).and_return(content) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 13f5154b..b558cdaf 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,7 +1,6 @@ require "coveralls" -require "pry" require "simplecov" -require "xdg" +require "pry" formatters = [ SimpleCov::Formatter::HTMLFormatter, diff --git a/tmuxinator.gemspec b/tmuxinator.gemspec index a725bcc2..a055ac5e 100644 --- a/tmuxinator.gemspec +++ b/tmuxinator.gemspec @@ -38,19 +38,18 @@ Gem::Specification.new do |s| s.required_rubygems_version = ">= 1.8.23" s.required_ruby_version = ">= 2.0.0" - s.add_dependency "erubis", "~> 2.6" s.add_dependency "thor", "~> 0.19", ">= 0.15.0" - s.add_dependency "xdg", "~>2.2", ">= 2.2.3" + s.add_dependency "erubis", "~> 2.6" - s.add_development_dependency "activesupport", "< 5.0.0" # Please see issue #432 - s.add_development_dependency "awesome_print", "~> 1.2" s.add_development_dependency "bundler", "~> 1.3" - s.add_development_dependency "coveralls", "~> 0.7" - s.add_development_dependency "factory_girl", "~> 4.5" - s.add_development_dependency "pry", "~> 0.10" s.add_development_dependency "rake", "~> 10.4" s.add_development_dependency "rspec", "~> 3.3" - s.add_development_dependency "rubocop", "~> 0.35.1" s.add_development_dependency "simplecov", "~> 0.11.0" + s.add_development_dependency "coveralls", "~> 0.7" + s.add_development_dependency "awesome_print", "~> 1.2" + s.add_development_dependency "pry", "~> 0.10" + s.add_development_dependency "factory_girl", "~> 4.5" + s.add_development_dependency "activesupport", "< 5.0.0" # Please see issue #432 + s.add_development_dependency "rubocop", "~> 0.35.1" end