Skip to content

Commit

Permalink
version 1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
YehudaKremer committed Mar 23, 2021
1 parent c15fc37 commit 1c84029
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 147 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## 1.0.0

- null safety
- code refactoring
- move to sync code to increase stability
- fix: Wrong executable selection - https://github.com/YehudaKremer/msix/pull/32

## 0.1.19

- fix: Sometimes VC libraries are not copied - https://github.com/YehudaKremer/msix/issues/30
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ In your `pubspec.yaml`, add `msix` as a new dependency.
dev_dependencies:
flutter_test:
sdk: flutter
msix: ^0.1.19
msix: ^1.0.0
```
## Create Msix
Expand Down
58 changes: 29 additions & 29 deletions lib/msix.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import 'src/constants.dart';
import 'src/msixFiles.dart';

class Msix {
Configuration _configuration;
MsixFiles _msixFiles;
late Configuration _configuration;
late MsixFiles _msixFiles;

Msix() {
ansiColorDisabled = false;
Expand All @@ -19,16 +19,16 @@ class Msix {
/// Create and sign msix installer file
Future<void> createMsix(List<String> args) async {
await _configuration.getConfigValues(args);
await _configuration.validateConfigValues();
await _msixFiles.cleanTemporaryFiles();
await _msixFiles.createIconsFolder();
await _msixFiles.copyIcons();
await _msixFiles.generateAppxManifest();
_configuration.validateConfigValues();
_msixFiles.cleanTemporaryFiles();
_msixFiles.createIconsFolder();
_msixFiles.copyIcons();
_msixFiles.generateAppxManifest();
_msixFiles.copyVCLibsFiles();

if (!isNullOrStringNull(_configuration.vsGeneratedImagesFolderPath)) {
if (!_configuration.vsGeneratedImagesFolderPath.isNull) {
stdout.write(white('generate PRI file.. '));
var priResults = await _generatePRI();
var priResults = _generatePRI();

if (priResults.stderr.toString().length > 0) {
print(red(priResults.stdout));
Expand All @@ -42,7 +42,7 @@ class Msix {
}

stdout.write(white('packing.. '));
var packResults = await _pack();
var packResults = _pack();

if (packResults.stderr.toString().length > 0) {
print(red(packResults.stdout));
Expand All @@ -54,12 +54,12 @@ class Msix {
}
print(green('[√]'));

if (isNullOrStringNull(_configuration.certificatePath)) {
if (_configuration.certificatePath.isNull) {
print(yellow(
'skip signing step reason: Publisher provided but not Certificate Path'));
} else {
stdout.write(white('signing.. '));
var signResults = await _sign();
var signResults = _sign();

if (!signResults.stdout
.toString()
Expand All @@ -71,7 +71,7 @@ class Msix {
if (signResults.stdout
.toString()
.contains('Error: SignerSign() failed.') &&
!isNullOrStringNull(_configuration.publisher)) {
!_configuration.publisher.isNull) {
printCertificateSubjectHelp();
}

Expand All @@ -88,7 +88,7 @@ class Msix {
print(green('[√]'));
}

await _msixFiles.cleanTemporaryFiles();
_msixFiles.cleanTemporaryFiles();

print('');
print(green('Msix installer created in:'));
Expand All @@ -97,15 +97,15 @@ class Msix {
if (_configuration.isUsingTestCertificate) printTestCertificateHelp();
}

Future<ProcessResult> _generatePRI() async {
ProcessResult _generatePRI() {
var msixPath =
'${_configuration.buildFilesFolder}\\${_configuration.appName}.msix';
var makepriPath =
'${_configuration.msixToolkitPath()}/Redist.${_configuration.architecture}/makepri.exe';

if (await File(msixPath).exists()) await File(msixPath).delete();
if (File(msixPath).existsSync()) File(msixPath).deleteSync();

var result = await Process.run(makepriPath, [
var result = Process.runSync(makepriPath, [
'createconfig',
'/cf',
'${_configuration.buildFilesFolder}\\priconfig.xml',
Expand All @@ -123,7 +123,7 @@ class Msix {
exit(0);
}

result = await Process.run(makepriPath, [
result = Process.runSync(makepriPath, [
'new',
'/cf',
'${_configuration.buildFilesFolder}\\priconfig.xml',
Expand All @@ -137,20 +137,20 @@ class Msix {
]);

var priconfig = File('${_configuration.buildFilesFolder}/priconfig.xml');
if (await priconfig.exists()) await priconfig.delete();
if (priconfig.existsSync()) priconfig.deleteSync();

return result;
}

Future<ProcessResult> _pack() async {
ProcessResult _pack() {
var msixPath =
'${_configuration.buildFilesFolder}\\${_configuration.appName}.msix';
var makeappxPath =
'${_configuration.msixToolkitPath()}/Redist.${_configuration.architecture}/makeappx.exe';

if (await File(msixPath).exists()) await File(msixPath).delete();
if (File(msixPath).existsSync()) File(msixPath).deleteSync();

return await Process.run(makeappxPath, [
return Process.runSync(makeappxPath, [
'pack',
'/v',
'/o',
Expand All @@ -161,31 +161,31 @@ class Msix {
]);
}

Future<ProcessResult> _sign() async {
ProcessResult _sign() {
var signtoolPath =
'${_configuration.msixToolkitPath()}/Redist.${_configuration.architecture}/signtool.exe';

if (extension(_configuration.certificatePath) == '.pfx') {
return await Process.run(signtoolPath, [
if (extension(_configuration.certificatePath!) == '.pfx') {
return Process.runSync(signtoolPath, [
'sign',
'/fd',
'SHA256',
'/a',
'/f',
_configuration.certificatePath,
_configuration.certificatePath!,
'/p',
_configuration.certificatePassword,
_configuration.certificatePassword!,
'/tr',
'http://timestamp.digicert.com',
'${_configuration.buildFilesFolder}\\${_configuration.appName}.msix',
]);
} else {
return await Process.run(signtoolPath, [
return Process.runSync(signtoolPath, [
'sign',
'/fd',
'SHA256',
'/a',
_configuration.certificatePath,
_configuration.certificatePath!,
'${_configuration.buildFilesFolder}\\${_configuration.appName}.msix',
]);
}
Expand Down
113 changes: 54 additions & 59 deletions lib/src/configuration.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,41 @@ import 'utils.dart';
import 'constants.dart';

class Configuration {
ArgResults argResults;
late ArgResults argResults;
String msixAssetsPath = '';
String appName;
String publisherName;
String identityName;
String msixVersion;
String appDescription;
String publisher;
String? appName;
String? publisherName;
String? identityName;
String? msixVersion;
String? appDescription;
String? publisher;
String buildFilesFolder =
'${Directory.current.path}/build/windows/runner/Release';
String certificatePath;
String certificatePassword;
String displayName;
String architecture;
String capabilities;
String logoPath;
String startMenuIconPath;
String tileIconPath;
String vsGeneratedImagesFolderPath;
String executableFileName;
String iconsBackgroundColor;
String? certificatePath;
String? certificatePassword;
String? displayName;
String? architecture;
String? capabilities;
String? logoPath;
String? startMenuIconPath;
String? tileIconPath;
String? vsGeneratedImagesFolderPath;
String? executableFileName;
String? iconsBackgroundColor;
bool isUsingTestCertificate = false;
String defaultsIconsFolderPath() => '$msixAssetsPath/icons';
String vcLibsFolderPath() => '$msixAssetsPath/VCLibs';
String msixToolkitPath() => '$msixAssetsPath/MSIX-Toolkit';

Future<void> getConfigValues(List<String> args) async {
stdout.write(white('getting config values.. '));

_parseCliArguments(args);

await _getAssetsFolderPath();

var pubspec = await _getPubspec();

var pubspec = _getPubspec();
appName = pubspec['name'].toString();
appDescription = pubspec['description'].toString();
if (!isNullOrStringNull(pubspec['msix_config'].toString())) {

if (!pubspec['msix_config'].toString().isNull) {
displayName = pubspec['msix_config']['display_name'].toString();
publisherName =
pubspec['msix_config']['publisher_display_name'].toString();
Expand Down Expand Up @@ -76,9 +73,8 @@ class Configuration {
}

/// parse the cli options
Future<void> _parseCliArguments(List<String> args) async {
var parser = ArgParser();
parser.addOption('password', abbr: 'p');
void _parseCliArguments(List<String> args) {
var parser = ArgParser()..addOption('password', abbr: 'p');

try {
argResults = parser.parse(args);
Expand All @@ -102,66 +98,65 @@ class Configuration {
}

/// Get pubspec.yaml content
dynamic _getPubspec() async {
var pubspecFile = File("pubspec.yaml");
var pubspecString = await pubspecFile.readAsString();
dynamic _getPubspec() {
var pubspecString = File("pubspec.yaml").readAsStringSync();
var pubspec = loadYaml(pubspecString);
return pubspec;
}

/// Validate the configuration values and set default values
Future<void> validateConfigValues() async {
void validateConfigValues() {
stdout.write(white('validate config values.. '));

if (isNullOrStringNull(appName))
if (appName.isNull)
throw (red('App name is empty, check \'appName\' at pubspec.yaml'));

if (isNullOrStringNull(appDescription)) appDescription = appName;
if (isNullOrStringNull(displayName))
displayName = appName.replaceAll('_', '');
if (isNullOrStringNull(identityName))
identityName = 'com.flutter.${appName.replaceAll('_', '')}';
if (isNullOrStringNull(publisherName)) publisherName = identityName;
if (isNullOrStringNull(msixVersion)) msixVersion = '1.0.0.0';
if (isNullOrStringNull(architecture)) architecture = 'x64';
if (isNullOrStringNull(capabilities))
if (appDescription.isNull) appDescription = appName;
if (displayName.isNull) displayName = appName!.replaceAll('_', '');
if (identityName.isNull)
identityName = 'com.flutter.${appName!.replaceAll('_', '')}';
if (publisherName.isNull) publisherName = identityName;
if (msixVersion.isNull) msixVersion = '1.0.0.0';
if (architecture.isNull) architecture = 'x64';
if (capabilities.isNull)
capabilities = 'internetClient,location,microphone,webcam';
if (isNullOrStringNull(iconsBackgroundColor))
iconsBackgroundColor = 'transparent';
if (iconsBackgroundColor.isNull) iconsBackgroundColor = 'transparent';

if (!await Directory(buildFilesFolder).exists())
if (!Directory(buildFilesFolder).existsSync())
throw (red(
'Build files not found as $buildFilesFolder, first run "flutter build windows" then try again'));

executableFileName = await Directory(buildFilesFolder)
.list()
.map((file) => basename(file.path))
.firstWhere((fileName) => fileName.contains('.exe'),
orElse: () => '$appName.exe');
final executables = Directory(buildFilesFolder)
.listSync()
.where((file) => file.path.endsWith('.exe'))
.map((file) => basename(file.path));

executableFileName = executables.firstWhere(
(exeName) => exeName == '$appName.exe',
orElse: () => executables.first);

if (!RegExp(r'^(\*|\d+(\.\d+){3,3}(\.\*)?)$').hasMatch(msixVersion))
if (!RegExp(r'^(\*|\d+(\.\d+){3,3}(\.\*)?)$').hasMatch(msixVersion!))
throw (red('Msix version can be only in this format: "1.0.0.0"'));

/// If no certificate was chosen then use test certificate
if (isNullOrStringNull(certificatePath)) {
if (isNullOrStringNull(publisher)) {
if (certificatePath.isNull) {
if (publisher.isNull) {
certificatePath = '$msixAssetsPath/test_certificate.pfx';
certificatePassword = '1234';
publisher = defaultPublisher;
isUsingTestCertificate = true;
}
} else if (!await File(certificatePath).exists())
} else if (!File(certificatePath!).existsSync())
throw (red(
'The file certificate not found in: $certificatePath, check "msix_config: certificate_path" at pubspec.yaml'));
else if (isNullOrStringNull(publisher)) {
else if (publisher.isNull) {
print(red(
'Certificate subject is empty, check "msix_config: publisher" at pubspec.yaml'));
print(yellow('see what certificate-subject value is:'));
print(blue(
'https://drive.google.com/file/d/1oAsnrp2Kf-jZ_kaRjyF5llQ0YZy1IwNe/view?usp=sharing'));
exit(0);
} else if (extension(certificatePath) == '.pfx' &&
isNullOrStringNull(certificatePassword))
} else if (extension(certificatePath!) == '.pfx' &&
certificatePassword.isNull)
throw (red(
'Certificate password is empty, check "msix_config: certificate_password" at pubspec.yaml'));

Expand All @@ -170,10 +165,10 @@ class Configuration {
'Architecture can be "x86" or "x64", check "msix_config: architecture" at pubspec.yaml'));

if (iconsBackgroundColor != 'transparent' &&
!iconsBackgroundColor.contains('#'))
!iconsBackgroundColor!.contains('#'))
iconsBackgroundColor = '#$iconsBackgroundColor';
if (iconsBackgroundColor != 'transparent' &&
!RegExp(r'^#(?:[0-9a-fA-F]{3}){1,2}$').hasMatch(iconsBackgroundColor))
!RegExp(r'^#(?:[0-9a-fA-F]{3}){1,2}$').hasMatch(iconsBackgroundColor!))
throw (red(
'Icons background color can be only in this format: "#ffffff"'));

Expand Down
Loading

0 comments on commit 1c84029

Please sign in to comment.