-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Missing File::Info data. #8357
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
What are your use cases? |
Detecting hard links needs Also getting or setting flags like |
We specifically didn't expose Exposing the number of links would be fine - with a usecase. Exposing more times is interesting: many filesystems don't support the birth time, and there's discrepancies between windows and linux on ctime and atime, iirc. Go supports only modification time for this same reason. Stat flags are already exposed. The blocks and block size are useless on modern-day filesystems. |
There is also |
I recently had a use case for
Note that Go has a non-portable direct access to the |
A platform specific API should exist for this kind of non-portable, low-level operations, like Rust std::os::unix, and Go unix package. |
No they aren't. Crystal split I need what BSD systems refer to as flags or Linux as attributes (not to be confused with extended attributes). On BSD it's part of the stat structure in |
My laptop has 3 million files. How do I find the hard links? I can't keep 3 million files open. Comparing every file against every file is unacceptably slow so that won't work either. I also can't compare incrementally or between program runs by saving state. So no this doesn't work for my use cases at all. I've mentioned what I for porting one ruby program. What is the solution? Either I make my own shard which monkey patches or duplicates the stat structure already available in
I can handle the differences and expect to. On systems supporting birth time I use birth time (which includes Windows). Otherwise fall back to POSIX Additional use cases that I need
Additional use cases:
Most of the flags could be handled by an enum. The ones I need are mostly portable like So how do I make this work in crystal considering when everything except |
Yeah, this is the solution I prefer too - just expose a stat struct with a
My bad. Looks like this needs statx though. Just like
Thanks for the usecase! I agree, indexing hardlinks is impossible with |
So make |
What about |
I prefer |
No platform specific data, please. A Crystal program should compile and run exactly the same on all platforms. Or, said another way, the API should be exactly the same for all platforms. But it's fine if a method raises on one platform but works on another, given that it's documented to only work on certain platforms. |
Instead of handling it at compile time:
I have to use exception handling at runtime:
@asterite How much overhead does that add when traversing file systems with > 10 million files? 100 million? They won't use spinning rust so seek times are not as much of a concern. But it's not one exception handler. It's several. One for flags, another for acl's, another for resource forks, another for extended attributes plus anything I missed. I'd much rather use feature checks than exception handling. To me the code is clearer. I know it's a platform feature check and only runs on specific platforms. With the exception handler am I handling an os error or the platform unsupported? It's even less clear when trying to understand someone else's code. What did they intend? |
Exception handling doesn't add overhead unless an exception is raised (as far as I know). Additionally, if a method doesn't raise (the compiler knows which methods raise), and methods you want to use in an OS and they are available won't raise, then the compiler will skip the entire exception handler (or LLVM will do this). So zero overhead, really.
The problem is that if someone forgets to check for a feature flag in a library, nobody can use that library in some OS, even if the library never calls that code (for example if they call it conditionally at runtime). This was discussed in the past. |
@asterite If they forget a If anything it's worse. A clear compile time error is changed in to a maybe run time error. Do the specs test that part of the code? If not the program appears to compile and function correctly but raises unhandled exceptions when run in the real world. In both compile time feature checking and exception:
The difference is when the error occurs. Compile or runtime. Compile time is more robust. |
@asterite No OS has all the features I'm checking. That means 2-3 exceptions on average, not zero overhead. |
When the methods raise on specific platforms, you can use conditional macro branches: {% if flag?(:win32) %}
stat.birth_time
{% else %}
stat.ctime
{% end %} This ensures only the non-raising methods are invoked on a platform. Some of these features however are not even platform-specific but depend on the file system. In that case, the API should provide nilable getters to avoid exception overhead. if birth_time = stat.birth_time?
birth_time
elsif ctime = stat.ctime?
ctime
end |
But that's worse than a feature flag! What's the point of raising an exception? Without You also duplicated code. Crystal already has to know which platforms are supported or not in order to |
It would be intersting to know how this is solved in Go, Java and other languages. |
@asterite as said above, Go has a platform agnostic interface (FileInfo) with the portable info that works everywhere the same, but also exposes the raw, system specific, info (FileInfo Sys()). This is IMO an acceptable solution. We have a platform agnostic API that works everywhere for 99% of use cases, but allow the 1% remaining use cases to be implemented. Also I prefer a program that won't compile on some platforms (I must deal with it), than a program that silently compiles but will raise NotImplementError exceptions at runtime (useless). It could just be that some methods don't exist for some targets, but I think the Go way to handle FileInfo is better, and makes the distinction between (not) portable API. |
Rather than do it the java/gofy way, I'd rather ask: "what would @asterite do?" @asterite had this great idea to take ruby and add So I crossed the vast ocean, climbed the highest mountian and slept with the ugliest of mountain goats (it was cold... and lonely). He wasn't there. So I used the internet to ask the great sage: "Is a method that may or may not be like a the
Side note, if you use lambskin they think it's another goat. And in a booming voice the great sage @asterite squeeked: |
My child. You have come far in your journey and learned much. The nilable approach suggested by @straight-shoota seems to be a good option: you ask it, but you have to check whether it's really supported. But maybe it depends on the API. |
That's not quite what I had i mind but I'll take it. It'd be nice to have a clear split between platform if's and runtime
The operator above is only an example. Feel free to change it. I prefer to check if the bar has (.)(.)'s. |
I'd like to propose a standard annotation or other method to indicate platform variant behavior. Advantages:
This should work regardless of whether using |
It looks like atime and birthtime are available on all supported platforms already? EDIT: birth time is available via On Windows ctime is accessible in the Win32 API via |
Crystal::System::FileInfo
is missing public accessors. I'd like to create a PR to expose some or all of the information below.Most of the data is cross platform with some exceptions. The list is not exhaustive.
Suggested names:
Currently I need ctime, birth_time, ino, dev, nlink, flags. I assume others may want the full stat structure when more non web applications are written.
The text was updated successfully, but these errors were encountered: