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

Allow specifying a stack.yaml for stack configurations #230

Merged
merged 15 commits into from
Aug 23, 2020

Conversation

WorldSEnder
Copy link
Contributor

@WorldSEnder WorldSEnder commented Jul 31, 2020

In response to #44 this PR adds an argument to Stack/StackMulti configurations for providing an explicit stack.yaml file to use. This is hard to do with generic additional arguments as mentioned in #44 since stackCradleDependencies has to know about it, so I decided to give it special syntax. Example hie.yaml (which I'd use for agda/agda)

cradle:
  stack:
    - path: "./src/full"
      component: Agda:lib
      stackYaml: stack-8.8.3.yaml
    - path: "./src/main"
      component: Agda:exe:agda
      stackYaml: stack-8.8.3.yaml

A few questions remain, of course, hence this is a draft.

  • Naming for stackYaml could simply be yaml

  • A small semantic change is that multistack/multicabal configurations are now allowed to only have a path key, defaulting the rest, not requiring a component. Imo, this is better behaviour anyway.

  • Test cases

  • Documentation

Copy link
Collaborator

@fendor fendor left a comment

Choose a reason for hiding this comment

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

Hi!
Looks nice already!

I think it would be better if you could declare the stackYaml per cradle, not only per component. e.g. turn this

cradle:
  stack:
    - path: "./src/full"
      component: Agda:lib
      stackYaml: stack-8.8.3.yaml
    - path: "./src/main"
      component: Agda:exe:agda
      stackYaml: stack-8.8.3.yaml

into, e.g.

cradle:
  stack:
    - path: "./src/full"
      component: Agda:lib
    - path: "./src/main"
      component: Agda:exe:agda
stackYaml: stack-8.8.3.yaml

or something else to avoid all this repetition.


Also, are these paths expected to be relative to the cradle root directory?
What would happen in the face of nested multi-cradles, such as:

cradle:
  multi:
    - path: "appA"
      config:
        cradle:
          stack:
            - path: ./src
              component: appA:lib
              stackYaml: stack-8.8.3.yaml
    - path: "appB"
      config:
        cradle:
          stack:
            - path: ./src
              component: appB:lib
              stackYaml: stack-8.8.3.yaml

I guess in this case, the stackYaml needs to be relative to the cradleRootDir, otherwise we can not express the case that appA and appB have the same parent stack.yaml file.

@jneira
Copy link
Member

jneira commented Jul 31, 2020

Unfortunately stack shoud be a list or key-values.
My ideal shape would be

cradle:
  stack:
    config: stack-8.8.3.yaml
    components:
      - path: "./src/full"
        target: Agda:lib
      - path: "./src/main"
        target: Agda:exe:agda

But it would be out of scope of this pr...

@WorldSEnder
Copy link
Contributor Author

Paths are supposed to be relative to the hie.yaml file, which also is the working directory of the stack command. I favor @jneira's config shape, and I suppose the following would work during parsing:

  • Look at the Value under stack:
  • If it's a list, do what has already been implemented in this PR.
  • If it's a an object with a components: key, parse those as a list of configurations, parse the rest of the object as a single configuration, then monoidally combine these configurations, where the more specific options overwrite the options in the parent one.
  • If there is no components:, parse it as a single configuration.

@WorldSEnder
Copy link
Contributor Author

WorldSEnder commented Jul 31, 2020

Also, are these paths expected to be relative to the cradle root directory?
What would happen in the face of nested multi-cradles, such as:

cradle:
  multi:
    - path: "appA"
      config:
        cradle:
          stack:
            - path: ./src
              component: appA:lib
              stackYaml: stack-8.8.3.yaml
    - path: "appB"
      config:
        cradle:
          stack:
            - path: ./src
              component: appB:lib
              stackYaml: stack-8.8.3.yaml

I guess in this case, the stackYaml needs to be relative to the cradleRootDir, otherwise we can not express the case that appA and appB have the same parent stack.yaml file.

I added a test case (multi-stack-with-yaml) with this config, where I needed to say -path: appA/src instead of ./src. Not sure if this is intended behaviour, have a look once I pushed. So it seems that your guess is already the behaviour implemented. To be concrete, the stackYaml is relative to the working directory, which is, as far as I can tell, the cradleRootDir.

cradle:
  multi:
    - path: "appA"
      config:
        cradle:
          stack:
            - path: appA/src
              component: appA:lib
              stackYaml: stack-8.8.3.yaml
    - path: "appB"
      config:
        cradle:
          stack:
            - path: appB/src
              component: appB:lib
              stackYaml: stack-8.8.3.yaml

@WorldSEnder
Copy link
Contributor Author

WorldSEnder commented Jul 31, 2020

I'm a bit lost as to why the 8.10.1 test cases are failing, after all. I use ghc 8.10.1 locally, too. Apart from this issue the test appear just fine. Secondly, the Travis CI build seems to not find files, that the other builds do find, what is going on there? Figured out I forgot to add files to Extra-Source-Files for travis to pick them up.

Copy link
Collaborator

@fendor fendor left a comment

Choose a reason for hiding this comment

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

Everything looks pretty nice so far!
I dont have much time this week, but I plan to review it next weekend!

EDIT: should I forget to review till next week, feel free to ping me.

README.md Show resolved Hide resolved
@WorldSEnder
Copy link
Contributor Author

Ping @fendor

Copy link
Collaborator

@fendor fendor left a comment

Choose a reason for hiding this comment

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

Sorry for the long wait!
Awesome work, I just have a few questions.

The config parser is way more permissive than it used to. While that is ok in principle, there are some oddities.

E.g. this configuration:

cradle:
  cabal:
    component: "exe:cabal"
    components:
      - path: "./src"
        component: "lib:hie-bios"
      - path: "./"
        component: "lib:hie-bios"
    components:
      - path: "./src"
        component: "exe:hie-bios"
      - path: "./"
        component: "exe:hie-bios"

is allowed and produces this config, which seems weird and wrong in my opinion:

Config
  { cradle =
      CradleConfig
        { cradleDependencies = []
        , cradleType =
            CabalMulti
              { defaultCabal = Cabal { component = Just "exe:cabal" }
              , subCabalComponents =
                  [ ( "./src" , Cabal { component = Just "exe:hie-bios" } )
                  , ( "./" , Cabal { component = Just "exe:hie-bios" } )
                  ]
              }
        }
  }

I don't think this should be allowed, even if it semi well-defined.

Other than that, LGTM. Just the parser is a bit too permissive in my opinion. But if you would like to tackle that in a follow up PR, I don't mind merging it.

| Stack { component :: Maybe String }
| StackMulti [ (FilePath, String) ]
= Cabal { cabalType :: !CabalType }
| CabalMulti { defaultCabal :: !CabalType, subCabalComponents :: [ (FilePath, CabalType) ] }
Copy link
Collaborator

Choose a reason for hiding this comment

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

This also allows the config file:

cradle:
  cabal:
    components:
      - path: "./src"
        component: "lib:hie-bios"
      - path: "./"
        component: "lib:hie-bios"

While I dont expect any harm of it (and maybe we want soonish a similar field for cabal) but I just wanted to document it.

= fail "Not a valid Configuration type, following keys are allowed: component"
parseStackOrCabal _ multiConstructor (Array x) = do
let parseOne e
parseSingleOrMultiple single multiple parse = doParse where
Copy link
Collaborator

Choose a reason for hiding this comment

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

Interestingly, this allows this configuration:

cradle:
  cabal:
    components:
      - path: "./src"
        component: "lib:hie-bios"
      - path: "./"
        component: "lib:hie-bios"
    components:
      - path: "./src"
        component: "exe:hie-bios"
      - path: "./"
        component: "exe:hie-bios"

with this result:

Config
  { cradle =
      CradleConfig
        { cradleDependencies = []
        , cradleType =
            CabalMulti
              { defaultCabal = Cabal { component = Nothing }
              , subCabalComponents =
                  [ ( "./src" , Cabal { component = Just "exe:hie-bios" } )
                  , ( "./" , Cabal { component = Just "exe:hie-bios" } )
                  ]
              }
        }
  }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's a good catch, didn't think about multiple components entries. I'll fix this before the PR is merged.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thinking about this a little bit more, isn't a duplicate key (components) an error according to the yaml spec?

Mapping nodes are somewhat tricky because their keys are unordered and must be unique.

In that case, I suppose this PR is relevant and https://github.com/mpickering/hie-bios/pull/230/files#diff-0478bef4574ee638b0c136cccc31479aR288 should use decodeFileWithWarnings

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I added a test case that's supposed to fail on the config with duplicate components key.

@lukel97
Copy link
Contributor

lukel97 commented Aug 18, 2020

This makes a lot of sense to have, what is the stackYaml path relative to? To me I would intuitively expect it to be relative to the hie.yaml file, not the component/cradle root

@WorldSEnder
Copy link
Contributor Author

@bubba Maybe I'm missing something but I was basing the consideration on the implemented reality in multiCradle. The cur_dir is taken as the base path to append the component sub-paths cur_dir </> p off of. As I read it, this is relative to the cradle root, then. I would also agree with the suggestion to unambiguously make all paths inside hie.yaml relative to the file itself.

Additionally, it seems that the main entry point loadCradleWithOpts simply takes the directory containing hie.yaml as the cradle root directory, so it seems that relative to cradle root and relative to hie.yaml often means the same thing.

@lukel97
Copy link
Contributor

lukel97 commented Aug 19, 2020

@WorldSEnder

I would also agree with the suggestion to unambiguously make all paths inside hie.yaml relative to the file itself.
This is probably worthy of a separate issue and discussion, but for now in this PR probably best then to just stick with making it relative to the cur_dir for consistency

Copy link
Collaborator

@fendor fendor left a comment

Choose a reason for hiding this comment

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

LGTM, thank you!

src/HIE/Bios/Cradle.hs Outdated Show resolved Hide resolved
Copy link
Collaborator

@fendor fendor left a comment

Choose a reason for hiding this comment

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

LGTM!

Co-authored-by: fendor <fendor@users.noreply.github.com>
@fendor fendor mentioned this pull request Aug 23, 2020
@fendor fendor merged commit 0ed7604 into haskell:master Aug 23, 2020
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.

None yet

4 participants