diff --git a/lib/apis/git_migration.dart b/lib/apis/git_migration.dart deleted file mode 100644 index b5e9de92..00000000 --- a/lib/apis/git_migration.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'dart:async'; -import 'dart:io'; - -import 'package:flutter/foundation.dart'; - -import 'package:git_bindings/git_bindings.dart'; -import 'package:path/path.dart' as p; - -import 'package:gitjournal/utils/logger.dart'; - -// -// FIXME: This isn't ideal as we are skipping all the edits / deletes -// -Future migrateGitRepo({ - @required String gitBasePath, - @required String fromGitBasePath, - @required String toGitBaseFolder, - @required String gitAuthor, - @required String gitAuthorEmail, -}) async { - Log.d("migrateGitRepo $fromGitBasePath $toGitBaseFolder"); - var fromBasePath = p.join(gitBasePath, fromGitBasePath); - var toGitRepoPath = p.join(gitBasePath, toGitBaseFolder); - Log.d("toGitRemotePath $toGitRepoPath"); - - final dir = Directory(fromBasePath); - var lister = dir.list(recursive: false); - await for (var fileEntity in lister) { - if (fileEntity is! File) { - continue; - } - File file = fileEntity; - var fileName = p.basename(file.path); - var toPath = p.join(toGitRepoPath, fileName); - - Log.d("Migrating " + file.path + " --> " + toPath); - - await file.copy(toPath); - - var gitRepo = GitRepo(folderPath: toGitRepoPath); - await gitRepo.add(fileName); - await gitRepo.commit( - message: "Added Note", - authorEmail: gitAuthorEmail, - authorName: gitAuthor, - ); - } - Log.d("migrateGitRepo: Done"); -} diff --git a/lib/app.dart b/lib/app.dart index 6d223c70..c7077a9a 100644 --- a/lib/app.dart +++ b/lib/app.dart @@ -67,12 +67,16 @@ class JournalApp extends StatefulWidget { } Log.i('-----'); + await settings.migrate(pref, appState.gitBaseDirectory); + + // FIXME: This can be replaced with a fs stat if (settings.localGitRepoConfigured == false) { + settings.internalRepoFolderName = "journal"; + // FIXME: What about exceptions! - settings.localGitRepoFolderName = "journal_local"; var repoPath = p.join( appState.gitBaseDirectory, - settings.localGitRepoFolderName, + settings.internalRepoFolderName, ); await GitRepository.init(repoPath); @@ -381,8 +385,9 @@ class _JournalAppState extends State { return SettingsScreen(); case '/setupRemoteGit': return GitHostSetupScreen( - "journal", - stateContainer.completeGitHostSetup, + repoFolderName: settings.internalRepoFolderName, + remoteName: "origin", + onCompletedFunction: stateContainer.completeGitHostSetup, ); case '/onBoarding': return OnBoardingScreen(); diff --git a/lib/core/git_repo.dart b/lib/core/git_repo.dart index 52922bfe..0a36c2d6 100644 --- a/lib/core/git_repo.dart +++ b/lib/core/git_repo.dart @@ -180,14 +180,18 @@ class GitNoteRepository { Future merge() async { var repo = await git.GitRepository.load(gitDirPath); var branch = await repo.currentBranch(); - if (branch == null) { + var branchConfig = repo.config.branch(branch); + if (branchConfig == null) { logExceptionWarning(Exception("Current Branch null"), StackTrace.current); return; } + assert(branchConfig.name != null); + assert(branchConfig.merge != null); + try { await _gitRepo.merge( - branch: branch.remoteTrackingBranch(), + branch: branchConfig.remoteTrackingBranch(), authorEmail: settings.gitAuthorEmail, authorName: settings.gitAuthor, ); diff --git a/lib/screens/settings_git_remote.dart b/lib/screens/settings_git_remote.dart index 22773871..59cf466f 100644 --- a/lib/screens/settings_git_remote.dart +++ b/lib/screens/settings_git_remote.dart @@ -148,8 +148,9 @@ class _GitRemoteSettingsScreenState extends State { var route = MaterialPageRoute( builder: (context) => GitHostSetupScreen( - repoFolderName, - stateContainer.completeGitHostSetup, + repoFolderName: repoFolderName, + remoteName: 'origin', + onCompletedFunction: stateContainer.completeGitHostSetup, ), settings: const RouteSettings(name: '/setupRemoteGit'), ); diff --git a/lib/settings.dart b/lib/settings.dart index 4618095a..c1231123 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -1,12 +1,16 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:collection/collection.dart'; import 'package:easy_localization/easy_localization.dart'; +import 'package:path/path.dart' as p; import 'package:shared_preferences/shared_preferences.dart'; import 'package:gitjournal/core/sorting_mode.dart'; import 'package:gitjournal/folder_views/common.dart'; import 'package:gitjournal/screens/note_editor.dart'; +import 'package:gitjournal/utils/logger.dart'; class Settings extends ChangeNotifier { Settings(); @@ -34,7 +38,7 @@ class Settings extends ChangeNotifier { SettingsFolderViewType defaultView = SettingsFolderViewType.Default; bool showNoteSummary = true; String folderViewHeaderType = "TitleGenerated"; - int version = 0; + int version = 1; SettingsHomeScreen homeScreen = SettingsHomeScreen.Default; @@ -56,10 +60,9 @@ class Settings extends ChangeNotifier { bool bottomMenuBar = false; // From AppState - String localGitRepoFolderName = ""; + String internalRepoFolderName = ""; bool localGitRepoConfigured = false; - String remoteGitRepoFolderName = ""; bool remoteGitRepoConfigured = false; bool storeInternally = true; @@ -131,8 +134,7 @@ class Settings extends ChangeNotifier { // From AppState localGitRepoConfigured = pref.getBool("localGitRepoConfigured") ?? false; remoteGitRepoConfigured = pref.getBool("remoteGitRepoConfigured") ?? false; - localGitRepoFolderName = pref.getString("localGitRepoPath") ?? ""; - remoteGitRepoFolderName = pref.getString("remoteGitRepoPath") ?? ""; + internalRepoFolderName = pref.getString("remoteGitRepoPath") ?? ""; bottomMenuBar = pref.getBool("bottomMenuBar") ?? bottomMenuBar; storeInternally = pref.getBool("storeInternally") ?? storeInternally; @@ -221,8 +223,7 @@ class Settings extends ChangeNotifier { pref.setBool("localGitRepoConfigured", localGitRepoConfigured); pref.setBool("remoteGitRepoConfigured", remoteGitRepoConfigured); - pref.setString("localGitRepoPath", localGitRepoFolderName); - pref.setString("remoteGitRepoPath", remoteGitRepoFolderName); + pref.setString("remoteGitRepoPath", internalRepoFolderName); notifyListeners(); } @@ -302,8 +303,7 @@ class Settings extends ChangeNotifier { 'emojiParser': emojiParser.toString(), 'localGitRepoConfigured': localGitRepoConfigured.toString(), 'remoteGitRepoConfigured': remoteGitRepoConfigured.toString(), - 'localGitRepoFolderName': localGitRepoFolderName.toString(), - 'remoteGitRepoFolderName': remoteGitRepoFolderName.toString(), + 'remoteGitRepoPath': internalRepoFolderName.toString(), 'bottomMenuBar': bottomMenuBar.toString(), 'storeInternally': storeInternally.toString(), 'storageLocation': storageLocation, @@ -317,6 +317,24 @@ class Settings extends ChangeNotifier { m.remove("defaultNewNoteFolderSpec"); return m; } + + Future migrate(SharedPreferences pref, String gitBaseDir) async { + if (version == 0) { + if (localGitRepoConfigured && !remoteGitRepoConfigured) { + Log.i("Migrating from local and remote repos to a single one"); + var oldName = p.join(gitBaseDir, "journal_local"); + var newName = p.join(gitBaseDir, "journal"); + + await Directory(oldName).rename(newName); + internalRepoFolderName = "journal"; + + version = 1; + pref.setInt("settingsVersion", version); + pref.setString('remoteGitRepoPath', internalRepoFolderName); + return; + } + } + } } class NoteFileNameFormat { diff --git a/lib/setup/screens.dart b/lib/setup/screens.dart index b70a8e1f..e935dc26 100644 --- a/lib/setup/screens.dart +++ b/lib/setup/screens.dart @@ -3,10 +3,11 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:dart_git/git.dart'; import 'package:dots_indicator/dots_indicator.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:function_types/function_types.dart'; -import 'package:git_bindings/git_bindings.dart'; +import 'package:git_bindings/git_bindings.dart' as git_bindings; import 'package:path/path.dart' as p; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -27,9 +28,14 @@ import 'package:gitjournal/utils/logger.dart'; class GitHostSetupScreen extends StatefulWidget { final String repoFolderName; - final Func1 onCompletedFunction; + final String remoteName; + final Func2 onCompletedFunction; - GitHostSetupScreen(this.repoFolderName, this.onCompletedFunction); + GitHostSetupScreen({ + @required this.repoFolderName, + @required this.remoteName, + @required this.onCompletedFunction, + }); @override GitHostSetupScreenState createState() { @@ -203,7 +209,10 @@ class GitHostSetupScreenState extends State { } else if (_keyGenerationChoice == KeyGenerationChoice.UserProvided) { return GitHostUserProvidedKeys( doneFunction: (String publicKey, String privateKey) async { - await setSshKeys(publicKey: publicKey, privateKey: privateKey); + await git_bindings.setSshKeys( + publicKey: publicKey, + privateKey: privateKey, + ); setState(() { this.publicKey = publicKey; _pageCount = pos + 2; @@ -284,7 +293,8 @@ class GitHostSetupScreenState extends State { } else if (_keyGenerationChoice == KeyGenerationChoice.UserProvided) { return GitHostUserProvidedKeys( doneFunction: (String publicKey, String privateKey) async { - await setSshKeys(publicKey: publicKey, privateKey: privateKey); + await git_bindings.setSshKeys( + publicKey: publicKey, privateKey: privateKey); setState(() { this.publicKey = publicKey; _pageCount = pos + 2; @@ -399,7 +409,7 @@ class GitHostSetupScreenState extends State { "-" + DateTime.now().toIso8601String().substring(0, 10); // only the date - generateSSHKeys(comment: comment).then((String publicKey) { + git_bindings.generateSSHKeys(comment: comment).then((String publicKey) { setState(() { this.publicKey = publicKey; Log.d("PublicKey: " + publicKey); @@ -471,17 +481,21 @@ class GitHostSetupScreenState extends State { var stateContainer = Provider.of(context, listen: false); var basePath = stateContainer.appState.gitBaseDirectory; - // Just in case it was half cloned because of an error - String repoPath = p.join(basePath, widget.repoFolderName); - await _removeExistingClone(repoPath); + var settings = Provider.of(context, listen: false); + var repoName = settings.internalRepoFolderName; + var repoPath = p.join(basePath, repoName); + Log.i("RepoPath: $repoPath"); String error; try { - Log.d("Cloning " + _gitCloneUrl); - await GitRepo.clone(repoPath, _gitCloneUrl); - } on GitException catch (e) { + var repo = await GitRepository.load(repoPath); + await repo.addRemote(widget.remoteName, _gitCloneUrl); + + var repoN = git_bindings.GitRepo(folderPath: repoPath); + await repoN.fetch(widget.remoteName); + } on Exception catch (e) { Log.e(e.toString()); - error = e.cause; + error = e.toString(); } if (error != null && error.isNotEmpty) { @@ -507,9 +521,7 @@ class GitHostSetupScreenState extends State { var ignoreFile = File(p.join(repoPath, ".gitignore")); ignoreFile.createSync(); - var repo = GitRepo( - folderPath: repoPath, - ); + var repo = git_bindings.GitRepo(folderPath: repoPath); await repo.add('.gitignore'); var settings = Provider.of(context, listen: false); @@ -525,7 +537,7 @@ class GitHostSetupScreenState extends State { parameters: _buildOnboardingAnalytics(), ); Navigator.pop(context); - widget.onCompletedFunction(widget.repoFolderName); + widget.onCompletedFunction(widget.repoFolderName, widget.remoteName); } Future _completeAutoConfigure() async { @@ -536,7 +548,7 @@ class GitHostSetupScreenState extends State { setState(() { _autoConfigureMessage = tr('setup.sshKey.generate'); }); - var publicKey = await generateSSHKeys(comment: "GitJournal"); + var publicKey = await git_bindings.generateSSHKeys(comment: "GitJournal"); Log.i("Adding as a deploy key"); _autoConfigureMessage = tr('setup.sshKey.addDeploy'); @@ -594,17 +606,6 @@ class GitHostSetupScreenState extends State { return map; } - - Future _removeExistingClone(String baseDirPath) async { - var baseDir = Directory(baseDirPath); - var dotGitDir = Directory(p.join(baseDir.path, ".git")); - bool exists = dotGitDir.existsSync(); - if (exists) { - Log.d("Removing " + baseDir.path); - await baseDir.delete(recursive: true); - await baseDir.create(); - } - } } class GitHostChoicePage extends StatelessWidget { diff --git a/lib/state_container.dart b/lib/state_container.dart index 6526852a..29c100c8 100644 --- a/lib/state_container.dart +++ b/lib/state_container.dart @@ -4,11 +4,11 @@ import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:dart_git/dart_git.dart'; import 'package:path/path.dart' as p; import 'package:synchronized/synchronized.dart'; import 'package:gitjournal/analytics.dart'; -import 'package:gitjournal/apis/git_migration.dart'; import 'package:gitjournal/appstate.dart'; import 'package:gitjournal/core/git_repo.dart'; import 'package:gitjournal/core/note.dart'; @@ -40,22 +40,11 @@ class StateContainer with ChangeNotifier { @required this.gitBaseDirectory, }) { assert(settings.localGitRepoConfigured); - - String repoPath; - if (settings.remoteGitRepoConfigured) { - repoPath = p.join(gitBaseDirectory, settings.remoteGitRepoFolderName); - } else if (settings.localGitRepoConfigured) { - repoPath = p.join(gitBaseDirectory, settings.localGitRepoFolderName); - } + var repoPath = p.join(gitBaseDirectory, settings.internalRepoFolderName); _gitRepo = GitNoteRepository(gitDirPath: repoPath, settings: settings); appState.notesFolder = NotesFolderFS(null, _gitRepo.gitDirPath, settings); - // Just a fail safe - if (!settings.remoteGitRepoConfigured) { - removeExistingRemoteClone(); - } - // Makes it easier to filter the analytics getAnalytics().firebase.setUserProperty( name: 'onboarded', @@ -81,17 +70,6 @@ class StateContainer with ChangeNotifier { Log.i("Finished loading all the notes"); } - void removeExistingRemoteClone() async { - var remoteGitDir = - Directory(p.join(gitBaseDirectory, settings.remoteGitRepoFolderName)); - var dotGitDir = Directory(p.join(remoteGitDir.path, ".git")); - - bool exists = dotGitDir.existsSync(); - if (exists) { - await remoteGitDir.delete(recursive: true); - } - } - Future _loadNotes() async { // FIXME: We should report the notes that failed to load return _loadLock.synchronized(() async { @@ -351,29 +329,25 @@ class StateContainer with ChangeNotifier { }); } - void completeGitHostSetup(String repoFolderName) { + // FIXME: Pass the remote name that was added + void completeGitHostSetup(String repoFolderName, String remoteName) { () async { - var reconfiguringRemote = settings.remoteGitRepoConfigured; + var repo = await GitRepository.load(_gitRepo.gitDirPath); + var remote = repo.config.remote(remoteName); + var remoteBranchName = 'master'; + // FIXME: How to get this? + // + // There is no way to get it, just need to iterate over the refs + // and look for one! + await repo.setUpstreamTo(remote, remoteBranchName); + + // At this point the remote should have been added and fetched + + await _gitRepo.merge(); settings.remoteGitRepoConfigured = true; - settings.remoteGitRepoFolderName = repoFolderName; - - if (!reconfiguringRemote) { - await migrateGitRepo( - fromGitBasePath: settings.localGitRepoFolderName, - toGitBaseFolder: settings.remoteGitRepoFolderName, - gitBasePath: gitBaseDirectory, - gitAuthor: settings.gitAuthor, - gitAuthorEmail: settings.gitAuthorEmail, - ); - } - - var repoPath = p.join(gitBaseDirectory, settings.remoteGitRepoFolderName); - _gitRepo = GitNoteRepository(gitDirPath: repoPath, settings: settings); - appState.notesFolder.reset(_gitRepo.gitDirPath); await _persistConfig(); - await _notesCache.clear(); _loadNotes(); _syncNotes(); diff --git a/pubspec.lock b/pubspec.lock index 45d721d1..28048a31 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -181,7 +181,7 @@ packages: description: path: "." ref: HEAD - resolved-ref: "8e7e782f32f6cb1f39e39036d795f06ddecc56aa" + resolved-ref: aed5883fd17219c778cdf2d0d613a873d0b20f6c url: "https://github.com/GitJournal/dart_git.git" source: git version: "0.0.1" @@ -226,7 +226,7 @@ packages: name: equatable url: "https://pub.dartlang.org" source: hosted - version: "1.1.1" + version: "1.2.5" ext_storage: dependency: "direct main" description: