Reputation: 1233
I want to recursively build a json tree of directories and permissions beginning with one input directory. For example, having input "/initial_directory", I expect the following output:
{
"initial_directory": {
"permissions": "755",
"children": {
"file_a": {
"permissions": "755"
},
"directory_two": {
"permissions": "600",
"children": {
"file_b": {
"permissions": "777"
}
}
}
}
}
}
This is my code so far:
def build_json(directory)
json = {}
Dir.foreach(directory) do |file|
perm, file = (`stat -f '%A %N' #{file} `).split(' ')
json[file] = perm
json
end
end
I want to update this to recursively get all the child directories. My problem is that I need to know the json path upfront for this. Is there a better approach to achieve this?
Upvotes: 0
Views: 128
Reputation: 165396
Do build something recursively, you need to recurse. That involves calling a function inside itself and having a termination condition.
While you might turn it into JSON later, you're not building JSON. You're building a Hash of a directory tree. dir_tree
.
Finally, we'll use Pathname instead of File and Dir. Pathname does everything File and Dir do, but represents them with objects. This makes them much easier to work with. Critically, a Pathname object knows its absolute path. This will be important when we start recursing into subdirectories.
require 'pathname'
# Start with a directory and an empty tree.
def dir_tree(directory)
tree={}
# Pathname#children skips . and .., else we'd go in circles.
Pathname.new(directory).children.each do |path|
# Get the permissions with Ruby, not a program. Faster, simpler.
info = { permissions: path.stat.mode }
# If it's a directory, recurse. Instead of passing in the whole
# tree, we start fresh. Assign the result to be its children.
# Because we're using Pathnames, `path` knows its absolute path
# and everything still works.
if path.directory?
children = dir_tree(path)
info[:children] = children unless children.empty?
end
# Stick just the filename into the tree. Stringify it else we get
# a Pathname object.
tree[path.basename.to_s] = info
end
# And here is the termination of the recursion once a directory with
# no children is reached.
return tree
end
p dir_tree(ARGV[0])
Upvotes: 2