11namespace AgileObjects . ReadableExpressions . Visualizers . Installer . Custom
22{
33 using System ;
4+ using System . Diagnostics ;
5+ using System . IO ;
6+ using System . Linq ;
7+ using System . Reflection ;
8+ using System . Text ;
9+ using System . Text . RegularExpressions ;
410 using Microsoft . Win32 ;
511
612 internal class Visualizer : IDisposable
713 {
8- public int VsVersionNumber { get ; set ; }
14+ private static readonly Assembly _thisAssembly = typeof ( Visualizer ) . Assembly ;
15+
16+ private readonly Action < string > _logger ;
17+ private readonly Version _version ;
18+ private readonly string _vsixManifest ;
19+ private RegistryKey _registryKey ;
20+ private string _vsExePath ;
21+ private string _vsSetupArgument ;
22+ private string _installPath ;
23+ private string _vsixManifestPath ;
24+
25+ public Visualizer (
26+ Action < string > logger ,
27+ FileVersionInfo version ,
28+ string vsixManifest ,
29+ string resourceName )
30+ : this ( logger , new Version ( version . FileVersion ) , vsixManifest , resourceName , GetVsVersionNumber ( resourceName ) )
31+ {
32+ }
33+
34+ #region Setup
35+
36+ private static readonly Regex _versionNumberMatcher =
37+ new Regex ( @"Vs(?<VersionNumber>[\d]+)\.dll$" , RegexOptions . IgnoreCase ) ;
38+
39+ private static int GetVsVersionNumber ( string resourceName )
40+ {
41+ var matchValue = _versionNumberMatcher
42+ . Match ( resourceName )
43+ . Groups [ "VersionNumber" ]
44+ . Value ;
45+
46+ return int . Parse ( matchValue ) ;
47+ }
48+
49+ #endregion
50+
51+ private Visualizer (
52+ Action < string > logger ,
53+ Version version ,
54+ string vsixManifest ,
55+ string resourceName ,
56+ int vsVersionNumber )
57+ {
58+ _logger = logger ;
59+ _version = version ;
60+ _vsixManifest = vsixManifest ;
61+ ResourceName = resourceName ;
62+ VsVersionNumber = vsVersionNumber ;
63+ }
64+
65+ public int VsVersionNumber { get ; }
966
1067 public string VsFullVersionNumber => VsVersionNumber + ".0" ;
1168
12- public string ResourceName { get ; set ; }
69+ public string ResourceName { get ; }
70+
71+ public string GetResourceFileName ( )
72+ {
73+ var resourceAssemblyNameLength = ( typeof ( Visualizer ) . Namespace ? . Length + 1 ) . GetValueOrDefault ( ) ;
74+ var resourceFileName = ResourceName . Substring ( resourceAssemblyNameLength ) ;
75+
76+ return resourceFileName ;
77+ }
78+
79+ public string VsInstallDirectory { get ; private set ; }
80+
81+ public void SetInstallPath ( string pathToVisualizers )
82+ => _installPath = Path . Combine ( pathToVisualizers , GetResourceFileName ( ) ) ;
83+
84+ public void SetVsixManifestPath ( string pathToExtensions )
85+ => _vsixManifestPath = Path . Combine ( pathToExtensions , "extension.vsixmanifest" ) ;
86+
87+ public void Install ( )
88+ {
89+ // ReSharper disable once AssignNullToNotNullAttribute
90+ if ( ! Directory . Exists ( Path . GetDirectoryName ( _installPath ) ) )
91+ {
92+ Log ( "Skipping as directory does not exist: " + _installPath ) ;
93+ return ;
94+ }
95+
96+ using ( var resourceStream = _thisAssembly . GetManifestResourceStream ( ResourceName ) )
97+ using ( var visualizerFileStream = File . OpenWrite ( _installPath ) )
98+ {
99+ Log ( "Writing visualizer to " + _installPath ) ;
100+ // ReSharper disable once PossibleNullReferenceException
101+ resourceStream . CopyTo ( visualizerFileStream ) ;
102+ }
103+
104+ var manifestDirectory = Path . GetDirectoryName ( _vsixManifestPath ) ;
105+
106+ Log ( "Writing manifest to " + _vsixManifestPath ) ;
107+ // ReSharper disable once AssignNullToNotNullAttribute
108+ Directory . CreateDirectory ( manifestDirectory ) ;
109+ File . WriteAllText ( _vsixManifestPath , _vsixManifest , Encoding . ASCII ) ;
110+
111+ ResetVsExtensions ( ) ;
112+ }
113+
114+ public DirectoryInfo GetVsixManifestDirectory ( )
115+ {
116+ // ReSharper disable once AssignNullToNotNullAttribute
117+ return new DirectoryInfo ( Path . GetDirectoryName ( _vsixManifestPath ) ) ;
118+ }
119+
120+ public void Uninstall ( )
121+ {
122+ DeletePreviousManifests ( ) ;
123+
124+ // ReSharper disable PossibleNullReferenceException
125+ if ( File . Exists ( _vsixManifestPath ) )
126+ {
127+ var vsixManifestDirectory = GetVsixManifestDirectory ( ) ;
128+ var productDirectory = vsixManifestDirectory . Parent ;
129+ var companyDirectory = productDirectory . Parent ;
130+
131+ Log ( "Deleting previous manifest directory " + vsixManifestDirectory . FullName ) ;
132+ vsixManifestDirectory . Delete ( recursive : true ) ;
133+
134+ if ( ! productDirectory . GetDirectories ( ) . Any ( ) )
135+ {
136+ Log ( "Deleting previous manifest product directory " + productDirectory . FullName ) ;
137+ productDirectory . Delete ( recursive : true ) ;
138+
139+ if ( ! companyDirectory . GetDirectories ( ) . Any ( ) )
140+ {
141+ Log ( "Deleting previous manifest company directory " + companyDirectory . FullName ) ;
142+ companyDirectory . Delete ( recursive : true ) ;
143+ }
144+ }
145+
146+ ResetVsExtensions ( ) ;
147+ }
148+ // ReSharper restore PossibleNullReferenceException
149+
150+ if ( File . Exists ( _installPath ) )
151+ {
152+ File . Delete ( _installPath ) ;
153+ }
154+ }
13155
14- public RegistryKey RegistryKey { get ; set ; }
156+ private void DeletePreviousManifests ( )
157+ {
158+ var productDirectory = GetVsixManifestDirectory ( ) . Parent ;
15159
16- public string VsInstallDirectory { get ; set ; }
160+ if ( ( productDirectory == null ) || ! productDirectory . Exists )
161+ {
162+ return ;
163+ }
17164
18- public string InstallPath { get ; set ; }
165+ // ReSharper disable once PossibleNullReferenceException
166+ foreach ( var versionDirectory in productDirectory . GetDirectories ( "*" ) )
167+ {
168+ if ( Version . TryParse ( versionDirectory . Name , out var directoryVersion ) )
169+ {
170+ if ( directoryVersion != _version )
171+ {
172+ Log ( "Deleting previous manifest version directory " + versionDirectory . FullName ) ;
173+ versionDirectory . Delete ( recursive : true ) ;
174+ }
175+ }
176+ }
177+ }
19178
20- public string VsixManifestPath { get ; set ; }
179+ private void ResetVsExtensions ( )
180+ {
181+ if ( _vsExePath == null )
182+ {
183+ return ;
184+ }
21185
22- public string VsExePath { get ; set ; }
186+ Log ( "Updating VS extension records using " + _vsExePath ) ;
187+ using ( Process . Start ( _vsExePath , _vsSetupArgument ) ) { }
188+ }
23189
24- public string VsSetupArgument { get ; set ; }
190+ public void PopulateVsSetupData ( )
191+ {
192+ var pathToDevEnv = Path . Combine ( VsInstallDirectory , "devenv.exe" ) ;
193+
194+ if ( ! File . Exists ( pathToDevEnv ) )
195+ {
196+ return ;
197+ }
198+
199+ _vsExePath = pathToDevEnv ;
200+ _vsSetupArgument = _registryKey ? . GetValue ( "SetupCommandLine" ) as string ?? "/setup" ;
201+ }
25202
26203 public Visualizer With ( RegistryKey registryKey , string vsInstallPath )
27204 {
28- return new Visualizer
205+ return new Visualizer ( _logger , _version , _vsixManifest , ResourceName , VsVersionNumber )
29206 {
30- VsVersionNumber = VsVersionNumber ,
31- ResourceName = ResourceName ,
32- RegistryKey = registryKey ,
207+ _registryKey = registryKey ,
33208 VsInstallDirectory = vsInstallPath
34209 } ;
35210 }
36211
37- public void Dispose ( )
38- {
39- RegistryKey ? . Dispose ( ) ;
40- }
212+ private void Log ( string message ) => _logger . Invoke ( message ) ;
213+
214+ public void Dispose ( ) => _registryKey ? . Dispose ( ) ;
41215 }
42216}
0 commit comments