felangel / mason

Tools which allow developers to create and consume reusable templates called bricks.
https://docs.brickhub.dev
964 stars 98 forks source link

feat: Read a default configuration file by convention instead of configuration #508

Open jsroest opened 2 years ago

jsroest commented 2 years ago

Description

I have a brick that generates two files:

  1. page
  2. controller

To be able to share the brick across projects, I've added some variables:

  1. project_name
  2. page_id
  3. page_name

This works great, but when you are working on a project, the project_name is for that project always the same. Asking the project_name is redundant and error-prone.

So I've added a configuration file mason-variables.json.

The Flutter project source is also generated using Mason, which means that this file is in my case always available and the content is specific for the generated Flutter project.

{
    "project_name": "flutter_demo_app"
}

So now I can run:

mason make rubigo_page -c mason-variables.json

and now the brick only asks for

  1. page_id
  2. page_name

Is there a way that I can eliminate the need for adding -c mason-variables.json to the mason command?

Of course, I could write a shell script, but that's not platform-independent. I also tried mason_hooks, but the pre_gen hook is executed after the variables are asked to the user.

A better idea might be to solve this by convention, for example, that a file with the name mason-variables.json in the working directory is read by default by Mason.

felangel commented 2 years ago

Hi @jsroest šŸ‘‹ Thanks for opening an issue!

Can you please provide a bit more context?

Using the -c flag is what Iā€™d recommend in this case. Do you just not like specifying the path to the configuration file?

You should be able to use a pre_gen.dart hook to dynamically set the project name. You can remove the project name from vars in the brick.yaml and just use the hook to populate the variable.

Lastly, you can always create an alias for this if you want to type slightly slightly fewer characters.

Let me know what you think, thanks!

jsroest commented 2 years ago

Hi,

Thanks for your quick reply.

Do you just not like specifying the path to the configuration file?

That's exactly the case.

Lastly, you can always create an alias for this if you want to type slightly fewer characters.

We have a mixed environment here, macOS and Windows. That would not be cross-platform.

You should be able to use a pre_gen.dart hook to dynamically set the project name. You can remove the project name from vars in the brick.yaml and just use the hook to populate the variable.

I've tried that.

This is the content of pre_gen.dart:

import 'package:mason/mason.dart';

void run(HookContext context) {
  // Read/Write vars
  context.vars = {...context.vars, 'project_name': 'flutter_demo_app'};

  // Use the logger
  context.logger.info('hook says hi!');
}

The problem with that is the variable project_name is still asked by Mason, and after that, overwritten by the pre_gen hook. This is confusing.

johannesroest@ws-z14 app % mason make rubigo_page
? What is the project name? this_will_be_overwritten
? What is the page id? s010
? What is the page name? ask_for_credentials
hook says hi!
āœ“ Made brick rubigo_page (64ms)
āœ“ Generated 2 file(s):
  /Users/johannesroest/repos/1122334-flutter_demo_app/packages/app/lib/pages/s010_ask_for_credentials/s010_ask_for_credentials_controller.dart (identical)
  /Users/johannesroest/repos/1122334-flutter_demo_app/packages/app/lib/pages/s010_ask_for_credentials/s010_ask_for_credentials_page.dart (identical)

This is the brick where you can find the {{project_name}}.

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:{{project_name}}/pages/pages.dart';
import 'package:{{project_name}}/pages/{{#snakeCase}}{{page_id}}_{{page_name}}{{/snakeCase}}/{{#snakeCase}}{{page_id}}_{{page_name}}{{/snakeCase}}_controller.dart';
import 'package:rubigo_navigator/rubigo_navigator.dart';

class {{#pascalCase}}{{page_id}}{{/pascalCase}}{{#pascalCase}}{{page_name}}{{/pascalCase}}Page extends RubigoPage<Pages, {{#pascalCase}}{{page_id}}{{/pascalCase}}{{#pascalCase}}{{page_name}}{{/pascalCase}}Controller> {
  const {{#pascalCase}}{{page_id}}{{/pascalCase}}{{#pascalCase}}{{page_name}}{{/pascalCase}}Page(ChangeNotifierProvider<{{#pascalCase}}{{page_id}}{{/pascalCase}}{{#pascalCase}}{{page_name}}{{/pascalCase}}Controller> controllerProvider,
      {Key? key})
      : super(controllerProvider, key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('{{#snakeCase}}{{page_id}}_{{page_name}}{{/snakeCase}}'),
      ),
      body: Container(),
    );
  }
}

That's why it's great for my case if Mason loads a configuration file with a specific name, for example mason-variables.json in the current folder by default. If the file is there, it will be read automatically, if the file is not there, Mason will ask for the variable.

It's not something that I can not live without, but it does streamline our use case.