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

Flutter wrapper to bundle flutter within a project #12827

Closed
passsy opened this Issue Nov 1, 2017 · 4 comments

Comments

Projects
None yet
3 participants
@passsy
Contributor

passsy commented Nov 1, 2017

It would be ideal if all devs and CI would use the exact same version of flutter to build and develop an app. Right now it's hard to bundle flutter within a repository. Git submodule would be one solution but it is currently not working #3770.

Gradle had the same problem and solved this with the gradle wrapper, automatically downloading the gradle binaries to a fixed version which is part of the projects repository. Instead of calling gradle everybody is used to call ./gradlew when executing gradle tasks.

There should be a ./flutterw which does exactly this, downloading the correct flutter version based on a version file which can be part of the repository.

working flutterw implementation

Here is my current ./flutterw implementation which works by putting it top level into a flutter project:

#!/bin/bash

# Use this flutter wrapper to bundle flutter within your project to make sure everybody builds with the same version
# put `flutterw` into the root of your flutter project and execute it. It will download all dependencies automatically when calling it.
# Use `./flutterw upgrade` to upgrade the flutter version, using the channel defined in flutter/wrapper/flutter-wrapper.properties

FLUTTERW_DIR="$(pwd -P)/flutter/wrapper"
FLUTTER_DIR="$(pwd -P)/.flutter"
WRAPPER_PROPERTIES="$FLUTTERW_DIR/flutter-wrapper.properties"
FLUTTER_REPO_URL="https://github.com/flutter/flutter.git"

DEFAULT_CHANNEL="alpha"

# Check if wrapper config file exists otherwise create with default values
if [ ! -d $FLUTTERW_DIR ]; then
    mkdir -p $FLUTTERW_DIR
fi

# Create wrapper properties file if it doesn't exit
if [ ! -f $WRAPPER_PROPERTIES ]; then
    # Use alpha here as recommended, will be replaced with explicit sha1 once cloned
    echo "flutter_channel=$DEFAULT_CHANNEL" > $WRAPPER_PROPERTIES
fi

# read all properties from config file
while IFS='=' read -r key value; do
    key=$(echo $key | tr '.' '_')
    eval "${key}='${value}'"
done < "$WRAPPER_PROPERTIES"


# Clone Flutter when not already cloned in project dir, the outer git repo will ignore this sub repo
if [ ! -d $FLUTTER_DIR ]; then
    echo "Downloading Flutter with wrapper"
    git clone $FLUTTER_REPO_URL $FLUTTER_DIR
fi

upgradeWrapperConfigFile () {
    FLUTTER_SHA1="$(git -C $FLUTTER_DIR rev-parse HEAD)"
    if [ ! -z "$FLUTTER_SHA1" ]; then
        # Write config file with updated version
        echo "flutter_channel=$flutter_channel" > $WRAPPER_PROPERTIES
        echo "flutter_version=$FLUTTER_SHA1" >> $WRAPPER_PROPERTIES
    else
        echo "Error: could not get version from flutter repo"
        exit 1
    fi
}

FLUTTER_SHA1="$(git -C $FLUTTER_DIR rev-parse HEAD)"

# When wrapper file version was changed, update flutter accordingly before executing
if [ "$flutter_version" != "$FLUTTER_SHA1" ]; then
    # use version when available, otherwise the channel on initial checkout
    if [ -z $flutter_version ]; then REV="$flutter_channel"; else REV="$flutter_version"; fi

    echo "Change Flutter version to $REV"

    git -C $FLUTTER_DIR checkout $REV -q
    upgradeWrapperConfigFile

    # when changing version also update binaries
    echo "Upgrading engine"
    $FLUTTER_DIR/bin/flutter precache
    $FLUTTER_DIR/bin/flutter packages upgrade
fi

# Flutter wrapper operates with detached HEAD. Upgrade won't work, flutter has to be on a branch to pull
# Checkout channel before upgrading
if [[ $@ == *"upgrade"* ]]; then
    echo "Switch to channel '$flutter_channel' before upgrading"
    git -C $FLUTTER_DIR checkout $flutter_channel -q
fi

set -e
"$FLUTTER_DIR/bin/flutter" "$@"


# Automatically update the flutter version in wrapper after upgrade; or at initial run without existing version
if [[ $@ == *"upgrade"* ]]; then
    upgradeWrapperConfigFile
fi

Benefits:

  • No more "works on my machine". Everybody uses the same flutter version (exact commit)
  • App version and flutter version are locked together. You'll never build an old app version with a never flutter version which could fail due to breaking changes or misbehave because of implementation detail changes.
  • Flutter doesn't have to be explicitly installed on CI, neither on any development machine. Basically all the Flutter installation & setup will be obsolete. It's only required to create a new project which could be moved into the flutter IntelliJ plugin.
  • It would simplify the logic to get the path of the flutter sdk by pointing to a fixed location within the repository ('../../.flutter')
    I could replace the logic with
project.ext.setProperty('flutter.sdk', file('../../.flutter').absolutePath)
apply from: "${rootProject.projectDir}/../.flutter/packages/flutter_tools/gradle/flutter.gradle"
  • It's easy to change the channel or specific commit of flutter. flutter upgrade is great but using a specific commit requires git checkout.

Missing

  • flutterw.bat for windows users
  • The IntelliJ plugin should automatically use the local flutter sdk (./flutterw) if available instead of the global one. This is already kind of working because flutter remembers which sdk was last used and it gets picked up by IntelliJ.
@eseidelGoogle

This comment has been minimized.

Show comment
Hide comment
@eseidelGoogle

eseidelGoogle Nov 6, 2017

Contributor

The way we've seen teams work around #3770 for now is to make their own fork of flutter/flutter and all pull from that fork.

Contributor

eseidelGoogle commented Nov 6, 2017

The way we've seen teams work around #3770 for now is to make their own fork of flutter/flutter and all pull from that fork.

@passsy

This comment has been minimized.

Show comment
Hide comment
@passsy

passsy Nov 6, 2017

Contributor

The main purpose of flutterw is that a flutter version - a file, containing the channel and exact commit hash - is part of the project and added to CVS. By using ./flutterw instead of flutter it is guaranteed that the app builds with the flutter version it was made for.

A fork is not a workaround to bind a specific flutter version to a project. It would fail when someone updates the fork. It would require everyone to update their dev machines and the CI environment to guarantee stable builds for everyone.
Working on different projects would require me to update all projects at once or me to manually change the version everytime I switch the project (multiple times a day).
Also, building a hotfix release for a previous version could cause new problems because the flutter version has also changed.
I don't think I have to add more arguments why the flutter version should be bundled with a project. In the end flutter is a dependency and dependencies shouldn't use dynamic versions.

Contributor

passsy commented Nov 6, 2017

The main purpose of flutterw is that a flutter version - a file, containing the channel and exact commit hash - is part of the project and added to CVS. By using ./flutterw instead of flutter it is guaranteed that the app builds with the flutter version it was made for.

A fork is not a workaround to bind a specific flutter version to a project. It would fail when someone updates the fork. It would require everyone to update their dev machines and the CI environment to guarantee stable builds for everyone.
Working on different projects would require me to update all projects at once or me to manually change the version everytime I switch the project (multiple times a day).
Also, building a hotfix release for a previous version could cause new problems because the flutter version has also changed.
I don't think I have to add more arguments why the flutter version should be bundled with a project. In the end flutter is a dependency and dependencies shouldn't use dynamic versions.

@Hixie

This comment has been minimized.

Show comment
Hide comment
@Hixie

Hixie May 24, 2018

Contributor

The solution we've been suggesting more recently is to use git submodules to import flutter as part of the git repo for your app.

Contributor

Hixie commented May 24, 2018

The solution we've been suggesting more recently is to use git submodules to import flutter as part of the git repo for your app.

@Hixie Hixie closed this May 24, 2018

@passsy

This comment has been minimized.

Show comment
Hide comment
@passsy

passsy May 24, 2018

Contributor

That's what I'm now suggesting as well. Here's my solution to ease the installation

Medium: https://medium.com/grandcentrix/flutter-wrapper-bind-your-project-to-an-explicit-flutter-release-4062cfe6dcaf
GitHub: https://github.com/passsy/flutter_wrapper

Contributor

passsy commented May 24, 2018

That's what I'm now suggesting as well. Here's my solution to ease the installation

Medium: https://medium.com/grandcentrix/flutter-wrapper-bind-your-project-to-an-explicit-flutter-release-4062cfe6dcaf
GitHub: https://github.com/passsy/flutter_wrapper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment