Skip to content

Commit f3cde07

Browse files
author
Kapil Borle
committed
Fix parse error caused by missing dsc module
One solution to solve this is to download the missing modules to a temporary path and then add that temporary path to PSModulePath when isa is run and remove the temp path when isa is finished running. But at this iteration this approach doesn't seem to work and needs further investigation. The solution, that we pursue, is to download the missing module to a temp path. This temp path and its data is persistent in the sense that the temp path information is stored in $LOCALAPPDATA/PSScriptAnalyzer (pssaappdata). Whenver isa in invoked, it checks the temp path pointed in pssaappdata, checks if the modules are present in the temp directory and if so, copies them to the user psmodule path, which is typcially $HOME/Documents/WindowsPowerShell/Modules. And, when isa is finished running we remove those copied modues from the user psmodule path.
1 parent cba1f64 commit f3cde07

File tree

1 file changed

+148
-34
lines changed

1 file changed

+148
-34
lines changed

Engine/Generic/ModuleDependencyHandler.cs

Lines changed: 148 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,15 @@ public class ModuleDependencyHandler : IDisposable
1818
private Runspace runspace;
1919
private readonly string moduleRepository;
2020
private string tempDirPath;
21+
private string localPSModulePath;
2122
Dictionary<string, PSObject> modulesFound;
22-
HashSet<string> modulesSaved;
23-
private string oldPSModulePath;
24-
private string currentModulePath;
23+
HashSet<string> modulesSavedInModulePath;
24+
HashSet<string> modulesSavedInTempPath;
25+
private string localAppdataPath;
26+
private string pssaAppdataPath;
27+
private const string symLinkName = "TempModuleDir";
28+
private const string tempPrefix = "PSSAModules-";
29+
private string symLinkPath;
2530

2631
#endregion Private Variables
2732

@@ -36,7 +41,7 @@ public Runspace Runspace
3641
get { return runspace; }
3742
}
3843

39-
#endregion
44+
#endregion Properties
4045

4146
#region Private Methods
4247
private static void ThrowIfNull<T>(T obj, string name)
@@ -46,44 +51,96 @@ private static void ThrowIfNull<T>(T obj, string name)
4651
throw new ArgumentNullException(name);
4752
}
4853
}
54+
55+
private void SetupCache()
56+
{
57+
// check if pssa exists in local appdata
58+
if (Directory.Exists(pssaAppdataPath))
59+
{
60+
// check if there is a link
61+
if (File.Exists(symLinkPath))
62+
{
63+
tempDirPath = GetTempDirPath(symLinkPath);
64+
65+
// check if the temp dir exists
66+
if (tempDirPath != null
67+
&& Directory.Exists(tempDirPath))
68+
{
69+
SetModulesInTempPath();
70+
return;
71+
}
72+
}
73+
SetupTempDir();
74+
}
75+
else
76+
{
77+
Directory.CreateDirectory(pssaAppdataPath);
78+
SetupTempDir();
79+
}
80+
}
81+
82+
private void SetModulesInTempPath()
83+
{
84+
// we assume the modules have not been tampered with
85+
foreach (var dir in Directory.EnumerateDirectories(tempDirPath))
86+
{
87+
modulesSavedInTempPath.Add(Path.GetFileName(dir));
88+
}
89+
}
90+
4991
private void SetupTempDir()
5092
{
51-
//var tempPath = Path.GetTempPath();
52-
//do
53-
//{
54-
// tempDirPath = Path.Combine(
55-
// tempPath,
56-
// Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));
57-
//} while (Directory.Exists(tempDirPath));
58-
//Directory.CreateDirectory(tempDirPath);
59-
tempDirPath = "C:\\Users\\kabawany\\tmp\\modules\\";
93+
CreateTempDir();
94+
UpdateSymLinkFile();
6095
}
6196

62-
private void RemoveTempDir()
97+
private void UpdateSymLinkFile()
6398
{
64-
//Directory.Delete(tempDirPath, true);
99+
File.WriteAllLines(symLinkPath, new string[] { tempDirPath });
65100
}
66101

67-
private void SetupPSModulePath()
102+
private void CreateTempDir()
68103
{
69-
oldPSModulePath = Environment.GetEnvironmentVariable("PSModulePath", EnvironmentVariableTarget.Process);
70-
var sb = new StringBuilder();
71-
sb.Append(oldPSModulePath)
72-
.Append(Path.DirectorySeparatorChar)
73-
.Append(tempDirPath);
74-
currentModulePath = sb.ToString();
104+
tempDirPath = GetTempDirPath();
105+
Directory.CreateDirectory(tempDirPath);
106+
}
107+
108+
private string GetTempDirPath()
109+
{
110+
var tempPathRoot = Path.GetTempPath();
111+
string tempPath;
112+
do
113+
{
114+
tempPath = Path.Combine(
115+
tempPathRoot,
116+
tempPrefix + Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));
117+
} while (Directory.Exists(tempPath));
118+
return tempPath;
119+
}
120+
121+
// Return the first line of the file
122+
private string GetTempDirPath(string symLinkPath)
123+
{
124+
var symLinkLines = File.ReadAllLines(symLinkPath);
125+
if(symLinkLines.Length != 1)
126+
{
127+
return null;
128+
}
129+
return symLinkLines[0];
75130
}
76131

77132
private void CleanUp()
78133
{
79134
runspace.Dispose();
80-
RemoveTempDir();
81-
RestorePSModulePath();
82-
}
83135

84-
private void RestorePSModulePath()
85-
{
86-
Environment.SetEnvironmentVariable("PSModulePath", oldPSModulePath, EnvironmentVariableTarget.Process);
136+
// remove the modules from local psmodule path
137+
foreach (var dir in Directory.EnumerateDirectories(localPSModulePath))
138+
{
139+
if (modulesSavedInModulePath.Contains(Path.GetFileName(dir)))
140+
{
141+
Directory.Delete(dir, true);
142+
}
143+
}
87144
}
88145

89146
private void SaveModule(PSObject module)
@@ -98,6 +155,33 @@ private void SaveModule(PSObject module)
98155
ps.Invoke();
99156
}
100157

158+
// TODO Use powershell copy-item
159+
private void CopyDir(string srcParentPath,
160+
string srcName,
161+
string dstParentPath,
162+
string dstName = null,
163+
bool recurse = false)
164+
{
165+
if (dstName == null)
166+
{
167+
dstName = srcName;
168+
}
169+
var srcPath = Path.Combine(srcParentPath, srcName);
170+
var dstPath = Path.Combine(dstParentPath, dstName);
171+
Directory.CreateDirectory(dstPath);
172+
foreach (var file in Directory.EnumerateFiles(srcPath))
173+
{
174+
File.Copy(file, Path.Combine(dstPath, Path.GetFileName(file)));
175+
}
176+
foreach (var dir in Directory.EnumerateDirectories(srcPath))
177+
{
178+
CopyDir(srcPath,
179+
Path.GetFileName(dir),
180+
dstPath,
181+
recurse: true);
182+
}
183+
}
184+
101185
#endregion Private Methods
102186

103187
#region Public Methods
@@ -106,10 +190,21 @@ public ModuleDependencyHandler()
106190
{
107191
runspace = null;
108192
moduleRepository = "PSGallery";
109-
modulesSaved = new HashSet<string>();
193+
modulesSavedInModulePath = new HashSet<string>();
194+
modulesSavedInTempPath = new HashSet<string>();
110195
modulesFound = new Dictionary<string, PSObject>();
111-
SetupTempDir();
112-
//SetupPSModulePath();
196+
197+
// TODO search it in the $psmodulepath instead of constructing it
198+
localPSModulePath = Path.Combine(
199+
Environment.GetEnvironmentVariable("USERPROFILE"),
200+
"Documents\\WindowsPowerShell\\Modules");
201+
localAppdataPath = Environment.GetEnvironmentVariable("LOCALAPPDATA");
202+
203+
// TODO Add PSSA Version in the path
204+
pssaAppdataPath = Path.Combine(localAppdataPath, "PSScriptAnalyzer");
205+
symLinkPath = Path.Combine(pssaAppdataPath, symLinkName);
206+
207+
SetupCache();
113208
}
114209

115210
public ModuleDependencyHandler(Runspace runspace) : this()
@@ -163,13 +258,28 @@ public PSObject FindModule(string moduleName)
163258
return module;
164259
}
165260

261+
262+
public bool ModuleExists(string moduleName)
263+
{
264+
throw new NotImplementedException();
265+
}
266+
267+
166268
public void SaveModule(string moduleName)
167269
{
168270
ThrowIfNull(moduleName, "moduleName");
169-
if (modulesSaved.Contains(moduleName))
271+
if (modulesSavedInModulePath.Contains(moduleName))
272+
{
273+
return;
274+
}
275+
if (modulesSavedInTempPath.Contains(moduleName))
170276
{
277+
// copy to local ps module path
278+
CopyDir(tempDirPath, moduleName, localPSModulePath, recurse: true);
279+
modulesSavedInModulePath.Add(moduleName);
171280
return;
172281
}
282+
173283
var module = FindModule(moduleName);
174284
if (module == null)
175285
{
@@ -180,7 +290,11 @@ public void SaveModule(string moduleName)
180290
moduleRepository));
181291
}
182292
SaveModule(module);
183-
modulesSaved.Add(moduleName);
293+
modulesSavedInTempPath.Add(moduleName);
294+
295+
// copy to local ps module path
296+
CopyDir(tempDirPath, moduleName, localPSModulePath, recurse: true);
297+
modulesSavedInModulePath.Add(moduleName);
184298
}
185299

186300
public static string GetModuleNameFromErrorExtent(ParseError error, ScriptBlockAst ast)
@@ -229,4 +343,4 @@ public void Dispose()
229343

230344
#endregion Public Methods
231345
}
232-
}
346+
}

0 commit comments

Comments
 (0)