andrewchambers / hpkgs

A package repository for hermes
45 stars 3 forks source link

mkdir-p #92

Open sogaiu opened 4 years ago

sogaiu commented 4 years ago

I don't think there is a built-in way in Janet to do the equivalent of mkdir-p.

This seems like a useful function to have.

roobie commented 4 years ago

I can see a use for that. https://github.com/janet-lang/path will probably be helpful.

sogaiu commented 4 years ago

I thought that the path module might be helpful too.

On a related note, @ahungry posted a sketch of something to the Janet gitter channel yesterday. I've edited it a bit, but it's basically:

(defn mkdir-p
  [path]
  (->> (string/split "/" path)
       (reduce (fn [acc x]
                 (when (> (length acc) 0)
                   (os/mkdir acc))
                 (string acc "/" x))
               "")
       os/mkdir))

# (mkdir-p "/tmp/foo/bar/baz")
sogaiu commented 4 years ago

I think we might want to account for mkdir failing too.

sogaiu commented 4 years ago

Here is an imperative version that should return false if mkdir does not succeed at some point:

(defn mkdir-p
  [path]
  (def path-buf @"")
  (each path-part (string/split "/" path)
    (let [path-str (string path-buf path-part "/")]
      (when (and (not (os/lstat path-str))
                 (not (os/mkdir path-str)))
        (break false))
      (buffer/push-string path-buf path-part "/")))
  (buffer/slice path-buf 0 -2))
andrewchambers commented 4 years ago

mkdir I think throws an error on failure, it returns false if the dir already exists.

sogaiu commented 4 years ago

Ah, thanks for that, my mistake.

sogaiu commented 4 years ago

So this version will just error if mkdir fails I guess:

(defn mkdir-p
  [path]
  (def path-buf @"")
  (each path-part (string/split "/" path)
    (let [path-str (string path-buf path-part "/")]
      (when (not (os/lstat path-str))
        (os/mkdir path-str))
      (buffer/push-string path-buf path-part "/")))
  (buffer/slice path-buf 0 -2))
sogaiu commented 4 years ago

Here's another version:

(defn mkdir-p
  [path]
  (each idx (string/find-all "/" path)
    (when (< 0 idx)
      (let [curr-path (string/slice path 0 idx)]
        (when (not (os/lstat curr-path))
          (os/mkdir curr-path)))))
  (os/mkdir path))
sogaiu commented 4 years ago

It looks like there is a fileystem-related library now that has a relevant-looking function: https://github.com/jeannekamikaze/janet-filesystem/blob/1298a023ebe866b9410b3259198277defb9292e4/filesystem.janet#L60_L66

sogaiu commented 4 years ago

I noticed that jpm has a version too:

(defn create-dirs
  "Create all directories needed for a file (mkdir -p)."
  [dest]
  (def segs (peg/match path-splitter dest))
  (for i 1 (length segs)
    (def path (string/join (slice segs 0 i) sep))
    (unless (empty? path) (os/mkdir path))))

depends on:

(def- path-splitter
  "split paths on / and \\."
  (peg/compile ~(any (* '(any (if-not (set `\/`) 1)) (+ (set `\/`) -1)))))