vaclavsvejcar / headroom

©️ Manager for license headers in source code files.
https://doc.norcane.com/headroom/latest/
BSD 3-Clause "New" or "Revised" License
48 stars 3 forks source link

Source file standard license headers #75

Open jhenahan opened 3 years ago

jhenahan commented 3 years ago

Is there a straightforward way to add a standard license header (in my specific case, to a Haskell source file)? That is, I'd like to be able to have a comment like

{-
This file is part of My Project
Copyright 2021 Me

Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file or at
https://spdx.org/licenses/BSD-3-Clause.html
-}

I tried a couple of hacky ways that have their own tradeoffs:

I'm not particularly happy with either of those, but I figured I'd see if there was maybe an undocumented footer variable or something that I could co-opt for the purpose.

If this isn't currently possible, I'd likely be interested in putting in some work to get something working. In that event, would you imagine this would be best handled with

The last one feels like a scary regex mess waiting to happen, so I'm hopeful one of the other options would be a sensible place to start.

Thanks for Headroom and any input!

vaclavsvejcar commented 3 years ago

Hello @jhenahan, thanks for reporting this, I'll have closer look. By the way, is the project where you try to use headroom publicly accessible somewhere (so I can eventually check your configuration and/or recommend you some fixes if possible)?

jhenahan commented 3 years ago

It's not currently public, but I expect it will be eventually. Here's a reproducer:

Relevant settings:

variables:
  _haskell_module_longdesc: |-
    !!! Write a description !!!
license-headers:
  haskell:
    put-after: ["^{-#"]
    block-comment:
      starts-with: ^{- \|
      ends-with: (?<!#)-}$

Inlining the text

{- |
Module                  : {{{ _haskell_module_name }}}
Description             : {{{ _haskell_module_shortdesc }}}
Copyright               : {{ _current_year }} {{ author }} <{{ email }}>
SPDX-License-Identifier : {{ spdx }}
Maintainer              : {{ email }}
Stability               : experimental
Portability             : POSIX

@
This file is part of {{ project }}.
Copyright {{ _current_year }} {{ author }}
{{{ license_text }}}
@

{{{ _haskell_module_longdesc }}}
-}

This is is fine in add mode. The header is added as expected. The duplication arises in replace mode. In replace mode, a second run produces

{- |
Module                  : {{{ _haskell_module_name }}}
Description             : {{{ _haskell_module_shortdesc }}}
Copyright               : {{ _current_year }} {{ author }} <{{ email }}>
SPDX-License-Identifier : {{ spdx }}
Maintainer              : {{ email }}
Stability               : experimental
Portability             : POSIX

@
This file is part of {{ project }}.
Copyright {{ _current_year }} {{ author }}
{{{ license_text }}}
@

@
This file is part of {{ project }}.
Copyright {{ _current_year }} {{ author }}
{{{ license_text }}}
@

{{{ _haskell_module_longdesc }}}
-}
module Main where

That is, the comment (actually rendered in my files, rather than untemplated as in this example) ends up duplicated on every run. I suspect that what's happening is that on subsequent runs, _haskell_module_longdesc is taken to be

@
This file is part of {{ project }}.
Copyright {{ _current_year }} {{ author }}
{{{ license_text }}}
@

!!! Write a description !!!

so it (correctly, but unintentionally) inlines the comment a second (third, etc.) time.

Separate comment

{- |
Module                  : {{{ _haskell_module_name }}}
Description             : {{{ _haskell_module_shortdesc }}}
Copyright               : {{ _current_year }} {{ author }} <{{ email }}>
SPDX-License-Identifier : {{ spdx }}
Maintainer              : {{ email }}
Stability               : experimental
Portability             : POSIX

{{{ _haskell_module_longdesc }}}
-}
{-
This file is part of {{ project }}.
Copyright {{ _current_year }} {{ author }}
{{{ license_text }}}
-}

Again, this works fine in add mode, but in replace mode it again duplicates the comment. That is,

{- |
Module                  : {{{ _haskell_module_name }}}
Description             : {{{ _haskell_module_shortdesc }}}
Copyright               : {{ _current_year }} {{ author }} <{{ email }}>
SPDX-License-Identifier : {{ spdx }}
Maintainer              : {{ email }}
Stability               : experimental
Portability             : POSIX

{{{ _haskell_module_longdesc }}}
-}
{-
This file is part of {{ project }}.
Copyright {{ _current_year }} {{ author }}
{{{ license_text }}}
-}
{-
This file is part of {{ project }}.
Copyright {{ _current_year }} {{ author }}
{{{ license_text }}}
-}
module Main where

and so on for additional runs.

drop mode behaves correctly in all cases, removing the templated sections, duplicates and all.

vaclavsvejcar commented 3 years ago

@jhenahan big thanks for the reproductions steps. I'm afraid this one will not be trivial and unfortunately I'm not aware of any workaround at this moment. The thing is that I'm reusing piece of code from Haddock that parses Haddock header and from Haddock point of view, everything after that Key : Value fields in header is just the long description, so strictly speaking the greed you mention is the correct behaviour. On the other hand I fully understand the need of having this style of comment with something in between key/values and long description in Haddock header.

Regarding your proposed solutions, IMO the post-processor could be way to go, but I'll need some more time to think about it. But I think it should be possible to just add new post-processor that would allow to define preamble/postamble with either specific behaviour to the Haddock headers, or maybe it could be even more generalized also for other types of source codes so end-user would be able to define some rules (regex?) where exactly to insert the extra snippet. What I can think about at this moment, this is probably easiest and cleaniest way to go. I'd really like to avoid touching the Haddock parsing behaviour, as I'd like to keep as much on track with actual Haddock implementation as possible.

jhenahan commented 3 years ago

Totally onboard with maintaining the Haddock integration as is. 👍 I'll see if I can grok the postprocessing machinery and try a PR once I'm through a bit of what I'm working on now. Thanks very much for the explanation and the pointers!

vaclavsvejcar commented 3 years ago

I think I'll have some free time to have a look and eventually start the implementation, it should be relatively straightforward. 🙂