patheditor 1.1.0-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt ADDED
@@ -0,0 +1,74 @@
1
+ = PathEditor
2
+
3
+ Anyone who's had to change their Windows PATH environment variable more than once in a week knows it's a frustrating and error prone process.
4
+
5
+ This command line utility intends to fix that. It allows you to view, add, or remove paths from the PATH variable. It will also clean the variable of directorries that no longer exist. It's even smart enough to expand system variables such as %SystemRoot% when cleaning the path.
6
+
7
+ When the path is modified, all system processes are notified immediately. Not all programs will respond to the notification, but the current shell and future shells opened from the Start | Run box will.
8
+
9
+ = Usage
10
+
11
+ For help, just type
12
+
13
+ path_editor --help
14
+
15
+ To list the current path settings, just run the program without any arguments:
16
+
17
+ path_editor
18
+
19
+ == Adding a Path
20
+
21
+ To add a directory to the path:
22
+
23
+ path_editor --add "full path" --no-test
24
+
25
+ Note, because of the way the Windows shell works, if you wish to add a path with a trailing slash, you must use a double slash at the end:
26
+
27
+ path_editor --add "c:\program files\\" --no-test
28
+
29
+ If the path already given already exists, it will not be added again.
30
+
31
+ == Removing a path
32
+
33
+ To remove a directory from the path:
34
+
35
+ path_editor --remove "full path"
36
+
37
+ Limited regular expressions can be used - essentially "*" or "?", like filename wild cards. If more than one path matches the expression given, you will be asked for confirmation before the path variable is updated.
38
+
39
+ == Cleaning the Path
40
+
41
+ To clean your path:
42
+
43
+ path_editor --clean
44
+
45
+ This process will remove directories which no longer exist, and will remove any duplicate directories from the path.
46
+
47
+ = Acknowledgements
48
+
49
+ Of course, my thanks to Matz for creating Ruby. What a joy it is to program in. I'm also indebted to the fine coders of the "commandline" and "highline" libraries. Finally, my thanks to the King of Kings, Jesus Christ, for the gift of this life. Amen.
50
+
51
+ = LICENSE:
52
+
53
+ (The MIT License)
54
+
55
+ Copyright (c) 2007 Justin Bailey
56
+
57
+ Permission is hereby granted, free of charge, to any person obtaining
58
+ a copy of this software and associated documentation files (the
59
+ 'Software'), to deal in the Software without restriction, including
60
+ without limitation the rights to use, copy, modify, merge, publish,
61
+ distribute, sublicense, and/or sell copies of the Software, and to
62
+ permit persons to whom the Software is furnished to do so, subject to
63
+ the following conditions:
64
+
65
+ The above copyright notice and this permission notice shall be
66
+ included in all copies or substantial portions of the Software.
67
+
68
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
69
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
70
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
71
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
72
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
73
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
74
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ require 'rubygems'
2
+ Gem::manage_gems
3
+ require 'rake/gempackagetask'
4
+
5
+ spec = Gem::Specification.new do |s|
6
+ s.name = "patheditor"
7
+ s.summary = "A simple program to manage the Windows PATH environment variable."
8
+ s.version = "1.1.0"
9
+ s.author = "Justin Bailey"
10
+ s.email = "jgbailey@nospam@gmail.com"
11
+ s.homepage = "http://rubyforge.org/projects/patheditor/"
12
+ s.rubyforge_project = "http://rubyforge.org/projects/patheditor/"
13
+
14
+ s.description = <<EOS
15
+ This gem provides an application, path_editor, which makes it easy to add, remove, display or clean up the
16
+ Windows System and User PATH variables. Note this does NOT any transient variables active in the current process -
17
+ it only affects those which are stored in the registry and set before each process begins. It's a nice
18
+ alternative to using "Computer / Properties / Advanced" for updating environment variables.
19
+ EOS
20
+
21
+ s.platform = Gem::Platform::CURRENT
22
+ s.files = FileList["lib/**/*", "test/**/*", "*.txt", "Rakefile"].to_a
23
+
24
+ s.bindir = "bin"
25
+ s.executables = ["path_editor"]
26
+ s.require_path = "lib"
27
+
28
+ s.has_rdoc = true
29
+ s.extra_rdoc_files = ["README.txt"]
30
+ s.rdoc_options << '--title' << 'PathEditor -- A PATH environment variable editor' <<
31
+ '--main' << 'README.txt' <<
32
+ '--line-numbers'
33
+
34
+ s.add_dependency("highline", ">= 1.2.3")
35
+ s.add_dependency("commandline", ">= 0.7.10")
36
+ end
37
+
38
+ Rake::GemPackageTask.new(spec) do |pkg|
39
+ pkg.need_tar = true
40
+ end
data/bin/path_editor ADDED
@@ -0,0 +1,133 @@
1
+ # A simple application for editing the environment's path information.
2
+ require 'rubygems'
3
+ require 'highline'
4
+ require 'commandline'
5
+ require 'pathname'
6
+
7
+ $: << (Pathname.new(__FILE__).dirname + '..\lib') unless $:.include?(Pathname.new(__FILE__).dirname + '..\lib')
8
+ require 'windows_path'
9
+
10
+ class App < CommandLine::Application
11
+ def initialize
12
+ synopsis "[[-c, --clean] [-a, --add PATH] [r, --remove EXPR]] [--case-sensitive] [-n, --no-confirmation] [-h, --help]"
13
+ short_description <<-EOS
14
+ With no arguments, displays the current path, broken into separate entries. Arguments allow directories to be added to or removed from the path. The path can also be cleaned of directories which no longer exist."
15
+ EOS
16
+
17
+ long_description <<-EOS
18
+ A script for manipulating the environment's PATH variable. Editing this variable is a huge pain in Windows - this script aims to make it easier.
19
+ EOS
20
+
21
+ option :names => %w(-c --clean), :arity => 0,
22
+ :opt_found => proc { |opt, user_option, opt_args|
23
+ @clean = true
24
+ },
25
+ :opt_description => <<-EOS
26
+ Cleans directories which no longer exist from the path, and removes any duplicate directories.
27
+ EOS
28
+
29
+ option :names => %w(-a --add), :arity => 1, :arg_description => "path",
30
+ :opt_found => proc { |opt, user_option, opt_args|
31
+ @add = Pathname.new opt_args.first
32
+ },
33
+ :opt_description => <<-EOS
34
+ Adds the given path to the PATH environment variable. If the path already exists (in the exact form given), it will not be added.
35
+ EOS
36
+
37
+ option :names => %w(-r --remove), :arity => 1, :arg_description => "expression",
38
+ :opt_found => proc { |opt, user_option, opt_args|
39
+ @remove = opt_args.first
40
+ },
41
+ :opt_description => <<-EOS
42
+ Removes the given path from the environment variable. Special characters such as "?" and "*" will be treated
43
+ as wildcards, just like at the command line. Be sure to enclose the expression in quotes, or the command prompt will
44
+ attempt to expand them for you. Note also that the command prompt seems to switch "\" characters to "/", so matches
45
+ with those characters will appear odd.
46
+ EOS
47
+
48
+ option :names => %w(--case-sensitive), :arity => 0,
49
+ :opt_found => proc { |opt, user_option, opt_args|
50
+ @case_sensitive = true
51
+ },
52
+ :opt_description => <<-EOS
53
+ Makes path comparisons case-sensitive if present. Path comparisons are case-insensitive otherwise.
54
+ EOS
55
+
56
+ option :names => %w(-n --no-confirmation), :arity => 0,
57
+ :opt_found => proc { @confirm_disabled = true},
58
+ :opt_description => <<-EOS
59
+ Forces changes to occur with confirmation. True by default unless paths are being removed with a regular expression and more than one path is matched - then it is false. This is intended to prevent the accidental remove of all paths or a similar disaster.
60
+ EOS
61
+
62
+ option :debug, :help
63
+ end
64
+
65
+ def main
66
+ @hl = HighLine.new
67
+ @currPath = WindowsPath.new
68
+
69
+ if @clean || @add || @remove
70
+ if @clean
71
+ @currPath.clean do |path, reason|
72
+ case reason
73
+ when :dup
74
+ @hl.say "Removing #{path} (duplicate)"
75
+ when :notfound
76
+ @hl.say "Removing #{path} (doesn't exist)"
77
+ end
78
+
79
+ path_removed
80
+ end
81
+ end
82
+
83
+ if @add
84
+ unless @currPath.paths.include?(@add)
85
+ @currPath.paths.add(@add)
86
+ @path_updated = true
87
+ @hl.say "Added #{@add} to path."
88
+ else
89
+ @hl.say "#{@add} not added because it already exists in the path."
90
+ end
91
+ end
92
+
93
+ if @remove
94
+ @currPath.remove(@remove) do |p|
95
+ @hl.say "Removing path #{p}"
96
+ path_removed
97
+ end
98
+ end
99
+
100
+ if @path_updated
101
+ if confirmation_needed?
102
+ @currPath.update if @hl.agree("Would you like to commit the changes made? [Yn] ", true)
103
+ else
104
+ @currPath.update
105
+ end
106
+ end
107
+ else
108
+ # Print path
109
+ @hl.say "Current path entries:"
110
+ @currPath.paths.each { |p| @hl.say "\t#{p}" }
111
+ end
112
+ rescue
113
+ puts "Exception: #{$!.message}"
114
+ puts $!.backtrace.join("\n")
115
+ end
116
+
117
+ def confirmation_needed?
118
+ # No need to confirm if either the user specified no confirmation explicitly, or
119
+ # the automatic confirmation never got set.
120
+ (@automatic_confirm && ! @confirm_disabled) || false
121
+ end
122
+
123
+ # Records that a path was removed
124
+ def path_removed
125
+ @path_updated = true
126
+ # first time through, @paths_removed is false. Automatic confimration
127
+ # should happen with more than one directory, therefore this will succeed.
128
+ @automatic_confirm = true if @paths_removed
129
+ @paths_removed = true
130
+ end
131
+ end
132
+
133
+ App.run unless $0 == __FILE__
@@ -0,0 +1,167 @@
1
+ require 'win32ole'
2
+ require 'pathname'
3
+
4
+ # Specialized array that knows how to compare paths.
5
+ class WindowsPathArray < Array
6
+
7
+ def include?(path)
8
+ # Compare paths case-insensitive, and also checking
9
+ # trailing separators (so c:\program files == c:\program files\)
10
+ self.any? { |p| compare_paths(path, p) }
11
+ end
12
+
13
+ def compare_paths(left, right)
14
+ left = Pathname.new(WindowsPath.expand_vars(left.to_s).downcase).cleanpath
15
+ right = Pathname.new(WindowsPath.expand_vars(right.to_s).downcase).cleanpath
16
+
17
+ return left.eql?(right)
18
+ end
19
+
20
+ def <<(p)
21
+ super(p.to_s)
22
+ end
23
+
24
+ alias_method :add, :<<
25
+
26
+ def delete(path)
27
+ self.delete_if { |p| compare_paths(path, p) }
28
+ end
29
+
30
+ def each
31
+ for i in 0..size - 1
32
+ yield WindowsPath.expand_vars(raw_item(i))
33
+ end
34
+ end
35
+
36
+ # Preserve access to base class definition of []
37
+ alias_method :raw_item, :[]
38
+
39
+ def [](idx)
40
+ WindowsPath.expand_vars(super)
41
+ end
42
+ end
43
+
44
+ # Manages access to and updating of windows path setting.
45
+ class WindowsPath
46
+ include Enumerable
47
+ FILE_SEPARATOR = File::ALT_SEPARATOR
48
+
49
+ # paths is a WindowsPathArray holding all paths in the system.
50
+ attr_accessor :paths
51
+
52
+ # Holds a reference to the Win32 Shell COM object.
53
+ def self.shell
54
+ @shell ||= WIN32OLE.new("WScript.Shell")
55
+ end
56
+
57
+ # Given a path, expands any environment variables found in it.
58
+ # Returns the expanded path.
59
+ def self.expand_vars(path)
60
+ while m = path.match(/%.*?%/)
61
+ path = path.gsub(m[0], shell.ExpandEnvironmentStrings(m[0]))
62
+ end
63
+
64
+ path
65
+ end
66
+
67
+ def initialize
68
+ @source = Hash.new
69
+ @paths = WindowsPathArray.new
70
+ @system = WindowsPath.shell.Environment("System")
71
+ @user = WindowsPath.shell.Environment("User")
72
+
73
+ [@system, @user].each do |which|
74
+ which.Item("Path").split(";").each do |p|
75
+ @paths.add(p.strip)
76
+ source[p] = which
77
+ end
78
+ end
79
+ end
80
+
81
+ # Update any changes
82
+ def update
83
+ # Map paths back to origina environment object
84
+ env = Hash.new
85
+
86
+ @paths.each do |p|
87
+ o = (source[p] || @user)
88
+ env[o] ||= []
89
+ env[o] << p
90
+ end
91
+
92
+ # Update each source object
93
+ env.each { |o, p| o["Item", "Path"] = p.join(";") }
94
+ end
95
+
96
+ # Cleans the current path of any non-existent or duplicate directories.
97
+ # If a block is given, yields each directory removed along with a
98
+ # the symbol :dup or :notfound.
99
+ def clean # :yields: path, reason
100
+ nonexistent = []
101
+ found = WindowsPathArray.new
102
+ duplicates = []
103
+ idx = 0
104
+ @paths.each do |p|
105
+ pathname = Pathname.new(p).cleanpath
106
+ if ! pathname.exist?
107
+ nonexistent << p
108
+ elsif found.include?(pathname)
109
+ duplicates << idx
110
+ else
111
+ found << pathname
112
+ end
113
+ idx += 1
114
+ end
115
+
116
+ unless duplicates.empty?
117
+ remove_paths(duplicates) { |p| yield p, :dup if block_given? }
118
+ end
119
+
120
+ unless nonexistent.empty?
121
+ remove_paths(nonexistent) { |p| yield p, :notfound if block_given? }
122
+ end
123
+ end
124
+
125
+ # Removes paths matching the path given. If path is regular
126
+ # expression, it is matched directly. Any other
127
+ # pattern is treated as a potential shell "glob"
128
+ # match, which means "*" and "?" are treated
129
+ # specially.
130
+ #
131
+ # In all cases, the path(s) removed are yielded.
132
+ def remove(pattern) # :yields: path
133
+ paths_to_remove = []
134
+ @paths.each do |p|
135
+ if pattern.is_a?(Regexp)
136
+ paths_to_remove << p if pattern.match(p)
137
+ else
138
+ paths_to_remove << p if File.fnmatch(pattern, p, File::FNM_CASEFOLD | File::FNM_NOESCAPE)
139
+ end
140
+ end
141
+
142
+ paths_to_remove.each do |p|
143
+ yield p if block_given?
144
+ @paths.delete(p)
145
+ end
146
+ end
147
+
148
+ private
149
+
150
+ attr_accessor :source
151
+
152
+ def remove_paths(paths_to_remove)
153
+ adjust = 0
154
+ paths_to_remove.each do |p|
155
+ if p.is_a?(Fixnum)
156
+ idx = p - adjust # adjust index based on paths removed so far.
157
+ yield @paths[idx] if block_given?
158
+ @paths.delete_at(idx)
159
+ else
160
+ yield p if block_given?
161
+ @paths.delete p
162
+ end
163
+
164
+ adjust += 1
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,128 @@
1
+ require 'test/unit'
2
+ $:.unshift File.dirname(__FILE__) + "/../lib" unless $:.include?(File.dirname(__FILE__) + "../lib")
3
+ require 'windows_path'
4
+
5
+ class WindowsPathTests < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @path = WindowsPath.new
9
+ end
10
+
11
+ def test_clean
12
+ # add some non-existent directories
13
+ fake = add_fake
14
+
15
+ assert_dir_found fake, "Fake directory not added to current path."
16
+ @path.clean
17
+ assert_dir_not_found fake, "Fake directory found in current path after cleaning!"
18
+ end
19
+
20
+ def test_clean_dups
21
+ fake = add_fake_dup
22
+
23
+ assert_dir_found fake, "Duplicate directory not found in path."
24
+ assert_dup_found fake, "Did not find the right number of duplicates directories in the path."
25
+
26
+ @path.clean
27
+ assert_dir_not_found fake, "Duplicate directory found in current path after cleaning!"
28
+ end
29
+
30
+ def test_clean_and_notfound
31
+ fake_dup = add_fake_dup
32
+ fake_not_found = add_fake
33
+
34
+ assert_dup_found fake_dup, "Did not find the right number of duplicates directories in the path."
35
+ assert_dir_found fake_not_found, "Nonexistent directory not found in path."
36
+
37
+ @path.clean
38
+ assert_dir_not_found fake_dup, "Duplicate directory found in current path after cleaning!"
39
+ assert_dir_not_found fake_not_found, "Nonexistent directory found in current path after cleaning!"
40
+ end
41
+
42
+ def test_remove_dir
43
+ fake_dir = add_fake
44
+ assert_dir_found fake_dir, "Fake directory not found in path."
45
+ @path.remove fake_dir
46
+ assert_dir_not_found fake_dir, "Fake directory found in path after removal."
47
+ end
48
+
49
+ def test_remove_glob
50
+ fake_dir = add_fake
51
+ assert_dir_found fake_dir, "Fake directory not found in path."
52
+ fake_glob = fake_dir.chop << "*"
53
+ @path.remove fake_glob
54
+ assert_dir_not_found fake_dir, "Fake directory not removed by glob: #{fake_glob}"
55
+ end
56
+
57
+ def test_remove_regexp
58
+ fake_dir = add_fake
59
+ assert_dir_found fake_dir, "Fake directory not found in path."
60
+ fake_regex = Regexp.new("^" << fake_dir.gsub('\\', '\\\\\\\\') << "$")
61
+ @path.remove fake_regex
62
+ assert_dir_not_found fake_dir, "Fake directory not removed by regex: #{fake_regex}"
63
+ end
64
+
65
+ def test_remove_case_sensitive_glob
66
+ # Ensure matches with different case works.
67
+ fake_dir = add_fake "C:\\program files"
68
+ fake_glob = "C:\\PROGRAM*"
69
+ @path.remove fake_glob
70
+ assert_dir_not_found fake_dir, "Fake directory not removed by glob: #{fake_glob}"
71
+ end
72
+
73
+ def test_remove_glob_two_stars
74
+ # Test that a glob with wildcards on both ends works
75
+ fake_dir = add_fake "C:\\program files"
76
+ fake_glob = "*PROGRAM*"
77
+ @path.remove fake_glob
78
+ assert_dir_not_found fake_dir, "Fake directory not removed by glob: #{fake_glob}"
79
+ end
80
+
81
+ def test_remove_glob_single_char
82
+ # Test that a glob with question mark works
83
+ fake_dir = add_fake
84
+ fake_glob = fake_dir.chop << "?"
85
+ @path.remove fake_glob
86
+ assert_dir_not_found fake_dir, "Fake directory not removed by glob: #{fake_glob}"
87
+ end
88
+
89
+ # Makes a directory guarnteed not to exist
90
+ def make_fake_dir(dir)
91
+ cnt = 1
92
+ fake_dir = dir
93
+ while @path.paths.include? fake_dir
94
+ fake_dir = dir << cnt
95
+ cnt += 1
96
+ end
97
+
98
+ fake_dir
99
+ end
100
+
101
+ # Add a fake path
102
+ def add_fake(base = "C:\\foobar")
103
+ @path.paths << fake = make_fake_dir(base)
104
+ fake
105
+ end
106
+
107
+ # Add a duplicated fake path
108
+ def add_fake_dup
109
+ fake = add_fake
110
+ @path.paths << fake
111
+
112
+ fake
113
+ end
114
+
115
+ def assert_dir_found(dir, msg)
116
+ assert @path.paths.include?(dir), msg
117
+ end
118
+
119
+ def assert_dir_not_found(dir, msg)
120
+ assert ! @path.paths.include?(dir), msg
121
+ end
122
+
123
+ def assert_dup_found(dir, msg)
124
+ cnt = 0
125
+ @path.paths.each { |p| cnt += 1 if p == dir }
126
+ assert cnt == 2, msg
127
+ end
128
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: patheditor
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: x86-mswin32-60
6
+ authors:
7
+ - Justin Bailey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-09-22 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: highline
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.3
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: commandline
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.7.10
34
+ version:
35
+ description: This gem provides an application, path_editor, which makes it easy to add, remove, display or clean up the Windows System and User PATH variables. Note this does NOT any transient variables active in the current process - it only affects those which are stored in the registry and set before each process begins. It's a nice alternative to using "Computer / Properties / Advanced" for updating environment variables.
36
+ email: jgbailey@nospam@gmail.com
37
+ executables:
38
+ - path_editor
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - README.txt
43
+ files:
44
+ - lib/windows_path.rb
45
+ - test/test_windows_path.rb
46
+ - README.txt
47
+ - Rakefile
48
+ has_rdoc: true
49
+ homepage: http://rubyforge.org/projects/patheditor/
50
+ post_install_message:
51
+ rdoc_options:
52
+ - --title
53
+ - PathEditor -- A PATH environment variable editor
54
+ - --main
55
+ - README.txt
56
+ - --line-numbers
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project: http://rubyforge.org/projects/patheditor/
74
+ rubygems_version: 1.2.0
75
+ signing_key:
76
+ specification_version: 2
77
+ summary: A simple program to manage the Windows PATH environment variable.
78
+ test_files: []
79
+