Skip to content

Example: Directory Walking with ddn.os.path.Path

This example demonstrates how to use the ddn.os.path.Path module to iterate over directories and files, perform recursive walks, and apply custom pruning logic. The code is based on the demo.os.path_walk demo.


Overview

The Path struct provides convenient methods for directory iteration and recursive walking, similar to Python's os.walk. This example shows how to:

  • List directory contents (shallow and recursive)
  • Walk directories in top-down and bottom-up order
  • Prune directories during traversal
  • Handle symlinks (on POSIX systems)

Example Code

#! /usr/bin/env dub
/+ dub.sdl:
     name "os-path-walk"
     dependency "ddn" version=">=1.0.0"
+/

/**
 * Demo: directory iteration and walking with ddn.os.path.Path
 *
 * Run:
 *   ./demo.sh demo-os-path_walk
 * or:
 *   dub run --single demo/os/path_walk.d
 */
module demo.os.path_walk;

import std.stdio;
import std.file;
import std.path;
import std.algorithm;
import std.array;
import std.uuid : randomUUID;
import ddn.os.path;

void main() {
  writeln("=== ddn.os.path.walk demo ===");

  // Create a temporary directory tree
  auto base = buildPath("tmp_demo_walk_" ~ randomUUID().toString());
  scope (exit) { if (exists(base)) rmdirRecurse(base); }

  Path(buildPath(base, "sub", "nested")).mkdir(true);
  Path(buildPath(base, "skip")).mkdir(true);
  Path(buildPath(base, ".hidden")).mkdir(true);
  Path(buildPath(base, "a.txt")).writeText("A\n");
  Path(buildPath(base, "sub", "b.txt")).writeText("B\n");
  Path(buildPath(base, "sub", "nested", "c.txt")).writeText("C\n");
  version (Posix) {
    // best-effort: a symlink to sub
    Path(buildPath(base, "link")).symlinkTo("sub");
  }

  auto root = Path(base);

  writeln("-- iterdir() (shallow)");
  foreach (p; root.iterdir()) {
    writeln("  ", baseName(p.str()));
  }

  writeln("-- walk(topDown=true)");
  foreach (e; root.walk(true, false)) {
    writeln("  [", e.root.str(), "]");
    if (e.dirs.length) {
      writeln("    dirs: ", e.dirs.map!(d => baseName(d.str())).array);
    }
    if (e.files.length) {
      writeln("    files: ", e.files.map!(f => baseName(f.str())).array);
    }
  }

  writeln("-- walk(topDown=false)");
  foreach (e; root.walk(false, false)) {
    writeln("  ", e.root.str());
  }

  writeln("-- walk with pruning (skip directory named 'skip')");
  bool delegate(const Path) prune = (const Path p) {
    return baseName(p.str()) != "skip";
  };
  foreach (e; root.walk(true, false, prune)) {
    writeln("  ", e.root.str());
  }

  version (Posix) {
    writeln("-- walk(followSymlinks=true)");
    foreach (e; root.walk(true, true)) {
      // just enumerate; loop protection prevents cycles
      writeln("  ", e.root.str());
    }
  }

  writeln("=== End walk demo ===");
}

Key Points

  • Shallow Iteration: Use iterdir() to list immediate children of a directory.
  • Recursive Walk: Use walk(topDown, followSymlinks) to traverse directories recursively.
  • Pruning: Pass a delegate to walk to skip certain directories (e.g., by name).
  • Symlink Handling: On POSIX systems, you can follow symlinks safely with loop protection.

Output Example

The output will show the structure of the temporary directory tree, including directories, files, and the effect of pruning and symlink following.


See Also