@@ -18,10 +18,15 @@ public class ModuleDependencyHandler : IDisposable
18
18
private Runspace runspace ;
19
19
private readonly string moduleRepository ;
20
20
private string tempDirPath ;
21
+ private string localPSModulePath ;
21
22
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 ;
25
30
26
31
#endregion Private Variables
27
32
@@ -36,7 +41,7 @@ public Runspace Runspace
36
41
get { return runspace ; }
37
42
}
38
43
39
- #endregion
44
+ #endregion Properties
40
45
41
46
#region Private Methods
42
47
private static void ThrowIfNull < T > ( T obj , string name )
@@ -46,44 +51,96 @@ private static void ThrowIfNull<T>(T obj, string name)
46
51
throw new ArgumentNullException ( name ) ;
47
52
}
48
53
}
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
+
49
91
private void SetupTempDir ( )
50
92
{
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 ( ) ;
60
95
}
61
96
62
- private void RemoveTempDir ( )
97
+ private void UpdateSymLinkFile ( )
63
98
{
64
- //Directory.Delete(tempDirPath, true );
99
+ File . WriteAllLines ( symLinkPath , new string [ ] { tempDirPath } ) ;
65
100
}
66
101
67
- private void SetupPSModulePath ( )
102
+ private void CreateTempDir ( )
68
103
{
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 ] ;
75
130
}
76
131
77
132
private void CleanUp ( )
78
133
{
79
134
runspace . Dispose ( ) ;
80
- RemoveTempDir ( ) ;
81
- RestorePSModulePath ( ) ;
82
- }
83
135
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
+ }
87
144
}
88
145
89
146
private void SaveModule ( PSObject module )
@@ -98,6 +155,33 @@ private void SaveModule(PSObject module)
98
155
ps . Invoke ( ) ;
99
156
}
100
157
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
+
101
185
#endregion Private Methods
102
186
103
187
#region Public Methods
@@ -106,10 +190,21 @@ public ModuleDependencyHandler()
106
190
{
107
191
runspace = null ;
108
192
moduleRepository = "PSGallery" ;
109
- modulesSaved = new HashSet < string > ( ) ;
193
+ modulesSavedInModulePath = new HashSet < string > ( ) ;
194
+ modulesSavedInTempPath = new HashSet < string > ( ) ;
110
195
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 ( ) ;
113
208
}
114
209
115
210
public ModuleDependencyHandler ( Runspace runspace ) : this ( )
@@ -163,13 +258,28 @@ public PSObject FindModule(string moduleName)
163
258
return module ;
164
259
}
165
260
261
+
262
+ public bool ModuleExists ( string moduleName )
263
+ {
264
+ throw new NotImplementedException ( ) ;
265
+ }
266
+
267
+
166
268
public void SaveModule ( string moduleName )
167
269
{
168
270
ThrowIfNull ( moduleName , "moduleName" ) ;
169
- if ( modulesSaved . Contains ( moduleName ) )
271
+ if ( modulesSavedInModulePath . Contains ( moduleName ) )
272
+ {
273
+ return ;
274
+ }
275
+ if ( modulesSavedInTempPath . Contains ( moduleName ) )
170
276
{
277
+ // copy to local ps module path
278
+ CopyDir ( tempDirPath , moduleName , localPSModulePath , recurse : true ) ;
279
+ modulesSavedInModulePath . Add ( moduleName ) ;
171
280
return ;
172
281
}
282
+
173
283
var module = FindModule ( moduleName ) ;
174
284
if ( module == null )
175
285
{
@@ -180,7 +290,11 @@ public void SaveModule(string moduleName)
180
290
moduleRepository ) ) ;
181
291
}
182
292
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 ) ;
184
298
}
185
299
186
300
public static string GetModuleNameFromErrorExtent ( ParseError error , ScriptBlockAst ast )
@@ -229,4 +343,4 @@ public void Dispose()
229
343
230
344
#endregion Public Methods
231
345
}
232
- }
346
+ }
0 commit comments