jondot / hygen

The simple, fast, and scalable code generator that lives in your project.
http://www.hygen.io
MIT License
5.68k stars 256 forks source link

Inject : create file if it doesn't exist #115

Open bhavyaw opened 5 years ago

bhavyaw commented 5 years ago

Hi!

Thanks for the amazing Project!

Problem statement : Is there any way we can create a file if it doesn't exist while injection. Went through the docs and issues but couldn't find anything related there.

Detailed Description :

jondot commented 5 years ago

Interesting requirement! What you're giving as an example is the .gitignore file, which I guess we kind of want to append to (if we did cat >> foobar to an existing or missing file), the end result would be the same -- file will be created (if missing) and content appended.

So what we're essentially missing is a way to create a file if its missing, and a no-op if it exists. I believe right now you can do this with a shell action (touch your-file), followed by your injection action as usual.

In the meanwhile, I'll find a way to include this without overloading the surface API for Hygen.

PS. Just to keep in mind, including _templates is a safer bet in terms of maintainability, even if brought in from hygen-add -- you gain flexibility by "pay" by having duplicates. It is much like vendoring dependencies in Go, Ruby, and others. Of course each direction has its own pros/cons.

benyap commented 3 years ago

Hello! Are there any updates on this? I have another (similar) use case for this requirement.

I'm using hygen to scaffold services in a certain directory (which may or may not exist yet), which all need to be exported through a shared index.ts file. I have two template files - one to create the new service, and another to inject an export statement into the index file.

What happens currently

When I use a template where inject is true, it will fail if the file it is supposed to inject to does not exist. Nothing wrong with that behaviour - but I would like the ability to configure it so that it creates the file if it does not exist.

My use case and suggestion

Ideally when inject is set to to true, and another property, such as force, or a new property like create_if_not_exist, is also set to true, the following behaviour would occur:

Scenario 1 - directory/index.ts does not exist

When I run hygen, I want to:

  1. Create a file using the service template at directory/<%=Name%>Service.ts.
  2. Since the injection template is trying to inject into a file that doesn't exist, it will first create directory/index.ts, then inject the export statement. If there were other properties such as append/prepend or before/after, it would ignore them since it's a new file and not really relevant.

Scenario 2 - directory/index.ts already exists (because another service was already created)

This scenario currently works without any issues.

When I run hygen, I want to:

  1. Create a file using the service template at directory/<%=Name%>Service.ts.
  2. Inject an export statement for the newly created service into the existing index.ts file.

Current workarounds

Using a shell action in injection template

As suggested by @jondot above. Unfortunately this doesn't quite work if you're suggesting adding the shell action in the same template, because in my testing, injection happens before the shell action is run, so there is an error message and no injection actually happens.

Alternatively, because templates are generated in alphabetical order, you can kind of make it work if you make a seperate template with the shell action that has a name that comes before your template alphabetically, and leave the inject template as you would have unmodified.

That being said, this workaround requires you to create an extra file and forces you to name the file a certain way - it feels a little hacky and unnatural.

Have a template that creates + skips if exists, and another one that injects

This is kind of similar to using the shell action, but instead of using a shell action, just use an empty template and use the unless_exists property.

In my use case, I would create a template to create an empty index file, and use the unless_exists property to only create if it doesn't exist. I would then have a second file that does the injection. The same caveat here applies that I would need to make sure I name the templates in a certain way such that the creation template is executed before the injection template. Also not ideal, but works for now.