Renaming task will eventually cause file to have no content (0 bytes)

Background

I have been making a set of tasks for my IntelliJ Color Scheme Plugin that will rename all .icls color scheme files into the older .xml scheme that IntelliJ used to use. That is because the new .icls files have some issues that I cannot overcome.

I have created one copy task that will make sure my project has the same files and content that is used by IntelliJ IDEA; it basically functions as a manual sync between the IDEA files and my project files. This task appears to work correctly.

Issue

I am using a 3rd party sync application that will monitor any changes to my IntelliJ IDEA color scheme files, and if a change is detected, it will automatically sync the new file (.icls) to my project.

Now I need to only change the icls file to be an xml file via another Gradle task. That is what the below code does. On the first run, the code seems to work correctly as intended; however, on the second run when I see a new .icls file in my project, it will rename that one file, but all the xml files will now be 0 bytes in size, and I cannot figure out why that is. (EDIT: it will always cause the xml files to have 0 bytes on the second run regardless if there are icls files or not)

(EDIT: Check out the gist to get the below code but is easier to modify. Please check the revisions to see the difference)

task ChroMATERIAL_RenameFiles(type: Copy) {

    // "Copy" files into the same directory.
    from 'src/colors'
    destinationDir file('src/colors')

    String fileName

    rename { String file ->

        // Only delete the xml file of the associated icls files that are present in the directory
        if (file.contains('.icls')) {

            fileName = file.replace('.icls', '')
            delete fileName.concat('.xml')

        }

        // Rename all icls file extensions to be xml files
        file.replace('.icls', '.xml')
    }

    // Lastly, delete all remaining icls files from the directory
    doLast {
        delete fileTree('src/colors') {
            include('**/*.icls')
        }
    }
}

I think Copy is the wrong kind of task for this (that’s why you’re having to do weird things with delete). The issue is that you’re copying the destination onto the source, so Gradle zeroes all of the “destination” files.

You can do this with ant.move:

task ChroMATERIAL_RenameFiles {
    doLast {
        ant.move(todir: "src/colors") {
            fileset(dir: "src/colors")
            mapper(type: "glob", from: "*.icls", to: "*.xml")
        }
    }
}

This is a bit weird, since usually you wouldn’t copy generated things into your source directories (because they would be checked in) and you wouldn’t delete things from your source directories (again, because they would be checked in). But I think this does what you were trying to do.

1 Like

I agree with you, but src/colors is not my source of truth; that is located at C:\Users\Christopher\.IdeaIC2017.2\config\colors. I can modify the source of truth via the IntelliJ IDEA’s color scheme settings window. Therefore, I need to move those files into my project’s source directory for my plugin to work. However, there are issues with the newer icls files, so I have to change the file extension.

This is something I have been doing manually, and I am glad I can finally do this more easily with a Gradle Task.

@sterling 2 questions.

  1. Is there a way to make this task automatic? Where anytime a new icls file is detected in the src/colors directory, this task will be run. EDIT: I am currently using build.dependsOn ChroMATERIALRenameFiles. I also am doing that on clean. Is this the best that I can do?

  2. Also, in the future, I am wondering if I will need to know about which files were changed (an icls file was renamed into an xml file). Is the best way to do that just to create a fileTree that includes icls files outside of the doLast block? Or is there something with Ant?

OK, from your example above, you were copying from src/colors into src/colors, which is the same directory. If you are copying from one directory into another, you could still use Copy.

If you’re importing your project directly into Intellij (not running gradle idea), you could run this task after creating .icls files and synchronizing your project. If you were using gradle idea, you could use dependsOn.

I think if you need anything more complicated than this, you’ll probably want to roll your own custom task that uses ant.move or project.copy under the covers.