Skip to content

Feature- Cleanup Files #29

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

Closed
wants to merge 2 commits into from
Closed
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
94 changes: 53 additions & 41 deletions bin/flutterflow_cli.dart
Original file line number Diff line number Diff line change
@@ -1,55 +1,25 @@
import 'dart:io';

import 'package:args/args.dart';
import 'package:flutterflow_cli/src/flutterflow_api_client.dart';
import 'package:flutterflow_cli/flutterflow_cli.dart';

const kDefaultEndpoint = 'https://api.flutterflow.io/v1';

Future<void> appMain(List<String> args) async {
final parsedArguments = _parseArgs(args);
late Map<String,String> projectInfo;

final token =
parsedArguments['token'] ?? Platform.environment['FLUTTERFLOW_API_TOKEN'];

final project = parsedArguments.command!['project'] ??
Platform.environment['FLUTTERFLOW_PROJECT'];

if (project == null || project.isEmpty) {
stderr.write(
'Either --project option or FLUTTERFLOW_PROJECT environment variable must be set.\n');
exit(1);
}

if (parsedArguments['endpoint'] != null &&
parsedArguments['environment'] != null) {
stderr.write(
'Only one of --endpoint and --environment options can be set.\n');
exit(1);
}

if (token?.isEmpty ?? true) {
stderr.write(
'Either --token option or FLUTTERFLOW_API_TOKEN environment variable must be set.\n');
exit(1);
}

late String endpoint;
if (parsedArguments['endpoint'] != null) {
endpoint = parsedArguments['endpoint'];
} else if (parsedArguments['environment'] != null) {
endpoint =
"https://api-${parsedArguments['environment']}.flutterflow.io/v1";
} else {
endpoint = Platform.environment['FLUTTERFLOW_ENDPOINT'] ?? kDefaultEndpoint;
if (parsedArguments.command?.name != 'cleanup-files') {
projectInfo=getProjectInfo(parsedArguments);
}

try {
switch (parsedArguments.command?.name) {
case 'export-code':
await exportCode(
token: token,
endpoint: endpoint,
projectId: project,
token: projectInfo['token']!,
endpoint: projectInfo['endpoint']!,
projectId: projectInfo['project']!,
destinationPath: parsedArguments.command!['dest'],
includeAssets: parsedArguments.command!['include-assets'],
branchName: parsedArguments.command!['branch-name'],
Expand All @@ -63,12 +33,17 @@ Future<void> appMain(List<String> args) async {
break;
case 'deploy-firebase':
await firebaseDeploy(
token: token,
projectId: project,
token: projectInfo['token']!,
endpoint: projectInfo['endpoint']!,
projectId: projectInfo['project']!,
appendRules: parsedArguments.command!['append-rules'],
endpoint: endpoint,
);
break;
case 'cleanup-files':
await cleanupFiles(
autoDelete: parsedArguments.command!['auto-delete'],
folderPath: parsedArguments.command!['path']);
break;
default:
}
} catch (e) {
Expand Down Expand Up @@ -147,13 +122,22 @@ ArgResults _parseArgs(List<String> args) {
defaultsTo: false,
);

final cleanupFilesCommandParser = ArgParser()
..addOption('path', help: 'Project path', defaultsTo: '')
..addFlag('auto-delete',
abbr: 'd',
help: 'Automatically delete unused files',
negatable: true,
defaultsTo: false);

final parser = ArgParser()
..addOption('endpoint', abbr: 'e', help: 'Endpoint', hide: true)
..addOption('environment', help: 'Environment', hide: true)
..addOption('token', abbr: 't', help: 'API Token')
..addFlag('help', negatable: false, abbr: 'h', help: 'Help')
..addCommand('export-code', exportCodeCommandParser)
..addCommand('deploy-firebase', firebaseDeployCommandParser);
..addCommand('deploy-firebase', firebaseDeployCommandParser)
..addCommand('cleanup-files', cleanupFilesCommandParser);

late ArgResults parsed;
try {
Expand Down Expand Up @@ -183,6 +167,34 @@ ArgResults _parseArgs(List<String> args) {
return parsed;
}

/// Retrieves API Token, Project ID, and Endpoint
Map<String, String> getProjectInfo(ArgResults parsedArguments) {
final token = parsedArguments['token'] ?? Platform.environment['FLUTTERFLOW_API_TOKEN'];
final project = parsedArguments.command?['project'] ?? Platform.environment['FLUTTERFLOW_PROJECT'];

if (project == null || project.isEmpty) {
stderr.writeln('Error: Either --project option or FLUTTERFLOW_PROJECT environment variable must be set.');
exit(1);
}

if (token == null || token.isEmpty) {
stderr.writeln('Error: Either --token option or FLUTTERFLOW_API_TOKEN environment variable must be set.');
exit(1);
}

String endpoint = kDefaultEndpoint;
if (parsedArguments['endpoint'] != null && parsedArguments['environment'] != null) {
stderr.writeln('Error: Only one of --endpoint and --environment options can be set.');
exit(1);
} else if (parsedArguments['endpoint'] != null) {
endpoint = parsedArguments['endpoint'];
} else if (parsedArguments['environment'] != null) {
endpoint = "https://api-${parsedArguments['environment']}.flutterflow.io/v1";
}

return {'token': token, 'project': project, 'endpoint': endpoint};
}

void main(List<String> args) async {
await appMain(args);
}
1 change: 1 addition & 0 deletions lib/flutterflow_cli.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
library flutterflow_cli;

export 'package:flutterflow_cli/src/flutterflow_api_client.dart';
export 'package:flutterflow_cli/src/flutterflow_cleanup.dart';
69 changes: 69 additions & 0 deletions lib/src/flutterflow_cleanup.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import 'dart:io';

Future<void> cleanupFiles({bool autoDelete=false, String folderPath='lib'}) async {

print("Running DCM Analyzer for path: $folderPath...\n");

// Ensure dcm is installed
ProcessResult checkDcm = await Process.run('dcm', ['--version'], runInShell: true);
if (checkDcm.exitCode != 0) {
print("Error: 'dcm' is not installed. Install it using:\n dart pub global activate dcm");
exit(1);
}

// Run dcm check-unused-files
ProcessResult result = await Process.run('dcm', ['check-unused-files', folderPath], runInShell: true);
String output = result.stdout.trim();

// Using the working regex to extract file paths
RegExp unusedFilePattern = RegExp(r"⚠ unused file\s*\n\s*(.+)");
List<String> unusedFiles = [];

for (var match in unusedFilePattern.allMatches(output)) {
unusedFiles.add(match.group(1)!.trim());
}

// Show unused files
if (unusedFiles.isNotEmpty) {
print("\nUnused Files Found in '$folderPath':");
for (var file in unusedFiles) {
print(" - $file");
}

// Auto-delete if flag is set
if (autoDelete) {
print("\nAuto-deleting unused files...\n");
deleteFiles(unusedFiles);
} else {
// Ask user for confirmation before deletion
print("\nDo you want to delete these files? (yes/no)");
String? response = stdin.readLineSync();

if (response?.toLowerCase() == 'yes') {
deleteFiles(unusedFiles);
} else {
print("\nDeletion cancelled.");
}
}
} else {
print("\nNo unused files found in '$folderPath'.");
}
}

/// Function to delete files and handle errors
void deleteFiles(List<String> files) {
for (var file in files) {
File f = File(file);
if (f.existsSync()) {
try {
f.deleteSync();
print("Deleted: $file");
} catch (e) {
print("Failed to delete: $file. Error: $e");
}
} else {
print("File not found: $file");
}
}
print("\nCleanup completed successfully.");
}