rmtree 2.2.3
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.
- 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: []
|