Skip to content
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

Adding 'MustExist' constructor to assert a file is assumed to exist #85

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

recursion-ninja
Copy link

There are times when it is advantageous to assert that a file "must already exist" on the file system and if it does not exist, a FsResourceDoesNotExist exception ought to be thrown. To enable these semantics through the API of the fs-api/fs-sim packages, I have added a MustExist constructor to the AllowExisting type.

@recursion-ninja recursion-ninja requested a review from a team as a code owner December 21, 2024 17:28
Copy link
Collaborator

@jorisdral jorisdral left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feature! Some suggestions below

Comment on lines +234 to +237
-- | Open a file: create it if necessary or throw an error if either:
-- 1. It existed already while we were supposed to create it from scratch
-- (when passed 'MustBeNew').
-- 2. It did not already exists when we expected to (when passed 'MustExist').
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's link to AllowExisting instead, which already describes the intended semantics

Suggested change
-- | Open a file: create it if necessary or throw an error if either:
-- 1. It existed already while we were supposed to create it from scratch
-- (when passed 'MustBeNew').
-- 2. It did not already exists when we expected to (when passed 'MustExist').
-- | Open a file based on an 'AllowExisting'.

Comment on lines +242 to +248
caseAlreadyExist a = case ex of
MustBeNew -> Left (FsExists fp)
_ -> Right a

caseDoesNotExist = case ex of
MustExist -> Left (FsMissing fp (pathLast fp :| []))
_ -> Right mempty
Copy link
Collaborator

@jorisdral jorisdral Dec 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preferably, list all constructors, so that we won't forget to update the cases if the AllowExisting type changes in the future

Comment on lines +482 to +485
let assumedExistance (WriteMode MustExist) = True
assumedExistance (AppendMode MustExist) = True
assumedExistance (ReadWriteMode MustExist) = True
assumedExistance _ = False
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe name it fileShouldExist?

-- ('FsResourceAlreadyExist') is thrown.
| MustExist
-- ^ The file must already exist. If it does not, an error
-- ('FsResourceDoesNotExist') is thrown.
deriving (Eq, Show)

allowExisting :: OpenMode -> AllowExisting
Copy link
Collaborator

@jorisdral jorisdral Dec 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder, should allowExisting ReadMode = MustExist? That seems to be line with the semantics of hOpen on Unix at least.

Let's also take this opportunity to document the semantics of ReadMode. Something like: if opening a file in read mode, then the file must exist or an exception is thrown

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also add a TODO to test that this is the actual behaviour on both Windows and Unix. Hopefully this is already checked by the state machine tests, but it does not hurt to have some more targeted property tests

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there should probably also be an issue to properly document OpenMode. I'll create that

Comment on lines 61 to +63
createNew AllowExisting = oPEN_ALWAYS
createNew MustBeNew = cREATE_NEW
createNew MustExist = oPEN_ALWAYS
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be wrong: MustExist and AllowExisting get the same file flags

Comment on lines +498 to 499
when (openMode == ReadMode || assumedExistance openMode) $ void $
checkFsTree $ FS.getFile fp (mockFiles fs)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we make the change allowExisting ReadMode = MustExist, then I think this check can go away completely. openFile should then already throw the correct error

@@ -1055,6 +1055,7 @@ data Tag =
-- > Get ..
| TagPutSeekNegGet


Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Comment on lines +1067 to +1071
-- Open with MustExist, but the file does not exist.
--
-- > DoesFileExist fp
-- > h <- Open fp (AppendMode _)
| TagAssumeExists
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A similar tag for opening a non-existent file in read mode would also be useful

@@ -1136,6 +1144,7 @@ tag = C.classify [
, tagPutSeekGet Set.empty Set.empty
, tagPutSeekNegGet Set.empty Set.empty
, tagExclusiveFail
-- , tagAssumeExistsFail -- Set.empty
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be updated

Comment on lines +1495 to +1502
{-
tagClosedTwice closed = successful $ \ev _suc ->
case eventMockCmd ev of
Close (Handle h _) | Set.member h closed -> Left TagClosedTwice
Close (Handle h _) -> Right $ tagClosedTwice $ Set.insert h closed
_otherwise -> Right $ tagClosedTwice closed
(DoesFileExist _, Bool False) -> Left TagDoesFileExistKO
-}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented out code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants