Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cabal init will relocate and rename project structure #8787

Open
cartazio opened this issue Feb 20, 2023 · 21 comments
Open

cabal init will relocate and rename project structure #8787

cartazio opened this issue Feb 20, 2023 · 21 comments

Comments

@cartazio
Copy link
Contributor

cartazio commented Feb 20, 2023

Describe the bug
cabal init MOVEs preexisting data

To Reproduce

  1. cabal fetch $anything on hackage

  2. cabal init

Expected behavior
i expect (as in previous to cabal-install 3.8 or perhaps even much longer ago), that cabal init uses the preexisting project structure as hinting to suggest directory convention and what not. And not touch code if something already exists.

I do not expect that cabal init to MOVE/RENAME preexisting directories.

I expect cabal init to only clobber a preexisting .cabal file, and maybe LICENSE file. I'm not sure honestly. But i was definitely surprised by the moving.

why did i do cabal init on a preexisting code base

I wanted to generate a more modern .cabal file for a project!

@cartazio
Copy link
Contributor Author

to be clear, I think this new behavior is pretty reasonable, just surprising. (and I did kinda like how interactive cabal init would use the preexisitng project structure as hinting)

@Mikolaj
Copy link
Member

Mikolaj commented Feb 20, 2023

Is it easily recoverable? Does a simple command suffice to get it where it was (other than git reset --hard)? Was any data lost? Asking just in case.

@cartazio
Copy link
Contributor Author

no data was lost, but editor state was very confused because i did have open buffers on all those files that suddenly weren't there. and DVCS tooling could totally salvage the state of affairs. or just a directory mv/rename

@cartazio
Copy link
Contributor Author

I guess what i'm trying to say is "cabal should not clobber stuff that isn't cabals". like i'm quite happy to use cabal user-config to update my ~/.cabal/config, but for cabal init to change my source code tree (when i have editors open), when i just wanted to "modernize" the package.cabal file, was an unpleasant suprise

@ffaf1 ffaf1 added the re: user experience User experience (UX) issue label Feb 21, 2023
@ffaf1
Copy link
Collaborator

ffaf1 commented Feb 21, 2023

Hello @cartazio, indeed changing folder structure can be stressing.

I tried (cabal-install 3.8.1.0): to get a package from Hackage, untar it, run cabal init, pres ⏎ numerous times. This is the tail of the output:

[Log] Using cabal specification: 3.0
[Log] Creating fresh file LICENSE...
[Log] Creating fresh file CHANGELOG.md...
[Log] Creating fresh directory ./app...
[Log] Creating fresh file app/Main.hs...
[Log] Creating fresh file venzone-1.1.0.1.cabal...
[Warning] No synopsis given. You should edit the .cabal file and add one.
[Info] You may want to edit the .cabal file and add a Description field.

I don't see — e.g. — my src/ folder moved to the newly created app/. Is there a repo I can clone to reproduce?

@andreasabel
Copy link
Member

@cartazio wrote:

i expect (as in previous to cabal-install 3.8 or perhaps even much longer ago), that cabal init uses the preexisting project structure as hinting to suggest directory convention and what not. And not touch code if something already exists.

This would also be my expectation: I write some Haskell code, and then cabalize it. So cabal init helps me with the initial .cabal file, e.g. finds the build-depends for some standard modules I import.

The new cabal init (#7344, @emilypi, @ptkato maybe #5705) follows a different philosophy: We start a new project from scratch and set it up using cabal init. Maybe the rationale there is that you cannot reasonably write any Haskell without having a .cabal file already (which has become more true with GHC 9 environment files and v2-cabal nix-style builds).

So the new cabal init initializes a new Haskell project more than initializing a .cabal file for some Haskell project.

Since old and new cabal init, while sharing some functionality, have different purposes, I think it would have been better to locate the new one under a new name, like cabal init-project. (Also because there was quite some API change from old to new.)

This path was not taken, so we just have one init now, that has to serve both philosophies. And I think it should make a best effort at doing so. I think it is possible, by discerning whether it is run in an existing project or on a clean slate.

@cartazio
Copy link
Contributor Author

@ffaf1 i always use cabal interactive init. And I have that reflected in my ~/.cabal/config. I also set it to be recent cabal version flavored.

@cartazio
Copy link
Contributor Author

@andreasabel thanks for adding some context!

It occurs to me that at least for how I always use cabal init (interactive mode), it should be possible to use the oracular power of interaction to ask the user if cabal-install should guess the default config choices based on the existing prject structure.

@ulysses4ever
Copy link
Collaborator

Just as @ffaf1, reading the bug report I fail to discern what exactly went wrong. @cartazio can you explain in a bit more detail what you had in the directory, what you did and what you ended up having in the directory. That would increase chances of at least estimating how much effort it would take to make you a happier user of cabal init with cabal 3.8+.

@cartazio
Copy link
Contributor Author

cartazio commented Feb 21, 2023 via email

@cartazio
Copy link
Contributor Author

cartazio commented Feb 21, 2023

ok, so it looks like theres actually a prompt that says "would you like to overwrite files" in the interactive ux that I didnt notice because its new:

edit: i have interactive: True in my .cabal/config

heres a transcript of how to repro stuff that should show that

> cabal get data-treify
Unpacking to data-treify-0.3.4/
carterschonwald@CarterHydra ~/D/scratch> cd data-treify-0.3.4/
carterschonwald@CarterHydra ~/D/s/data-treify-0.3.4> git init
Initialized empty Git repository in /Users/carter/Desktop/scratch/data-treify-0.3.4/.git/
carterschonwald@CarterHydra ~/D/s/data-treify-0.3.4 (main)> git add .
carterschonwald@CarterHydra ~/D/s/data-treify-0.3.4 (main)> cabal init --interactive
What does the package build:
   1) Library
 * 2) Executable
   3) Library and Executable
   4) Test suite
Your choice? [default: Executable] 3
Do you wish to overwrite existing files (backups will be created) (y/n)? [default: n] n
Package name? [default: data-treify-0.3.4]
Package version? [default: 0.1.0.0]
Please choose a license:
   1) BSD-2-Clause
   2) BSD-3-Clause
   3) Apache-2.0
   4) MIT
   5) MPL-2.0
   6) ISC
   7) GPL-2.0-only
   8) GPL-3.0-only
   9) LGPL-2.1-only
  10) LGPL-3.0-only
  11) AGPL-3.0-only
  12) GPL-2.0-or-later
  13) GPL-3.0-or-later
  14) LGPL-2.1-or-later
  15) LGPL-3.0-or-later
  16) AGPL-3.0-or-later
  17) Other (specify)
Your choice? 4
Author name? [default: Carter Tazio Schonwald]
Maintainer email? [default: carter.schonwald 
homepage URL? [optional]
Project synopsis? [optional]
Project category:
   1) Codec
   2) Concurrency
   3) Control
   4) Data
   5) Database
   6) Development
   7) Distribution
   8) Game
   9) Graphics
  10) Language
  11) Math
  12) Network
  13) Sound
  14) System
  15) Testing
  16) Text
  17) Web
  18) Other (specify)
Your choice? [default: (none)] 4
Library source directory:
 * 1) src
   2) lib
   3) src-lib
   4) Other (specify)
Your choice? [default: src]
Choose a language for your library:
 * 1) Haskell2010
   2) Haskell98
   3) GHC2021 (requires at least GHC 9.2)
   4) Other (specify)
Your choice? [default: Haskell2010]
What is the main module of the executable:
 * 1) Main.hs
   2) Main.lhs
   3) Other (specify)
Your choice? [default: Main.hs]
Application directory:
 * 1) app
   2) exe
   3) src-exe
   4) Other (specify)
Your choice? [default: app]
Choose a language for your executable:
 * 1) Haskell2010
   2) Haskell98
   3) GHC2021 (requires at least GHC 9.2)
   4) Other (specify)
Your choice? [default: Haskell2010]
Should I generate a test suite for the library? [default: y] y
What is the main module of the test suite?:
 * 1) Main.hs
   2) Main.lhs
   3) Other (specify)
Your choice? [default: Main.hs]
Test directory? [default: test]
Choose a language for your test suite:
 * 1) Haskell2010
   2) Haskell98
   3) GHC2021 (requires at least GHC 9.2)
   4) Other (specify)
Your choice? [default: Haskell2010]
Add informative comments to each field in the cabal file. (y/n)? [default: y] y
[Log] Using cabal specification: 3.6
[Log] Using existing file LICENSE...
[Log] Creating fresh file CHANGELOG.md...
[Log] Using existing directory ./src...
[Log] Creating fresh file src/MyLib.hs...
[Log] Creating fresh directory ./app...
[Log] Creating fresh file app/Main.hs...
[Log] Creating fresh directory ./test...
[Log] Creating fresh file test/Main.hs...
[Log] Creating fresh file data-treify-0.3.4.cabal...
[Warning] No synopsis given. You should edit the .cabal file and add one.
[Info] You may want to edit the .cabal file and add a Description field.

carterschonwald@CarterHydra ~/D/s/data-treify-0.3.4 (main)> git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   LICENSE
	new file:   Setup.lhs
	new file:   data-treify.cabal
	new file:   src/CustomTy.hs
	new file:   src/Data/Reify/TGraph.hs
	new file:   src/Data/TReify.hs
	new file:   src/Exp.hs

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	CHANGELOG.md
	app/
	data-treify-0.3.4.cabal
	src/MyLib.hs
	test/


@cartazio
Copy link
Contributor Author

cartazio commented Feb 21, 2023

the important bit that snuck up on me was
Do you wish to overwrite existing files (backups will be created) (y/n)? [default: n] y
because I think that was a new ux detail, previously there was no way cabal would ever clobber a preexisting source tree! (edit: and in the historical ux, saying y is usually just the "would you like explanatory comments included in the generated file")

the workflow failure itself would look like

> cabal init --interactive
What does the package build:
   1) Library
 * 2) Executable
   3) Library and Executable
   4) Test suite
Your choice? [default: Executable] 3
Do you wish to overwrite existing files (backups will be created) (y/n)? [default: n] y
Package name? [default: data-treify-0.3.4]
Package version? [default: 0.1.0.0]
Please choose a license:
   1) BSD-2-Clause
   2) BSD-3-Clause
   3) Apache-2.0
   4) MIT
   5) MPL-2.0
   6) ISC
   7) GPL-2.0-only
   8) GPL-3.0-only
   9) LGPL-2.1-only
  10) LGPL-3.0-only
  11) AGPL-3.0-only
  12) GPL-2.0-or-later
  13) GPL-3.0-or-later
  14) LGPL-2.1-or-later
  15) LGPL-3.0-or-later
  16) AGPL-3.0-or-later
  17) Other (specify)
Your choice? 4
Author name? [default: Carter Tazio Schonwald]
Maintainer email? [default: carter.schonwald]
Project homepage URL? [optional]
Project synopsis? [optional]
Project category:
   1) Codec
   2) Concurrency
   3) Control
   4) Data
   5) Database
   6) Development
   7) Distribution
   8) Game
   9) Graphics
  10) Language
  11) Math
  12) Network
  13) Sound
  14) System
  15) Testing
  16) Text
  17) Web
  18) Other (specify)
Your choice? [default: (none)] 4
Library source directory:
 * 1) src
   2) lib
   3) src-lib
   4) Other (specify)
Your choice? [default: src]
Choose a language for your library:
 * 1) Haskell2010
   2) Haskell98
   3) GHC2021 (requires at least GHC 9.2)
   4) Other (specify)
Your choice? [default: Haskell2010]
What is the main module of the executable:
 * 1) Main.hs
   2) Main.lhs
   3) Other (specify)
Your choice? [default: Main.hs]
Application directory:
 * 1) app
   2) exe
   3) src-exe
   4) Other (specify)
Your choice? [default: app]
Choose a language for your executable:
 * 1) Haskell2010
   2) Haskell98
   3) GHC2021 (requires at least GHC 9.2)
   4) Other (specify)
Your choice? [default: Haskell2010]
Should I generate a test suite for the library? [default: y]
What is the main module of the test suite?:
 * 1) Main.hs
   2) Main.lhs
   3) Other (specify)
Your choice? [default: Main.hs]
Test directory? [default: test]
Choose a language for your test suite:
 * 1) Haskell2010
   2) Haskell98
   3) GHC2021 (requires at least GHC 9.2)
   4) Other (specify)
Your choice? [default: Haskell2010]
Add informative comments to each field in the cabal file. (y/n)? [default: y]
[Log] Using cabal specification: 3.6
[Log] LICENSE already exists. Backing up old version in LICENSE.save0
[Log] Overwriting file LICENSE...
[Log] CHANGELOG.md already exists. Backing up old version in CHANGELOG.md.save0
[Log] Overwriting file CHANGELOG.md...
[Log] src already exists. Backing up old version in src.save0
[Log] Overwriting directory ./src...
[Log] Creating fresh file src/MyLib.hs...
[Log] app already exists. Backing up old version in app.save0
[Log] Overwriting directory ./app...
[Log] Creating fresh file app/Main.hs...
[Log] test already exists. Backing up old version in test.save0
[Log] Overwriting directory ./test...
[Log] Creating fresh file test/Main.hs...
[Log] data-treify-0.3.4.cabal already exists. Backing up old version in data-treify-0.3.4.cabal.save0
[Log] Overwriting file data-treify-0.3.4.cabal...
[Warning] No synopsis given. You should edit the .cabal file and add one.
[Info] You may want to edit the .cabal file and add a Description field.

carterschonwald@CarterHydra ~/D/s/data-treify-0.3.4 (main)> git status
On branch main

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
	new file:   LICENSE
	new file:   Setup.lhs
	new file:   data-treify.cabal
	new file:   src/CustomTy.hs
	new file:   src/Data/Reify/TGraph.hs
	new file:   src/Data/TReify.hs
	new file:   src/Exp.hs

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	modified:   LICENSE
	deleted:    src/CustomTy.hs
	deleted:    src/Data/Reify/TGraph.hs
	deleted:    src/Data/TReify.hs
	deleted:    src/Exp.hs

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	CHANGELOG.md
	CHANGELOG.md.save0
	LICENSE.save0
	app.save0/
	app/
	data-treify-0.3.4.cabal
	data-treify-0.3.4.cabal.save0
	src.save0/
	src/MyLib.hs
	test.save0/
	test/

@emilypi
Copy link
Member

emilypi commented Feb 21, 2023

I'm honestly confused as to what's the issue here.

This path was not taken, so we just have one init now, that has to serve both philosophies.

This is a bit of a mischaracterization of the history of init. init originally was meant to "cabalize" a haskell library when it was first created in 2011 when Cabal was still in its infancy, and Cabal needed backwards compatibility for pre-existing libraries that were still building with runhaskell. As the haskell community moved towards producing software that ran and did things and generally worked, however, that philosophy was no longer necessary: everyone had a stack.yaml or .cabal by the time the command changed. It has served two masters since at least 2015 (the earliest it was used to generate working executables that I can find without too much effort was ad95fb2), nearly a decade ago. Presumably this was to match the stack new functionality, but also because our needs changed. It's very hard to find un-cabalized or un-stackified code in the wild these days, so why should we focus on deriving a .cabal file exclusively?

My and Patrick's work invented nothing new. It cleaned up the codebase and clarified the idea that was already present: 99% of the time you want to build a project and just get going on typing (see also: cargo new), or in the .99% of other cases, you want to work with a library that's got a stack.yaml (see also: cargo init), and in the extremely rare 0.01% case you happen to have a project from a decade ago that you care to run.

Let's be clear here tho: I don't care about the 0.01% case. In any other ecosystem, you'd be told you're SOL and go find an old sourceforge copy of a compiler that supports it, along with a copy of the build tool, and emulate your own windows XP enviornment to get it building. The fact that we're even deigning to support extremely old, unmaintained code listed without a .cabal file or at least a stack.yaml is, frankly, a waste of time.

@emilypi
Copy link
Member

emilypi commented Feb 21, 2023

So the short answer here is: interactive and noninteractive exist because of historical reasons, and while we did propose something like cabal new (vis: cargo new, stack new), there was no reason to introduce a new command for a process that had already been in place for a long time. This would also have invalidated nearly a decade of community wisdom and tutorials, blogs, articles etc. surrounding how to get started.

@cartazio
Copy link
Contributor Author

to be clear: my use case is to upgrade/modernize a cabalized project's foo.cabal file .

Which maybe is something that could be done as its own tool once the cabal-syntax library has stabilized. I totally agree supporting "guessing on an uncabalized project" is a crazy rabbit hole, and in fact thats not how i use it.

I'd be more than happy to explore leveraging cabal-syntax and tooling on top of that as a path going forward for myself.

@cartazio
Copy link
Contributor Author

a simple near term UX tweak could be as simple as

changing the line
Do you wish to overwrite existing files (backups will be created) (y/n)? [default: n]
to something like
Do you wish to overwrite existing files (this may include source files as well as cabal specific files ; backups will be created) (y/n)? [default: n] y.

any color of paint on the bike shed will protect the steel from the elements (or naive readers).

@Kleidukos
Copy link
Member

Kleidukos commented Feb 21, 2023

In terms of UX this is sub-optimal:

  1. The text to ingest is much, much longer
  2. Somehow raises more questions than the previous message
  3. The use of the conditional expresses uncertainty from our part -> trust is lost if we don't know what's going to happen to what files.
  4. No link to any user guide section for a longer write-up

The paint is full of lead.

@cartazio
Copy link
Contributor Author

Lead paint is only dangerous if you eat or inhale it. And the former only happens because lead acetate actually tastes sweet. This metaphor doesn’t scale.

Point being: it’s a new question in the interactive mode and it doesn’t give any hinting for what it’ll clobber.

@andreasabel
Copy link
Member

Do you wish to overwrite existing files (backups will be created) (y/n)? [default: n]

The problem with such "general permission" questions is that the user does not know what they will be buying themselves with either answer. So they have to try out both choices, and hopefully make their own backup first. The pain in this is that they will have to answer the other dozen question again in the same way on the second try.

The best UI will in such cases present the user with concrete plans to choose from. So it will say which files will get moved where, which files be created, which files overwritten.

Not sure if there is a design pattern for this, but if there isn't I call it 3P: plan/present/proceed.

  1. Gather information (here: from what is on disk, what the user answers).
  2. Create a value in a datatype of IO actions: the plan.
  3. Read the plan out to the user and confirm.
  4. Execute the plan by interpreting the plan in a suitable interpreter of IO actions.

It is important that step 4 does not take any further decisions (which would be unauthorized by the user).

If you want to think about it in terms of programming languages: The plan language is a mini DSL, the wizard cabal init creates a program in this DSL, prints it to the user, and then executes it if confirmed. The granularity of the plan/DSL can be chosen suitably to not flood the user with tons of details. Or the reading out of the plan could be parametrized by a verbosity level.

@cartazio
Copy link
Contributor Author

cartazio commented Feb 24, 2023 via email

@emilypi
Copy link
Member

emilypi commented Feb 24, 2023

Fair point Andreas, I look forward to your PR.

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

No branches or pull requests

7 participants