-
Notifications
You must be signed in to change notification settings - Fork 363
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
How to name (or rename) files based on a parameter? #1238
Comments
@sstchur - you can setup a parameter with the attribute "FileRename", which will cause files containing the value of "FileRename" to have that value replaced with the provided parameter value. No replacement occurs if the parameter isn't given a value and doesn't have a default. For example:
then on the command line, if you invoke the template with For your bonus question, we actually recently implemented something very similar, which should hopefully fit your needs. It's a new type of symbol called "derived". This allows setting up a symbol whose value is derived from the value of another symbol using what we call value forms. Check out this issue, which was the inspiration for derived symbols #1066 and this PR which implements it #1194. The issue discussion provides an example of setting up something like this, and the PR contains unit tests demonstrating its usage. Derived symbol types have pretty much the same options as parameters symbols (plus deriving their values). This feature is not available in the 2.0.0 release of dotnet, but is available in the 2.1.0 preview branch of this repo. Let me know if the usage is unclear, or if you need help with your specific use case. |
This works! Thanks. I haven't tried the preview version yet to get the derived symbols working, but the FileRename attribute worked like a charm. |
I just noticed what seems to be a bug -- perhaps it should be logged as a separate issue if indeed it is a bug? It seems that if you have multiple symbols with attribute "FileRename", only the first is honored and subsequent ones are ignored. For example:
In the above, only SFAPP1 will be replaced. SFSERVICE1 will remain untouched, even if when supplied via command line. Also, if I flip the parameters so that SFSERVICE1 comes first, then only it will be replaced, and all occurrences of SFAPP1 will remain untouched. Is this a bug? It feels like one to me. |
I would agree that this is a bug... I'll look into it and get back to you. |
@sstchur - I'm unable to repro this issue using dotnet 2.0.0 (or newer). Using a template with the above [partial] configuration, if you run a command such as: The renames are case-sensitive (because case matters for filenames on some systems, notably *nix). But with the behavior you're seeing, that is unlikely to be the issue. Is the problem with a file whose name contains both of the strings you're trying to replace? For example a file named |
So, I am in fact trying to rename something that contains both strings, and initially I thought that was the problem. However, my project/template has both: occurrences of SFSERVICE1 by itself that aren't getting renamed, AND occurrences of SFAPP1 along with SFSERVICE1 that aren't getting renamed. If the problem were only when both strings occur together, shouldn't at least the occurrences of SFSERVICE1 alone be working? It works when I flip the order of parameters in my template.json file. For example, my project has: Folder: SFAPP1 // this gets renamed Under folder SFAPP1.Services.SFSERVICE1 And then, there are many text occurrences of SFSERVICE1 inside of .cs and .json files that do not get renamed, but all occurrences of SFAPP1 do. Not sure what I'm doing wrong? My parameters are defined in my template.json exactly as I pasted in my previous comment. By the way: I am using version 2.0.0 according to dotnet new --version |
@sstchur - you're absolutely correct, what you're describing should not be happening. Would you be able to zip up your template and send me a copy to help diagnose the problem? If there's proprietary IP or sensitive information, those parts could be removed. My email is: sepeters@microsoft.com |
Yes, I will contact you directly, thanks. |
@sstchur - I've had a chance to look at your template, and have unfortunately discovered a couple bugs in the templating code, fixes should be coming in the next few days. On a side note, I noticed that in ServiceEventSource.cs, there are some preprocessor directives. That is fine, but due to the way templating deals with conditionals vs. preprocessor directives, we require the conditions to be inside parentheses. They sometimes happen to work without parentheses, but this is not guaranteed to be supported - in fact, they don't work properly in 2.1.0-preview1. This should be a minor, painless change. For the file content replacements, the only potential replacements I saw which didn't get properly replaced are due to casing differences. The file content replacements are case sensitive, so places where a file contained, for example "sfapp1", that string will not be replaced, because the string configured to be replaced is "SFAPP1". For 2.1.0-preview1, we introduced a mechanism where you can setup symbols so that different "forms" of the value being replaced can all be replaced, in additional to the literal "replaces" value (PR #867). In your case, we could set things up so that "SFAPP1" gets replaced by the literal input value of the appName parameter, and also have "sfapp1" be replaced by the lowercased version of the appName input value. There is a bug in the code to handle this mechanism, but I have a PR which fixes the issue #1241 Setting up the lowercase replacements is configured on the parameters, like this:
The "forms" indicate the transformations to perform on both the "replaces" value and the user input values, the results of those transforms are used for the replacements. Using "serviceName" as an example, lets say I invoke the template with
There was also one place in your template with mixed-case in the source, specifically in HomeController.cs, the namespace beings with "SPApp1". If you want to retain that formatting, we'll need to come up with a custom value form for handling that situation... I'll need to give it more thought. But if that can be changed in your source to "SFAPP1", the file content replacements should be good to go - assuming you use 2.1.0-preview1 or newer, and PR #1241 is merged. I still need to make a fix for the bug with multiple replacements in a single filename. If there's other problems you're having which I didn't cover here, or if you have additional questions, please let me know. |
Thanks @seancpeters Point take on the preprocessor directives -- that seems easy enough. Seems to me that once that fixes are in, all my issues will have been addressed. Thanks! |
PR #1245 takes care of your file rename problem / my file rename bug :) |
@sstchur - The changes necessary for your template to work are now merged into dotnet:rel/2.1.0-preview1. |
any way to have it do camelCasing/PascalCasing renames too? Instead of just lower/upper. I have this in my
I supply a value of
Some are correctly replaced, but the camelcased ones aren't touched. I want them to turn into Any suggestions if that is possible right now @seancpeters? |
Ok, this is ugly, but it works....
All of this because .NET Regex doesn't allow |
The "fileRename" option was exactly what I was looking for. I just want to note that it is not in the JSON Schema. You might want to add that. |
I can only seem to get this working for parameter symbols, could it be extended for other symbol types as well? (Generated ones, particularly.) |
How do you parse names with relative paths so that the class name will not be replaced with directory paths? For example, my template is ServiceNameService, then, when you run the command template.json {
"$schema": "http://json.schemastore.org/template",
"author": "Me",
"classifications": [ "Common", "Code" ],
"identity": "My.Templates.CSharp",
"name": "MyTemplates",
"shortName": "mytemplate",
"tags": {
"language": "C#",
"type": "item"
},
"symbols": {
"ServiceName": {
"type": "parameter",
"datatype": "text",
"description": "Renames files containing 'ServiceName'",
"fileRename": "ServiceName",
"replaces": "ServiceName",
"isRequired": true,
"defaultValue": "MyService"
}
}
} Template: public class ServiceNameService
{
} Generated file:
The actual class or content of the generated file: public class Services/PayrollService
{
} Expected: public class PayrollService
{
} |
per closed issue dotnet#1238 a sample has been created to demonstrate renaming a file.
I've been unable to find any way to ensure that a file in my template project ends up with a specific name.
Note that I'm not talking about sourceName. I understand how that works, and it works just fine for what it is.
Rather, I'm trying to do the following: suppose I have a file called MyService.cs in my project. And further suppose that I have a parameter defined in my template.json as:
When the user runs: dotnet new MyTemplate -s FuzzyMonkey
I want the file MyService.cs to be renamed FuzzyMonkey.cs
I can make the actually class name inside of MyService.cs get renamed easily enough. That seems to work if I name the class
public class MYSERVICE
{...}
But it does not seem to rename the file, even if the file is named "MYSERVICE.cs"
Is there any way to do this?
As a bonus, it would be even better if I could default the serviceName parameter not to a hardcoded value, but to a derivative of sourceName. Like:
Something like the above, which I just totally made up. But I trust you get the idea. I'd like the default value for serviceName to be derived from the value of sourceName.
The text was updated successfully, but these errors were encountered: