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`
openSUSE Build Service is sponsored by