open System.IO open System.Text.RegularExpressions let readlines (path:string) = let generator (reader:StreamReader) = match reader.ReadLine() with | null -> None | str -> Some (str, reader) let reader = new StreamReader(path) Seq.unfold generator reader let touch path = File.Create(path).Close() let up path = Path.GetFullPath(Path.Combine(path, "..")) let upx x path = [1..x] |> List.fold (fun p _ -> up p) path let mkdir current folder = let path = Path.Combine(current, folder) Directory.CreateDirectory(path) |> ignore path let parse line = let re = new Regex(@"^(?\|\s*)*((?\\|\+)---)?\s*(?.*)$") let m = re.Match(line) if m.Success then let count = m.Groups.["blanks"].Captures.Count let kind = m.Groups.["kind"].Value let path = m.Groups.["path"].Value Some (count, kind, path) else None let (|Out|File|Folder|) line = match parse line with | Some (count, "", "") -> Out count | Some (count, "\\", path) -> Folder (count + 1, path) | Some (count, "+", path) -> Folder (count, path) | Some (count, "", path) -> File path | _ -> failwith <| sprintf "error parsing line %s" line let traverse path lines = let folder (depth,path) line = match line with | Out count -> (count, upx (depth - count) path) | File file -> touch <| Path.Combine(path, file) (depth, path) | Folder (d, folder) -> (d + 1, mkdir path folder) lines |> Seq.fold folder (0, path) |> ignore let doit tree target = readlines tree |> Seq.skip 3 |> traverse target