File PACKAGING_NOTES.md of Package flutter
# Flutter Package - Technical Notes
## Overview
This document describes the technical details and solutions for packaging Flutter SDK as an RPM package for openSUSE.
## Key Challenges and Solutions
### Challenge 1: Flutter Requires a .git Directory
**Problem:**
Flutter SDK requires a `.git` directory to function. Many Flutter commands check git status, determine version information, and manage SDK updates through git operations.
**Initial Approach:**
OBS's `tar_scm` service by default excludes `.git` directories when creating source tarballs.
**Solution:**
We create a minimal git repository during the `%prep` phase of the build process. This approach:
- Initializes a fresh git repository
- Commits all Flutter SDK files
- Configures proper branch tracking
- Is replicated in the installed package at `/opt/flutter/.git`
### Challenge 2: Flutter Shows "unknown source" and Wrong Channel
**Problem:**
After initial implementation, Flutter showed:
```
Flutter • channel master • unknown source
```
When it should show:
```
Flutter • channel stable • https://github.com/flutter/flutter.git
```
**Root Cause:**
The minimal git repository created in `%prep` lacked:
1. A properly named branch matching the desired channel (stable, master, beta)
2. Upstream tracking configuration for the branch
3. Git configuration that Flutter's version detection code expects
**Flutter's Detection Logic:**
Flutter determines channel and source in `/opt/flutter/packages/flutter_tools/lib/src/version.dart`:
1. **Channel detection** (lines 603-607):
```dart
String get channel {
final String branch = getBranchName(); // Runs: git symbolic-ref --short HEAD
return kOfficialChannels.contains(branch) ? branch : '[user-branch]';
}
```
2. **Source URL detection** (lines 568-586):
```dart
final String gitChannel = _runGit(
'git rev-parse --abbrev-ref --symbolic @{upstream}', // Gets "origin/stable"
...
);
final int slash = gitChannel.indexOf('/');
if (slash != -1) {
final String remote = gitChannel.substring(0, slash); // Extracts "origin"
_repositoryUrl = _runGit(
'git ls-remote --get-url $remote', // Gets the URL
...
);
}
```
**Solution:**
Enhanced the `%prep` section to:
1. Create a branch named "stable" (`git checkout -b stable`)
2. Configure upstream tracking (`git branch --set-upstream-to=origin/stable stable`)
3. Verify the configuration meets Flutter's expectations
**Git Configuration Required:**
```ini
# Remote configuration (already present)
remote.origin.url=https://github.com/flutter/flutter.git
# Branch tracking configuration (ADDED)
branch.stable.remote=origin
branch.stable.merge=refs/heads/stable
```
**Verification:**
```bash
# Should output: stable
git symbolic-ref --short HEAD
# Should output: origin/stable
git rev-parse --abbrev-ref --symbolic @{upstream}
# Should output: https://github.com/flutter/flutter.git
git ls-remote --get-url origin
# Flutter version should now show:
flutter --version
# Flutter • channel stable • https://github.com/flutter/flutter.git
```
### Challenge 3: Permission Issues for User Access
**Problem:**
Flutter needs to download additional components and update its cache during `flutter doctor` and other operations. With a system-wide installation at `/opt/flutter`, regular users would lack write permissions.
**Solution:**
In the `%post` scriptlet:
1. Set ownership to `root:users` (most openSUSE users are in the `users` group)
2. Grant group write permissions (`chmod -R g+w`)
3. Configure git safe directory globally to prevent "dubious ownership" errors
This allows:
- Users to run `flutter doctor` and download SDK components
- Flutter to manage its cache directory
- Git operations to work without permission errors
## Implementation Details
### File: _service
Controls how OBS fetches the source code:
```xml
<service name="tar_scm">
<param name="url">https://github.com/flutter/flutter.git</param>
<param name="scm">git</param>
<param name="revision">stable</param> <!-- Tracks stable branch -->
<param name="version">3.27.4</param>
<param name="versionformat">@PARENT_TAG@+@TAG_OFFSET@</param>
</service>
```
**Key Parameter:**
- `revision=stable`: Ensures the source tarball is created from the stable branch
### File: flutter.spec
The RPM spec file that defines the build process.
**Key Sections:**
1. **%prep - Git Repository Setup (lines 52-103):**
```bash
# Initialize git repository
git init
git config user.email "build@opensuse.org"
git config user.name "OBS Build"
# Configure remote
git remote add origin https://github.com/flutter/flutter.git
# Initial commit
git add -A
git commit -m "Flutter SDK %{version}" --no-verify
# Create stable branch with upstream tracking
git checkout -b stable
git branch --set-upstream-to=origin/stable stable
# Verify configuration
git symbolic-ref --short HEAD # Should output: stable
git rev-parse --abbrev-ref --symbolic @{upstream} # Should output: origin/stable
```
2. **%install - Including .git Directory (lines 85-110):**
```bash
# Use -aT to preserve all attributes and copy .git
cp -aT . %{buildroot}/opt/flutter/
# Verify .git was copied
if [ -d %{buildroot}/opt/flutter/.git ]; then
echo "✓ .git directory present in buildroot"
fi
```
3. **%post - Permission Configuration (lines 114-123):**
```bash
# Allow users group to write to flutter directory
chown -R root:users /opt/flutter
chmod -R g+w /opt/flutter
# Mark as safe directory for git
git config --system --add safe.directory /opt/flutter
```
4. **%files - Explicitly Including .git (line 136):**
```
/opt/flutter/.git
```
This ensures RPM knows about the `.git` directory and includes it in the package.
## Switching Channels
To switch between stable/beta/master:
1. **Update `_service` file:**
```xml
<param name="revision">beta</param> <!-- or master -->
```
2. **Update `flutter.spec` %prep section:**
```bash
git checkout -b beta # or master
git branch --set-upstream-to=origin/beta beta # or origin/master master
```
3. **Rebuild:**
```bash
osc ci -m "Switch to beta channel"
osc rebuild home:Fitzmachine flutter
```
The rest of the configuration is channel-agnostic.
## Verification Procedures
### After Building
Check build logs for verification output:
```bash
osc buildlog home:Fitzmachine flutter openSUSE_Slowroll x86_64 | grep -A10 "Verifying git configuration"
```
Expected output:
```
=== Verifying git configuration for Flutter ===
Current branch: stable
Upstream tracking: origin/stable
Remote URL: https://github.com/flutter/flutter.git
✓ Git configuration correct for stable channel
```
### After Installation
1. **Check git configuration:**
```bash
cd /opt/flutter
git symbolic-ref --short HEAD # Should output: stable
git rev-parse --abbrev-ref --symbolic @{upstream} # Should output: origin/stable
git ls-remote --get-url origin # Should output: https://github.com/flutter/flutter.git
```
2. **Test Flutter version:**
```bash
flutter --version
# Should show: Flutter • channel stable • https://github.com/flutter/flutter.git
```
3. **Test Flutter doctor:**
```bash
flutter doctor -v
# Should complete without git-related errors
```
## Technical References
### Flutter Version Detection Code
Location: `/opt/flutter/packages/flutter_tools/lib/src/version.dart`
**Key Methods:**
- `getBranchName()` - Returns current git branch (lines 379-389)
- `channel` property - Determines if branch is an official channel (lines 603-607)
- `repositoryUrl` property - Extracts remote URL from upstream tracking (lines 568-586)
**Official Channels (lines 46-51):**
- `master` (or `main`)
- `beta`
- `stable`
### Git Configuration Details
The git configuration created by the %prep section:
```ini
[remote "origin"]
url = https://github.com/flutter/flutter.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "stable"]
remote = origin
merge = refs/heads/stable
```
**Why This Configuration is Required:**
1. Flutter calls: `git rev-parse --abbrev-ref --symbolic @{upstream}`
2. Without upstream tracking, this command fails with: "fatal: no upstream configured for branch"
3. When it fails, the returned string has no slash (`/`)
4. Without a slash, Flutter can't extract the remote name
5. Without a remote name, it can't get the URL via `git ls-remote --get-url`
6. `_repositoryUrl` stays `null`
7. In output, `${repositoryUrl ?? 'unknown source'}` shows "unknown source"
## Future Maintenance
### Monitoring Flutter Changes
Watch for changes to:
- `packages/flutter_tools/lib/src/version.dart` - Version detection logic
- Official channel names and conventions
- Git repository structure requirements
### Known Issues
None currently. If issues arise:
1. Check build logs for git configuration verification output
2. Verify installed package has proper git config: `cd /opt/flutter && git config --local --list`
3. Test with `flutter --version` to see actual detection results
## Build and Installation Commands
```bash
# Navigate to package directory
cd /home/FmX/OBS/home:Fitzmachine/flutter
# Commit changes
osc ci -m "Description of changes"
# Rebuild package
osc rebuild home:Fitzmachine flutter
# Check build status
osc results
# Get built packages
osc getbinaries home:Fitzmachine flutter openSUSE_Slowroll x86_64
# Install (if needed)
sudo zypper in --allow-unsigned-rpm binaries/flutter-*.rpm
```
## Package Information
- **Package Name:** flutter
- **Installation Path:** `/opt/flutter`
- **Binaries:** `/usr/bin/flutter`, `/usr/bin/dart` (symlinks)
- **License:** BSD-3-Clause
- **Upstream:** https://github.com/flutter/flutter
## Support and Issues
For issues with this package:
- Check verification procedures in this document
- Review build logs: `osc buildlog home:Fitzmachine flutter openSUSE_Slowroll x86_64`
- Verify git configuration in installed package: `cd /opt/flutter && git config --local --list`