Skip to content
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

fix file permissions in bundle #32

Merged
merged 1 commit into from
Aug 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion lib/src/build_system/build_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import 'dart:async';
import 'package:file/file.dart';
import 'package:flutterpi_tool/src/build_system/extended_environment.dart';
import 'package:flutterpi_tool/src/build_system/targets.dart';
import 'package:flutterpi_tool/src/cache.dart';
import 'package:flutterpi_tool/src/common.dart';
import 'package:flutterpi_tool/src/devices/flutterpi_ssh/device.dart';
import 'package:flutterpi_tool/src/fltool/common.dart';
import 'package:flutterpi_tool/src/fltool/globals.dart' as globals;
import 'package:flutterpi_tool/src/more_os_utils.dart';
import 'package:unified_analytics/unified_analytics.dart';

Future<FlutterpiAppBundle> buildFlutterpiApp({
Expand All @@ -16,6 +18,7 @@ Future<FlutterpiAppBundle> buildFlutterpiApp({
required FlutterpiTargetPlatform target,
required BuildInfo buildInfo,
required FlutterpiArtifactPaths artifactPaths,
required MoreOperatingSystemUtils operatingSystemUtils,
FlutterProject? project,
String? mainPath,
String manifestPath = defaultManifestPath,
Expand All @@ -38,6 +41,7 @@ Future<FlutterpiAppBundle> buildFlutterpiApp({
buildInfo: buildInfo,
artifactPaths: artifactPaths,
outDir: outDir,
operatingSystemUtils: operatingSystemUtils,
);

return PrebuiltFlutterpiAppBundle(
Expand All @@ -53,6 +57,7 @@ Future<void> buildFlutterpiBundle({
required FlutterpiTargetPlatform target,
required BuildInfo buildInfo,
required FlutterpiArtifactPaths artifactPaths,
required MoreOperatingSystemUtils operatingSystemUtils,
FlutterProject? project,
String? mainPath,
String manifestPath = defaultManifestPath,
Expand Down Expand Up @@ -89,7 +94,7 @@ Future<void> buildFlutterpiBundle({
}

// If the precompiled flag was not passed, force us into debug mode.
final environment = Environment(
final environment = ExtendedEnvironment(
projectDir: project.directory,
outputDir: outDir,
buildDir: project.dartTool.childDirectory('flutter_build'),
Expand Down Expand Up @@ -127,6 +132,7 @@ Future<void> buildFlutterpiBundle({
usage: globals.flutterUsage,
platform: globals.platform,
generateDartPluginRegistry: true,
operatingSystemUtils: operatingSystemUtils,
);

final buildTarget = switch (buildInfo.mode) {
Expand Down
112 changes: 112 additions & 0 deletions lib/src/build_system/extended_environment.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import 'package:file/file.dart';
import 'package:flutterpi_tool/src/fltool/common.dart';
import 'package:flutterpi_tool/src/more_os_utils.dart';
import 'package:process/process.dart';
import 'package:unified_analytics/unified_analytics.dart';

class ExtendedEnvironment implements Environment {
factory ExtendedEnvironment({
required Directory projectDir,
required Directory outputDir,
required Directory cacheDir,
required Directory flutterRootDir,
required FileSystem fileSystem,
required Logger logger,
required Artifacts artifacts,
required ProcessManager processManager,
required Platform platform,
required Usage usage,
required Analytics analytics,
String? engineVersion,
required bool generateDartPluginRegistry,
Directory? buildDir,
required MoreOperatingSystemUtils operatingSystemUtils,
Map<String, String> defines = const <String, String>{},
Map<String, String> inputs = const <String, String>{},
}) {
return ExtendedEnvironment.wrap(
operatingSystemUtils: operatingSystemUtils,
delegate: Environment(
projectDir: projectDir,
outputDir: outputDir,
cacheDir: cacheDir,
flutterRootDir: flutterRootDir,
fileSystem: fileSystem,
logger: logger,
artifacts: artifacts,
processManager: processManager,
platform: platform,
usage: usage,
analytics: analytics,
engineVersion: engineVersion,
generateDartPluginRegistry: generateDartPluginRegistry,
buildDir: buildDir,
defines: defines,
inputs: inputs,
),
);
}

ExtendedEnvironment.wrap({
required this.operatingSystemUtils,
required Environment delegate,
}) : _delegate = delegate;

final Environment _delegate;

@override
Analytics get analytics => _delegate.analytics;

@override
Artifacts get artifacts => _delegate.artifacts;

@override
Directory get buildDir => _delegate.buildDir;

@override
Directory get cacheDir => _delegate.cacheDir;

@override
Map<String, String> get defines => _delegate.defines;

@override
DepfileService get depFileService => _delegate.depFileService;

@override
String? get engineVersion => _delegate.engineVersion;

@override
FileSystem get fileSystem => _delegate.fileSystem;

@override
Directory get flutterRootDir => _delegate.flutterRootDir;

@override
bool get generateDartPluginRegistry => _delegate.generateDartPluginRegistry;

@override
Map<String, String> get inputs => _delegate.inputs;

@override
Logger get logger => _delegate.logger;

@override
Directory get outputDir => _delegate.outputDir;

@override
Platform get platform => _delegate.platform;

@override
ProcessManager get processManager => _delegate.processManager;

@override
Directory get projectDir => _delegate.projectDir;

@override
Directory get rootBuildDir => _delegate.rootBuildDir;

@override
Usage get usage => _delegate.usage;

final MoreOperatingSystemUtils operatingSystemUtils;
}
145 changes: 122 additions & 23 deletions lib/src/build_system/targets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
import 'dart:async';

import 'package:file/file.dart';
import 'package:flutterpi_tool/src/build_system/extended_environment.dart';
import 'package:flutterpi_tool/src/cache.dart';
import 'package:flutterpi_tool/src/common.dart';
import 'package:flutterpi_tool/src/fltool/common.dart';
import 'package:flutterpi_tool/src/fltool/globals.dart';
import 'package:flutterpi_tool/src/more_os_utils.dart';

class ReleaseBundleFlutterpiAssets extends CompositeTarget {
ReleaseBundleFlutterpiAssets({
Expand Down Expand Up @@ -127,6 +130,51 @@ class CopyIcudtl extends Target {
}
}

extension _FileExecutableBits on File {
(bool owner, bool group, bool other) getExecutableBits() {
// ignore: constant_identifier_names
const S_IXUSR = 00100, S_IXGRP = 00010, S_IXOTH = 00001;

final stat = statSync();
final mode = stat.mode;

return (
(mode & S_IXUSR) != 0,
(mode & S_IXGRP) != 0,
(mode & S_IXOTH) != 0
);
}
}

void fixupExePermissions(
File input,
File output, {
required Platform platform,
required Logger logger,
required MoreOperatingSystemUtils os,
}) {
if (platform.isLinux || platform.isMacOS) {
final inputExeBits = input.getExecutableBits();
final outputExeBits = output.getExecutableBits();

if (outputExeBits != (true, true, true)) {
if (inputExeBits == outputExeBits) {
logger.printTrace(
'${input.basename} in cache was not universally executable. '
'Changing permissions...',
);
} else {
logger.printTrace(
'Copying ${input.basename} from cache to output directory did not preserve executable bit. '
'Changing permissions...',
);
}

os.chmod(output, 'ugo+x');
}
}
}

class CopyFlutterpiBinary extends Target {
CopyFlutterpiBinary({
required this.target,
Expand All @@ -147,7 +195,31 @@ class CopyFlutterpiBinary extends Target {

final outputFile = environment.outputDir.childFile('flutter-pi');

if (!outputFile.parent.existsSync()) {
outputFile.parent.createSync(recursive: true);
}
file.copySync(outputFile.path);

if (environment.platform.isLinux || environment.platform.isMacOS) {
final inputExeBits = file.getExecutableBits();
final outputExeBits = outputFile.getExecutableBits();

if (outputExeBits != (true, true, true)) {
if (inputExeBits == outputExeBits) {
environment.logger.printTrace(
'flutter-pi binary in cache was not universally executable. '
'Changing permissions...',
);
} else {
environment.logger.printTrace(
'Copying flutter-pi binary from cache to output directory did not preserve executable bit. '
'Changing permissions...',
);
}

os.chmod(outputFile, 'ugo+x');
}
}
}

@override
Expand Down Expand Up @@ -222,22 +294,30 @@ class CopyFlutterpiEngine extends Target {
];

@override
Future<void> build(Environment environment) async {
Future<void> build(covariant ExtendedEnvironment environment) async {
final outputFile = environment.outputDir.childFile('libflutter_engine.so');
if (!outputFile.parent.existsSync()) {
outputFile.parent.createSync(recursive: true);
}

_artifactPaths
.getEngine(
engineCacheDir: environment.cacheDir
.childDirectory('artifacts')
.childDirectory('engine'),
hostPlatform: _hostPlatform,
target: flutterpiTargetPlatform,
flavor: _engineFlavor,
)
.copySync(outputFile.path);
final engine = _artifactPaths.getEngine(
engineCacheDir: environment.cacheDir
.childDirectory('artifacts')
.childDirectory('engine'),
hostPlatform: _hostPlatform,
target: flutterpiTargetPlatform,
flavor: _engineFlavor,
);

engine.copySync(outputFile.path);

fixupExePermissions(
engine,
outputFile,
platform: environment.platform,
logger: environment.logger,
os: environment.operatingSystemUtils,
);

if (includeDebugSymbols) {
final dbgsymsOutputFile =
Expand All @@ -246,15 +326,24 @@ class CopyFlutterpiEngine extends Target {
dbgsymsOutputFile.parent.createSync(recursive: true);
}

(_artifactPaths as FlutterpiArtifactPathsV2)
.getEngineDbgsyms(
engineCacheDir: environment.cacheDir
.childDirectory('artifacts')
.childDirectory('engine'),
target: flutterpiTargetPlatform,
flavor: _engineFlavor,
)
.copySync(dbgsymsOutputFile.path);
final dbgsyms =
(_artifactPaths as FlutterpiArtifactPathsV2).getEngineDbgsyms(
engineCacheDir: environment.cacheDir
.childDirectory('artifacts')
.childDirectory('engine'),
target: flutterpiTargetPlatform,
flavor: _engineFlavor,
);

dbgsyms.copySync(dbgsymsOutputFile.path);

fixupExePermissions(
dbgsyms,
dbgsymsOutputFile,
platform: environment.platform,
logger: environment.logger,
os: environment.operatingSystemUtils,
);
}
}
}
Expand Down Expand Up @@ -286,9 +375,19 @@ class FlutterpiAppElf extends Target {
];

@override
Future<void> build(Environment environment) async {
final File outputFile = environment.buildDir.childFile('app.so');
outputFile.copySync(environment.outputDir.childFile('app.so').path);
Future<void> build(covariant ExtendedEnvironment environment) async {
final appElf = environment.buildDir.childFile('app.so');
final outputFile = environment.outputDir.childFile('app.so');

appElf.copySync(outputFile.path);

fixupExePermissions(
appElf,
outputFile,
platform: environment.platform,
logger: logger,
os: environment.operatingSystemUtils,
);
}
}

Expand Down
1 change: 1 addition & 0 deletions lib/src/cli/commands/build.dart
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ class BuildCommand extends FlutterpiCommand {
buildInfo: buildInfo,
mainPath: targetFile,
artifactPaths: flutterpiCache.artifactPaths,
operatingSystemUtils: os,

// for `--debug-unoptimized` build mode
unoptimized: flavor.unoptimized,
Expand Down
1 change: 1 addition & 0 deletions lib/src/devices/flutterpi_ssh/device.dart
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ class FlutterpiSshDevice extends Device {
buildInfo: debuggingOptions.buildInfo,
artifactPaths: cache.artifactPaths,
mainPath: mainPath,
operatingSystemUtils: os,
);
}

Expand Down