util.ha (1754B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use ascii; 5 use fs; 6 use os; 7 use strings; 8 use time; 9 10 // insert a string into a sorted list of strings, deduplicated. 11 fn insert_uniq(into: *[]str, s: str) void = { 12 let i = 0z; 13 // the `into` slice is generally small enough that a linear search is 14 // fine 15 for (i < len(into) && strings::compare(into[i], s) < 0) { 16 i += 1; 17 }; 18 if (i == len(into) || into[i] != s) { 19 insert(into[i], strings::dup(s)); 20 }; 21 }; 22 23 // Checks if the file at 'target' is out-of-date, given a list of dependency 24 // files, and the last time the deps list changed. If "target" doesn't exist, 25 // returns true. If any of the deps don't exist, they are skipped. 26 export fn outdated(target: str, deps: []str, mtime: time::instant) bool = { 27 let current = match (os::stat(target)) { 28 case fs::error => 29 return true; 30 case let stat: fs::filestat => 31 yield stat.mtime; 32 }; 33 if (time::compare(current, mtime) < 0) { 34 return true; 35 }; 36 for (let dep .. deps) { 37 match (os::stat(dep)) { 38 case fs::error => 39 continue; 40 case let stat: fs::filestat => 41 if (time::compare(current, stat.mtime) < 0) { 42 return true; 43 }; 44 }; 45 }; 46 return false; 47 }; 48 49 // Wrapper for [[fs::next]] that only returns valid submodule directories. 50 export fn next(it: *fs::iterator) (fs::dirent | done | fs::error) = { 51 for (let d => fs::next(it)?) { 52 if (!fs::isdir(d.ftype)) { 53 continue; 54 }; 55 if (is_submodule(d.name)) { 56 return d; 57 }; 58 }; 59 return done; 60 }; 61 62 fn is_submodule(path: str) bool = { 63 let it = strings::iter(path); 64 65 let first = true; 66 for (let r => strings::next(&it)) { 67 if (!ascii::isalpha(r) && r != '_' 68 && (first || !ascii::isdigit(r))) { 69 return false; 70 }; 71 72 first = false; 73 }; 74 return true; 75 };