mate 2.0.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- ZThjZDYxNDA5NWZlMDI2Y2UxNmYzNDNjZGJmNjBkNTViZjEyZWI0Ng==
5
- data.tar.gz: !binary |-
6
- ZWUzYjViZWY0MTRhZDU5YTZjZGU3MGI3ZGViMjJkZWZjZjc4Nzk0Zg==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- NGI2YzFhY2Q0ODczYzEzNTQwOTYwYzBiYzM2NzA1MTJlNWUxYzBmOWFmMjdm
10
- MjZkZjc2OTFiY2JiN2UwMmVhOTUwYTAzOTRkNzFlMTc2MmJmNGEyNjdhN2M2
11
- MjYyZTgxMmQ4MDEyYTEzYmE2MzNlZTRiM2Y4ODFmNzUwODMwNGM=
12
- data.tar.gz: !binary |-
13
- ODE0YTQyZjdmOGVjMTNlYjY1NzNhODg2ODAzMTJhMjRhNjkwYzJkZWM0M2Fm
14
- NmY3NzE3NjcxMzg0ZGE1Nzk2YWEzZDM3ODFhNWU2ZTE5YjliZDg2ODgzMWM0
15
- OGIwMDUwYTI1MzBiN2Q3MjU4MmUyODRiNTJiM2NkNjk4OWFlMjY=
2
+ SHA256:
3
+ metadata.gz: a711bce5d45e59407c4f0d6e035f90adeba73720e7e48c9a294277f4cea9feb2
4
+ data.tar.gz: 355ae26696d775c4b4839bfe554d950a64e166e5f847bbf800bd2d5607f18ee4
5
+ SHA512:
6
+ metadata.gz: c395940fd1aa663fa41b313341a044b40eb6fe457a3dd77ff37e14abae6b79ce94c8c3f079e85fd83251ca6cc86546a2cad72085cd763c7dcb2b39ec6afe30de
7
+ data.tar.gz: '049d6a9ac5c97ad7c64b91326d238f52ca2c12487b611913662d8beb45f63226a706c5df518353cecf00c65109c70fb8aace5df0051b0d7e98a57d19f14860ef'
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2014 Ivan Kuchin
1
+ Copyright (c) 2010-2021 Ivan Kuchin
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.markdown CHANGED
@@ -1,11 +1,11 @@
1
1
  # mate
2
2
 
3
- TextMate project builder and TextMate 2 properties builder using git ignores for exclusions.
3
+ TextMate 2 properties builder using git ignores for exclusions.
4
4
 
5
- You can add `alias mate='tm'` or `alias mate='tm2'` to your `.profile`, `.bash_profile` …
5
+ You can add `alias mate='tm2'` to your `.profile`, `.bash_profile` …
6
6
 
7
- When `tm` command (or `mate` if aliased) is called with one or more paths and any of them is a directory, than project is created in `~/.tmprojs/` and opened. When `tm2` command (or `mate` if aliased) is called with one or more paths, for all directories a `.tm_properties` file is generated or changed and mate is called. Its file and folder filters are built based on all types of git ignores (global, `.gitignore` and `.git/info/exclude`) and special `.tmignore` which works like other ignore files for project but doesn't affect git itself (you can use global `~/.tmignore` file), also `.git` folder and certain files (images, archives, media files, logs and some other binary files) are filtered.
7
+ When `tm2` command (or `mate` if aliased) is called with one or more paths, for all directories a `.tm_properties` file is generated or changed and mate is called. Its file and folder filters are built based on all types of git ignores (global, `.gitignore` and `.git/info/exclude`) and special `.tmignore` which works like other ignore files for project but doesn't affect git itself (you can use global `~/.tmignore` file), also `.git` folder and certain files (images, archives, media files, logs and some other binary files) are filtered.
8
8
 
9
9
  ## Copyright
10
10
 
11
- Copyright (c) 2010-2014 Ivan Kuchin. See LICENSE.txt for details.
11
+ Copyright (c) 2010-2021 Ivan Kuchin. See LICENSE.txt for details.
data/bin/tm2 CHANGED
@@ -1,11 +1,22 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'optparse'
4
+
3
5
  require 'mate/bin'
4
6
  require 'mate/tm_properties'
5
7
 
8
+ options = {}
9
+ OptionParser.new do |op|
10
+ op.banner = "Usage: #{op.program_name} [options] dir [...]"
11
+
12
+ op.on('--no-info-exclude', 'Skip reading .git/info/exclude') do
13
+ options[:skip_info_exclude] = true
14
+ end
15
+ end.order!
16
+
6
17
  ARGV.each do |arg|
7
- if File.directory?(arg) && File.directory?(File.join(arg, '.git'))
8
- Mate::TmProperties.new(arg).save
18
+ if File.directory?(arg)
19
+ Mate::TmProperties.create(arg, options)
9
20
  end
10
21
  end
11
22
 
data/lib/mate/bin.rb CHANGED
@@ -3,10 +3,6 @@ require 'shellwords'
3
3
  module Mate
4
4
  module Bin
5
5
  class << self
6
- def v1
7
- mate_version(/^mate r\d+/) or abort 'Can\'t find mate binary v1'
8
- end
9
-
10
6
  def v2
11
7
  mate_version(/^mate 2.\d+/) or abort 'Can\'t find mate binary v2'
12
8
  end
data/lib/mate/git.rb ADDED
@@ -0,0 +1,32 @@
1
+ module Mate
2
+ module Git
3
+ class << self
4
+ def excludesfile(workind_dir)
5
+ expand_path IO.popen(%W[git -C #{workind_dir} config --get core.excludesfile], &:read)
6
+ end
7
+
8
+ def global_tmignore
9
+ expand_path '~/.tmignore'
10
+ end
11
+
12
+ def toplevel(workind_dir)
13
+ expand_path IO.popen(%W[git -C #{workind_dir} rev-parse --show-toplevel], err: '/dev/null', &:read)
14
+ end
15
+
16
+ def git_dir(workind_dir)
17
+ expand_path IO.popen(%W[git -C #{workind_dir} rev-parse --absolute-git-dir], err: '/dev/null', &:read)
18
+ end
19
+
20
+ private
21
+
22
+ def expand_path(path)
23
+ return unless path
24
+
25
+ path = path.strip
26
+ return if path == ''
27
+
28
+ Pathname(path).expand_path
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,26 +1,40 @@
1
1
  require 'pathname'
2
+ require 'mate/git'
2
3
 
3
4
  module Mate
4
5
  class TmProperties
5
- attr_reader :dir, :file
6
- def initialize(dir)
6
+ def self.create(dir, options)
7
+ new(Git.toplevel(dir) || dir, options).save
8
+ end
9
+
10
+ def initialize(dir, options)
7
11
  @dir = Pathname(dir).expand_path
8
12
  @file = @dir + '.tm_properties'
13
+ @lines = @file.exist? ? @file.read.split("\n") : []
14
+ @other_lines = @lines.reject{ |line| line =~ Ignores::GENERATED_R }
15
+ @options = options
9
16
  end
10
17
 
11
18
  def save
12
- ignores = Ignores.new(dir)
19
+ ignores = Ignores.new(@dir, @options)
20
+
21
+ write(ignores.lines + @other_lines)
22
+ end
13
23
 
14
- lines = if file.exist?
15
- file.readlines.reject do |line|
16
- line =~ Ignores::GENERATED_R
17
- end
24
+ def cleanup
25
+ if @other_lines.empty?
26
+ @file.unlink if @file.exist?
18
27
  else
19
- []
28
+ write(@other_lines)
20
29
  end
30
+ end
31
+
32
+ private
33
+
34
+ def write(lines)
35
+ return if lines == @lines
21
36
 
22
37
  @file.open('w') do |f|
23
- f.puts ignores.lines
24
38
  f.puts lines
25
39
  end
26
40
  end
@@ -1,23 +1,39 @@
1
+ require 'mate/git'
2
+
1
3
  module Mate
2
4
  class TmProperties::Ignores
3
- GENERATED_SUFFIX = "## GENERATED ##"
5
+ GENERATED_SUFFIX = '## GENERATED ##'
4
6
  GENERATED_R = /^exclude(?:Directories)? = .* #{Regexp.escape(GENERATED_SUFFIX)}$/
5
7
 
6
8
  attr_reader :dir
7
- def initialize(dir)
9
+ def initialize(dir, options)
8
10
  @dir = dir
9
11
  @exclude = ['**/.git']
10
12
  @exclude_directories = []
11
13
 
12
- process(dir, '.', Pathname(`git config --get core.excludesfile`.strip).expand_path)
13
- process(dir, '.', Pathname('~/.tmignore').expand_path)
14
+ process('.', Git.excludesfile(dir))
15
+ process('.', Git.global_tmignore)
16
+ if !options[:skip_info_exclude] && (git_dir = Git.git_dir(dir))
17
+ process('.', git_dir + 'info/exclude')
18
+ end
14
19
 
15
20
  dir.find do |path|
16
- if path.directory?
17
- %w[.gitignore .tmignore .git/info/exclude].each do |ignore_file_name|
18
- if (ignore_file = path + ignore_file_name).file?
19
- process(dir, path.relative_path_from(dir).to_s, ignore_file)
20
- end
21
+ next unless path.lstat.directory?
22
+
23
+ toplevel = dir == path
24
+
25
+ if !toplevel && (path + '.git').exist?
26
+ TmProperties.new(path, options).save
27
+ Find.prune
28
+ else
29
+ relative_path = path.relative_path_from(dir).to_s
30
+ Find.prune if ignore_dir?(relative_path)
31
+ %w[.gitignore .tmignore].each do |ignore_file_name|
32
+ process(relative_path, path + ignore_file_name)
33
+ end
34
+
35
+ if !toplevel && (path + '.tm_properties').exist?
36
+ TmProperties.new(path, options).cleanup
21
37
  end
22
38
  end
23
39
  end
@@ -33,8 +49,16 @@ module Mate
33
49
 
34
50
  private
35
51
 
36
- def process(parent, subdirectory, ignore_file)
37
- return unless ignore_file.exist?
52
+ def ignore_dir?(path)
53
+ [@exclude, @exclude_directories].any? do |patterns|
54
+ patterns.any? do |pattern|
55
+ File.fnmatch(pattern, path, File::FNM_PATHNAME)
56
+ end
57
+ end
58
+ end
59
+
60
+ def process(subdirectory, ignore_file)
61
+ return unless ignore_file && ignore_file.exist?
38
62
 
39
63
  prefix = subdirectory == '.' ? '' : glob_escape("#{subdirectory}/")
40
64
 
data/mate.gemspec CHANGED
@@ -2,18 +2,20 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'mate'
5
- s.version = '2.0.1'
6
- s.summary = %q{TextMate project builder and TextMate 2 properties builder using git ignores for exclusions}
7
- s.homepage = "http://github.com/toy/#{s.name}"
5
+ s.version = '3.0.0'
6
+ s.summary = %q{TextMate 2 properties builder using git ignores for exclusions}
7
+ s.homepage = "https://github.com/toy/#{s.name}"
8
8
  s.authors = ['Ivan Kuchin']
9
9
  s.license = 'MIT'
10
10
 
11
- s.rubyforge_project = s.name
11
+ s.metadata = {
12
+ 'bug_tracker_uri' => "https://github.com/toy/#{s.name}/issues",
13
+ 'documentation_uri' => "https://www.rubydoc.info/gems/#{s.name}/#{s.version}",
14
+ 'source_code_uri' => "https://github.com/toy/#{s.name}",
15
+ }
12
16
 
13
17
  s.files = `git ls-files`.split("\n")
14
18
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
20
  s.require_paths = %w[lib]
17
-
18
- s.add_runtime_dependency 'plist'
19
21
  end
metadata CHANGED
@@ -1,71 +1,55 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mate
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ivan Kuchin
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-01 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: plist
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ! '>='
18
- - !ruby/object:Gem::Version
19
- version: '0'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ! '>='
25
- - !ruby/object:Gem::Version
26
- version: '0'
27
- description:
28
- email:
11
+ date: 2021-05-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
29
15
  executables:
30
- - tm
31
16
  - tm2
32
17
  extensions: []
33
18
  extra_rdoc_files: []
34
19
  files:
35
- - .gitignore
20
+ - ".gitignore"
36
21
  - LICENSE.txt
37
22
  - README.markdown
38
- - bin/tm
39
23
  - bin/tm2
40
24
  - lib/mate/bin.rb
25
+ - lib/mate/git.rb
41
26
  - lib/mate/tm_properties.rb
42
27
  - lib/mate/tm_properties/ignores.rb
43
- - lib/mate/tmproj.rb
44
- - lib/mate/tmproj/ignores.rb
45
28
  - mate.gemspec
46
- homepage: http://github.com/toy/mate
29
+ homepage: https://github.com/toy/mate
47
30
  licenses:
48
31
  - MIT
49
- metadata: {}
50
- post_install_message:
32
+ metadata:
33
+ bug_tracker_uri: https://github.com/toy/mate/issues
34
+ documentation_uri: https://www.rubydoc.info/gems/mate/3.0.0
35
+ source_code_uri: https://github.com/toy/mate
36
+ post_install_message:
51
37
  rdoc_options: []
52
38
  require_paths:
53
39
  - lib
54
40
  required_ruby_version: !ruby/object:Gem::Requirement
55
41
  requirements:
56
- - - ! '>='
42
+ - - ">="
57
43
  - !ruby/object:Gem::Version
58
44
  version: '0'
59
45
  required_rubygems_version: !ruby/object:Gem::Requirement
60
46
  requirements:
61
- - - ! '>='
47
+ - - ">="
62
48
  - !ruby/object:Gem::Version
63
49
  version: '0'
64
50
  requirements: []
65
- rubyforge_project: mate
66
- rubygems_version: 2.0.3
67
- signing_key:
51
+ rubygems_version: 3.2.16
52
+ signing_key:
68
53
  specification_version: 4
69
- summary: TextMate project builder and TextMate 2 properties builder using git ignores
70
- for exclusions
54
+ summary: TextMate 2 properties builder using git ignores for exclusions
71
55
  test_files: []
data/bin/tm DELETED
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'mate/bin'
4
- require 'mate/tmproj'
5
-
6
- if !ARGV.empty? && ARGV.all?(&File.method(:exist?)) && ARGV.any?(&File.method(:directory?))
7
- Mate::Tmproj.new(ARGV).open
8
- else
9
- system Mate::Bin.v1, *ARGV
10
- end
data/lib/mate/tmproj.rb DELETED
@@ -1,66 +0,0 @@
1
- require 'pathname'
2
- require 'digest/sha2'
3
- require 'plist'
4
-
5
- module Mate
6
- class Tmproj
7
- TMPROJ_DIR = Pathname('~').expand_path + '.tmprojs'
8
-
9
- attr_reader :dirs, :file
10
- def initialize(dirs)
11
- @dirs = dirs.map{ |dir| Pathname(dir).expand_path }
12
- @file = TMPROJ_DIR + [
13
- Digest::SHA256.hexdigest(@dirs.join('-').downcase),
14
- "#{common_dir(@dirs).basename}.tmproj"
15
- ].join('/')
16
- end
17
-
18
- def open
19
- data = Plist::parse_xml(file) rescue {}
20
-
21
- data['documents'] = dirs.map do |dir|
22
- ignores = Ignores.new(dir)
23
- {
24
- :expanded => true,
25
- :name => dir.basename.to_s,
26
- :regexFileFilter => "!#{ignores.file_r}",
27
- :regexFolderFilter => "!#{ignores.folder_r}",
28
- :sourceDirectory => dir.to_s
29
- }
30
- end
31
- data['fileHierarchyDrawerWidth'] ||= 269
32
- data['metaData'] ||= {}
33
- data['showFileHierarchyDrawer'] = true unless data.has_key?('showFileHierarchyDrawer')
34
- dimensions = IO.popen(%q{osascript -e 'tell application "Finder" to get bounds of window of desktop'}, &:read).scan(/\d+/).map(&:to_i)
35
- data['windowFrame'] ||= "{{#{dimensions[0] + 100}, #{dimensions[1] + 50}}, {#{dimensions[2] - 200}, #{dimensions[3] - 100}}}"
36
-
37
- file.dirname.mkpath
38
- file.open('w'){ |f| f.write(data.to_plist) }
39
-
40
- system 'open', file.to_s
41
- end
42
-
43
- private
44
-
45
- def common_dir(paths)
46
- common = nil
47
- paths.each do |path|
48
- if path.file?
49
- path = path.dirname
50
- end
51
- ascendants = []
52
- path.ascend do |ascendant|
53
- ascendants << ascendant
54
- end
55
- unless common
56
- common = ascendants
57
- else
58
- common &= ascendants
59
- end
60
- end
61
- common && common.first
62
- end
63
- end
64
- end
65
-
66
- require 'mate/tmproj/ignores'
@@ -1,100 +0,0 @@
1
- module Mate
2
- class Tmproj::Ignores
3
- BINARY_EXTENSIONS = [
4
- %w[jpe?g png gif psd], # images
5
- %w[zip tar t?(?:g|b)z], # archives
6
- %w[mp3 mov], # media
7
- %w[log tmp swf fla pdf], # other
8
- ]
9
- DOUBLE_ASTERISK_R = '(?:.+/)?'
10
-
11
- attr_reader :dir, :file_pattern, :folder_pattern
12
- def initialize(dir)
13
- @dir = dir
14
- @file_pattern = ["#{DOUBLE_ASTERISK_R}.+\\.(?:#{BINARY_EXTENSIONS.flatten.join('|')})"]
15
- @folder_pattern = ["#{DOUBLE_ASTERISK_R}.git"]
16
-
17
- process(dir, Pathname(`git config --get core.excludesfile`.strip).expand_path)
18
- process(dir, Pathname('~/.tmignore').expand_path)
19
-
20
- dir.find do |path|
21
- Find.prune if ignore?(path)
22
- if path.directory?
23
- %w[.gitignore .tmignore .git/info/exclude].each do |ignore_file_name|
24
- if (ignore_file = path + ignore_file_name).file?
25
- process(path, ignore_file)
26
- end
27
- end
28
- end
29
- end
30
- end
31
-
32
- def ignore?(path)
33
- case
34
- when path.file?
35
- path.to_s =~ /#{file_r}/
36
- when path.directory?
37
- path.to_s =~ /#{folder_r}/
38
- end
39
- end
40
-
41
- def file_r
42
- "^#{Regexp.escape(dir.to_s)}/(?:#{file_pattern.join('|')})$"
43
- end
44
- def folder_r
45
- "^#{Regexp.escape(dir.to_s)}/(?:#{folder_pattern.join('|')})$"
46
- end
47
-
48
- private
49
-
50
- def process(parent, ignore_file)
51
- return unless ignore_file.exist?
52
- current_file_pattern = []
53
- current_folder_pattern = []
54
- ignore_file.readlines.map do |line|
55
- line.lstrip[/(.*?)(\r?\n)?$/, 1] # this strange stuff strips line, but allows mac Icon\r files to be ignored
56
- end.reject do |line|
57
- line.empty? || %w[# !].include?(line[0, 1])
58
- end.each do |line|
59
- pattern = glob2regexp(line)
60
- unless pattern.sub!(/^\//, '')
61
- pattern = "#{DOUBLE_ASTERISK_R}#{pattern}"
62
- end
63
- unless pattern.sub!(/\/$/, '')
64
- current_file_pattern << pattern
65
- end
66
- current_folder_pattern << pattern
67
- end
68
- current_file_pattern = current_file_pattern.join('|')
69
- current_folder_pattern = current_folder_pattern.join('|')
70
- unless parent == dir
71
- parent_pattern = Regexp.escape(parent.relative_path_from(dir).to_s)
72
- current_file_pattern = "#{parent_pattern}/(?:#{current_file_pattern})"
73
- current_folder_pattern = "#{parent_pattern}/(?:#{current_folder_pattern})"
74
- end
75
- file_pattern << current_file_pattern
76
- folder_pattern << current_folder_pattern
77
- end
78
-
79
- def glob2regexp(glob)
80
- glob.gsub(/\[([^\]]*)\]|\{([^\}]*)\}|(\*+)|(\?+)|./) do |m|
81
- case
82
- when $1
83
- "[#{Regexp.escape($1)}]"
84
- when $2
85
- "(?:#{Regexp.escape($2).split(',').join('|')})"
86
- when $3 == '*'
87
- '[^/]*'
88
- when $3
89
- '.*'
90
- when $4 == '?'
91
- '[^/]'
92
- when $4
93
- "[^/]{#{$4.length}}"
94
- else
95
- Regexp.escape(m)
96
- end
97
- end
98
- end
99
- end
100
- end