updo (empty) → 1.0.0
raw patch · 53 files changed
+2728/−0 lines, 53 filesdep +aesondep +basedep +dhall
Dependencies added: aeson, base, dhall, filepath, text, turtle, utf8-string
Files
- ALTERNATIVES.md +76/−0
- CHANGELOG.md +2/−0
- HACKING.md +70/−0
- LICENSE +373/−0
- Makefile +103/−0
- README.md +567/−0
- TEMPLATES.md +21/−0
- TESTING.md +185/−0
- alternatives/cabal2stack/Makefile +19/−0
- alternatives/cabal2stack/README.md +4/−0
- alternatives/stack2cabal/Makefile +12/−0
- alternatives/stack2cabal/README.md +4/−0
- alternatives/yaml2stack/Makefile +74/−0
- alternatives/yaml2stack/README.md +13/−0
- alternatives/yaml2stack/join-sort-fragments.sh +26/−0
- package.dhall +34/−0
- project-dhall/Makefile +76/−0
- project-dhall/README.md +7/−0
- project-dhall/pkgs-sorted.hs +27/−0
- project-dhall/pkgs-upgrade-done.hs +20/−0
- project-dhall/pkgs-upgrade-partition.hs +34/−0
- project-dhall/pkgs-upgrade.dhall +65/−0
- project-dhall2config/Makefile +75/−0
- project-dhall2config/README.md +27/−0
- project-dhall2config/pkg-groups.hs +52/−0
- project-nix/Makefile +19/−0
- project-nix/README.md +67/−0
- project-nix/project-versions.dhall +15/−0
- project-nix/sha256map.hs +76/−0
- project-nix/sha256map.py +50/−0
- text-templates/cabal/package.dhall +11/−0
- text-templates/cabal/pkg-groups.dhall +20/−0
- text-templates/cabal/repo-items.dhall +20/−0
- text-templates/dhall2cabal.dhall +86/−0
- text-templates/dhall2config.dhall +15/−0
- text-templates/dhall2stack.dhall +89/−0
- text-templates/internal/constraint-items.dhall +18/−0
- text-templates/internal/constraint-section.dhall +15/−0
- text-templates/internal/pkg-items.dhall +13/−0
- text-templates/internal/pkg-section.dhall +12/−0
- text-templates/internal/sub-items.dhall +14/−0
- text-templates/stack/package.dhall +9/−0
- text-templates/stack/repo-items.dhall +22/−0
- text-templates/yaml2stack/constraints.dhall +13/−0
- text-templates/yaml2stack/pkgs.dhall +1/−0
- text-templates/yaml2stack/repo-items.dhall +13/−0
- types.dhall +6/−0
- types/CabalRelativity.dhall +1/−0
- types/PkgSet.dhall +3/−0
- types/PkgTodoList.dhall +1/−0
- types/PkgVer.dhall +1/−0
- types/SourceRepoPkg.dhall +1/−0
- updo.cabal +151/−0
+ ALTERNATIVES.md view
@@ -0,0 +1,76 @@+# Alternatives to Updo++Updo uses `.dhall` configuration but you may want to configure your project in+stack and mirror it to cabal or vica-versa with a project-to-project conversion.++Updo can be of help with mirroring if you chose stack-first or cabal-first+project maintenance but then you're own your own as far as managing GHC upgrades+goes.++## Project to Project Conversion++We provide makefiles for converting a stack project to a cabal project with+[`stack2cabal`](https://github.com/hasufell/stack2cabal) and for going the other+way with [`cabal2stack`](https://github.com/iconnect/cabal2stack).++### Configure with Stack++A stack project is YAML, `stack.yaml` by default. Without conditionals or+imports everything has to be in the same file except for stack's own [snapshot+indirection](https://docs.haskellstack.org/en/stable/custom_snapshot/) to+another file.++There are a bunch of YAML formatting tools such as+[vscode-yaml](https://www.npmjs.com/package/vscode-yaml).++### Configure with Cabal++A cabal project, `cabal.project` by default, is its own format. It has+conditionals and imports.++There is not a tool for formatting it. The `cabal format` command and the+[cabal-fmt](https://github.com/phadej/cabal-fmt) tool both format packages, not+projects.++### Mirroring with `stack2cabal`++This tool inspects the stack project and downloads source repositories to check+for version constraints and generates a `cabal.project` and+`cabal.project.freeze`.++This tool is slow as it clones whole and sometimes large source repositories+locally. This can be skipped with `--no-inspect-remotes` but the inspection+ensures correct versions in the freeze file.++```+> stack2cabal --help+Usage: stack2cabal [-f|--file STACK_YAML] [-o|--output-file CABAL_PROJECT] + [--no-inspect-remotes] [--no-pin-ghc] [--no-sort-repos] + [--no-run-hpack] [-p|--pin-hackage-index FUZZY_DATE]++Available options:+ --no-inspect-remotes Don't check package names from remote git sources+ (this is faster, but may leave incorrect versions in+ cabal.project.freeze if remote packages overwrite+ stack resolver versions)+```++It generates a freeze file but these locks are problematic as they don't+function as people expect and there are platform-specific [freeze+problems](https://github.com/haskell/cabal/issues/8059).++### Mirroring with `cabal2stack`++This tool inspects cabal's plan so is more tied to the machine architecture+where the plan was created by cabal. The generated stack project will differ if+created on mac or linux but by adding a `--resolver` flag the generated project+is buildable on both mac and linux.++Like `stack2cabal`, this tool also needs to download remote source repositories+and is about as slow because the download takes most of the time.++The generated stack project will [vary by platform][c2s1] and it will [repeat+dependencies][c2s4] already in the resolver.++[c2s1]: https://github.com/iconnect/cabal2stack/issues/1+[c2s4]: https://github.com/iconnect/cabal2stack/issues/4
+ CHANGELOG.md view
@@ -0,0 +1,2 @@+### 1.0.0+* First release
+ HACKING.md view
@@ -0,0 +1,70 @@+# Updo Hacking++## Package Groups++During the cabal solving step, cabal would fail to solve for dependencies for+packages in a particular order. The grouping of packages preserves this.++To mirror package groups from `project-dhall/pkgs/*.dhall` to+`project-cabal/pkgs/*.config` use make, either for `pkgs.config` that imports+all `pkgs/*.config` or for a single package group.++```+$ make project-cabal/pkgs.config+$ cat project-cabal/pkgs.config+import: project-cabal/pkgs/shims.config+...+import: project-cabal/pkgs/tools.config+```++When `project-dhall/pkgs-upgrade-todo.dhall` is:++```dhall+[ "./jobs/runner/" ]+```++Then the single `jobs.config` package group as generated is:++```+$ make project-cabal/pkgs/jobs.config+$ cat project-cabal/pkgs/jobs.config+if impl(ghc <= 8.10.7)+ packages:+ ./jobs/core/+ , ./jobs/runner/+else+ packages:+ ./jobs/core/++-- TODO for impl(ghc >= 9.2.5)+-- ./jobs/runner/+```++To split a group of packages into a dhall record of `{pkgs, done, todo}`:++```+$ ./updo/project-dhall/pkgs-upgrade-partition.hs ./project-dhall/pkgs/jobs.dhall+{ pkgs = [ "./jobs/core/", "./jobs/runner/" ]+, done = [ "./jobs/core/" ]+, todo = [ "./jobs/runner/" ]+}+```++## GHC Upgrade Hacking++During a GHC version uprade, start by putting all packages into+`pkgs-upgrade-todo.dhall` and progressively take one or a few packages out at at+time and rerun the make targets to build the project you want to use.++To sort all the packages.++```+$ cd project-dhall+$ ./pkgs-sorted.hs+[ "./admin-client/"+, "./aeson-shim/"+...+, "./docs/"+, "./testing/"+]+```
+ LICENSE view
@@ -0,0 +1,373 @@+Mozilla Public License Version 2.0+==================================++1. Definitions+--------------++1.1. "Contributor"+ means each individual or legal entity that creates, contributes to+ the creation of, or owns Covered Software.++1.2. "Contributor Version"+ means the combination of the Contributions of others (if any) used+ by a Contributor and that particular Contributor's Contribution.++1.3. "Contribution"+ means Covered Software of a particular Contributor.++1.4. "Covered Software"+ means Source Code Form to which the initial Contributor has attached+ the notice in Exhibit A, the Executable Form of such Source Code+ Form, and Modifications of such Source Code Form, in each case+ including portions thereof.++1.5. "Incompatible With Secondary Licenses"+ means++ (a) that the initial Contributor has attached the notice described+ in Exhibit B to the Covered Software; or++ (b) that the Covered Software was made available under the terms of+ version 1.1 or earlier of the License, but not also under the+ terms of a Secondary License.++1.6. "Executable Form"+ means any form of the work other than Source Code Form.++1.7. "Larger Work"+ means a work that combines Covered Software with other material, in+ a separate file or files, that is not Covered Software.++1.8. "License"+ means this document.++1.9. "Licensable"+ means having the right to grant, to the maximum extent possible,+ whether at the time of the initial grant or subsequently, any and+ all of the rights conveyed by this License.++1.10. "Modifications"+ means any of the following:++ (a) any file in Source Code Form that results from an addition to,+ deletion from, or modification of the contents of Covered+ Software; or++ (b) any new file in Source Code Form that contains any Covered+ Software.++1.11. "Patent Claims" of a Contributor+ means any patent claim(s), including without limitation, method,+ process, and apparatus claims, in any patent Licensable by such+ Contributor that would be infringed, but for the grant of the+ License, by the making, using, selling, offering for sale, having+ made, import, or transfer of either its Contributions or its+ Contributor Version.++1.12. "Secondary License"+ means either the GNU General Public License, Version 2.0, the GNU+ Lesser General Public License, Version 2.1, the GNU Affero General+ Public License, Version 3.0, or any later versions of those+ licenses.++1.13. "Source Code Form"+ means the form of the work preferred for making modifications.++1.14. "You" (or "Your")+ means an individual or a legal entity exercising rights under this+ License. For legal entities, "You" includes any entity that+ controls, is controlled by, or is under common control with You. For+ purposes of this definition, "control" means (a) the power, direct+ or indirect, to cause the direction or management of such entity,+ whether by contract or otherwise, or (b) ownership of more than+ fifty percent (50%) of the outstanding shares or beneficial+ ownership of such entity.++2. License Grants and Conditions+--------------------------------++2.1. Grants++Each Contributor hereby grants You a world-wide, royalty-free,+non-exclusive license:++(a) under intellectual property rights (other than patent or trademark)+ Licensable by such Contributor to use, reproduce, make available,+ modify, display, perform, distribute, and otherwise exploit its+ Contributions, either on an unmodified basis, with Modifications, or+ as part of a Larger Work; and++(b) under Patent Claims of such Contributor to make, use, sell, offer+ for sale, have made, import, and otherwise transfer either its+ Contributions or its Contributor Version.++2.2. Effective Date++The licenses granted in Section 2.1 with respect to any Contribution+become effective for each Contribution on the date the Contributor first+distributes such Contribution.++2.3. Limitations on Grant Scope++The licenses granted in this Section 2 are the only rights granted under+this License. No additional rights or licenses will be implied from the+distribution or licensing of Covered Software under this License.+Notwithstanding Section 2.1(b) above, no patent license is granted by a+Contributor:++(a) for any code that a Contributor has removed from Covered Software;+ or++(b) for infringements caused by: (i) Your and any other third party's+ modifications of Covered Software, or (ii) the combination of its+ Contributions with other software (except as part of its Contributor+ Version); or++(c) under Patent Claims infringed by Covered Software in the absence of+ its Contributions.++This License does not grant any rights in the trademarks, service marks,+or logos of any Contributor (except as may be necessary to comply with+the notice requirements in Section 3.4).++2.4. Subsequent Licenses++No Contributor makes additional grants as a result of Your choice to+distribute the Covered Software under a subsequent version of this+License (see Section 10.2) or under the terms of a Secondary License (if+permitted under the terms of Section 3.3).++2.5. Representation++Each Contributor represents that the Contributor believes its+Contributions are its original creation(s) or it has sufficient rights+to grant the rights to its Contributions conveyed by this License.++2.6. Fair Use++This License is not intended to limit any rights You have under+applicable copyright doctrines of fair use, fair dealing, or other+equivalents.++2.7. Conditions++Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted+in Section 2.1.++3. Responsibilities+-------------------++3.1. Distribution of Source Form++All distribution of Covered Software in Source Code Form, including any+Modifications that You create or to which You contribute, must be under+the terms of this License. You must inform recipients that the Source+Code Form of the Covered Software is governed by the terms of this+License, and how they can obtain a copy of this License. You may not+attempt to alter or restrict the recipients' rights in the Source Code+Form.++3.2. Distribution of Executable Form++If You distribute Covered Software in Executable Form then:++(a) such Covered Software must also be made available in Source Code+ Form, as described in Section 3.1, and You must inform recipients of+ the Executable Form how they can obtain a copy of such Source Code+ Form by reasonable means in a timely manner, at a charge no more+ than the cost of distribution to the recipient; and++(b) You may distribute such Executable Form under the terms of this+ License, or sublicense it under different terms, provided that the+ license for the Executable Form does not attempt to limit or alter+ the recipients' rights in the Source Code Form under this License.++3.3. Distribution of a Larger Work++You may create and distribute a Larger Work under terms of Your choice,+provided that You also comply with the requirements of this License for+the Covered Software. If the Larger Work is a combination of Covered+Software with a work governed by one or more Secondary Licenses, and the+Covered Software is not Incompatible With Secondary Licenses, this+License permits You to additionally distribute such Covered Software+under the terms of such Secondary License(s), so that the recipient of+the Larger Work may, at their option, further distribute the Covered+Software under the terms of either this License or such Secondary+License(s).++3.4. Notices++You may not remove or alter the substance of any license notices+(including copyright notices, patent notices, disclaimers of warranty,+or limitations of liability) contained within the Source Code Form of+the Covered Software, except that You may alter any license notices to+the extent required to remedy known factual inaccuracies.++3.5. Application of Additional Terms++You may choose to offer, and to charge a fee for, warranty, support,+indemnity or liability obligations to one or more recipients of Covered+Software. However, You may do so only on Your own behalf, and not on+behalf of any Contributor. You must make it absolutely clear that any+such warranty, support, indemnity, or liability obligation is offered by+You alone, and You hereby agree to indemnify every Contributor for any+liability incurred by such Contributor as a result of warranty, support,+indemnity or liability terms You offer. You may include additional+disclaimers of warranty and limitations of liability specific to any+jurisdiction.++4. Inability to Comply Due to Statute or Regulation+---------------------------------------------------++If it is impossible for You to comply with any of the terms of this+License with respect to some or all of the Covered Software due to+statute, judicial order, or regulation then You must: (a) comply with+the terms of this License to the maximum extent possible; and (b)+describe the limitations and the code they affect. Such description must+be placed in a text file included with all distributions of the Covered+Software under this License. Except to the extent prohibited by statute+or regulation, such description must be sufficiently detailed for a+recipient of ordinary skill to be able to understand it.++5. Termination+--------------++5.1. The rights granted under this License will terminate automatically+if You fail to comply with any of its terms. However, if You become+compliant, then the rights granted under this License from a particular+Contributor are reinstated (a) provisionally, unless and until such+Contributor explicitly and finally terminates Your grants, and (b) on an+ongoing basis, if such Contributor fails to notify You of the+non-compliance by some reasonable means prior to 60 days after You have+come back into compliance. Moreover, Your grants from a particular+Contributor are reinstated on an ongoing basis if such Contributor+notifies You of the non-compliance by some reasonable means, this is the+first time You have received notice of non-compliance with this License+from such Contributor, and You become compliant prior to 30 days after+Your receipt of the notice.++5.2. If You initiate litigation against any entity by asserting a patent+infringement claim (excluding declaratory judgment actions,+counter-claims, and cross-claims) alleging that a Contributor Version+directly or indirectly infringes any patent, then the rights granted to+You by any and all Contributors for the Covered Software under Section+2.1 of this License shall terminate.++5.3. In the event of termination under Sections 5.1 or 5.2 above, all+end user license agreements (excluding distributors and resellers) which+have been validly granted by You or Your distributors under this License+prior to termination shall survive termination.++************************************************************************+* *+* 6. Disclaimer of Warranty *+* ------------------------- *+* *+* Covered Software is provided under this License on an "as is" *+* basis, without warranty of any kind, either expressed, implied, or *+* statutory, including, without limitation, warranties that the *+* Covered Software is free of defects, merchantable, fit for a *+* particular purpose or non-infringing. The entire risk as to the *+* quality and performance of the Covered Software is with You. *+* Should any Covered Software prove defective in any respect, You *+* (not any Contributor) assume the cost of any necessary servicing, *+* repair, or correction. This disclaimer of warranty constitutes an *+* essential part of this License. No use of any Covered Software is *+* authorized under this License except under this disclaimer. *+* *+************************************************************************++************************************************************************+* *+* 7. Limitation of Liability *+* -------------------------- *+* *+* Under no circumstances and under no legal theory, whether tort *+* (including negligence), contract, or otherwise, shall any *+* Contributor, or anyone who distributes Covered Software as *+* permitted above, be liable to You for any direct, indirect, *+* special, incidental, or consequential damages of any character *+* including, without limitation, damages for lost profits, loss of *+* goodwill, work stoppage, computer failure or malfunction, or any *+* and all other commercial damages or losses, even if such party *+* shall have been informed of the possibility of such damages. This *+* limitation of liability shall not apply to liability for death or *+* personal injury resulting from such party's negligence to the *+* extent applicable law prohibits such limitation. Some *+* jurisdictions do not allow the exclusion or limitation of *+* incidental or consequential damages, so this exclusion and *+* limitation may not apply to You. *+* *+************************************************************************++8. Litigation+-------------++Any litigation relating to this License may be brought only in the+courts of a jurisdiction where the defendant maintains its principal+place of business and such litigation shall be governed by laws of that+jurisdiction, without reference to its conflict-of-law provisions.+Nothing in this Section shall prevent a party's ability to bring+cross-claims or counter-claims.++9. Miscellaneous+----------------++This License represents the complete agreement concerning the subject+matter hereof. If any provision of this License is held to be+unenforceable, such provision shall be reformed only to the extent+necessary to make it enforceable. Any law or regulation which provides+that the language of a contract shall be construed against the drafter+shall not be used to construe this License against a Contributor.++10. Versions of the License+---------------------------++10.1. New Versions++Mozilla Foundation is the license steward. Except as provided in Section+10.3, no one other than the license steward has the right to modify or+publish new versions of this License. Each version will be given a+distinguishing version number.++10.2. Effect of New Versions++You may distribute the Covered Software under the terms of the version+of the License under which You originally received the Covered Software,+or under the terms of any subsequent version published by the license+steward.++10.3. Modified Versions++If you create software not governed by this License, and you want to+create a new license for such software, you may create and use a+modified version of this License if you rename the license and remove+any references to the name of the license steward (except to note that+such modified license differs from this License).++10.4. Distributing Source Code Form that is Incompatible With Secondary+Licenses++If You choose to distribute Source Code Form that is Incompatible With+Secondary Licenses under the terms of this version of the License, the+notice described in Exhibit B of this License must be attached.++Exhibit A - Source Code Form License Notice+-------------------------------------------++ This Source Code Form is subject to the terms of the Mozilla Public+ License, v. 2.0. If a copy of the MPL was not distributed with this+ file, You can obtain one at http://mozilla.org/MPL/2.0/.++If it is not possible or desirable to put the notice in a particular+file, then You may include the notice in a location (such as a LICENSE+file in a relevant directory) where a recipient would be likely to look+for such a notice.++You may add additional accurate notices of copyright ownership.++Exhibit B - "Incompatible With Secondary Licenses" Notice+---------------------------------------------------------++ This Source Code Form is "Incompatible With Secondary Licenses", as+ defined by the Mozilla Public License, v. 2.0.
+ Makefile view
@@ -0,0 +1,103 @@+# How are we going to generate stack.yaml and stack.yaml.lock files?+#+# Choices are:+# - dhall2stack = via a temporary ghc-x.y.z.dhall2stack.yaml+# - dhall2yaml2stack = via a temporary ghc-x.y.z.dhall2yaml2stack.yaml+STACK_VIA := dhall2stack++# How are we going to generate the cabal.project file?+#+# Choices are:+# - dhall2config = via a temporary ghc-x.y.z.dhall2config.project+# - dhall2cabal = via a temporary ghc-x.y.z.dhall2cabal.project+#+# dhall2config is good when upgrading to a new GHC version. The+# <pkg-group>.config files will show how many in a group are yet to be upgraded.+# With the cabal imports it is possible to try things out quickly by editing the+# config files themselves if you want to momentarily sidestep Updo's make cabal+# project generation.+#+# dhall2cabal is good if you want the cabal project to closely match the layout+# of the stack project when that is generated using dhall2stack.++# dhall2cabal is also good if you need to use cabal < 3.8 where everything needs+# to be in one file. To achieve this, the+# project-dhall/project-dhall2cabal.dhall template will need to bring in the+# contents of the stackage import like this:+#+# ${../../project-stackage/$(STACKAGE_VERSION).config as Text}+CABAL_VIA := dhall2config++UPDO_TMP := .updo++# Updo Dhall gives us these targets:+# - dhall2stack-projects+# - dhall2cabal-projects+# - dhall2config-projects+# - project-sha256maps+include updo/project-dhall/Makefile+include updo/project-dhall2config/Makefile+include updo/project-nix/Makefile++# Project (and related sha256map) files used in production, not in GHC upgrade.+.PHONY: projects+projects: \+ ghc-$(GHC_VERSION).sha256map.nix \+ stack.yaml \+ stack.yaml.lock \+ cabal.project++.PHONY: upgrade-projects+upgrade-projects: \+ project-nix/ghc-$(GHC_UPGRADE)/sha256map.nix \+ stack.upgrade.yaml \+ stack.upgrade.yaml.lock \+ cabal.upgrade.project \+ ghc-$(GHC_UPGRADE).dhall2stack.yaml \+ ghc-$(GHC_UPGRADE).dhall2stack.yaml.lock \+ ghc-$(GHC_UPGRADE).dhall2cabal.project++# All the kinds of project files we might want to generate.+#+# These are alternative methods we could include but don't.+# - dhall2yaml2stack-projects+.PHONY: all-possible-projects+all-possible-projects: \+ projects \+ dhall2config-projects \+ dhall2cabal-projects \+ dhall2stack-projects++.PHONY: clean+clean:+ rm -f ghc-*.stack.* ghc-*.dhall2config.* ghc-*.dhall2cabal.* ghc-*.dhall2stack.* ghc-*.stack2cabal.* ghc-*.cabal2stack.* ghc-*.dhall2yaml2stack.* ghc-*.sha256map.nix++.PHONY: cabal+cabal: \+ ghc-$(GHC_VERSION).$(CABAL_VIA).project \+ ghc-$(GHC_UPGRADE).$(CABAL_VIA).project++.PHONY: stack+stack: \+ ghc-$(GHC_VERSION).$(STACK_VIA).yaml \+ ghc-$(GHC_VERSION).$(STACK_VIA).yaml.lock \+ ghc-$(GHC_UPGRADE).$(STACK_VIA).yaml \+ ghc-$(GHC_UPGRADE).$(STACK_VIA).yaml.lock++cabal.project: ghc-$(GHC_VERSION).$(CABAL_VIA).project+ cp $^ $@++cabal.upgrade.project: ghc-$(GHC_UPGRADE).$(CABAL_VIA).project+ cp $^ $@++stack.yaml: ghc-$(GHC_VERSION).$(STACK_VIA).yaml+ cp $< $@++stack.upgrade.yaml: ghc-$(GHC_UPGRADE).$(STACK_VIA).yaml+ cp $< $@++stack.yaml.lock: stack.yaml+ stack build --test --no-run-tests --bench --no-run-benchmarks --dry-run --stack-yaml $<++stack.upgrade.yaml.lock: stack.upgrade.yaml+ stack build --test --no-run-tests --bench --no-run-benchmarks --dry-run --stack-yaml $<
+ README.md view
@@ -0,0 +1,567 @@+# 🫸 Updo 🫷++> A hairstyle and a way of maintaining and upgrading Haskell projects.++### What is a Project?++Updo is good for project packages, constraints, source repository packages and+stackage resolver[^download-stackage-config]. More than this can be added into a+project template.++[^download-stackage-config]: For cabal, the cabal.config will have to be+ downloaded to `project-stackage/resolver.config` and then edited to comment+ out constraints that would otherwise lead to impossible to solve conflicting+ constraints because cabal constraints are additive and cannot be overridden.++### Goals++1. Map a single set of packages, constraints and source repository packages to+ projects for cabal and stack.+2. Minimize the effort of upgrading constraints, source repository packages and+ GHC versions.++We do this with configuration in `.dhall` files, makefiles and `dhall text`+templates. We also have some simple Haskell scripts for operations not possible+in Dhall like sorting a `List Text`[^dhall-sort-list-nat].++[^dhall-sort-list-nat]: Dhall can only sort `List Natural`.++# Template Outputs++We generate projects from the configured inputs using templates. With the+`dhall text` command we're able to mirror to both stack and cabal projects using+text templates. See [templates](./TEMPLATES.md) for more.++We provide one stack template `dhall2stack`. The `dhall2cabal` template for+cabal is so similar that the generated outputs can be compared using file diff+tooling. However, we prefer the `dhall2config` template because it retains+package groups that can bring order to an [upgrade](#upgrading-a-project) if the+cabal solving order is roughly captured by package group ordering.++We provide one level of nesting for grouping packages together as inputs. Groups+are preserved or flattened depending on the template.++* `dhall2stack` - Stack projects cannot import so necessarily must lose the+ grouping and contain the list of packages.+* `dhall2cabal` - This template lists packages within the cabal project.+* `dhall2config` - When generating the cabal project we keep [package+ groups](#package-groups), generating the same tree structure but replacing the+ leaves. From each `group-name.dhall` we generate a `group-name.config` file.++It is nice to be able to look at packages both grouped and as one sorted list.+Find the flat sorted lists of packages used by some templates in the `.updo`+folder.++```+.updo+├── pkgs-sorted.dhall ▨ List Text+└── pkgs-upgrade-done.dhall ▨ List Text+```++If you don't want groups then please put all packages in the one group.++# Maintaining a Project++Maintaining a project involves configuring or reconfiguring inputs and then+using make to generate the projects. What do we want to configure? We don't need+much:++1. A stackage resolver[^download-stackage-config].+2. A list of constraints (package dependencies with their versions).+3. A list of source repository packages, for unpublished[^unpublished-packages]+ packages or for unpublished versions of packages.+4. A list of packages.++[^unpublished-packages]: A package not published to hackage or stackage.+++All configuration goes into `./project-dhall` (where `.` is the root folder for+your Haskell project) except for the `cabal.config` that we'll need to download+from stackage. Save this file as `project-stackage/lts-m.n.config` using the+exact resolver name.++```+project-stackage+└── lts-m.n.config+```++For each `ghc-x.y.z` compiler version, create this set of inputs and templates:++```+project-dhall+└── ghc-x.y.z+ ├── constraints.dhall ▨ List { dep : Text, ver : Text }+ ├── deps-external.dhall ▨ List { loc : Text, tag : Text, sub : List Text }+ ├── deps-internal.dhall ▨ List { loc : Text, tag : Text, sub : List Text }+ ├── forks-external.dhall ▨ List { loc : Text, tag : Text, sub : List Text }+ ├── forks-internal.dhall ▨ List { loc : Text, tag : Text, sub : List Text }+ └── text-templates+ ├── dhall2cabal.dhall ▨ template for ghc-x.y.z.dhall2cabal.project+ ├── dhall2config.dhall ▨ template for ghc-x.y.z.dhall2config.project+ ├── dhall2stack.dhall ▨ template for ghc-x.y.z.dhall2stack.yaml+ └── stacksnippet.dhall ▨ anything for ghc-x.y.z.dhall2stack.yaml+```++Anything in `stacksnippet.dhall` gets added to the top of the generated stack+project[^base.yaml]. The rest of the files are inputs.++[^base.yaml]: Anything in `stacksnippet.dhall` will be used by+ [dhall2yaml2stack](alternatives/yaml2stack#readme) too and is put into a+ `base.yaml`, the topmost fragment when stitching together fragments.++### 1. Stackage Resolver and Constraints++The stackage resolver is able to provide us with a list of packages that work+together for both stack and cabal. Any other dependencies as constraints or+source packages are either not found on stackage or are different versions.++By specifying a resolver with stack we get a list of exact `==` versions for+packages published to stackage. Stackage also publishes a `cabal.config` file+that has these package versions as cabal constraints. As cabal constraints are+additive, in practice importing directly from stackage often leads to conflicts+between stackage's constraints and the project's own constraints and for that+reason we'll usually have to download the `cabal.config` from+stackage[^stackage-config-url-path] and comment out lines that are conflicted.++[^stackage-config-url-path]: The URL path to download this file from is+ `/resolver/cabal.config`. The latest nightly is always at+ https://www.stackage.org/nightly/cabal.config.++We don't expect any packages to impose constraints on their dependencies at the+package level, in their `.cabal` files, but if they do then these constraints+must fit with constraints at the project level.++### 2. Constraints++In constraints[^constraints] put published packages that you want to use that are+not on stackage or if they are on stackage where you want to use a different+version.++[^constraints]: To stack, constraints and source repository packages are+ both `extra-deps`. We use cabal-like nomenclature but, be warned, cabal+ constraints cover more than just `package ==version`, such as flags:+ ```cabal+ constraints:+ bson -_old-network+ , HaXml +splitbase+ ```++```dhall+[ { dep = "diagrams-postscript", ver = "1.5" }+, { dep = "diagrams-svg", ver = "1.4.3" }+]+```++The type of constraints is a list of records with dependency and version fields:++```dhall+List { dep : Text, ver : Text }+```++### 3. Source Repository Packages++There are various reasons to depend on source packages and forks of source+packages; to keep a mirror within your organization, to add fixes that haven't been+upstreamed yet, or to pick up a fix someone else has made but hasn't yet been merged+upstream, released and published.++```+project-dhall+└── ghc-x.y.z+ ├── deps-external.dhall ▨ List { loc : Text, tag : Text, sub : List Text }+ ├── deps-internal.dhall ▨ List { loc : Text, tag : Text, sub : List Text }+ ├── forks-external.dhall ▨ List { loc : Text, tag : Text, sub : List Text }+ └── forks-internal.dhall ▨ List { loc : Text, tag : Text, sub : List Text }+```++The type of these files are all the same. They contain a list of records with+fields for location, tag (commit SHA) and subdirectories:++```dhall+List { loc : Text, tag : Text, sub : List Text }+```++Any empty `sub` field must be type annotated like this `[] : List Text`. Each+source repository package record will bring in one dependency or as many as+there are `sub` fields.++These source repository `*.dhall` files are for original work from your+organisation (internal) and from third parties (external) and for internal and+external forks. If using the empty list in any one of these files then use an+explicit type annotation:++```dhall+[] : List { loc : Text, tag : Text, sub : List Text }+```++### 4. Package Groups+In the `pkgs` folder, create one or more groups for related packages.++```+project-dhall+├── ghc-x.y.z+├── pkgs+│ ├── db.dhall ▨ List Text+│ ├── server.dhall ▨ List Text+│ └── tools.dhall ▨ List Text+└── pkg-groups.dhall ▨ List Text+```++The contents of each group is a `List Text` of relative paths to folders+containing package `.cabal` files.++```dhall+-- ./project-dhall/pkgs/tools.dhall+[ "tool/linter/"+, "tool/formatter/"+]+```++List the package groups in `pkg-groups.dhall`[^pkg-groups]. A good order to use+is the order of cabal constraint solving that you may witness when upgrading a+project and seeing solving failures.++[^pkg-groups]: Dhall can't do arbitrary IO like reading files from a folder.++```dhall+-- ./project-dhall/pkg-groups.dhall+[ "tools"+, "db"+, "server"+]+```++This gives you control of the imports in the generated+`./project-cabal/pkgs.config`, itself imported into+`ghc-x.y.z.dhall2config.project`:++* Use `CABAL_RELATIVITY=ImportRelative` to be import-compatible with `cabal-3.10`.+ ```cabal+ -- ./project-cabal/pkgs.config+ import: ./pkgs/tools.config+ import: ./pkgs/db.config+ import: ./pkgs/server.config+ ```+* The default of `CABAL_RELATIVITY=ProjectRelative` is import-compatible with `cabal-3.8`.+ ```cabal+ -- ./project-cabal/pkgs.config+ import: ./project-cabal/pkgs/tools.config+ import: ./project-cabal/pkgs/db.config+ import: ./project-cabal/pkgs/server.config+ ```+++```cabal+-- ./ghc-x.y.z.dhall2config.project+import: ./project-stackage/lts-m.n.config++import: ./project-cabal/pkgs.config++import: ./project-cabal/ghc-x.y.z/constraints.config+import: ./project-cabal/ghc-x.y.z/deps-external.config+import: ./project-cabal/ghc-x.y.z/deps-internal.config+import: ./project-cabal/ghc-x.y.z/forks-external.config+import: ./project-cabal/ghc-x.y.z/forks-internal.config+```++# Upgrading a Project++### GHC Upgrade+For a GHC compiler upgrade, add another folder to `project-dhall` for the+upgrade from `ghc-u.v.w` to `ghc-x.y.z`:++```+project-dhall+├── ghc-u.v.w+├── ghc-x.y.z+├── pkgs+├── pkg-groups.dhall ▨ List Text+└── pkgs-upgrade-todo.dhall ▨ List Text+```++At the start of a GHC upgrade put all packages into+`project-dhall/pkgs-upgrade-todo.dhall`. As the upgrade progresses remove+packages from this list as you work on them.++### Constraint Upgrade+For a dependency version upgrade, add or change an entry in `constraints.dhall`+and if that dependency is on stackage for the resolver we're using and if the+version there differs then comment out that entry in the downloaded+`project-stackage/resolver-name.config` file to avoid impossible constraint+solving conflicts with cabal.++### Source Repository Upgrade+For a source repository upgrade, bump the `tag` field if picking up a newer+version.++If the `tag` you were on has been superseded by a published version then delete+the entry and add a constraint unless the published version is already a match+in the downloaded `cabal.config` file from stackage.++### Adding a Fork+If you are forking then you'll want to add a record to `fork-internal.dhall` and+then:+- If forking a stackage package: comment out the entry in the downloaded `cabal.config`+- If forking a hackage package: delete the matching entry in `constraints.dhall`++Using someone else's fork is the same except add the record to+`fork-external.dhall`.++Unforking goes the other way, remove the `fork-*.dhall` entry and either+fallback to the stackage version or another version for which you'll add an+entry in `constraints.dhall`.++# Getting Started++Dhall is a prerequisite.++As well as other make targets, updo can bootstrap itself by adding one of two+recipes to `project-files.mk`:++```make+UPDO_VERSION ?= 1.0.0+HACKAGE := http://hackage.haskell.org/package+UPDO_URL := ${HACKAGE}/updo-${UPDO_VERSION}/updo-${UPDO_VERSION}.tar.gz+```++1. When opting for the scripts:++```make+updo/Makefile:+ rm -rf updo+ curl -sSL ${UPDO_URL} | tar -xz+ mv updo-* updo+ chmod +x $$(grep -RIl '^#!' updo)+```++2. When opting to install the included executables:++```make+updo/Makefile:+ rm -rf updo+ curl -sSL ${UPDO_URL} | tar -xz+ cd updo-${UPDO_VERSION}+ stack install+ cd -+ mv updo-* updo+```++Instead of curl and tar, `cabal get` or `stack unpack` can unpack package sources.++# Make Targets++In the root of your project, add two files.++```+.+├── project-files.mk+└── project-versions.mk+```++In `project-versions.mk` set variables for GHC and STACKAGE.++```make+GHC_VERSION := u.v.w+GHC_UPGRADE := x.y.z+STACKAGE_VERSION := lts-j.k+STACKAGE_UPGRADE := lts-m.n+```++Here is a basic set up for `project-files.mk`:++```make+include project-versions.mk+include updo/Makefile+```++### Canonical Targets++We consider the following as canonical project names and no target is required+to build them (they're built by the default `all` target):++```+$ make -f project-files.mk+```++- `stack.yaml`+- `cabal.project`+- `stack.upgrade.yaml`+- `cabal.upgrade.project`++We use CABAL_VIA and STACK_VIA makefile variables to decide which `ghc-x.y.z`+prefixed projects will be copied to the default project names (`cabal.project`+and `stack.yaml`). This way, Updo will create a single pair of projects for one+version of GHC.++### GHC-Prefixed Targets++We can build `ghc-x.y.z` projects explicitly:++```+$ make -f project-files.mk ghc-x.y.z.dhall2config.project+$ make -f project-files.mk ghc-x.y.z.dhall2cabal.project+$ make -f project-files.mk ghc-x.y.z.dhall2stack.yaml+```++### Modified Time Travel++Be careful with modified time that make relies on. If you hand-modify a target+so that it is newer than a prerequisite then make will not use its recipe to+build the target. This is easy to do inadvertently with a git GUI tool when+discarding changes or by doing a `git restore <project-name>`. As git advances+the modified time, this is effectively the same as `touch <project-name>`. To+recover from this situation, either;+- Remove the target with `rm <project-name>`.+- Run make with its `--always-make` flag but be careful with this if+ bootstrapping updo itself within the makefile.++### Lock Files++For stack, the project and its lock are separate targets (`.yaml` and+`.yaml.lock`).++```+$ make -f project-files.mk ghc-x.y.z.dhall2stack.yaml+dhall text --file project-dhall/ghc-x.y.z/project-stack.dhall > ghc-x.y.z.dhall2stack.yaml+```++```+$ make -f project-files.mk ghc-x.y.z.dhall2stack.yaml.lock+stack build --dry-run --stack-yaml ghc-x.y.z.dhall2stack.yaml+```++We don't provide a make target for cabal `.project.freeze` files, relying+instead on a combination of constraints, those in the `cabal.config` downloaded+from stackage and those we add ourselves to `constraints.dhall`. If you do want+to freeze anyway there's a cabal command to generate a freeze file.++```+$ make -f project-files.mk ghc-x.y.z.dhall2cabal.project+dhall text --file project-dhall/ghc-x.y.z/project-cabal.dhall > ghc-x.y.z.dhall2cabal.project+```++# Clean GHC-Prefixed Projects++There's a make target to remove all `ghc-x.y.z` prefixed projects:++```+$ make -f project-files.mk clean+rm -f ghc-*.stack.* ghc-*.dhall2config.* ghc-*.dhall2cabal.* ghc-*.dhall2stack.*+ghc-*.stack2cabal.* ghc-*.cabal2stack.* ghc-*.dhall2yaml2stack.* ghc-*.sha256map.nix+```++# GHC-Prefixed Projects as Temporary++To treat `ghc-x.y.z` prefixed files as temporary, add lines like these to+`project-files.mk`:++```make+.INTERMEDIATE: ghc-$(GHC_VERSION).dhall2config.project+.INTERMEDIATE: ghc-$(GHC_VERSION).dhall2cabal.project+.INTERMEDIATE: ghc-$(GHC_VERSION).dhall2stack.yaml+.INTERMEDIATE: ghc-$(GHC_VERSION).sha256map.nix+```++# SHA256 Map Generation Method++With this snippet from `project-files.mk`, we can switch between two methods of+generating `ghc-x.y.z.sha256map.nix`.++```make+# How to generate project-nix/ghc-$(GHC_VERSION)/sha256map.nix?+# This is copied from ghc-$(GHC_VERSION).sha256map.nix.+# - false to generate from *.dhall inputs via sha256map.hs.+# - true to generate from stack.yaml via sha256map.py.+SHA256MAP_VIA_PYTHON ?= false++# If true, generate the sha256map from the stack.yaml with python,+# overriding the recipe for this target.+ifeq ($(SHA256MAP_VIA_PYTHON), true)+ghc-$(GHC_VERSION).sha256map.nix: stack.yaml+ updo/project-nix/sha256map.py <$^ >$@+endif+```++The default is to use the `sha256map.hs` script to generate+it[^replacing_versions]:++[^replacing_versions]: Using ghc-x.y.z and lts-m.n in the example output, not+ the actual GHC version or resolver.++```+$ make -f project-files.mk ghc-x.y.z.sha256map.nix+echo \+ '[./project-dhall/ghc-x.y.z/deps-external.dhall+ , ./project-dhall/ghc-x.y.z/deps-internal.dhall+ , ./project-dhall/ghc-x.y.z/forks-external.dhall+ , ./project-dhall/ghc-x.y.z/forks-internal.dhall+ , ([] : List {loc : Text, tag : Text, sub : List Text})+ ]' \+ | ./updo/project-nix/sha256map.hs > ghc-x.y.z.sha256map.nix+```++To use the `sha256map.py` script instead that is much slower:++```+$ SHA256MAP_VIA_PYTHON=true \+ make -f project-files.mk project-nix/ghc-x.y.z/sha256map.nix+updo/project-nix/sha256map.py <stack.yaml >ghc-x.y.z.sha256map.nix+mkdir -p project-nix/ghc-x.y.z && cp ghc-x.y.z.sha256map.nix project-nix/ghc-x.y.z/sha256map.nix+rm ghc-x.y.z.sha256map.nix++```++You can [read more about Updo Nix](project-nix#readme) and its use with+haskell.nix.++# Installed Exes or Scripts++To use the executables of Updo's own package, by default, instead of its+scripts, add these lines to `project-files.mk`:++```make+SHA256MAP_HS_EXE ?= true+PKG_GROUPS_HS_EXE ?= true+PKGS_SORTED_HS_EXE ?= true+PKGS_UPGRADE_DONE_HS_EXE ?= true+```++### Why Dhall for Configuration?++Dhall has excellent imports and is an intentionally limited typed programming+language. We use dhall's `text` command to write cabal and stack projects using+[dhall text templating][dhall-text-templating].++The `dhall` executable comes with a `format` command[^format-lsp]. This helps in+the maintenance of the various `.dhall` files.++An example of the limits of the language we encountered in Updo is not being+able to compare anything but `Natural` values. Sorting something like `List+Text` is not possible but there is great interop with Haskell so this can be+done over there as we do with scripts.++## Acknowledgements++I already knew Dhall well from maintaining hpack-dhall. Thanks Simon Hengel for+suggesting I take over its maintenance.++FP Complete is the corporate sponsor of this tooling. Thanks to my collegues;+Daniel Herrera Rendón for first seeing this could work, Neil Mayhew for makefile+tips and tricks, Abel Sen for careful reviews and thoughtful suggestions and+Eduardo Lemos Rocha for advocacy and enthusiasm.++Please contact me for any questions, problems, suggestions or the like.+Maintenance of Updo will be coming from me and not FP Complete.++Updo grew to fill a need after every other way I could find to maintain projects+was unsatisfactory for the specific problem I had, herding hundreds of packages+and their dependencies into buildable projects over two compiler versions for+both cabal and stack. The more I use it, the more I love it as a fast, simple+and appropriate solution for maintaining Haskell projects.++Thanks FP Complete.++[^format-lsp]: Formatting is also available with the [Dhall LSP Server][LSP].++[dhall-text-templating]: https://www.haskellforall.com/2017/06/dhall-is-now-template-engine.html+[LSP]: https://github.com/PanAeon/vscode-dhall-lsp-server
+ TEMPLATES.md view
@@ -0,0 +1,21 @@+# Dhall Text Templates++We use Dhall text templates in `project-dhall/ghc-x.y.z/text-templates`:++- From template `dhall2cabal.dhall`, we generate `ghc-x.y.z.dhall2cabal.project`+- From template `dhall2stack.dhall`, we generate `ghc-x.y.z.dhall2stack.yaml`++Dhall text templating was+[announced](https://www.haskellforall.com/2017/06/dhall-is-now-template-engine.html)+in June 2017 and this is now a command of the dhall executable:++```+$ dhall text --help`+Usage: dhall text [--file FILE] [--output FILE]+ Render a Dhall expression that evaluates to a Text literal++Available options:+ --file FILE Read expression from a file instead of standard input+ --output FILE Write result to a file instead of standard output+ -h,--help Show this help text+```
+ TESTING.md view
@@ -0,0 +1,185 @@+# Testing Updo++Assuming this layout of make files in updo and at the root of your project.++```+├── updo+│ ├── Makefile+│ ├── project-dhall+│ │ └── Makefile+│ ├── project-dhall2config+│ │ ├── Makefile+│ └── project-nix+│ └── Makefile+├── project-files.mk+└── project-versions.mk+```++We'll need some versions, something like:++```+$ cat project-versions.mk +# Versions of GHC and stackage resolver, the ones we're on and the next ones+# we're upgrading to.+GHC_VERSION := 8.10.7+GHC_UPGRADE := 9.2.5+STACKAGE_VERSION := lts-18.27+STACKAGE_UPGRADE := lts-20.5+```++We'll need to set up our `project-files.mk`:++```make+# How to generate project-nix/ghc-$(GHC_VERSION)/sha256map.nix?+# This is copied from ghc-$(GHC_VERSION).sha256map.nix.+# - false to generate from *.dhall inputs via sha256map.hs.+# - true to generate from stack.yaml via sha256map.py.+SHA256MAP_VIA_PYTHON := false++include project-versions.mk+include updo/Makefile++project-nix/ghc-%/sha256map.nix: ghc-%.sha256map.nix+ mkdir -p $(@D) && cp $^ $@++.PHONY: all+all: \+ projects \+ project-nix/ghc-$(GHC_VERSION)/sha256map.nix++# To make stack.yaml or cabal.project and no other, mark the file we copy from+# as intermediate. This is all we want when not doing a GHC upgrade.+#+# Comment out these .INTERMEDIATE targets to allow these files to be kept.+.INTERMEDIATE: ghc-$(GHC_VERSION).$(CABAL_VIA).project+.INTERMEDIATE: ghc-$(GHC_UPGRADE).$(CABAL_VIA).project+.INTERMEDIATE: ghc-$(GHC_VERSION).$(STACK_VIA).yaml+.INTERMEDIATE: ghc-$(GHC_UPGRADE).$(STACK_VIA).yaml+.INTERMEDIATE: ghc-$(GHC_VERSION).sha256map.nix+.INTERMEDIATE: ghc-$(GHC_UPGRADE).sha256map.nix++# Alternative targets for generating project files (not recommended):+# - ghc-x.y.z.stack2cabal.project+# - ghc-x.y.z.cabal2stack.yaml+# - ghc-x.y.z.dhall2yaml2stack.yaml+include updo/alternatives/cabal2stack/Makefile+include updo/alternatives/stack2cabal/Makefile+include updo/alternatives/yaml2stack/Makefile++# If true, generate the sha256map from the stack.yaml with python,+# overriding the recipe for this target.+ifeq ($(SHA256MAP_VIA_PYTHON), true)+ghc-$(GHC_VERSION).sha256map.nix: stack.yaml+ updo/project-nix/sha256map.py <$^ >$@+ghc-$(GHC_UPGRADE).sha256map.nix: stack.yaml+ updo/project-nix/sha256map.py <$^ >$@+endif++.DEFAULT_GOAL := all+```++## Default Targets++The default targets are `stack.yaml` and `cabal.project`.++* [ ] Can we build just those without leaving behind[^check-temp-files] any+ temporary files?++[^check-temp-files]: You could check for unwanted files with `git status`.++```+$ make -f project-files.mk all --always-make+$ make -f project-files.mk all+```++## All Possible Targets++Comment out the `.INTERMEDIATE` targets in `project-files.mk` and then:++```+$ make -f project-files.mk all-possible-projects --always-make --jobs+```++* [ ] Does this make two sets of each of the following?++- `ghc-x.y.z.dhall2cabal.project`+- `ghc-x.y.z.dhall2config.project`+- `ghc-x.y.z.dhall2stack.yaml`+- `ghc-x.y.z.dhall2stack.yaml.lock`+- `ghc-x.y.z.sha256map.nix`++## Clean++* [ ] After making `all-possible-projects`, can we clean all of these?++```+$ make -f project-files.mk clean+```++## SHA Map Targets++* [ ] Can we build `ghc-x.y.z.sha256map.nix`?++```+$ make -f project-files.mk project-sha256maps+```++Try again flipping the sense of the variable SHA256MAP_VIA_PYTHON or by setting+it on the command line:++```+$ make -f project-files.mk ghc-x.y.z.sha256map.nix --always-make SHA256MAP_VIA_PYTHON=true+```++* [ ] Is it generating maps using another script, the Python one instead of the Haskell one?+* [ ] Are the entries in the generated map sorted in both cases?++This should make two of `ghc-x.y.z.sha256map.nix`[^version_only]. You might like to use those+file names as targets explicitly.++[^version_only]: For now we only provide the option to pick which script to use+ to generate `ghc-$(GHC_VERSION).sha256map.nix`. The+ `ghc-$(GHC_UPGRADE).sha256map.nix` is only ever generated using the Haskell+ script.++## Sorting Packages Works++We need to run a Haskell script to generate `.updo/pkgs-sorted.dhall`. After a+cabal clean, this script will need to download dependencies.++* [ ] Can it do that without polluting the generated file with status updates from cabal saying+ that it has downloaded this or that dependency[^silent-script]?+ +[^silent-script]: The Haskell script must run silently for this to work.++```+$ cabal clean+$ make -f project-files.mk pkgs-sorted --always-make+updo/project-dhall/pkgs-sorted.hs > .updo/pkgs-sorted.dhall+```++## Upgrade Packages Done Works++Generated files, not for source control are written to `.updo`.++* [ ] Can we generate `.updo/pkgs-upgrade-done.dhall`?+* [ ] Does adding or removing packages from+ `project-dhall/pkgs-upgrade-todo.dhall` change the list of packages in+ `.updo/pkgs-upgrade-done.dhall`?++```+$ make -f project-files.mk pkgs-upgrade-done --always-make+updo/project-dhall/pkgs-sorted.hs > .updo/pkgs-sorted.dhall+./updo/project-dhall/pkgs-upgrade-done.hs \+ ./.updo/pkgs-sorted.dhall \+ ./project-dhall/pkgs-upgrade-todo.dhall \+ > .updo/pkgs-upgrade-done.dhall+```++## Alternative Targets++* [ ] Can we build these targets?++- `ghc-x.y.z.dhall2yaml2stack.yaml`+- `ghc-x.y.z.stack2cabal.project`+- `ghc-x.y.z.cabal2stack.yaml`
+ alternatives/cabal2stack/Makefile view
@@ -0,0 +1,19 @@+.PHONY: cabal2stack-projects+cabal2stack-projects: \+ ghc-$(GHC_VERSION).cabal2stack.yaml \+ ghc-$(GHC_VERSION).cabal2stack.yaml.lock \+ ghc-$(GHC_UPGRADE).cabal2stack.yaml \+ ghc-$(GHC_UPGRADE).cabal2stack.yaml.lock++ghc-$(GHC_VERSION).cabal2stack.yaml: ghc-$(GHC_VERSION).$(CABAL_VIA).project+ rm -rf dist-newstyle/cache+ cabal build all --enable-tests --project-file=$< --dry-run+ cabal2stack --resolver=$(STACKAGE_VERSION) --allow-newer --output $@ --plan-json dist-newstyle/cache/plan.json++ghc-$(GHC_UPGRADE).cabal2stack.yaml: ghc-$(GHC_UPGRADE).$(CABAL_VIA).project+ rm -rf dist-newstyle/cache+ cabal build all --enable-tests --project-file=$< --dry-run+ cabal2stack --resolver=$(STACKAGE_UPGRADE) --allow-newer --output $@ --plan-json dist-newstyle/cache/plan.json++ghc-%.cabal2stack.yaml.lock: ghc-%.cabal2stack.yaml+ stack build --test --no-run-tests --bench --no-run-benchmarks --dry-run --stack-yaml $<
+ alternatives/cabal2stack/README.md view
@@ -0,0 +1,4 @@+# Updo Cabal2Stack++Using [cabal2stack](https://github.com/iconnect/cabal2stack), the `Makefile` has+targets for `ghc-x.y.z.cabal2stack.yaml` and its `.lock` file.
+ alternatives/stack2cabal/Makefile view
@@ -0,0 +1,12 @@+.PHONY: stack2cabal-projects+stack2cabal-projects: \+ ghc-$(GHC_VERSION).stack2cabal.project \+ ghc-$(GHC_UPGRADE).stack2cabal.project++ghc-$(GHC_VERSION).stack2cabal.project: ghc-$(GHC_VERSION).$(STACK_VIA).yaml+ stack2cabal --file $< --output-file $@++ghc-$(GHC_UPGRADE).stack2cabal.project: ghc-$(GHC_UPGRADE).$(STACK_VIA).yaml+ stack2cabal --file $< --output-file $@++ghc-%.stack2cabal.project.freeze: ghc-%.stack2cabal.project
+ alternatives/stack2cabal/README.md view
@@ -0,0 +1,4 @@+# Updo Stack2Cabal++Using [stack2cabal](https://github.com/hasufell/stack2cabal), the `Makefile` has+targets for `ghc-x.y.z.stack2cabal.project`.
+ alternatives/yaml2stack/Makefile view
@@ -0,0 +1,74 @@+# When the prerequisites are a function and a list, we echo a dhall expression+# that calls this function with the list. Both function and list are in dhall+# files that must be ./ prefixed to be imported into the expression.+#+# $(^:%=./%) does the ./ prefixing that dhall needs to recognize the imports.+#+# "The import resolution phase replaces all imports with the expression located+# at that import, transitively resolving imports within the imported expression+# if necessary."+# SOURCE:https://github.com/dhall-lang/dhall-lang/blob/master/standard/imports.md#import-resolution-judgment++UPDO_TMP := .updo+Y2S_TMP := $(UPDO_TMP)/dhall2yaml2stack++.PHONY: dhall2yaml2stack-projects+dhall2yaml2stack-projects: \+ ghc-$(GHC_VERSION).dhall2yaml2stack.yaml \+ ghc-$(GHC_VERSION).dhall2yaml2stack.yaml.lock \+ ghc-$(GHC_UPGRADE).dhall2yaml2stack.yaml \+ ghc-$(GHC_UPGRADE).dhall2yaml2stack.yaml.lock++.INTERMEDIATE: $(Y2S_TMP)/ghc-$(GHC_VERSION)/base.yaml+$(Y2S_TMP)/ghc-$(GHC_VERSION)/base.yaml: \+ project-dhall/ghc-$(GHC_VERSION)/text-templates/stacksnippet.dhall+ mkdir -p $(@D) && echo '$(<:%=./%) (Some "$(STACKAGE_VERSION)" : Optional Text)' | dhall text --output $@++.INTERMEDIATE: $(Y2S_TMP)/ghc-$(GHC_UPGRADE)/base.yaml+$(Y2S_TMP)/ghc-$(GHC_UPGRADE)/base.yaml: \+ project-dhall/ghc-$(GHC_UPGRADE)/text-templates/stacksnippet.dhall+ mkdir -p $(@D) && echo '$(<:%=./%) (Some "$(STACKAGE_UPGRADE)" : Optional Text)' | dhall text --output $@++# Mirror pkgs from dhall to yaml.+.INTERMEDIATE: $(Y2S_TMP)/ghc-$(GHC_VERSION)/pkgs.yaml+$(Y2S_TMP)/ghc-$(GHC_VERSION)/pkgs.yaml: \+ updo/text-templates/yaml2stack/pkgs.dhall \+ $(UPDO_TMP)/pkgs-sorted.dhall+ echo "$(^:%=./%)" | dhall text --output $@++.INTERMEDIATE: $(Y2S_TMP)/ghc-$(GHC_UPGRADE)/pkgs.yaml+$(Y2S_TMP)/ghc-$(GHC_UPGRADE)/pkgs.yaml: \+ updo/text-templates/yaml2stack/pkgs.dhall \+ $(UPDO_TMP)/pkgs-upgrade-done.dhall+ echo "$(^:%=./%)" | dhall text --output $@++# Mirror constraints from dhall to yaml.+$(Y2S_TMP)/ghc-%/constraints.yaml: \+ updo/text-templates/yaml2stack/constraints.dhall \+ project-dhall/ghc-%/constraints.dhall+ echo "$(^:%=./%)" | dhall text --output $@++# Mirror source repositories from dhall to yaml.+$(Y2S_TMP)/ghc-%.yaml: \+ updo/text-templates/yaml2stack/repo-items.dhall \+ project-dhall/ghc-%.dhall+ echo "$(^:%=./%)" | dhall text --output $@++# Join the YAML fragments into a single file, the stack project.+ghc-%.dhall2yaml2stack.yaml: \+ $(Y2S_TMP)/ghc-%/base.yaml \+ $(Y2S_TMP)/ghc-%/pkgs.yaml \+ $(Y2S_TMP)/ghc-%/constraints.yaml \+ $(Y2S_TMP)/ghc-%/deps-external.yaml \+ $(Y2S_TMP)/ghc-%/deps-internal.yaml \+ $(Y2S_TMP)/ghc-%/forks-external.yaml \+ $(Y2S_TMP)/ghc-%/forks-internal.yaml \+ updo/alternatives/yaml2stack/join-sort-fragments.sh+ ./updo/alternatives/yaml2stack/join-sort-fragments.sh $(<D) >$@++ghc-%.dhall2yaml2stack.yaml.lock: ghc-%.dhall2yaml2stack.yaml+ stack build --test --no-run-tests --bench --no-run-benchmarks --dry-run --stack-yaml $<++# To keep dhall to yaml intermediate files, uncomment the following (no need to+# comment out the .INTERMEDIATE lines above):+# .SECONDARY: $(wildcard $(Y2S_TMP)/*.yaml)
+ alternatives/yaml2stack/README.md view
@@ -0,0 +1,13 @@+# Updo Dhall2Yaml2Stack++The `Makefile` has targets for `ghc-x.y.z.dhall2yaml2stack.yaml` and its `.lock`+file.++The `.dhall` files are mirrored to `.yaml` files[^working-dir] followed by a very lightweight+stitching together of these fragments with+[yq](https://mikefarah.gitbook.io/yq/), removing comments and sorting+dependencies.++[^working-dir]: The `.yaml` fragments are written to `.updo/dhall2yaml2stack`,+copied to a bash `$(mktemp -d)` temporary directory and then stitched together+there. There's a note in the make file explaining how to keep these fragments.
+ alternatives/yaml2stack/join-sort-fragments.sh view
@@ -0,0 +1,26 @@+#!/bin/sh+set -eu++WORKDIR=$(mktemp -d)+trap 'rm -rf "$WORKDIR"' EXIT++cd "$1"++for f in *.yaml+do+ cp "$PWD/${f}" "$WORKDIR/${f}"+done++cd "$WORKDIR"+for f in *.yaml+do+ yq '... comments=""' --inplace --prettyPrint "${f}"+done++yq '.extra-deps |= sort' --inplace constraints.yaml+yq '.packages |= sort_by(sub("\/", ""))' --inplace pkgs.yaml+yq '.extra-deps |= sort_by(.git | sub("(.*\.com:|.*\.com\/)(.+$)", "$2"))' --inplace deps-external.yaml+yq '.extra-deps |= sort_by(.git | sub("(.*\.com:|.*\.com\/)(.+$)", "$2"))' --inplace deps-internal.yaml+yq '.extra-deps |= sort_by(.git | sub("(.*\.com:|.*\.com\/)(.+$)", "$2"))' --inplace forks-external.yaml+yq '.extra-deps |= sort_by(.git | sub("(.*\.com:|.*\.com\/)(.+$)", "$2"))' --inplace forks-internal.yaml+yq eval-all '. as $item ireduce ({}; . *+ $item )' base.yaml pkgs.yaml deps-external.yaml deps-internal.yaml forks-external.yaml forks-internal.yaml constraints.yaml
+ package.dhall view
@@ -0,0 +1,34 @@+{ name = "updo"+, version = "1.0.0"+, synopsis = "A style of maintaining and upgrading Haskell projects"+, description =+ ''+ From configuration in .dhall, generate projects (stack.yaml and+ cabal.project) and progressively upgrade projects.+ ''+, category = "Development"+, github = "cabalism/updo"+, author = "Phil de Joux"+, maintainer = "phil.dejoux@blockscope.com"+, copyright = "© 2023 Phil de Joux, © 2023 Block Scope Limited"+, tested-with =+ [ "GHC == 8.6.5", "GHC == 8.10.7", "GHC == 9.2.8", "GHC == 9.4.5" ]+, extra-source-files =+ [ "**/*.md", "**/*.dhall", "**/Makefile", "**/*hs", "**/*.py", "**/*.sh" ]+, dependencies =+ [ "aeson >= 2.1.2 && <2.2"+ , "base >=4.12 && <5"+ , "dhall >= 1.41.1 && <1.42"+ , "filepath >= 1.4.2 && <1.5"+ , "text >= 1.2.3 && <2.1"+ , "turtle >= 1.6.1 && <1.7"+ , "utf8-string >= 1.0.2 && <1.1"+ ]+, executables =+ { updo-pkgs-sorted.main = "project-dhall/pkgs-sorted.hs"+ , updo-pkgs-upgrade-done.main = "project-dhall/pkgs-upgrade-done.hs"+ , updo-pkgs-upgrade-partition.main = "project-dhall/pkgs-upgrade-partition.hs"+ , updo-pkg-groups.main = "project-dhall2config/pkg-groups.hs"+ , updo-sha256map.main = "project-nix/sha256map.hs"+ }+}
+ project-dhall/Makefile view
@@ -0,0 +1,76 @@+UPDO_TMP := ./.updo++ifeq ($(PKGS_SORTED_HS_EXE), true)+PKGS_SORTED_HS := updo-pkgs-sorted+else+PKGS_SORTED_HS := ./updo/project-dhall/pkgs-sorted.hs+endif++ifeq ($(PKGS_UPGRADE_DONE_HS_EXE), true)+PKGS_UPGRADE_DONE_HS := updo-pkgs-upgrade-done+else+PKGS_UPGRADE_DONE_HS := ./updo/project-dhall/pkgs-upgrade-done.hs+endif++.PHONY: dhall2stack-projects+dhall2stack-projects: \+ ghc-$(GHC_VERSION).dhall2stack.yaml \+ ghc-$(GHC_VERSION).dhall2stack.yaml.lock \+ ghc-$(GHC_UPGRADE).dhall2stack.yaml \+ ghc-$(GHC_UPGRADE).dhall2stack.yaml.lock \++.PHONY: dhall2cabal-projects+dhall2cabal-projects: \+ ghc-$(GHC_VERSION).dhall2cabal.project \+ ghc-$(GHC_UPGRADE).dhall2cabal.project++.PHONY: pkgs-sorted+pkgs-sorted: $(UPDO_TMP)/pkgs-sorted.dhall++.PHONY: pkgs-upgrade-done+pkgs-upgrade-done: $(UPDO_TMP)/pkgs-upgrade-done.dhall++$(UPDO_TMP)/pkgs-sorted.dhall: \+ project-dhall/pkg-groups.dhall \+ project-dhall/pkgs/*.dhall+ mkdir -p $(@D) && $(PKGS_SORTED_HS) > $@++$(UPDO_TMP)/pkgs-upgrade-done.dhall: \+ project-dhall/pkgs/*.dhall \+ $(UPDO_TMP)/pkgs-sorted.dhall \+ project-dhall/pkgs-upgrade-todo.dhall+ ./updo/project-dhall/pkgs-upgrade-done.hs \+ ./$(UPDO_TMP)/pkgs-sorted.dhall \+ ./project-dhall/pkgs-upgrade-todo.dhall \+ > $@++ghc-$(GHC_VERSION).dhall2stack.yaml: \+ project-dhall/ghc-$(GHC_VERSION)/text-templates/dhall2stack.dhall \+ $(UPDO_TMP)/pkgs-sorted.dhall \+ project-dhall/ghc-$(GHC_VERSION)/*.dhall \+ updo/text-templates/stack/*.dhall+ echo './$< ./$(UPDO_TMP)/pkgs-sorted.dhall "$(STACKAGE_VERSION)"' | dhall text --output $@++ghc-$(GHC_UPGRADE).dhall2stack.yaml: \+ project-dhall/ghc-$(GHC_UPGRADE)/text-templates/dhall2stack.dhall \+ $(UPDO_TMP)/pkgs-upgrade-done.dhall \+ project-dhall/ghc-$(GHC_UPGRADE)/*.dhall \+ updo/text-templates/stack/*.dhall+ echo './$< ./$(UPDO_TMP)/pkgs-upgrade-done.dhall "$(STACKAGE_UPGRADE)"' | dhall text --output $@++ghc-$(GHC_VERSION).dhall2cabal.project: \+ project-dhall/ghc-$(GHC_VERSION)/text-templates/dhall2cabal.dhall \+ $(UPDO_TMP)/pkgs-sorted.dhall \+ project-dhall/ghc-$(GHC_VERSION)/*.dhall \+ updo/text-templates/cabal/*.dhall+ echo './$< ./$(UPDO_TMP)/pkgs-sorted.dhall "$(STACKAGE_VERSION)"' | dhall text --output $@++ghc-$(GHC_UPGRADE).dhall2cabal.project: \+ project-dhall/ghc-$(GHC_UPGRADE)/text-templates/dhall2cabal.dhall \+ $(UPDO_TMP)/pkgs-upgrade-done.dhall \+ project-dhall/ghc-$(GHC_UPGRADE)/*.dhall \+ updo/text-templates/cabal/*.dhall+ echo './$< ./$(UPDO_TMP)/pkgs-upgrade-done.dhall "$(STACKAGE_UPGRADE)"' | dhall text --output $@++ghc-%.dhall2stack.yaml.lock: ghc-%.dhall2stack.yaml+ stack build --test --no-run-tests --bench --no-run-benchmarks --dry-run --stack-yaml $<
+ project-dhall/README.md view
@@ -0,0 +1,7 @@+# Updo Dhall++The `Makefile` has targets for stack and cabal projects generated using Dhall+text templating:++* `ghc-x.y.z.dhall2stack.yaml`+* `ghc-x.y.z.dhall2cabal.project`
+ project-dhall/pkgs-sorted.hs view
@@ -0,0 +1,27 @@+#!/usr/bin/env stack+-- stack script --resolver=lts-18.27 --package=base --package=dhall --package=filepath --package=text+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Description: Sorts packages as a flat list.+module Main where++import Data.List (concat, sortOn)+import qualified Data.Text as T (filter, pack)+import qualified Data.Text.IO as T (putStrLn)+import Dhall (Text, auto, embed, inject, input)+import Dhall.Core (pretty)+import System.FilePath ((<.>), (</>))++grab :: String -> IO [Text]+grab name = input auto (T.pack $ "./project-dhall/pkgs" </> name <.> "dhall")++main :: IO ()+main = do+ pkgGroups :: [String] <- input auto "./project-dhall/pkg-groups.dhall"+ xs <- traverse grab pkgGroups+ -- Package items are (usually in this project) paths to folders containing a+ -- .cabal file. These aren't canonical so may or may not have a trailing+ -- slash. To sort them consistently, we filter out the slashes.+ let sortedPkgPaths = sortOn (T.filter (/= '/')) $ concat xs+ T.putStrLn . pretty $ embed inject sortedPkgPaths
+ project-dhall/pkgs-upgrade-done.hs view
@@ -0,0 +1,20 @@+#!/usr/bin/env stack+-- stack script --resolver=lts-18.27 --package=base --package=dhall --package=text+{-# LANGUAGE ScopedTypeVariables #-}++-- | Description: The difference between all packages and those in the todo+-- list, the packgaes that have been upgraded.+module Main where++import Data.List ((\\))+import qualified Data.Text as T (pack)+import qualified Data.Text.IO as T (putStrLn)+import Dhall (Text, auto, embed, inject, input)+import Dhall.Core (pretty)+import System.Environment (getArgs)++main = do+ sortedFile : todoFile : _ <- getArgs+ sorted :: [Text] <- input auto (T.pack sortedFile)+ todo :: [Text] <- input auto (T.pack todoFile)+ T.putStrLn . pretty $ embed inject (sorted \\ todo)
+ project-dhall/pkgs-upgrade-partition.hs view
@@ -0,0 +1,34 @@+#!/usr/bin/env stack+-- stack script --resolver=lts-18.27 --package=base --package=dhall --package=text+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Description: Partition the packages into those that have been upgraded and+-- those that have not.+module Main where++import Data.List (intersect, (\\))+import qualified Data.Text as T (pack)+import qualified Data.Text.IO as T (putStrLn)+import Dhall (FromDhall, Generic, Text, ToDhall, auto, embed, inject, input)+import Dhall.Core (pretty)+import System.Environment (getArgs)++data PkgUpgrade = PkgUpgrade+ { pkgs :: [Text]+ , done :: [Text]+ , todo :: [Text]+ }+ deriving (Show, Generic, ToDhall, FromDhall)++main :: IO ()+main = do+ file : _ <- getArgs+ pkgs :: [Text] <- input auto (T.pack file)+ remaining :: [Text] <- input auto "./project-dhall/pkgs-upgrade-todo.dhall"+ let todo = pkgs `intersect` remaining+ let done = pkgs \\ todo+ T.putStrLn . pretty $ embed inject PkgUpgrade{..}
+ project-dhall/pkgs-upgrade.dhall view
@@ -0,0 +1,65 @@+-- NOTE: With cabal-3.10, imports are relative to each other but imported+-- packages are not, they are still relative to the project root. With+-- cabal-3.8, the first version with imports, imports are relative to the+-- project root too.+let TYPES = ../types.dhall++in \(pkg-import : TYPES.CabalRelativity) ->+ \(ghc-version : Text) ->+ \(ghc-upgrade : Text) ->+ \(x : { pkgs : List Text, done : List Text, todo : List Text }) ->+ let N = https://prelude.dhall-lang.org/Natural/package.dhall++ let L = https://prelude.dhall-lang.org/List/package.dhall++ let concatMapSep = https://prelude.dhall-lang.org/Text/concatMapSep++ let relativePkg =+ merge+ { CabalProjectRelative = \(s : Text) -> "./${s}"+ , CabalImportRelative = \(s : Text) -> "./${s}"+ }+ pkg-import++ let pkgList =+ \(indent : Text) ->+ \(xs : List Text) ->+ concatMapSep+ ''++ ${indent}, ''+ Text+ relativePkg+ xs++ let pkgListComment =+ \(xs : List Text) ->+ concatMapSep "\n" Text (\(s : Text) -> "-- ${relativePkg s}") xs++ in if L.null Text x.todo+ || N.equal (L.length Text x.pkgs) (L.length Text x.done)+ then ''+ packages:+ ${pkgList " " x.pkgs}+ ''+ else ''+ if impl(ghc <= ${ghc-version})+ packages:+ ${pkgList " " x.pkgs}+ ''+ ++ ( if L.null Text x.done+ then ""+ else ''+ else+ packages:+ ${pkgList " " x.done}+ ''+ )+ ++ ( if L.null Text x.done+ then ""+ else ''++ -- TODO for impl(ghc >= ${ghc-upgrade})+ ${pkgListComment x.todo}+ ''+ )
+ project-dhall2config/Makefile view
@@ -0,0 +1,75 @@+ifeq ($(PKG_GROUPS_HS_EXE), true)+PKG_GROUPS_HS := updo-pkg-groups+else+PKG_GROUPS_HS := ./updo/project-dhall2config/pkg-groups.hs+endif++.PHONY: dhall2config-projects+dhall2config-projects: \+ ghc-$(GHC_VERSION).dhall2config.project \+ ghc-$(GHC_UPGRADE).dhall2config.project++project-cabal/pkgs.config: \+ updo/text-templates/cabal/pkg-groups.dhall \+ project-dhall/pkg-groups.dhall \+ $(patsubst project-dhall/pkgs/%.dhall, project-cabal/pkgs/%.config, $(wildcard project-dhall/pkgs/*.dhall))+ ifeq ($(CABAL_RELATIVITY), ImportRelative)+ echo 'let f = ./updo/types/CabalRelativity.dhall in ./$< f.CabalImportRelative ./project-dhall/pkg-groups.dhall' | dhall text --output $@+ else+ echo 'let f = ./updo/types/CabalRelativity.dhall in ./$< f.CabalProjectRelative ./project-dhall/pkg-groups.dhall' | dhall text --output $@+ endif++generate-pkg-configs: \+ project-dhall/pkg-groups.dhall \+ project-dhall/pkgs-upgrade-todo.dhall+ ifeq ($(CABAL_RELATIVITY), ImportRelative)+ mkdir -p project-cabal/pkgs && $(PKG_GROUPS_HS) "let f = ./updo/types/CabalRelativity.dhall in f.CabalImportRelative" "$(GHC_VERSION)" "$(GHC_UPGRADE)"+ else+ mkdir -p project-cabal/pkgs && $(PKG_GROUPS_HS) "let f = ./updo/types/CabalRelativity.dhall in f.CabalProjectRelative" "$(GHC_VERSION)" "$(GHC_UPGRADE)"+ endif++# Mirror packages (package groups) from dhall to config with+# generate-pkg-configs doing the work once for all package groups.+#+# The "target: prerequisites ;" explicitly defines an empty recipe.+# SEE: https://www.gnu.org/software/make/manual/html_node/Empty-Recipes.html+project-cabal/pkgs/%.config: project-dhall/pkgs/%.dhall generate-pkg-configs ;++# Mirror constraints from dhall to config. Any revisions in the constraints are+# stripped, like this for example:+# - hedgehog-quickcheck ==0.1.1@rev:4+# + hedgehog-quickcheck ==0.1.1+project-cabal/ghc-%/constraints.config : \+ updo/text-templates/cabal/package.dhall \+ project-dhall/ghc-%/constraints.dhall+ mkdir -p $(@D)+ echo "let f = ./$< in f.constraints ./project-dhall/ghc-$*/constraints.dhall" \+ | dhall text | sed "s/@rev:.*//" >$@++# Mirror source repositories from dhall to config.+project-cabal/ghc-%.config: \+ updo/text-templates/cabal/package.dhall \+ project-dhall/ghc-%.dhall+ mkdir -p $(@D) && echo "let f = ./$< in f.repo-items ./project-dhall/ghc-$*.dhall" | dhall text --output $@++ghc-$(GHC_VERSION).dhall2config.project: \+ project-dhall/ghc-$(GHC_VERSION)/text-templates/dhall2config.dhall \+ updo/text-templates/dhall2config.dhall \+ project-cabal/ghc-$(GHC_VERSION)/constraints.config \+ project-cabal/ghc-$(GHC_VERSION)/deps-external.config \+ project-cabal/ghc-$(GHC_VERSION)/deps-internal.config \+ project-cabal/ghc-$(GHC_VERSION)/forks-external.config \+ project-cabal/ghc-$(GHC_VERSION)/forks-internal.config \+ project-cabal/pkgs.config+ echo './$< "$(STACKAGE_VERSION)" "$(GHC_VERSION)"' | dhall text --output $@++ghc-$(GHC_UPGRADE).dhall2config.project: \+ project-dhall/ghc-$(GHC_UPGRADE)/text-templates/dhall2config.dhall \+ updo/text-templates/dhall2config.dhall \+ project-cabal/ghc-$(GHC_UPGRADE)/constraints.config \+ project-cabal/ghc-$(GHC_UPGRADE)/deps-external.config \+ project-cabal/ghc-$(GHC_UPGRADE)/deps-internal.config \+ project-cabal/ghc-$(GHC_UPGRADE)/forks-external.config \+ project-cabal/ghc-$(GHC_UPGRADE)/forks-internal.config \+ project-cabal/pkgs.config+ echo './$< "$(STACKAGE_UPGRADE)" "$(GHC_UPGRADE)"' | dhall text --output $@
+ project-dhall2config/README.md view
@@ -0,0 +1,27 @@+# Updo Cabal++We offer two ways of generating cabal projects, `dhall2cabal` and+`dhall2config`. This folder deals with the later.++The `Makefile` has targets for `ghc-x.y.z.dhall2config.project` that is mostly+imports of `.config` files generated from the `.dhall` configuration, something+like:++```+import: project-stackage/stackage-resolver.config++import: project-cabal/pkgs.config++import: project-cabal/ghc-x.y.z/constraints.config+import: project-cabal/ghc-x.y.z/deps-external.config+import: project-cabal/ghc-x.y.z/deps-internal.config+import: project-cabal/ghc-x.y.z/forks-external.config+import: project-cabal/ghc-x.y.z/forks-internal.config++build-info: True+```++For this rule using `make --jobs`[^parallel-make] will speed up the recipe a+lot.++[^parallel-make]: https://www.gnu.org/software/make/manual/html_node/Parallel.html
+ project-dhall2config/pkg-groups.hs view
@@ -0,0 +1,52 @@+#!/usr/bin/env stack+-- stack script --resolver=lts-18.27 --package=base --package=dhall --package=filepath --package=text++{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Description: Convert each package group from .dhall to .config with upgrade+-- conditionals if needed.+module Main where++import Control.Monad (forM_)+import Data.List (concat, filter, intersect, sortOn, (\\))+import qualified Data.Text as T (pack, unpack)+import qualified Data.Text.IO as T (putStrLn)+import Dhall (FromDhall, Generic, Text, ToDhall, auto, embed, inject, input)+import Dhall.Core (pretty)+import System.Environment (getArgs)+import System.FilePath ((<.>), (</>))++type UpgradeConfig = CabalRelativity -> Text -> Text -> PkgUpgrade -> Text++data PkgUpgrade = PkgUpgrade+ { pkgs :: [Text]+ , done :: [Text]+ , todo :: [Text]+ }+ deriving (Show, Generic, ToDhall, FromDhall)++data CabalRelativity = CabalProjectRelative | CabalImportRelative+ deriving (Show, Generic, ToDhall, FromDhall)++groupUpgrade :: [Text] -> String -> IO PkgUpgrade+groupUpgrade remaining name = do+ pkgs :: [Text] <- input auto (T.pack $ "./project-dhall/pkgs" </> name <.> "dhall")+ let todo = pkgs `intersect` remaining+ let done = pkgs \\ todo+ return PkgUpgrade{..}++main :: IO ()+main = do+ cabalRelativity : ghcVersion : ghcUpgrade : _ <- getArgs+ remaining :: [Text] <- input auto "./project-dhall/pkgs-upgrade-todo.dhall"+ relativity :: CabalRelativity <- input auto $ T.pack cabalRelativity+ pkgUpgrade :: UpgradeConfig <- input auto "./updo/project-dhall/pkgs-upgrade.dhall"+ pkgGroups :: [String] <- input auto "./project-dhall/pkg-groups.dhall"+ forM_ pkgGroups $ \p -> do+ up <- groupUpgrade remaining p+ let config = pkgUpgrade relativity (T.pack ghcVersion) (T.pack ghcUpgrade) up+ writeFile ("./project-cabal/pkgs" </> p <.> "config") (T.unpack config)
+ project-nix/Makefile view
@@ -0,0 +1,19 @@+ifeq ($(SHA256MAP_HS_EXE), true)+SHA256MAP_HS := updo-sha256map+else+SHA256MAP_HS := ./updo/project-nix/sha256map.hs+endif++project-sha256maps: \+ ghc-$(GHC_VERSION).sha256map.nix \+ ghc-$(GHC_UPGRADE).sha256map.nix++ghc-%.sha256map.nix: \+ project-dhall/ghc-%/deps-external.dhall \+ project-dhall/ghc-%/deps-internal.dhall \+ project-dhall/ghc-%/forks-external.dhall \+ project-dhall/ghc-%/forks-internal.dhall+ echo '[$(^:%=./%,) ([] : List {loc : Text, tag : Text, sub : List Text})]' | $(SHA256MAP_HS) > $@++project-versions.nix:+ echo './updo/project-nix/project-versions.dhall "$(GHC_VERSION)" "$(GHC_UPGRADE)"' | dhall text > $@
+ project-nix/README.md view
@@ -0,0 +1,67 @@+# Updo Nix++The `Makefile` has targets for `ghc-x.y.z.sha256map.nix` which has the form:++```nix+{+ "repo-url"."commit-rev" = "sha256";+}+```++This can be used with [haskell.nix][haskell-nix]. We grab the sha256 hash with+`nix-prefetch-git` from the shell so you'll need that installed.++[haskell-nix]: https://input-output-hk.github.io/haskell.nix/tutorials/source-repository-hashes.html#avoiding-modifying-cabalproject-and-stackyaml++```+$ nix-prefetch-git --help+syntax: nix-prefetch-git [options] [URL [REVISION [EXPECTED-HASH]]]++Options:+ --out path Path where the output would be stored.+ --url url Any url understood by 'git clone'.+ --rev ref Any sha1 or references (such as refs/heads/master)+ --hash h Expected hash.+ --branch-name Branch name to check out into+ --sparse-checkout Only fetch and checkout part of the repository.+ --deepClone Clone the entire repository.+ --no-deepClone Make a shallow clone of just the required ref.+ --leave-dotGit Keep the .git directories.+ --fetch-lfs Fetch git Large File Storage (LFS) files.+ --fetch-submodules Fetch submodules.+ --builder Clone as fetchgit does, but url, rev, and out option are mandatory.+ --quiet Only print the final json summary.+```++```+$ nix-prefetch-git https://github.com/input-output-hk/haskell.nix.git bc01ebc05a8105035c9449943046b46c8364b932+...+{+ "url": "https://github.com/input-output-hk/haskell.nix.git",+ "rev": "bc01ebc05a8105035c9449943046b46c8364b932",+ "date": "2019-05-30T13:13:18+08:00",+ "sha256": "003lm3pm024vhbfmii7xcdd9v2rczpflxf7gdl2pyxia7p014i8z",+ "fetchSubmodules": false+}+```++We also include a `sha256map.py` script from haskell.nix[^sorted] but this is 4+times slower.++The `Makefile` also has `project-versions.nix` as a target.++```nix+{ current-version =+ { ghc-xyz-project-stack = "stack.yaml";+ ghc-xyz-project-cabal = "cabal.project";+ ghc-xyz-sha256map = import ./project-nix/ghc-u.v.w/sha256map.nix;+ };+ upgrade-version =+ { ghc-xyz-project-stack = "stack.upgrade.yaml";+ ghc-xyz-project-cabal = "cabal.upgrade.project";+ ghc-xyz-sha256map = import ./project-nix/ghc-x.y.z/sha256map.nix;+ };+}+```++[^sorted]: Renamed from `sha256map-regenerate.py` and modified to sort the map by keys.
+ project-nix/project-versions.dhall view
@@ -0,0 +1,15 @@+\(ghc-version : Text) ->+\(ghc-upgrade : Text) ->+ ''+ { current-version =+ { ghc-xyz-project-stack = "stack.yaml";+ ghc-xyz-project-cabal = "cabal.project";+ ghc-xyz-sha256map = import ./project-nix/ghc-${ghc-version}/sha256map.nix;+ };+ upgrade-version =+ { ghc-xyz-project-stack = "stack.upgrade.yaml";+ ghc-xyz-project-cabal = "cabal.upgrade.project";+ ghc-xyz-sha256map = import ./project-nix/ghc-${ghc-upgrade}/sha256map.nix;+ };+ }+ ''
+ project-nix/sha256map.hs view
@@ -0,0 +1,76 @@+#!/usr/bin/env stack+-- stack script --resolver=lts-18.27 --package=aeson --package=base --package=dhall --package=text --package=turtle --package=utf8-string+{-# LANGUAGE DeriveAnyClass #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Description: Generates a sha256map.+module Main where++import Control.Monad (unless)+import Data.Aeson (FromJSON, decode)+import Data.ByteString.Lazy.UTF8 (fromString)+import Data.Either (partitionEithers)+import Data.Text (pack, unpack)+import qualified Data.Text.IO as T (getContents)+import Dhall (FromDhall, Generic, Text, ToDhall, auto, input)+import GHC.Generics+import System.Exit (ExitCode (..), die)+import Turtle (empty, parallel, shellStrictWithErr, sort)+import Turtle.Format (printf, (%), s)++data SourceRepoPkg = SourceRepoPkg+ { loc :: Text+ , tag :: Text+ , sub :: [Text]+ }+ deriving (Eq, Ord, Show, Generic, ToDhall, FromDhall)++data Warning+ = NixPrefetchGitFailed Int Text+ | InvalidPrefetchGitOutput Text+ deriving (Eq, Ord, Show)++data NixPrefetchGitOutput = NixPrefetchGitOutput+ { url :: Text+ , rev :: Text+ , sha256 :: Text+ , date :: Text+ }+ deriving (Eq, Ord, Show, Generic, FromJSON)++prefetchSourceRepoPkg :: SourceRepoPkg -> IO (Either Warning NixPrefetchGitOutput)+prefetchSourceRepoPkg SourceRepoPkg{..} = nixPrefetchGit (loc, tag)+{-# INLINE prefetchSourceRepoPkg #-}++nixPrefetchGit :: (Text, Text) -> IO (Either Warning NixPrefetchGitOutput)+nixPrefetchGit (repo, commit) = do+ (exitCode, stdout, stderr) <-+ shellStrictWithErr+ ("nix-prefetch-git " <> repo <> " " <> commit)+ empty+ case exitCode of+ ExitFailure e -> return (Left $ NixPrefetchGitFailed e stderr)+ ExitSuccess ->+ return $+ maybe+ (Left $ InvalidPrefetchGitOutput stdout)+ Right+ (decode (fromString $ unpack stdout))++printUrlTagSha :: NixPrefetchGitOutput -> IO ()+printUrlTagSha NixPrefetchGitOutput{..} =+ printf (" \""%s%"\".\""%s%"\" = \""%s%"\";\n") url rev sha256++main :: IO ()+main = do+ repos :: [[SourceRepoPkg]] <- input auto =<< T.getContents+ fetches <- sort . parallel $ prefetchSourceRepoPkg <$> concat repos+ let (errs, xs) = partitionEithers fetches+ unless (null errs) $+ die . unlines $ map show errs+ printf "{\n"+ mapM_ printUrlTagSha xs+ printf "}\n"
+ project-nix/sha256map.py view
@@ -0,0 +1,50 @@+#!/usr/bin/env python3+#+# NOTE: Adapted from input-output-hk/iohk-nix, a repository with no license.+# SOURCE: https://github.com/input-output-hk/iohk-nix/blob/master/ci/sha256map-regenerate/sha256map-regenerate.py+#+# This script is intended to be run as+#+# python3 sha256map.py+#+# And it will iterate over all git references in the given stack project (stack.yaml file)+# and generate a set of sha256 value for them to stdout.++# These can then be imported as:+# haskell-nix.stackProject' { sha256map = import ./sha256map.nix; }+#+# This allows building a project with haskell.nix in a restricted nix setup+# where network access is only permitted if the sha256 of the download is known+# beforehand.++# TODO: accept a cabal.project as input as well.++import re+import subprocess+import json+import sys++# Read stack.yaml from stin+project = sys.stdin.read()++# match looks like this:++#- git: https://github.com/input-output-hk/cardano-base+# commit: e8a48cf0500b03c744c7fc6f2fedb86e8bdbe055++pattern = r'\- git: (?P<loc>[^ \n]+).*\n' \+ + r'(?P<pad> .*)commit: (?P<tag>[^ \n]+).*\n'++def sha256entry(match):+ dict = match.groupdict()+ prefetchJSON = subprocess.run(+ ["nix-prefetch-git", "--fetch-submodules", "--quiet", dict['loc'], dict['tag']],+ capture_output=True, check=True).stdout+ sha256 = json.loads(prefetchJSON)["sha256"]+ return '"{loc}"."{tag}" = "{sha256}";'.format(**{**dict, **{"sha256": sha256}})++# Write sha256map to stdout+print("{")+for x in sorted([sha256entry(match) for match in re.finditer(pattern, project)]):+ print(" ", x)+print("}")
+ text-templates/cabal/package.dhall view
@@ -0,0 +1,11 @@+{ constraints =+ ../internal/constraint-section.dhall+ ""+ ''+ constraints:+ ''+ " , "+ (\(c : { dep : Text, ver : Text }) -> "${c.dep} ==${c.ver}")+, packages = ../internal/pkg-section.dhall "" " " " , "+, repo-items = ./repo-items.dhall (\(sub : Text) -> " ${sub}")+}
+ text-templates/cabal/pkg-groups.dhall view
@@ -0,0 +1,20 @@+let TYPES = ./../../types.dhall++in \(pkg-import : TYPES.CabalRelativity) ->+ \(pkg-groups : List Text) ->+ let null = https://prelude.dhall-lang.org/List/null++ let concatMapSep = https://prelude.dhall-lang.org/Text/concatMapSep++ let import-pkg =+ merge+ { CabalProjectRelative =+ \(pkg : Text) -> "import: ./project-cabal/pkgs/${pkg}.config"+ , CabalImportRelative =+ \(pkg : Text) -> "import: ./pkgs/${pkg}.config"+ }+ pkg-import++ in if null Text pkg-groups+ then ""+ else concatMapSep "\n" Text import-pkg pkg-groups
+ text-templates/cabal/repo-items.dhall view
@@ -0,0 +1,20 @@+let TYPES = ../../types.dhall++in \(sub-template : Text -> Text) ->+ \(deps-git : List TYPES.SourceRepoPkg) ->+ let T = https://prelude.dhall-lang.org/Text/package.dhall++ in T.concatMapSep+ "\n"+ TYPES.SourceRepoPkg+ ( \(s : TYPES.SourceRepoPkg) ->+ ''+ source-repository-package+ type: git+ location: ${s.loc}+ tag: ${s.tag}${../internal/sub-items.dhall+ " subdir:"+ sub-template+ s.sub}''+ )+ deps-git
+ text-templates/dhall2cabal.dhall view
@@ -0,0 +1,86 @@+let TYPES = ../types.dhall++let length = https://prelude.dhall-lang.org/List/length++let show = https://prelude.dhall-lang.org/Natural/show++in \(stackage-resolver : Text) ->+ \(pkg-set : TYPES.PkgSet) ->+ \ ( pkg-config+ : { constraints : List TYPES.PkgVer+ , source-pkgs :+ { deps-external : List TYPES.SourceRepoPkg+ , deps-internal : List TYPES.SourceRepoPkg+ , forks-external : List TYPES.SourceRepoPkg+ , forks-internal : List TYPES.SourceRepoPkg+ }+ }+ ) ->+ let deps-external = pkg-config.source-pkgs.deps-external++ let deps-internal = pkg-config.source-pkgs.deps-internal++ let forks-external = pkg-config.source-pkgs.forks-external++ let forks-internal = pkg-config.source-pkgs.forks-internal++ let source-deps =+ deps-external # deps-internal # forks-external # forks-internal++ let count =+ \(xs : List TYPES.SourceRepoPkg) ->+ show (length TYPES.SourceRepoPkg xs)++ let countPkgs = \(xs : List Text) -> show (length Text xs)++ let pkgs =+ merge+ { AllPkgs = \(pkgs : List Text) -> pkgs+ , PkgUpgrade = \(pkgs : TYPES.PkgTodoList) -> pkgs.done+ }+ pkg-set++ let pkgs-comment =+ merge+ { AllPkgs =+ \(pkgs : List Text) ->+ "-- We have ${countPkgs pkgs} packages."+ , PkgUpgrade =+ \(pkgs : TYPES.PkgTodoList) ->+ "-- We have upgraded ${countPkgs+ pkgs.done} packages and have ${countPkgs+ pkgs.todo} yet to do."+ }+ pkg-set++ let cabal = ./cabal/package.dhall++ in ''+ import: ./project-stackage/${stackage-resolver}.config++ ${pkgs-comment}+ ${cabal.packages pkgs}++ -- We have ${count source-deps} source packages listed in this order:+ -- * external ${count deps-external}+ -- * internal ${count deps-internal}+ -- * external forks ${count forks-external}+ -- * internal forks ${count forks-internal}++ -- Source Packages, external (3rd party).+ ${cabal.repo-items deps-external}++ -- Source Packages, internal to this organisation (private and public).+ ${cabal.repo-items deps-internal}++ -- Source Packages, external (3rd party) forks of other repositories.+ -- Can we help upstream?+ ${cabal.repo-items forks-external}++ -- Source Packages, internal forks of other repositories.+ -- Can we upstream and unfork?+ ${cabal.repo-items forks-internal}++ -- Constraints are equivalent to stack package-version extra dependencies.+ ${cabal.constraints pkg-config.constraints}+ ''
+ text-templates/dhall2config.dhall view
@@ -0,0 +1,15 @@+\(stackage-resolver : Text) ->+\(ghc-version : Text) ->+ ''+ import: ./project-stackage/${stackage-resolver}.config++ import: ./project-cabal/pkgs.config++ import: ./project-cabal/ghc-${ghc-version}/constraints.config+ import: ./project-cabal/ghc-${ghc-version}/deps-external.config+ import: ./project-cabal/ghc-${ghc-version}/deps-internal.config+ import: ./project-cabal/ghc-${ghc-version}/forks-external.config+ import: ./project-cabal/ghc-${ghc-version}/forks-internal.config++ build-info: True+ ''
+ text-templates/dhall2stack.dhall view
@@ -0,0 +1,89 @@+let TYPES = ../types.dhall++let L = https://prelude.dhall-lang.org/List/package.dhall++let show = https://prelude.dhall-lang.org/Natural/show++in \(stackage-resolver : Text) ->+ \(pkg-set : TYPES.PkgSet) ->+ \ ( pkg-config+ : { constraints : List TYPES.PkgVer+ , source-pkgs :+ { deps-external : List TYPES.SourceRepoPkg+ , deps-internal : List TYPES.SourceRepoPkg+ , forks-external : List TYPES.SourceRepoPkg+ , forks-internal : List TYPES.SourceRepoPkg+ }+ }+ ) ->+ let deps-external = pkg-config.source-pkgs.deps-external++ let deps-internal = pkg-config.source-pkgs.deps-internal++ let forks-external = pkg-config.source-pkgs.forks-external++ let forks-internal = pkg-config.source-pkgs.forks-internal++ let source-deps =+ deps-external # deps-internal # forks-external # forks-internal++ let count =+ \(xs : List TYPES.SourceRepoPkg) ->+ show (L.length TYPES.SourceRepoPkg xs)++ let countPkgs = \(xs : List Text) -> show (L.length Text xs)++ let pkgs =+ merge+ { AllPkgs = \(pkgs : List Text) -> pkgs+ , PkgUpgrade = \(pkgs : TYPES.PkgTodoList) -> pkgs.done+ }+ pkg-set++ let pkgs-comment =+ merge+ { AllPkgs =+ \(pkgs : List Text) -> "# We have ${countPkgs pkgs} packages."+ , PkgUpgrade =+ \(pkgs : TYPES.PkgTodoList) ->+ "# We have upgraded ${countPkgs+ pkgs.done} packages and have ${countPkgs+ pkgs.todo} yet to do."+ }+ pkg-set++ let stack = ./stack/package.dhall++ in ''+ resolver: ${stackage-resolver}++ ${pkgs-comment}+ ${stack.packages pkgs}+ # We have ${count+ source-deps} source packages listed in this order:+ # * external ${count deps-external}+ # * internal ${count deps-internal}+ # * external forks ${count forks-external}+ # * internal forks ${count forks-internal}+ ''+ ++ ( if L.null TYPES.SourceRepoPkg source-deps+ && L.null TYPES.PkgVer pkg-config.constraints+ then "extra-deps: []"+ else ''+ extra-deps:++ # Source Packages, external (3rd party).+ ${stack.repo-items deps-external}+ # Source Packages, internal to this organisation (private and public).+ ${stack.repo-items deps-internal}+ # Source Packages, external (3rd party) forks of other repositories.+ # Can we help upstream?+ ${stack.repo-items forks-external}+ # Source Packages, internal forks of other repositories.+ # Can we upstream and unfork?+ ${stack.repo-items forks-internal}+ # Package versions for published packages either not on Stackage or+ # not matching the version on Stackage for the resolver we use.+ # These package-version extra dependencies are equivalent to cabal constraints.+ ${stack.constraints pkg-config.constraints}''+ )
+ text-templates/internal/constraint-items.dhall view
@@ -0,0 +1,18 @@+let TYPES = ../../types.dhall++in \(separator : Text) ->+ \(dep-ver-template : TYPES.PkgVer -> Text) ->+ \(xs : List TYPES.PkgVer) ->+ let null = https://prelude.dhall-lang.org/List/null++ let concatMapSep = https://prelude.dhall-lang.org/Text/concatMapSep++ in if null TYPES.PkgVer xs+ then ""+ else concatMapSep+ ''++ ${separator}''+ TYPES.PkgVer+ dep-ver-template+ xs
+ text-templates/internal/constraint-section.dhall view
@@ -0,0 +1,15 @@+let TYPES = ../../types.dhall++in \(null-content : Text) ->+ \(leader : Text) ->+ \(separator : Text) ->+ \(dep-ver-template : TYPES.PkgVer -> Text) ->+ \(constraints : List TYPES.PkgVer) ->+ let null = https://prelude.dhall-lang.org/List/null++ in if null TYPES.PkgVer constraints+ then null-content+ else "${leader}${./constraint-items.dhall+ separator+ dep-ver-template+ constraints}"
+ text-templates/internal/pkg-items.dhall view
@@ -0,0 +1,13 @@+\(separator : Text) ->+\(xs : List Text) ->+ let null = https://prelude.dhall-lang.org/List/null++ let concatSep = https://prelude.dhall-lang.org/Text/concatSep++ in if null Text xs+ then ""+ else concatSep+ ''++ ${separator}''+ xs
+ text-templates/internal/pkg-section.dhall view
@@ -0,0 +1,12 @@+\(null-content : Text) ->+\(first-separator : Text) ->+\(separator : Text) ->+\(pkgs : List Text) ->+ let null = https://prelude.dhall-lang.org/List/null++ in if null Text pkgs+ then null-content+ else ''+ packages:+ ${first-separator}${./pkg-items.dhall separator pkgs}+ ''
+ text-templates/internal/sub-items.dhall view
@@ -0,0 +1,14 @@+\(sub-field : Text) ->+\(sub-template : Text -> Text) ->+\(xs : List Text) ->+ let L = https://prelude.dhall-lang.org/List/package.dhall++ let T = https://prelude.dhall-lang.org/Text/package.dhall++ in if L.null Text xs+ then ""+ else ''++ ${sub-field}+ ''+ ++ T.concatMapSep "\n" Text sub-template xs
+ text-templates/stack/package.dhall view
@@ -0,0 +1,9 @@+{ constraints =+ ../internal/constraint-section.dhall+ ""+ " - "+ " - "+ (\(c : { dep : Text, ver : Text }) -> "${c.dep}-${c.ver}")+, packages = ../internal/pkg-section.dhall "packages: []" " - ./" " - ./"+, repo-items = ./repo-items.dhall (\(sub : Text) -> " - ${sub}")+}
+ text-templates/stack/repo-items.dhall view
@@ -0,0 +1,22 @@+let TYPES = ../../types.dhall++in \(sub-template : Text -> Text) ->+ \(deps-git : List TYPES.SourceRepoPkg) ->+ let L = https://prelude.dhall-lang.org/List/package.dhall++ let T = https://prelude.dhall-lang.org/Text/package.dhall++ in if L.null TYPES.SourceRepoPkg deps-git+ then ""+ else T.concatMap+ TYPES.SourceRepoPkg+ ( \(s : TYPES.SourceRepoPkg) ->+ ''+ - git: ${s.loc}+ commit: ${s.tag}${../internal/sub-items.dhall+ " subdirs:"+ sub-template+ s.sub}+ ''+ )+ deps-git
+ text-templates/yaml2stack/constraints.dhall view
@@ -0,0 +1,13 @@+let TYPES = ../../types.dhall++in \(xs : List TYPES.PkgVer) ->+ let L = https://prelude.dhall-lang.org/List/package.dhall++ let x = ../stack/package.dhall++ in if L.null TYPES.PkgVer xs+ then "extra-deps: []"+ else ''+ extra-deps:+ ${x.constraints xs}+ ''
+ text-templates/yaml2stack/pkgs.dhall view
@@ -0,0 +1,1 @@+let x = ../stack/package.dhall in x.packages
+ text-templates/yaml2stack/repo-items.dhall view
@@ -0,0 +1,13 @@+let TYPES = ../../types.dhall++in \(xs : List TYPES.SourceRepoPkg) ->+ let L = https://prelude.dhall-lang.org/List/package.dhall++ let x = ../stack/package.dhall++ in if L.null TYPES.SourceRepoPkg xs+ then "extra-deps: []"+ else ''+ extra-deps:+ ${x.repo-items xs}+ ''
+ types.dhall view
@@ -0,0 +1,6 @@+{ PkgTodoList = ./types/PkgTodoList.dhall+, PkgSet = ./types/PkgSet.dhall+, PkgVer = ./types/PkgVer.dhall+, SourceRepoPkg = ./types/SourceRepoPkg.dhall+, CabalRelativity = ./types/CabalRelativity.dhall+}
+ types/CabalRelativity.dhall view
@@ -0,0 +1,1 @@+< CabalProjectRelative | CabalImportRelative >
+ types/PkgSet.dhall view
@@ -0,0 +1,3 @@+let PkgTodoList = ./PkgTodoList.dhall++in < AllPkgs : List Text | PkgUpgrade : PkgTodoList >
+ types/PkgTodoList.dhall view
@@ -0,0 +1,1 @@+{ done : List Text, todo : List Text }
+ types/PkgVer.dhall view
@@ -0,0 +1,1 @@+{ dep : Text, ver : Text }
+ types/SourceRepoPkg.dhall view
@@ -0,0 +1,1 @@+{ loc : Text, tag : Text, sub : List Text }
+ updo.cabal view
@@ -0,0 +1,151 @@+cabal-version: 1.12++-- This file has been generated from package.dhall by hpack version 0.35.2.+--+-- see: https://github.com/sol/hpack++name: updo+version: 1.0.0+synopsis: A style of maintaining and upgrading Haskell projects+description: From configuration in .dhall, generate projects (stack.yaml and+ cabal.project) and progressively upgrade projects.+category: Development+homepage: https://github.com/cabalism/updo#readme+bug-reports: https://github.com/cabalism/updo/issues+author: Phil de Joux+maintainer: phil.dejoux@blockscope.com+copyright: © 2023 Phil de Joux, © 2023 Block Scope Limited+license: MPL-2.0+license-file: LICENSE+build-type: Simple+tested-with:+ GHC == 8.6.5+ , GHC == 8.10.7+ , GHC == 9.2.8+ , GHC == 9.4.5+extra-source-files:+ ALTERNATIVES.md+ alternatives/cabal2stack/README.md+ alternatives/stack2cabal/README.md+ alternatives/yaml2stack/README.md+ CHANGELOG.md+ HACKING.md+ project-dhall/README.md+ project-dhall2config/README.md+ project-nix/README.md+ README.md+ TEMPLATES.md+ TESTING.md+ package.dhall+ project-dhall/pkgs-upgrade.dhall+ project-nix/project-versions.dhall+ text-templates/cabal/package.dhall+ text-templates/cabal/pkg-groups.dhall+ text-templates/cabal/repo-items.dhall+ text-templates/dhall2cabal.dhall+ text-templates/dhall2config.dhall+ text-templates/dhall2stack.dhall+ text-templates/internal/constraint-items.dhall+ text-templates/internal/constraint-section.dhall+ text-templates/internal/pkg-items.dhall+ text-templates/internal/pkg-section.dhall+ text-templates/internal/sub-items.dhall+ text-templates/stack/package.dhall+ text-templates/stack/repo-items.dhall+ text-templates/yaml2stack/constraints.dhall+ text-templates/yaml2stack/pkgs.dhall+ text-templates/yaml2stack/repo-items.dhall+ types.dhall+ types/CabalRelativity.dhall+ types/PkgSet.dhall+ types/PkgTodoList.dhall+ types/PkgVer.dhall+ types/SourceRepoPkg.dhall+ alternatives/cabal2stack/Makefile+ alternatives/stack2cabal/Makefile+ alternatives/yaml2stack/Makefile+ Makefile+ project-dhall/Makefile+ project-dhall2config/Makefile+ project-nix/Makefile+ project-dhall/pkgs-sorted.hs+ project-dhall/pkgs-upgrade-done.hs+ project-dhall/pkgs-upgrade-partition.hs+ project-dhall2config/pkg-groups.hs+ project-nix/sha256map.hs+ project-nix/sha256map.py+ alternatives/yaml2stack/join-sort-fragments.sh++source-repository head+ type: git+ location: https://github.com/cabalism/updo++executable updo-pkg-groups+ main-is: project-dhall2config/pkg-groups.hs+ other-modules:+ Paths_updo+ build-depends:+ aeson >=2.1.2 && <2.2+ , base >=4.12 && <5+ , dhall >=1.41.1 && <1.42+ , filepath >=1.4.2 && <1.5+ , text >=1.2.3 && <2.1+ , turtle >=1.6.1 && <1.7+ , utf8-string >=1.0.2 && <1.1+ default-language: Haskell2010++executable updo-pkgs-sorted+ main-is: project-dhall/pkgs-sorted.hs+ other-modules:+ Paths_updo+ build-depends:+ aeson >=2.1.2 && <2.2+ , base >=4.12 && <5+ , dhall >=1.41.1 && <1.42+ , filepath >=1.4.2 && <1.5+ , text >=1.2.3 && <2.1+ , turtle >=1.6.1 && <1.7+ , utf8-string >=1.0.2 && <1.1+ default-language: Haskell2010++executable updo-pkgs-upgrade-done+ main-is: project-dhall/pkgs-upgrade-done.hs+ other-modules:+ Paths_updo+ build-depends:+ aeson >=2.1.2 && <2.2+ , base >=4.12 && <5+ , dhall >=1.41.1 && <1.42+ , filepath >=1.4.2 && <1.5+ , text >=1.2.3 && <2.1+ , turtle >=1.6.1 && <1.7+ , utf8-string >=1.0.2 && <1.1+ default-language: Haskell2010++executable updo-pkgs-upgrade-partition+ main-is: project-dhall/pkgs-upgrade-partition.hs+ other-modules:+ Paths_updo+ build-depends:+ aeson >=2.1.2 && <2.2+ , base >=4.12 && <5+ , dhall >=1.41.1 && <1.42+ , filepath >=1.4.2 && <1.5+ , text >=1.2.3 && <2.1+ , turtle >=1.6.1 && <1.7+ , utf8-string >=1.0.2 && <1.1+ default-language: Haskell2010++executable updo-sha256map+ main-is: project-nix/sha256map.hs+ other-modules:+ Paths_updo+ build-depends:+ aeson >=2.1.2 && <2.2+ , base >=4.12 && <5+ , dhall >=1.41.1 && <1.42+ , filepath >=1.4.2 && <1.5+ , text >=1.2.3 && <2.1+ , turtle >=1.6.1 && <1.7+ , utf8-string >=1.0.2 && <1.1+ default-language: Haskell2010