tuist / tuist

Tuist's CLI
https://tuist.io
MIT License
4.57k stars 553 forks source link

Development/watch command for re-generating resources on the fly #2809

Open zdnk opened 3 years ago

zdnk commented 3 years ago

Context 🕵️‍♀️

With addition to synthesised resource accessors to Tuist, it would be awesome to also support some way the resources can be synthesised without regenerating and re-opening the whole project or workspace.

What 🌱

At the moment whenever I update string files or asset catalog I need to execute tuist generate to update generated Swift accessor to those resources. This means closing Xcode project, re-generating, opening Xcode project. Xcode checks SPM packages, starts indexing etc. Very annoying.

Proposal 🎉

Introduce Tuist Development mode. Tuist will watch resource directories and files for changes and regenerates accessors on the fly. I can imagine tuist dev, tuist development or tuist watch indefinitely running command.

fortmarek commented 3 years ago

Hi @zdnk, I agree it is not ideal to have to regenerate a project, especially early in the project's lifecycle.

This has also been proposed in Slack by @fila95 in a somewhat similar fashion. Rather than adding a watcher, I'd rather keep it simpler and create tuist synthesize command that would generate the accessors. Since this command would not modify .xcodeproj at hand, we'd also have to show a warning that you need to regenerate a project.

I think that a watcher should rather be implemented via a plugin, right now I am working on the possibility of adding custom tasks which would enable this.

What, I think, we should do first, though, is to look into why regenerating project with .xcworskpace cannot be done with Xcode opened. If you do this with .xcodeproj only, this works. @kwridan do you have any idea why that might be the case? It'd be quite a productivity boost to fix this.

zdnk commented 3 years ago

I see. Let me know if I can help in any way :)

Since this command would not modify .xcodeproj at hand, we'd also have to show a warning that you need to regenerate a project.

Why would we need to regenrate .xcodeproj? It would be great if Tuist created all the files needed for accessors even they'd be empty. That way you would never need to re-generate the project, right?

If you do this with .xcodeproj only, this works.

Are you sure? In our project Xcode always shows reload from disk or using current version dialog when we regenerate project with Xcode open. Sorry, I thought we have project, but for some reason Tuist is generating workspace.

ferologics commented 3 years ago

My 2 cents here -- using tuist generate --project-only still leads to the Build operations are disabled: 'project.xcworkspace' has changed and is reloading. error even if there_is_no_actual .xcworkspace in project root directory. Which confirms that the error is about the nested App.xcodeproj/project.xcworkspace :confused:

ferologics commented 3 years ago

Reposting a "workaround" script for project re-generation-opening that got posted in associated slack discussion (kuddos to @fortmarek -- and his coworker -- whoever it may be 😅)

alias tg="osascript -l JavaScript -e 'function run(a){Application(\"Xcode\").workspaceDocuments().forEach(d=>{if(d.path().includes(a))d.close()})}' $(pwd); tuist generate; xed -b ."
ferologics commented 3 years ago

If anyone is a fish shell user I modified the above script:

function tg
  set close_window 'tell application "Xcode" to close window 1'
  osascript -e $close_window
  tuist generate --project-only --open
end
ferologics commented 3 years ago

@zdnk does the 1.41.0 release resolve your issue? You should be able to keep your project/workspace open while running the tuist generate command 🙂

zdnk commented 3 years ago

It does not really, it changes nothing about the fact when I fetch new localization files or add/remove asset, I have to manually regenerate the project. The issue is having to do it manually every time anything changes.

Otherwise, yes, right now I am able to regenerate the project/workspace without Xcode complaining while open :)

ferologics commented 3 years ago

I see, that seems like the natural next step to take! This tuist dev command could cache output of tree . that can be diffed against the most recent snapshot (t-1) and if change is detected it would call to tuist generate 💡

fortmarek commented 3 years ago

This would be great, indeed! But maybe the implementation could be in a form of a plugin and run from Tasks.swift (PR here) - I think this command is general enough (and should be flexible enough) that there is not necessarily a need for it to live in the core repository.

zdnk commented 3 years ago

It would also make sense to regen just the Swift accessors for the properties instead of the whole project as it is more time consuming operation.

pepicrft commented 3 years ago

Here are some ideas:

danieleformichelli commented 2 years ago

What about adding a flag to tuist generate that just generates the accessors? Or maybe a separate command but I don't think it's worth to add one just for that 🤷

mgray88 commented 2 years ago

tuist generate derived? Since that's the folder they end up in, that's the first thing I'll think of when trying to remember what to type. User intuitive

pepicrft commented 2 years ago

What about adding a flag to tuist generate that just generates the accessors? Or maybe a separate command but I don't think it's worth to add one just for that 🤷

I'm more inclined towards this one. Perhaps tuist generate --only-resource-synthesizers

jesus-mg-ios commented 2 years ago

Hi community, I'm trying to develop this, but I'm lost in this large amount of mappers generators etc ... At the moment I added a flag to the generate command, but I'm not sure what to exclude of execute when this flag is passed as command-line argument.

Could Someone help me with the task? I don't know if you @danyf90 can give me a clue.

Thank you in advance

danieleformichelli commented 2 years ago

Not 100% sure, but it might be enough to load the graph and then fed it to the ResourcesProjectMapper, something like:

        let (graph, sideEffects) = try await load(path: path)

        // Load
        let graphTraverser = GraphTraverser(graph: graph)

        foreachproject {
          resourceMapper.map($0)
        }
enlivn commented 2 years ago

Is it possible to add a note about this to https://docs.tuist.io/guides/resources/#resourcesynthesizers? It's not clear that this is a limitation. I'm happy to PR that in if you like.

fortmarek commented 2 years ago

Is it possible to add a note about this to https://docs.tuist.io/guides/resources/#resourcesynthesizers? It's not clear that this is a limitation. I'm happy to PR that in if you like.

That'd be great, feel free to do so 🙌

enlivn commented 1 year ago

@fortmarek sorry, I didn't get pinged and just saw this in my Github notifications. I'll put a PR up in a couple days.

enlivn commented 1 year ago

@fortmarek I've put up PR #4868 with the documentation update.

thebarndog commented 8 months ago

Has there been any movement on this with the later versions of Tuist? It's by far the biggest pain point I face when using Tuist solely because of how often I have to drag in or change resources and having to run tuist generate every single time is not great.

danieleformichelli commented 8 months ago

Nope, unfortunately it hasn't been implemented yet