rmtree 2.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README +89 -0
- data/bin/rmtree +176 -0
- metadata +60 -0
data/README
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
NAME
|
2
|
+
|
3
|
+
rmtree - save and restore permissions of objects in a directory
|
4
|
+
|
5
|
+
SYNOPSIS
|
6
|
+
|
7
|
+
rmtree save [-C working_dir] [--files] [--dirs]
|
8
|
+
rmtree apply [-C working_dir] [--files] [--dirs] [--dry-run]
|
9
|
+
rmtree diff [-C working_dir] [--files] [--dirs]
|
10
|
+
rmtree load
|
11
|
+
rmtree help
|
12
|
+
|
13
|
+
DESCRIPTION
|
14
|
+
|
15
|
+
`rmtree` is a simple version of known tool `mtree` on *BSD system. The
|
16
|
+
primary purpose of the tool is to save some basic attributes of objects
|
17
|
+
in a directory to a text file and/or restore objects' properties from
|
18
|
+
a standard input of attributes.
|
19
|
+
|
20
|
+
The tool only works on file system that supports following attributes:
|
21
|
+
|
22
|
+
- File mode (like 0644 on Linux)
|
23
|
+
- File owner
|
24
|
+
- File group
|
25
|
+
|
26
|
+
When the action `save` is used, the tool will scan the working directory
|
27
|
+
for all files and directories, and read their properties and print in
|
28
|
+
YAML format -- the readable format used by the action `apply` (or `load`.)
|
29
|
+
|
30
|
+
EXAMPLES
|
31
|
+
|
32
|
+
To back up objects' attributes to a file
|
33
|
+
|
34
|
+
rmtree save -C /path/to/working/dir | gzip -9c > backup.gz
|
35
|
+
|
36
|
+
To restore file permissions
|
37
|
+
|
38
|
+
zcat backup.gz | rmtree apply -C /path/to/working/dir
|
39
|
+
|
40
|
+
Save and load at the same time
|
41
|
+
|
42
|
+
rmtree save -C /this/dir/ | rmtree apply -C /that/dir/
|
43
|
+
|
44
|
+
To compare this directory with another one
|
45
|
+
|
46
|
+
rmtree save -C /this/dir | rmtree diff -C /that/dir
|
47
|
+
|
48
|
+
OPTIONS
|
49
|
+
|
50
|
+
Actions
|
51
|
+
|
52
|
+
help Print some help messages
|
53
|
+
save Scan for objects' attributes
|
54
|
+
apply Apply attributes to objects in working directory
|
55
|
+
load Load attribute data and print to STDOUT
|
56
|
+
diff Compare STDIN with the working directory
|
57
|
+
|
58
|
+
Options
|
59
|
+
|
60
|
+
-d --dry-run Execute `apply` in dry-run mode
|
61
|
+
|
62
|
+
-C --directory Set the working directory. The program will change
|
63
|
+
to this directory before scanning/applying attributes.
|
64
|
+
Default: current directory
|
65
|
+
|
66
|
+
-F --files Only work on files. When being used with 'diff',
|
67
|
+
all directories in working directory are ignored.
|
68
|
+
|
69
|
+
-D --dirs Only work on directories. When being used with 'diff',
|
70
|
+
all regular files in working directory are ignored.
|
71
|
+
|
72
|
+
--full-path Print absolute path when 'saving'. As the output has
|
73
|
+
the full paths, you may use the output for the action
|
74
|
+
'apply' without specifying the working directory.
|
75
|
+
(This also means that you can't apply the output to
|
76
|
+
another directory.) By default, the program prints
|
77
|
+
the relative paths.
|
78
|
+
|
79
|
+
-h --help Print help message
|
80
|
+
|
81
|
+
INSTALLATION
|
82
|
+
|
83
|
+
This ruby tool requires the rubygem 'slop' (for arguments parsing.)
|
84
|
+
To build a rubygem, try `gem build rmtree.gemspec`.
|
85
|
+
|
86
|
+
To use this tool, simply make it executable (by `chmod 755 rmtree.rb`.)
|
87
|
+
If the rubygem 'rmtree-x.y.z' was installed, the binary can be found
|
88
|
+
in the binary directory of your gem environment. (Please run the command
|
89
|
+
`gem env | grep EXECUTABLE` for details.)
|
data/bin/rmtree
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Purpose: Backup & Restore attributes of objects in a directory
|
4
|
+
# Author : Anh K. Huynh
|
5
|
+
# License: GPL2
|
6
|
+
# Date : 2012 May 15th
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'rubygems'
|
10
|
+
require 'slop'
|
11
|
+
require 'find'
|
12
|
+
require 'fileutils'
|
13
|
+
require 'yaml'
|
14
|
+
rescue LoadError => e
|
15
|
+
STDERR.puts ":: Error: Can't load some of libraries with error '#{e}'"
|
16
|
+
exit(1)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Raise and message and exit
|
20
|
+
def _raise(msg)
|
21
|
+
STDERR.puts(":: #{msg}")
|
22
|
+
exit(1)
|
23
|
+
end
|
24
|
+
|
25
|
+
def _chdir(cwd, options)
|
26
|
+
begin
|
27
|
+
if options[:verbose]
|
28
|
+
STDERR.puts(":: Set working directory to #{cwd}")
|
29
|
+
end
|
30
|
+
FileUtils.chdir(cwd)
|
31
|
+
rescue => e
|
32
|
+
_raise "Error: Can't set working directory #{cwd} with error '#{e}'"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Scan a directory and print objects attributes
|
37
|
+
# * `source`: The source direction
|
38
|
+
# * `options`: Options for scanning
|
39
|
+
# FIXME: source may not work with working directory
|
40
|
+
def _fetch(options)
|
41
|
+
ret = []
|
42
|
+
path_prefix = options[:fullpath] ? "#{File.expand_path("./")}/" : ""
|
43
|
+
begin
|
44
|
+
Find.find("./") do |file|
|
45
|
+
next if file.match(/^\.\.?\/$/)
|
46
|
+
next if options[:files] && File.directory?(file)
|
47
|
+
next if options[:dirs] && File.file?(file)
|
48
|
+
begin
|
49
|
+
stat = File.stat(file)
|
50
|
+
ret << sprintf("%s%s:\n mode: %s\n uid: %s\n gid: %s",
|
51
|
+
path_prefix, file.slice(2,file.size), stat.mode.to_s(8), stat.uid, stat.gid)
|
52
|
+
rescue => e
|
53
|
+
ret << sprintf("%s%s:\n error: #{e}", path_prefix, file.slice(2,file.size))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
rescue => e
|
57
|
+
_raise("Error in _fetch(#{source}): #{e}")
|
58
|
+
end
|
59
|
+
ret = ret.join("\n")
|
60
|
+
if options[:to_stdout]
|
61
|
+
puts ret
|
62
|
+
else
|
63
|
+
YAML.load(ret)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Load YAML data from STDIN and return the hash
|
68
|
+
# FIXME: we should check the format of the input
|
69
|
+
def _load(options)
|
70
|
+
begin
|
71
|
+
yaml = YAML.load(STDIN.read)
|
72
|
+
rescue Psych::SyntaxError => e
|
73
|
+
_raise "Error: Can't load Rmtree data with error '#{e}'"
|
74
|
+
end
|
75
|
+
puts YAML.dump(yaml) if options[:to_stdout]
|
76
|
+
yaml
|
77
|
+
end
|
78
|
+
|
79
|
+
def _apply(yaml, options = nil)
|
80
|
+
yaml.each do |file, data|
|
81
|
+
next if options[:files] && File.directory?(file)
|
82
|
+
next if options[:dirs] && File.file?(file)
|
83
|
+
if not data["error"]
|
84
|
+
mode, uid, gid = data["mode"].to_s, data["uid"], data["gid"]
|
85
|
+
mode = mode.slice(mode.size - 4, mode.size)
|
86
|
+
if options[:dryrun]
|
87
|
+
puts "chown #{uid}:#{gid} '#{file}'" if uid or gid
|
88
|
+
puts "chmod #{mode} '#{file}'" # FIXME
|
89
|
+
else
|
90
|
+
begin
|
91
|
+
FileUtils.chown uid, gid, file if uid or gid
|
92
|
+
FileUtils.chmod mode.to_i(8), file # FIXME
|
93
|
+
rescue => e
|
94
|
+
STDERR.puts "Error: Can't apply attribute to file #{file}, error => '#{e}'"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
else
|
98
|
+
# Print some warning message
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Compare STDIN with current working directory
|
104
|
+
def _diff(this, that, options)
|
105
|
+
that = _fetch(options) unless that
|
106
|
+
this_keys = this.keys
|
107
|
+
that_keys = that.keys
|
108
|
+
|
109
|
+
common_keys = this_keys & that_keys
|
110
|
+
this_only = this_keys - common_keys
|
111
|
+
that_only = that_keys - common_keys
|
112
|
+
|
113
|
+
this_only.each {|k| puts "Only in source: #{k}" }
|
114
|
+
that_only.each {|k| puts "Only in working directory: #{k}" }
|
115
|
+
common_keys.each do |k|
|
116
|
+
this_data = %w{mode uid gid}.map{|v| this[k][v]}
|
117
|
+
that_data = %w{mode uid gid}.map{|v| that[k][v]}
|
118
|
+
next if this_data == that_data
|
119
|
+
puts "#{k}:"
|
120
|
+
puts "< #{this_data.join(", ")}"
|
121
|
+
puts "> #{that_data.join(", ")}"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
########################################################################
|
126
|
+
# main routine
|
127
|
+
########################################################################
|
128
|
+
|
129
|
+
valid_actions = %w{help save load apply diff}
|
130
|
+
|
131
|
+
action = ARGV.shift
|
132
|
+
_raise "Usage: rmtree #{valid_actions.join("|")} <options>" unless valid_actions.include?(action)
|
133
|
+
|
134
|
+
options = {:files => false, :dirs => false}
|
135
|
+
|
136
|
+
begin
|
137
|
+
opts = Slop.parse do
|
138
|
+
banner "Backup, restore or compare attributes of objects in two directories.
|
139
|
+
Syntax: rmtree.rb #{valid_actions.join("|")} [options]\n"
|
140
|
+
|
141
|
+
on "C", "directory=",'Set working directory'
|
142
|
+
on "F", "files", 'Only work on files'
|
143
|
+
on "D", "dirs", 'Only work on directories'
|
144
|
+
on "d", "dry-run", 'Apply with dry-run mode'
|
145
|
+
on "full-path", 'Print absolute paths when "saving"'
|
146
|
+
on "v", "verbose", 'Verbose output'
|
147
|
+
on "h", "help", 'Print help message'
|
148
|
+
end
|
149
|
+
rescue Slop::MissingArgumentError => e
|
150
|
+
_raise "Error: #{e}"
|
151
|
+
end
|
152
|
+
|
153
|
+
if opts.present?(:help) or action == "help"
|
154
|
+
puts opts.help
|
155
|
+
exit(0)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Set up file options
|
159
|
+
_raise "Error: You can only use one of two options `--files`, `--dirs`" \
|
160
|
+
if opts.present?(:files) and opts.present?(:dirs)
|
161
|
+
|
162
|
+
options.merge!(:files => true) if opts.present?(:files)
|
163
|
+
options.merge!(:dirs => true) if opts.present?(:dirs)
|
164
|
+
options.merge!(:dryrun => true) if opts.present?(:"dry-run")
|
165
|
+
options.merge!(:verbose => true) if opts.present?(:verbose)
|
166
|
+
options.merge!(:fullpath => true) if opts.present?(:"full-path")
|
167
|
+
|
168
|
+
cwd = opts.present?(:directory) ? opts[:directory] : "./"
|
169
|
+
_chdir(cwd, options)
|
170
|
+
|
171
|
+
case action
|
172
|
+
when "save" then _fetch(options.merge(:to_stdout => true))
|
173
|
+
when "diff" then _diff(_load(options), nil, options)
|
174
|
+
when "load" then _load(options.merge(:to_stdout => true))
|
175
|
+
when "apply" then _apply(_load(options), options)
|
176
|
+
end
|
metadata
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rmtree
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.2.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Anh K. Huynh
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: slop
|
16
|
+
requirement: &9582440 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.0.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *9582440
|
25
|
+
description: Backup & Restore attributes of objects in a directory
|
26
|
+
email: kyanh@viettug.org
|
27
|
+
executables:
|
28
|
+
- rmtree
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- README
|
33
|
+
- bin/rmtree
|
34
|
+
homepage: https://github.com/icy/rmtree
|
35
|
+
licenses: []
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options: []
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
none: false
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.8.16
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: ! '`rmtree` is a simple version of known tool `mtree` on *BSD system. The
|
58
|
+
primary purpose of the tool is to save some basic attributes of objects in a directory
|
59
|
+
to a text file and/or restore objects'' properties from a standard input of attributes.'
|
60
|
+
test_files: []
|