You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
First off - thank you for the grinder tool. It is great find for me, since I found make didn't manage files with spaces and I have a bunch of them.
I've created a set of extensions to String, Glob, File, Directory, Iterable<File>, FileSet, and List<DateTime> that I found quite useful so I decided to share them here if anyone wants to use them or add them to the package or for their personal use.
Consider them public domain. They are created for grinder: "0.8.5". So they might not work for future visitors in case the package introduces breaking changes.
// grind_ext.dartimport'dart:io';
import'package:grinder/grinder.dart';
import'package:glob/glob.dart';
// TODO: do we need more sophisticated glob detection?final _globRegex =newRegExp(r'[*?{\[]');
extensionFileSetStringExtonString {
/// Returns a [File]Fileget asFile =>File(this);
/// Returns a [Directory]Directoryget asDirectory =>Directory(this);
/// Converts this to a [File] and then to a [FileSet] /// /// If this includes [Glob] characters: *, ?, {, or [ it will first be /// converted to a [Glob] and that to a [FileSet]. /// /// Note: [Glob] doesn't exclude files and dirs starting with a dot, while /// a recursive [FileSet] does. /// /// If you know this is a [Directory], then better use [allFiles].FileSetget asFileSet {
if (this.contains(_globRegex)) {
returnGlob(this).asFileSet;
}
returnthis.asFile.asFileSet;
}
/// Converts this to a [Directory] and passes all params to its [allFiles] /// methodFileSetallFiles({String pattern, bool recurse =true}) =>this.asDirectory.allFiles(pattern: pattern, recurse: recurse);
/// Converts this to a [Directory] and passes all params to its [allDartFiles] /// methodFileSetallDartFiles({bool recurse =true}) =>this.asDirectory.allDartFiles(recurse: recurse);
}
extensionFileSetGlobExtonGlob {
/// Runs [listSync] and collects all [File] objects into a [FileSet]FileSetget asFileSet =>listSync(followLinks:false).whereType<File>().asFileSet;
}
extensionFileSetFileExtonFile {
/// Returns a [FileSet]FileSetget asFileSet =>FileSet.fromFile(this);
}
extensionFileSetDirExtonDirectory {
/// Returns a [FileSet], passing all params to [fromDir]FileSetfileSet({String pattern, bool recurse =true}) =>FileSet.fromDir(this, pattern: pattern, recurse: recurse);
/// Returns the last modified date of the directoryDateTimeget lastModified =>this.statSync().modified;
/// Returns a [FileSet] using [fileSet]FileSetallFiles({String pattern, bool recurse =true}) =>this.fileSet(pattern: pattern, recurse: recurse);
/// Returns a [FileSet] using [fileSet], scoped to Dart files onlyFileSetallDartFiles({bool recurse =true}) =>this.fileSet(pattern:'*.dart', recurse: recurse);
}
extensionListFileExtonIterable<File> {
/// Converts to a [FileSet]FileSetget asFileSet =>FileSet.fromFile(this.first)..addFiles(this.skip(1));
}
extensionListStringExtonIterable<String> {
/// Converts to a list of [File] and then to a [FileSet]FileSetget asFileSet =>map((el) => el.asFile).asFileSet;
}
extensionOperationsExtonFileSet {
/// Adds a [File] to the [files]voidaddFile(File file) {
this.files.add(file);
}
/// Appends all [File] objects to the [files]voidaddFiles(Iterable<File> files) {
this.files.addAll(files);
}
/// Adds a [String], [File], [Directory], [Glob] or another [FileSet], /// producing a new [FileSet]FileSetoperator+(dynamic value) {
if (value isFileSet) {
// break-out first
} elseif (value isString) {
value =FileSetStringExt(value).asFileSet;
} elseif (value isFile) {
value =FileSetFileExt(value).asFileSet;
} elseif (value isDirectory) {
value =FileSetDirExt(value).fileSet();
} elseif (value isGlob) {
value =FileSetGlobExt(value).asFileSet;
}
if (value isFileSet) {
returnFileSet.fromFile(this.files.first)
..addFiles(this.files.skip(1))
..addFiles(value.files);
}
throwArgumentError.value(value, 'value',
'must be either a String, File, Directory, Glob or another FileSet');
}
}
extensionListDateTimeExtonList<DateTime> {
/// Returns tha latest [DateTime] in the list (or `null`)DateTimeget latest {
if (isEmpty) returnnull;
final zero =DateTime.fromMillisecondsSinceEpoch(0);
returnreduce(
(curr, el) => el !=null&& el.isAfter(curr ?? zero) ? el : curr);
}
}
Open up these details if you want to see how I use them.
import'package:grinder/grinder.dart';
import'package:pubspec_yaml/pubspec_yaml.dart';
import'./grind_ext.dart';
const projectName ='Runner';
const iosOutDir ='build/ios';
// NOTE: these are evaluated lazily - when read for the first timefinal pubspec ='pubspec.yaml'.asFile;
final version =
pubspec.readAsStringSync().toPubspecYaml().version.valueOr(() =>null);
final appFiles = pubspec.asFileSet + libDir.allDartFiles();
// --- iOS valuesfinal iosFiles = appFiles +'ios/Podfile'+'ios/Flutter/{Debug,Release}.xcconfig'.asFileSet +'ios/$projectName'.allFiles() +'ios/$projectName.xcodeproj'.allFiles();
final iosFilesExists = iosFiles.exists;
final iosFilesLastModified = iosFiles.lastModified;
final iosIpa ='$iosOutDir/iphoneos/Runner.app'.asDirectory;
final iosXCArchiveName ='$projectName-$version';
final iosXCArchive ='$iosOutDir/$iosXCArchiveName.xcarchive'.asDirectory;
voidmain(List<String> args) =>grind(args, verifyProjectRoot:true);
// /////////////////////////////////////////////////////////////////////////////@DefaultTask()
voidusage() =>print('Run `grind --help` to list available tasks.');
// /////////////////////////////////////////////////////////////////////////////@Task('Builds a release iOS archive.')
voidbuildIos() {
if (version ==null) fail('unable to read version in pubspec.yaml');
if (!iosFilesExists) fail('missing iOS files');
final hasArchive = iosXCArchive.existsSync();
if (!hasArchive || iosFilesLastModified.isAfter(iosXCArchive.lastModified)) {
// NOTE: we only want to depend on this if any of the iosFiles have changed!// TODO: can we generate ios/Flutter/Generated.xcconfig without building via flutter?flutterBuildIos();
if (hasArchive) iosXCArchive.deleteSync(recursive:true);
run('bash',
arguments: ['build_release.sh'],
workingDirectory:'ios',
runOptions:RunOptions(environment: {'XCARCHIVE_NAME': iosXCArchiveName}));
} else {
log('Archive is in ${iosXCArchive.path}');
}
}
// /////////////////////////////////////////////////////////////////////////////voidflutterBuildIos() {
if (version ==null) fail('unable to read version in pubspec.yaml');
if (!iosFilesExists) fail('missing iOS files');
if (!iosIpa.existsSync() ||
iosFilesLastModified.isAfter(iosIpa.lastModified)) {
run('flutter', arguments: ['build', 'ios']);
}
}
// /////////////////////////////////////////////////////////////////////////////@Task('Deploys a release iOS archive.')
@Depends(buildIos)
voiddeployIos() {
final exportOpts ='ios/export_options.plist'.asFileSet;
if (!exportOpts.exists)
fail('Export options file is missing: ${exportOpts.files.first.path}');
if (!iosXCArchive.existsSync())
fail('Archive is missing: ${iosXCArchive.path}');
run('bash',
arguments: ['deploy_release.sh'],
workingDirectory:'ios',
runOptions:RunOptions(environment: {'XCARCHIVE_NAME': iosXCArchiveName}));
// TODO: add a file to track latest deployed version (hash?)
}
I couldn't find a way to put them in the codebase of the package, so no PR. Sorry.
The text was updated successfully, but these errors were encountered:
This is not an issue.
First off - thank you for the grinder tool. It is great find for me, since I found
make
didn't manage files with spaces and I have a bunch of them.I've created a set of extensions to
String
,Glob
,File
,Directory
,Iterable<File>
,FileSet
, andList<DateTime>
that I found quite useful so I decided to share them here if anyone wants to use them or add them to the package or for their personal use.Consider them public domain. They are created for
grinder: "0.8.5"
. So they might not work for future visitors in case the package introduces breaking changes.Open up these details if you want to see how I use them.
I couldn't find a way to put them in the codebase of the package, so no PR. Sorry.
The text was updated successfully, but these errors were encountered: