1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-10 04:22:20 +02:00

Relaxed project name restrictions. Auto-refresh of installed libraries.

This commit is contained in:
Brian Fiete 2020-08-31 11:32:33 -07:00
parent b3354ee635
commit 4d55a32c90
6 changed files with 143 additions and 27 deletions

View file

@ -3,6 +3,8 @@ using System;
using System.Collections; using System.Collections;
using System.IO; using System.IO;
using Beefy.utils; using Beefy.utils;
using System.Threading;
using System.Diagnostics;
namespace IDE namespace IDE
{ {
@ -14,6 +16,68 @@ namespace IDE
public SemVer mVersion ~ delete _; public SemVer mVersion ~ delete _;
public VerSpecRecord mLocation ~ delete _; public VerSpecRecord mLocation ~ delete _;
public ConfigFile mConfigFile; public ConfigFile mConfigFile;
public bool mParsedConfig;
}
public class Registry
{
public List<RegistryEntry> mEntries = new List<RegistryEntry>() ~ DeleteContainerAndItems!(_);
public Monitor mMonitor = new .() ~ delete _;
public WaitEvent mEvent = new .() ~ delete _;
public ~this()
{
mEvent.WaitFor();
}
public void ParseConfig(RegistryEntry entry)
{
entry.mParsedConfig = true;
if (entry.mLocation.mVerSpec case .Path(let path))
{
String configPath = scope String()..AppendF("{}/BeefProj.toml", path);
StructuredData sd = scope .();
if (sd.Load(configPath) case .Ok)
{
using (sd.Open("Project"))
{
var projName = scope String();
sd.GetString("Name", projName);
if (!projName.IsEmpty)
{
using (mMonitor.Enter())
entry.mProjName.Set(projName);
}
}
}
}
}
public void WaitFor()
{
mEvent.WaitFor();
}
void Resolve()
{
// NOTE: We allow a race condition where ParseConfig can possibly occur on multiple threads
// at the same time
for (var entry in mEntries)
{
if (!entry.mParsedConfig)
ParseConfig(entry);
}
mEvent.Set(true);
}
public void StartResolve()
{
var thread = new Thread(new => Resolve);
thread.Start(true);
}
} }
public class LibDirectory public class LibDirectory
@ -29,9 +93,16 @@ namespace IDE
} }
List<ConfigFile> mConfigFiles = new List<ConfigFile>() ~ DeleteContainerAndItems!(_); List<ConfigFile> mConfigFiles = new List<ConfigFile>() ~ DeleteContainerAndItems!(_);
public List<RegistryEntry> mRegistry = new List<RegistryEntry>() ~ DeleteContainerAndItems!(_); public Registry mRegistry ~ delete _;
List<String> mConfigPathQueue = new List<String>() ~ DeleteContainerAndItems!(_); List<String> mConfigPathQueue = new List<String>() ~ DeleteContainerAndItems!(_);
List<LibDirectory> mLibDirectories = new List<LibDirectory>() ~ DeleteContainerAndItems!(_); List<LibDirectory> mLibDirectories = new List<LibDirectory>() ~ DeleteContainerAndItems!(_);
List<FileSystemWatcher> mWatchers = new .() ~ DeleteContainerAndItems!(_);
public bool mLibsChanged;
void LibsChanged()
{
mLibsChanged = true;
}
Result<void> Load(StringView path) Result<void> Load(StringView path)
{ {
@ -49,7 +120,7 @@ namespace IDE
{ {
RegistryEntry regEntry = new RegistryEntry(); RegistryEntry regEntry = new RegistryEntry();
regEntry.mProjName = new String(projName); regEntry.mProjName = new String(projName);
mRegistry.Add(regEntry); mRegistry.mEntries.Add(regEntry);
regEntry.mConfigFile = configFile; regEntry.mConfigFile = configFile;
@ -80,18 +151,15 @@ namespace IDE
{ {
RegistryEntry regEntry = new RegistryEntry(); RegistryEntry regEntry = new RegistryEntry();
regEntry.mProjName = new String(projName); regEntry.mProjName = new String(projName);
mRegistry.Add(regEntry); mRegistry.mEntries.Add(regEntry);
regEntry.mConfigFile = configFile; regEntry.mConfigFile = configFile;
var verString = scope String();
data.GetString("Version", verString);
regEntry.mVersion = new SemVer(); regEntry.mVersion = new SemVer();
regEntry.mVersion.Parse("0.0.0"); regEntry.mVersion.Parse("0.0.0");
regEntry.mLocation = new VerSpecRecord(); regEntry.mLocation = new VerSpecRecord();
using (data.Open("Location")) regEntry.mLocation.SetPath(filePath);
regEntry.mLocation.SetPath(filePath);
} }
else else
{ {
@ -116,6 +184,16 @@ namespace IDE
Path.GetAbsolutePath(libDir.mPath, configFile.mConfigDir, absPath); Path.GetAbsolutePath(libDir.mPath, configFile.mConfigDir, absPath);
AddFromLibraryPath(absPath); AddFromLibraryPath(absPath);
absPath.Append(Path.DirectorySeparatorChar);
FileSystemWatcher watcher = new FileSystemWatcher(absPath);
watcher.OnChanged.Add(new (fileName) => LibsChanged());
watcher.OnCreated.Add(new (fileName) => LibsChanged());
watcher.OnDeleted.Add(new (fileName) => LibsChanged());
watcher.OnRenamed.Add(new (newName, oldName) => LibsChanged());
watcher.OnError.Add(new () => LibsChanged());
watcher.StartRaisingEvents();
mWatchers.Add(watcher);
} }
} }
@ -163,14 +241,18 @@ namespace IDE
public Result<void> Load() public Result<void> Load()
{ {
ClearAndDeleteItems(mRegistry); mLibsChanged = false;
delete mRegistry;
mRegistry = new Registry();
ClearAndDeleteItems(mConfigFiles); ClearAndDeleteItems(mConfigFiles);
ClearAndDeleteItems(mWatchers);
for (int i = mConfigPathQueue.Count - 1; i >= 0; i--) for (int i = mConfigPathQueue.Count - 1; i >= 0; i--)
{ {
let path = mConfigPathQueue[i]; let path = mConfigPathQueue[i];
Try!(Load(path)); Try!(Load(path));
} }
mRegistry.StartResolve();
return .Ok; return .Ok;
} }
} }

View file

@ -2616,18 +2616,30 @@ namespace IDE
if (let project = mWorkspace.FindProject(projectName)) if (let project = mWorkspace.FindProject(projectName))
return project; return project;
if (useVerSpecRecord.mVerSpec case .SemVer) if (useVerSpecRecord.mVerSpec case .SemVer)
{ {
for (int regEntryIdx = mBeefConfig.mRegistry.Count - 1; regEntryIdx >= 0; regEntryIdx--) // First pass we just try to use the 'expected' project name
FindLoop: for (int pass < 2)
{ {
var regEntry = mBeefConfig.mRegistry[regEntryIdx]; using (mBeefConfig.mRegistry.mMonitor.Enter())
if (regEntry.mProjName == projectName)
{ {
useVerSpecRecord = regEntry.mLocation; for (int regEntryIdx = mBeefConfig.mRegistry.mEntries.Count - 1; regEntryIdx >= 0; regEntryIdx--)
verConfigDir = regEntry.mConfigFile.mConfigDir; {
var regEntry = mBeefConfig.mRegistry.mEntries[regEntryIdx];
if ((regEntry.mProjName == projectName) && (!regEntry.mParsedConfig))
mBeefConfig.mRegistry.ParseConfig(regEntry);
if (regEntry.mProjName == projectName)
{
useVerSpecRecord = regEntry.mLocation;
verConfigDir = regEntry.mConfigFile.mConfigDir;
break FindLoop;
}
}
} }
mBeefConfig.mRegistry.WaitFor();
} }
} }
@ -11072,6 +11084,12 @@ namespace IDE
tabButton.Activate(); tabButton.Activate();
} }
public void CheckLoadConfig()
{
if (mBeefConfig.mLibsChanged)
LoadConfig();
}
void LoadConfig() void LoadConfig()
{ {
delete mBeefConfig; delete mBeefConfig;

View file

@ -1318,6 +1318,19 @@ namespace IDE
options.mBuildOptions.mOtherLinkFlags.Set("$(LinkFlags)"); options.mBuildOptions.mOtherLinkFlags.Set("$(LinkFlags)");
} }
public static void GetSanitizedName(String projectName, String outName, bool allowDot = false)
{
for (let c in projectName.RawChars)
{
if ((c.IsLetterOrDigit) || (c == '_'))
outName.Append(c);
else if (c == '-')
outName.Append('_');
else if ((c == '.') && (allowDot))
outName.Append(c);
}
}
public this() public this()
{ {
mRootFolder = new ProjectFolder(); mRootFolder = new ProjectFolder();
@ -1492,7 +1505,9 @@ namespace IDE
data.Add("Name", mProjectName); data.Add("Name", mProjectName);
data.ConditionalAdd("TargetType", mGeneralOptions.mTargetType, GetDefaultTargetType()); data.ConditionalAdd("TargetType", mGeneralOptions.mTargetType, GetDefaultTargetType());
data.ConditionalAdd("StartupObject", mBeefGlobalOptions.mStartupObject, IsSingleFile ? "Program" : ""); data.ConditionalAdd("StartupObject", mBeefGlobalOptions.mStartupObject, IsSingleFile ? "Program" : "");
data.ConditionalAdd("DefaultNamespace", mBeefGlobalOptions.mDefaultNamespace, mProjectName); var defaultNamespace = scope String();
GetSanitizedName(mProjectName, defaultNamespace, true);
data.ConditionalAdd("DefaultNamespace", mBeefGlobalOptions.mDefaultNamespace, defaultNamespace);
WriteStrings("Aliases", mGeneralOptions.mAliases); WriteStrings("Aliases", mGeneralOptions.mAliases);
WriteStrings("ProcessorMacros", mBeefGlobalOptions.mPreprocessorMacros); WriteStrings("ProcessorMacros", mBeefGlobalOptions.mPreprocessorMacros);
WriteDistinctOptions(mBeefGlobalOptions.mDistinctBuildOptions); WriteDistinctOptions(mBeefGlobalOptions.mDistinctBuildOptions);
@ -1807,7 +1822,9 @@ namespace IDE
data.GetString("Name", mProjectName); data.GetString("Name", mProjectName);
ReadStrings("Aliases", mGeneralOptions.mAliases); ReadStrings("Aliases", mGeneralOptions.mAliases);
data.GetString("StartupObject", mBeefGlobalOptions.mStartupObject, IsSingleFile ? "Program" : ""); data.GetString("StartupObject", mBeefGlobalOptions.mStartupObject, IsSingleFile ? "Program" : "");
data.GetString("DefaultNamespace", mBeefGlobalOptions.mDefaultNamespace, mProjectName); var defaultNamespace = scope String();
GetSanitizedName(mProjectName, defaultNamespace, true);
data.GetString("DefaultNamespace", mBeefGlobalOptions.mDefaultNamespace, defaultNamespace);
ReadStrings("ProcessorMacros", mBeefGlobalOptions.mPreprocessorMacros); ReadStrings("ProcessorMacros", mBeefGlobalOptions.mPreprocessorMacros);
for (data.Enumerate("DistinctOptions")) for (data.Enumerate("DistinctOptions"))
{ {
@ -2317,7 +2334,8 @@ namespace IDE
public void SetupDefault(BeefGlobalOptions generalOptions) public void SetupDefault(BeefGlobalOptions generalOptions)
{ {
generalOptions.mDefaultNamespace.Set(mProjectName); generalOptions.mDefaultNamespace.Clear();
GetSanitizedName(mProjectName, generalOptions.mDefaultNamespace, true);
generalOptions.mStartupObject.Set(scope String()..AppendF("{}.Program", generalOptions.mDefaultNamespace)); generalOptions.mStartupObject.Set(scope String()..AppendF("{}.Program", generalOptions.mDefaultNamespace));
} }

View file

@ -63,7 +63,9 @@ namespace IDE.ui
void FindProjects() void FindProjects()
{ {
for (let registryEntry in gApp.mBeefConfig.mRegistry) gApp.CheckLoadConfig();
gApp.mBeefConfig.mRegistry.WaitFor();
for (let registryEntry in gApp.mBeefConfig.mRegistry.mEntries)
{ {
InstalledProject installedProject = new .(); InstalledProject installedProject = new .();
installedProject.mName = new String(registryEntry.mProjName); installedProject.mName = new String(registryEntry.mProjName);

View file

@ -71,17 +71,11 @@ namespace IDE.ui
Path.GetAbsolutePath(origDirectory, gApp.mWorkspace.mDir, projDirectory); Path.GetAbsolutePath(origDirectory, gApp.mWorkspace.mDir, projDirectory);
} }
bool isNameValid = projName.Length > 0; bool isNameValid = projName.Length > 0;
for (int32 i = 0; i < projName.Length; i++)
{
char8 c = projName[i];
if ((!c.IsLetterOrDigit) && (c != '-') && (c != ' ') && (c != '_'))
isNameValid = false;
}
if (!isNameValid) if (!isNameValid)
{ {
mNameEdit.SetFocus(); mNameEdit.SetFocus();
app.Fail("Invalid project name. The project name can only consist of alphanumeric characters, spaces, dashes, and underscores."); app.Fail("Invalid project name");
return false; return false;
} }

View file

@ -1863,6 +1863,8 @@ namespace IDE.ui
return null; return null;
} }
gApp.CheckLoadConfig();
//TODO: Protect against importing an existing project //TODO: Protect against importing an existing project
Project proj = new Project(); Project proj = new Project();
String projFilePath = scope String(filePath); String projFilePath = scope String(filePath);