0

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?

1
  • You should include in your question "and when I run my code the output I get is this, and this doesn't work because of this" as well as any explanations of what you've tried changing to get your desired outcome and why those changes didn't work. Commented Nov 9, 2020 at 19:26

1 Answer 1

2

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])
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.