Browse Source

Added support for Setup program in managed packages

Brian Fiete 11 tháng trước cách đây
mục cha
commit
76c58b3ed0
4 tập tin đã thay đổi với 179 bổ sung43 xóa
  1. 20 6
      IDE/src/IDEApp.bf
  2. 20 0
      IDE/src/ui/ProjectPanel.bf
  3. 1 1
      IDE/src/ui/SourceViewPanel.bf
  4. 138 36
      IDE/src/util/PackMan.bf

+ 20 - 6
IDE/src/IDEApp.bf

@@ -515,6 +515,8 @@ namespace IDE
 			public bool mAutoDelete = true;
 			public bool mCanceled;
 			public bool mIsTargetRun;
+			public bool mDone;
+			public bool mSmartOutput;
 
 			public ~this()
 			{
@@ -545,6 +547,14 @@ namespace IDE
 				mCanceled = true;
 				mProcess.Kill(0, .KillChildren);
 			}
+
+			public void Release()
+			{
+				if (!mDone)
+					mAutoDelete = true;
+				else
+					delete this;
+			}
 		}
 		List<ExecutionInstance> mExecutionInstances = new List<ExecutionInstance>() ~ DeleteContainerAndItems!(_);
 		public int32 mHotIndex = 0;
@@ -3307,7 +3317,7 @@ namespace IDE
 			case .Git(let url, let ver):
 			
 				var checkPath = scope String();
-				if (mPackMan.CheckLock(projectName, checkPath))
+				if (mPackMan.CheckLock(projectName, checkPath, var projectFailed))
 				{
 					projectFilePath = scope:: String(checkPath);
 				}
@@ -8979,7 +8989,7 @@ namespace IDE
 
 		const int cArgFileThreshold = 0x2000 - 1;
 
-		public ExecutionQueueCmd QueueRun(String fileName, String args, String workingDir, ArgsFileKind argsFileKind = .None)
+		public ExecutionQueueCmd QueueRun(StringView fileName, StringView args, StringView workingDir, ArgsFileKind argsFileKind = .None)
 		{
 			var executionQueueCmd = new ExecutionQueueCmd();
 			executionQueueCmd.mFileName = new String(fileName);
@@ -8988,7 +8998,7 @@ namespace IDE
 			if (fileName.Length + args.Length + 1 > cArgFileThreshold)
 			{
 				// Only use UTF16 if we absolutely need to
-				if ((argsFileKind == .UTF16WithBom) && (!args.HasMultibyteChars()))
+				if ((argsFileKind == .UTF16WithBom) && (!args.HasMultibyteChars))
 					executionQueueCmd.mUseArgsFile = .UTF8;
 				else
 					executionQueueCmd.mUseArgsFile = argsFileKind;
@@ -9132,11 +9142,11 @@ namespace IDE
 			NoWait = 8,
 		}
 
-		public ExecutionInstance DoRun(String inFileName, String args, String workingDir, ArgsFileKind useArgsFile, Dictionary<String, String> envVars = null, String stdInData = null, RunFlags runFlags = .None, String reference = null)
+		public ExecutionInstance DoRun(StringView inFileName, StringView args, StringView workingDir, ArgsFileKind useArgsFile, Dictionary<String, String> envVars = null, String stdInData = null, RunFlags runFlags = .None, String reference = null)
 		{
 			//Debug.Assert(executionInstance == null);
 
-			String fileName = scope String(inFileName ?? "");
+			String fileName = scope String(inFileName);
 			QuoteIfNeeded(fileName);
 
 			ProcessStartInfo startInfo = scope ProcessStartInfo();
@@ -9330,7 +9340,10 @@ namespace IDE
 				{
 					for (var str in executionInstance.mDeferredOutput)
 					{
-						OutputLine(str);
+						if (executionInstance.mSmartOutput)
+							OutputLineSmart(str);
+						else
+							OutputLine(str);
 						delete str;
 					}
 					executionInstance.mDeferredOutput.Clear();
@@ -9406,6 +9419,7 @@ namespace IDE
 				if (isDone)
 				{
 					mExecutionInstances.RemoveAt(0);
+					executionInstance.mDone = true;
 					if (executionInstance.mAutoDelete)
 						delete executionInstance;
 				}

+ 20 - 0
IDE/src/ui/ProjectPanel.bf

@@ -3209,6 +3209,26 @@ namespace IDE.ui
 								}
 						    });
 
+						item = menu.AddItem("Clear Managed Cache");
+						item.mDisabled = (projectItem == null) || (!gApp.mPackMan.IsPathManaged(projectItem.mProject.mProjectDir));
+						item.mOnMenuItemSelected.Add(new (item) =>
+						    {
+								var projectItem = GetSelectedProjectItem();
+								if (projectItem != null)
+								{
+									let project = projectItem.mProject;
+									String hash = scope .();
+									if (gApp.mPackMan.GetManagedHash(project.mProjectDir, hash))
+									{
+										gApp.[Friend]SaveWorkspaceLockData(true);
+										gApp.CloseOldBeefManaged();
+										if (gApp.mPackMan.mCleanHashSet.TryAdd(hash, var entryPtr))
+											*entryPtr = new .(hash);
+										gApp.[Friend]ReloadWorkspace();
+									}
+								}
+						    });
+
 						item = menu.AddItem("Lock Project");
 						if (projectItem.mProject.mLocked)
 							item.mIconImage = DarkTheme.sDarkTheme.GetImage(.Check);

+ 1 - 1
IDE/src/ui/SourceViewPanel.bf

@@ -432,7 +432,7 @@ namespace IDE.ui
 		public bool mLoadFailed;
 		String mOldVerLoadCmd ~ delete _;
 		HTTPRequest mOldVerHTTPRequest ~ delete _;
-		IDEApp.ExecutionInstance mOldVerLoadExecutionInstance ~ { if (_ != null) _.mAutoDelete = true; };
+		IDEApp.ExecutionInstance mOldVerLoadExecutionInstance ~ _?.Release();
 		SourceFindTask mSourceFindTask ~ delete _;
 		HoverResolveTask mHoverResolveTask ~ delete _;
 		bool mWantsFastClassify;

+ 138 - 36
IDE/src/util/PackMan.bf

@@ -19,7 +19,8 @@ namespace IDE.util
 				None,
 				FindVersion,
 				Clone,
-				Checkout
+				Checkout,
+				Setup
 			}
 
 			public Kind mKind;
@@ -30,6 +31,7 @@ namespace IDE.util
 			public String mHash ~ delete _;
 			public String mPath ~ delete _;
 			public GitManager.GitInstance mGitInstance ~ _?.ReleaseRef();
+			public IDEApp.ExecutionInstance mExecInstance ~ _?.Release();
 
 			public ~this()
 			{
@@ -41,6 +43,7 @@ namespace IDE.util
 		public bool mInitialized;
 		public String mManagedPath ~ delete _;
 		public bool mFailed;
+		public HashSet<String> mCleanHashSet = new .() ~ DeleteContainerAndItems!(_);
 
 		public void Fail(StringView error)
 		{
@@ -53,6 +56,26 @@ namespace IDE.util
 			}
 		}
 
+		public bool IsPathManaged(StringView path)
+		{
+			if (path.IsEmpty)
+				return false;
+			if (String.IsNullOrEmpty(mManagedPath))
+				return false;
+			if (path.Length < mManagedPath.Length)
+				return false;
+			return Path.Equals(mManagedPath, path.Substring(0, mManagedPath.Length));
+		}
+
+		public bool GetManagedHash(StringView path, String outHash)
+		{
+			StringView subView = path.Substring(mManagedPath.Length + 1);
+			if (subView.Length < 40)
+				return false;
+			outHash.Append(subView.Substring(0, 40));
+			return true;
+		}
+
 		public bool CheckInit()
 		{
 			if ((gApp.mWorkspace.mProjectLoadState != .Preparing) && (mWorkItems.IsEmpty))
@@ -79,8 +102,10 @@ namespace IDE.util
 			outPath.AppendF($"{mManagedPath}/{hash}");
 		}
 
-		public bool CheckLock(StringView projectName, String outPath)
+		public bool CheckLock(StringView projectName, String outPath, out bool failed)
 		{
+			failed = false;
+
 			if (!CheckInit())
 				return false;
 
@@ -96,12 +121,19 @@ namespace IDE.util
 			switch (lock)
 			{
 			case .Git(let url, let tag, let hash):
+				if (mCleanHashSet.Contains(hash))
+					return false;
 				var path = GetPath(url, hash, .. scope .());
 				var managedFilePath = scope $"{path}/BeefManaged.toml";
 				if (File.Exists(managedFilePath))
 				{
+					StructuredData sd = scope .();
+					sd.Load(managedFilePath).IgnoreError();
 					outPath.Append(path);
 					outPath.Append("/BeefProj.toml");
+
+					if (!sd.GetBool("Setup"))
+						gApp.OutputErrorLine(scope $"Project '{projectName}' previous failed setup. Clean managed cache to try again.");
 					return true;
 				}
 			default:
@@ -110,20 +142,54 @@ namespace IDE.util
 			return false;
 		}
 
-		public void CloneCompleted(StringView projectName, StringView url, StringView tag, StringView hash, StringView path)
+		public void CloneCompleted(StringView projectName, StringView url, StringView tag, StringView hash, StringView path, bool writeFile, bool setupComplete)
 		{
+			if (mCleanHashSet.GetAndRemoveAlt(hash) case .Ok(let val))
+				delete val;
+
 			gApp.mWorkspace.SetLock(projectName, .Git(new .(url), new .(tag), new .(hash)));
 
-			StructuredData sd = scope .();
-			sd.CreateNew();
-			sd.Add("FileVersion", 1);
-			sd.Add("Version", tag);
-			sd.Add("GitURL", url);
-			sd.Add("GitTag", tag);
-			sd.Add("GitHash", hash);
-			var tomlText = sd.ToTOML(.. scope .());
-			var managedFilePath = scope $"{path}/BeefManaged.toml";
-			File.WriteAllText(managedFilePath, tomlText).IgnoreError();
+			if (writeFile)
+			{
+				StructuredData sd = scope .();
+				sd.CreateNew();
+				sd.Add("FileVersion", 1);
+				sd.Add("Version", tag);
+				sd.Add("GitURL", url);
+				sd.Add("GitTag", tag);
+				sd.Add("GitHash", hash);
+				sd.Add("Setup", setupComplete);
+				var tomlText = sd.ToTOML(.. scope .());
+				var managedFilePath = scope $"{path}/BeefManaged.toml";
+				File.WriteAllText(managedFilePath, tomlText).IgnoreError();
+			}
+		}
+
+		public void RunSetupProject(StringView projectName, StringView url, StringView tag, StringView hash, StringView path)
+		{
+			if (!CheckInit())
+				return;
+
+			String beefBuildPath = scope $"{gApp.mInstallDir}BeefBuild.exe";
+			String args = scope $"-run";
+			var execInst = gApp.DoRun(beefBuildPath, args, path, .None);
+			execInst?.mAutoDelete = false;
+			execInst?.mSmartOutput = true;
+
+			WorkItem workItem = new .();
+			workItem.mKind = .Setup;
+			workItem.mProjectName = new .(projectName);
+			workItem.mURL = new .(url);
+			workItem.mTag = new .(tag);
+			workItem.mHash = new .(hash);
+			workItem.mPath = new .(path);
+			workItem.mExecInstance = execInst;
+			mWorkItems.Add(workItem);
+
+			/*cmd.mDoneEvent.Add(new (success) =>
+				{
+					int a = 123;
+				});*/
 		}
 
 		public void GetWithHash(StringView projectName, StringView url, StringView tag, StringView hash)
@@ -136,25 +202,27 @@ namespace IDE.util
 			Directory.CreateDirectory(urlPath).IgnoreError();
 			if (Directory.Exists(destPath))
 			{
-				var managedFilePath = scope $"{destPath}/BeefManaged.toml";
-				if (File.Exists(managedFilePath))
+				if (!mCleanHashSet.ContainsAlt(hash))
 				{
-					if (gApp.mVerbosity >= .Normal)
+					var managedFilePath = scope $"{destPath}/BeefManaged.toml";
+					if (File.Exists(managedFilePath))
 					{
-						if (tag.IsEmpty)
-							gApp.OutputLine($"Git selecting library '{projectName}' at {hash.Substring(0, 7)}");
-						else
-							gApp.OutputLine($"Git selecting library '{projectName}' tag '{tag}' at {hash.Substring(0, 7)}");
-					}
+						if (gApp.mVerbosity >= .Normal)
+						{
+							if (tag.IsEmpty)
+								gApp.OutputLine($"Git selecting library '{projectName}' at {hash.Substring(0, 7)}");
+							else
+								gApp.OutputLine($"Git selecting library '{projectName}' tag '{tag}' at {hash.Substring(0, 7)}");
+						}
 
-					CloneCompleted(projectName, url, tag, hash, destPath);
-					ProjectReady(projectName, destPath);
-					return;
+						CloneCompleted(projectName, url, tag, hash, destPath, false, false);
+						ProjectReady(projectName, destPath);
+						return;
+					}
 				}
 
 				String tempDir = new $"{destPath}__{(int32)Internal.GetTickCountMicro():X}";
 
-				//if (Directory.DelTree(destPath) case .Err)
 				if (Directory.Move(destPath, tempDir) case .Err)
 				{
 					delete tempDir;
@@ -272,16 +340,31 @@ namespace IDE.util
 			// First handle active git items
 			for (var workItem in mWorkItems)
 			{
+				bool removeItem = false;
 				if (workItem.mGitInstance == null)
-					continue;
-
-				if (!workItem.mGitInstance.mDone)
+				{
+					switch (workItem.mKind)
+					{
+					case .Setup:
+						if ((workItem.mExecInstance == null) || (workItem.mExecInstance.mDone))
+						{
+							bool success = workItem.mExecInstance?.mExitCode == 0;
+							String projPath = Path.GetAbsolutePath("../", workItem.mPath, .. scope .());
+							CloneCompleted(workItem.mProjectName, workItem.mURL, workItem.mTag, workItem.mHash, projPath, true, success);
+							if (success)
+								ProjectReady(workItem.mProjectName, projPath);
+							else
+								gApp.OutputErrorLine(scope $"Failed to setup project '{workItem.mProjectName}' located at '{projPath}'");
+							removeItem = true;
+						}
+					default:
+					}
+				}
+				else if (!workItem.mGitInstance.mDone)
 				{
 					executingGit = true;
-					continue;
 				}
-
-				if (!workItem.mGitInstance.mFailed)
+				else if (!workItem.mGitInstance.mFailed)
 				{
 					switch (workItem.mKind)
 					{
@@ -343,21 +426,40 @@ namespace IDE.util
 					case .Clone:
 						Checkout(workItem.mProjectName, workItem.mURL, workItem.mPath, workItem.mTag, workItem.mHash);
 					case .Checkout:
-						CloneCompleted(workItem.mProjectName, workItem.mURL, workItem.mTag, workItem.mHash, workItem.mPath);
-						ProjectReady(workItem.mProjectName, workItem.mPath);
-
 						if (gApp.mVerbosity >= .Normal)
 							gApp.OutputLine($"Git cloning library '{workItem.mProjectName}' done.");
+
+						String setupPath = scope $"{workItem.mPath}/Setup";
+
+						/*if (workItem.mProjectName == "BeefProj0")
+						{
+							setupPath.Set("C:/proj/BeefProj0/Setup");
+						}*/
+
+						if (Directory.Exists(setupPath))
+						{
+							RunSetupProject(workItem.mProjectName, workItem.mURL, workItem.mTag, workItem.mHash, setupPath);
+						}
+						else
+						{
+							CloneCompleted(workItem.mProjectName, workItem.mURL, workItem.mTag, workItem.mHash, workItem.mPath, true, true);
+							ProjectReady(workItem.mProjectName, workItem.mPath);
+						}
 					default:
 					}
+					removeItem = true;
 				}
 				else
 				{
 					Fail(scope $"Failed to retrieve project '{workItem.mProjectName}' at '{workItem.mURL}'");
+					removeItem = true;
 				}
 
-				@workItem.Remove();
-				delete workItem;
+				if (removeItem)
+				{
+					@workItem.Remove();
+					delete workItem;
+				}
 			}
 
 			if (!executingGit)