Skip to content

Conversation

@ralph-bergmann
Copy link

@ralph-bergmann ralph-bergmann commented Apr 24, 2018

This commit adds a generator which generates a BuildConfig class located at lib/build_config.g.dart.

The generator runs when flutter run or flutter build is called (or its equivalent IDE methods).

The BuildConfig class holds some information about the current build; it looks like this:

// GENERATED CODE - DO NOT MODIFY BY HAND
// Will be (re-)generated by flutter run or flutter build command.

class BuildConfig {
  static const String kBuildTime = '2018-05-31T00:57:39.780680';
  static const int kBuildTimeMillisecondsSinceEpoch = 1527721059780;
  static const bool kDebug = false;
  static const String kModeName = 'release';
  static const String kFlavor = null;
  static const String kVersionName = '1.0.2';
  static const int kVersionNumber = 3;
  static const Map<String, dynamic> kBuildArguments = {
    'build-name': '1.0.2',
    'build-number': '5',
    'help': false,
    'target': 'lib/main.dart',
    'debug': false,
    'profile': false,
    'release': false,
    'pub': true,
    'preview-dart-2': true,
    'track-widget-creation': false,
    'prefer-shared-library': false,
    'target-platform': 'android-arm'
  };
}

If the project is executed or build with native tools the generator will not (re-)generate the BuildConfig class.

@ralph-bergmann ralph-bergmann force-pushed the add_buildconfig.dart branch 4 times, most recently from 10178ed to 453c9bf Compare April 25, 2018 09:15
@Hixie
Copy link
Contributor

Hixie commented Apr 27, 2018

Can you elaborate on what this patch does?

cc @tvolkert

Copy link
Contributor

@Hixie Hixie Apr 27, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(minor nit: our syntax for TODOs is // TODO(username): description, https://link_to_issue)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm guessing this wasn't intentional?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this presumably has to be generated at build time so shouldn't be in the template?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're actually trying to reduce our dependencies currently so we probably will want to avoid adding these if we can help it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can generate the code by hand but maybe it will not right formatted.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't actually use exact dartfmt style either so technically it might not be right formatted either way. :-)

@ralph-bergmann
Copy link
Author

@Hixie

When I call flutter build apk --debug --flavor="foo" the Flutter part knows nothing about it.

On Android, I have the BuildConfig class which knows all about the build, for example:

public final class BuildConfig {
  public static final boolean DEBUG = Boolean.parseBoolean("true");
  public static final String APPLICATION_ID = "eu.the4thfloor.msync.debug";
  public static final String BUILD_TYPE = "debug";
  public static final String FLAVOR = "";
  public static final int VERSION_CODE = 33;
  public static final String VERSION_NAME = "v1.0.15-debug (Build: d729bb8)";
}

This path creates a lib/build_config.g.dart file like this one:

// GENERATED CODE - DO NOT MODIFY BY HAND

class BuildConfig {
  static const bool kDebug = true;
  static const String kModeName = "debug";
  static const String kFlavor = null;
  static const String kVersionName = "1.0.0";
  static const int kVersionNumber = 1;
}

So it will be more comfortable on Dart side to do something depending on the build.

Copy link
Contributor

@Hixie Hixie May 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

syntax for TODOs is // TODO(username): description, https://link-to-issue

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not so easy to write a TODO in the right syntax :D

@Hixie
Copy link
Contributor

Hixie commented May 1, 2018

I'll let @mravn-google or @tvolkert do the actual review, I'm not familiar the Android build system.

@tvolkert
Copy link
Contributor

tvolkert commented May 1, 2018

I'm deferring to @mravn-google

@tvolkert
Copy link
Contributor

ping @mravn-google

@mravn-google
Copy link
Contributor

Sorry for the latency. Current behavior is that following flutter packages get, both the android/ and the ios/ sub-projects can be built using platform-specific tooling (Gradle for Android, Cocoapods+Xcode for iOS) with no need for flutter build xxx or flutter run. Does this PR change that behavior?

@ralph-bergmann
Copy link
Author

@mravn-google

This behaviour (build/run the project without Flutter tooling) isn't changed. But maybe the lib/build_config.g.dart file isn't (re-)generated which will let the app crash if the Dart part tries to access it. I will check it.

@Hixie
Copy link
Contributor

Hixie commented May 29, 2018

@the4thfloor Are you still looking into this? It's totally fine if not; we can take it over (though it might take longer). I'm just asking because I'm trying to clean out our review queue.

@ralph-bergmann
Copy link
Author

@Hixie it is still in progress :-)
I'm waiting for #16857 to be merged because I want to put the version info into the generated lib/build_config.g.dart file

@ralph-bergmann ralph-bergmann force-pushed the add_buildconfig.dart branch from de48f0d to 52b66dc Compare May 30, 2018 23:03
@ralph-bergmann ralph-bergmann changed the title [WIP] generate BuildConfig generate BuildConfig May 30, 2018
@ralph-bergmann ralph-bergmann force-pushed the add_buildconfig.dart branch 2 times, most recently from 10bb598 to 20bd871 Compare May 30, 2018 23:21
This commit adds a generator which generates a `BuildConfig` class located at `lib/build_config.g.dart`.
The generator runs when `flutter run` or `flutter build` is called.
The `BuildConfig` class holds some information about the current build.
@ralph-bergmann ralph-bergmann force-pushed the add_buildconfig.dart branch from 20bd871 to b0d7736 Compare May 30, 2018 23:30
@ralph-bergmann
Copy link
Author

@Hixie @mravn-google this PR is ready to review :-)

@mravn-google mravn-google changed the title generate BuildConfig Generate BuildConfig May 31, 2018
@mravn-google
Copy link
Contributor

Seems to me Flutter tooling needs a design change to provide a good user experience for working with generated files. This PR makes generated files part of default operation, which worries me a bit.

What is the intended status of the generated file? Is it supposed to be checked into version control?

  • If no, we'd want to add it to .gitignore, but then a newly checked-out project that uses BuildConfig in its Dart code will fail to be built by Gradle or Cocoapods+Xcode even after flutter packages get has been executed. That breaks a current property of Flutter tooling, as alluded to in an earlier comment.
  • If yes, any call to flutter run will make the repo dirty. That does not seem right either.

Other questions:

  • Should generated files be put in a special directory rather than next to main.dart?
  • Should plugins be able to use the generated file? If so, how could one set up a Flutter plugin project to accomplish that (right now, we seem to end up with a two-way dependency between the plugin and the hosting/example app)?
  • If somebody wanted to use protobufs or similar in their Flutter project, they would need generated Dart files too. One might wish for a standardized build step in the Flutter build tooling for codegen that should ideally work with codegen'ing plugins.

I think we should come up with reasonable answers to such questions, or at least make the generation of BuildConfig optional and non-default for now.

@ralph-bergmann
Copy link
Author

This BuildConfig class is inspired by the Android version of this class. And on Android app development, we use this class often.
In an ideal world, there is a "hidden" gen directory where the build tool can put generated classes, but I didn't find a way to add a second source folder beside the lib folder.
A standardized build step in the Flutter build tooling would be great but I'm not sure if I'm the right person to architect this change (i guess there are lots of pitfalls, etc.).

For now, I will add a flag to enable/disable this generation step. I would prefer to add this flag as an option in the Flutter part in the pubspec.yaml file to enable/disable this project-wide for all runs/builds. Are you fine with this?

@mravn-google
Copy link
Contributor

@devoncarew Any considerations on how the Flutter IDE plugins should handle codegen? This PR proposes to generate a build_config.g.dart file during execution of flutter run or flutter build.

@fmatosqg
Copy link
Contributor

My 2 cents is leaving lib/ alone, but as said above there's no built in way to add a gen folder.

Maybe we add a new package to hold generated files as part of the build? The advantage is that devs will clearly know what code was typed (lib) and what was generated (myapp_gen).

@zoechi
Copy link
Contributor

zoechi commented Jun 15, 2018

@fmatosqg all code-gen approaches (built_value, json_serializable, built_redux, ...) write to lib/ so I wouldn't be to worried about that.
I could imagine integrating https://github.com/dart-lang/build/tree/master/build_runner to be a great improvement and perhaps some config about what builders to run on what "lifecycle" events like before "flutter run", "flutter build", "packages get/upgrade", "on source file change (requires IDE support)" ...

If this PR would be implemented as such a builder there could also be a lib/version.dart file

part 'version.g.dart';
@versionInfo
class Version extends _$Version {}

and only if that file with that annotation exists the lib/version.g.dart file with the _$Version{...} class is generated.

@Hixie
Copy link
Contributor

Hixie commented Jul 3, 2018

@mravn-google How does this relate to the work you're doing? Is it compatible?

@mravn-google
Copy link
Contributor

Our work on add2app does not preclude code generation build steps. But for a seamless add2app experience, such steps should be executable via platform-specific build tooling (Gradle, CocoaPods and/or custom Xcode build scripts).

We already call flutter build aot from such tooling when building in non-debug mode and later flutter build bundle regardless of mode, so one approach would be extending flutter_tools/gradle/flutter.gradle and flutter_tools/bin/xcode_backend.sh with explicit calls to a Flutter CLI tool that does the code generation, before the optional flutter build aot step.

Maybe flutter build precompile?

@alexlovar
Copy link

alexlovar commented Jul 7, 2018

Hi, i implemented the changes on flutter folder files (Windows 10) in c:\flutter\packages\flutter_tools\lib\src\commands:
build.dart
build_apk.dart
build_ios.dart
run.dart
add the file: buildconfig_generator.dart in c:\flutter\packages\flutter_tools\lib\src
add on flutter _tools\test\buildconfig_generator_test.dart
follow the steps on https://medium.com/@ralphbergmann/versioning-with-flutter-299869e68af4
but i don't get the file lib/build_config.g.dart after run flutter command: run apk --release or Build...
the command run and the apk is generated but not build_config.g.dart is generated.
some guide or help? thank you!
buildconfig_generator.zip

@ralph-bergmann
Copy link
Author

@alexlovar I guess the best way to get is to check out this branch (and maybe rebase it with master)


dynamic _escape(dynamic value) {
if (value is String) {
return '\'$value\'';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is value contains an apostrophe or backslash?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is an excellent question. Currently, I don't know what happens, but I will look into it.

return output.toString();
}

dynamic _escape(dynamic value) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard for me to understand the range and domain of this method. It takes any type, and returns either an escaped string or the type unmodified? What if the type is an object whose toString isn't valid Dart, say?

];
await checkGenerator(manifest: manifest, buildInfo: buildInfo, expectedLines: expected);
});
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should probably also have a test that verifies that the generated file compiles and analyzes cleanly.


await generateBuildConfigClassAtPath(buildInfo: buildInfo, projectPath: projectPath);

final String srcFile = fs.path.join(projectPath, 'lib', 'build_config.g.dart');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to put this in the build/ directory?

@Hixie
Copy link
Contributor

Hixie commented Jul 21, 2018

@the4thfloor Sorry that we are not being very responsive and helpful on this PR... the truth is that we don't really have any build system experts on the team, and so we're somewhat stumbling around in the dark on this topic. It doesn't help that we'd like to keep things consistent between iOS and Android, so ideally anyone who owns this area would be an expert it both. We're hoping to have a more coherent solution to codegen at some point in the future, something that works reliably with hot reload, for example, but we haven't yet started thinking about that much and so we're not really sure what we want this to look like. As @mravn-google points out above, this is also something that interacts with our existing-app integration (where the build is driven not from the flutter tool but from the OEM build system).

It might be best to file a bug and list all the requirements (some of which are in comments on this PR), and then have a discussion about the overall architecture that will address all these requirements, before landing this PR.

@ralph-bergmann
Copy link
Author

@Hixie For me, it is okay when it needs longer than other PRs because it is a topic with a significant impact on the build system.
And on the other hand, currently, I'm on an iOS project and have not much time for Flutter :-(

My lasts thoughts before I switch to iOS was to use the hidden .dart_tools folder to store the generated files. But Flutter doesn't use this folder. I have to look into it why Flutter doesn't use it.

But if there is a more significant change in the build system in the pipe, it doesn't make sense to add other complicated things. Maybe it is better to discuss it first in a bug ticket.

@ycktw
Copy link

ycktw commented Aug 7, 2018

Hi, Is the file path possible to be the same with flutter i18n ?
I found flutter i18n use the path to generate lib/generated/i18n.dart
and the code also easy to rename from build_config.g.dart to lib/generated/build_config.dart

I think the4thfloor did a good job, thanks again.

--- a/packages/flutter_tools/lib/src/buildconfig_generator.dart
+++ b/packages/flutter_tools/lib/src/buildconfig_generator.dart
@@ -16,7 +16,7 @@ import 'bundle.dart' as bundle;
 import 'flutter_manifest.dart';
 import 'globals.dart';

-const String _kFileName = 'build_config.g.dart';
+const String _kFileName = 'generated/build_config.dart';

@fmatosqg
Copy link
Contributor

TL;DR I suggest using a convention where *.g.dart files get commited to git and lib/generated/*.dart are not.

I like lib/generated/build_config.dart, because it resonates with the idea of having lib/generated on .gitignore though not sure what's the role of that i18n file.

I believe 2 standards for generated files are needed, 1 for pre-build time such as autogenerated code that deals with json and people can argue whether they go in commits or note, and another for files that will be consistently overwritten during the build (as in C macros), meaning it's obvious nobody wants to commit them.

@Hixie
Copy link
Contributor

Hixie commented Aug 28, 2018

fyi @matthew-carroll you may find this bug relevant to your interests.

I think we should close this PR for now, because we don't have a complete handle on the problem space (as per my last comment). I think the next step is to file an issue that describes the problem we want solved, and to discuss a design there.

@Hixie
Copy link
Contributor

Hixie commented Sep 11, 2018

I'm going to close this PR per the last comment. Please do file an issue to discuss the design if you still desire a change in this area. Thanks.

@Hixie Hixie closed this Sep 11, 2018
@matthew-carroll
Copy link
Contributor

Sounds good. My 2 cents is that we need to figure out how to integrate Android's real BuildConfig on the engine side. We probably shouldn't imitate something that already exists, and I think it's our own build system shortcoming that we can't offer this Class as it usually exists.

@SteveAlexander
Copy link

I was a little disappointed this didn't get merged, as I wanted to be able to read the app's version data from within my app.

I worked around it by adding pubspec.yaml as an asset in the pubspec.yaml file, then using the pubspec_parse package to parse it.

rootBundle.loadStructuredData<Pubspec>(
  'pubspec.yaml',
  (string) async => await Pubspec.parse(string)
);

https://pub.dartlang.org/packages/pubspec_parse

@ralph-bergmann
Copy link
Author

@SteveAlexander try this plugin https://pub.dartlang.org/packages/package_info

@zoechi zoechi added the tool Affects the "flutter" command-line tool. See also t: labels. label Jan 5, 2019
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 8, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

tool Affects the "flutter" command-line tool. See also t: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.