mate 2.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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