OSDN Git Service

AppliStation-GUI,GetIconForPackageを別クラスに退避
[applistation/AppliStation.git] / archive-inst / Program.cs
1 using System;\r
2 using System.Text;\r
3 using System.IO;\r
4 using Microsoft.Build.BuildEngine;\r
5 using NaGet.Packages;\r
6 using NaGet.Packages.Install;\r
7 \r
8 namespace ArchiveInstall\r
9 {\r
10         class Program\r
11         {\r
12                 public const string InstalledFileListName = ".applistation.installedfiles.xml";\r
13                 \r
14                 public const string InstalledPackageFileName = ".applistation.package.xml";\r
15                 \r
16                 private static void extract(string arcFile, string extractDestDir)\r
17                 {\r
18                         StringBuilder output = new StringBuilder(1024);\r
19                         int res = NaGet.InteropServices.CommonArchiverExtracter.ExtractArchive(arcFile, extractDestDir, output, IntPtr.Zero);\r
20                         if (res != 0) {\r
21                                 Environment.Exit(res);\r
22                         }\r
23                 }\r
24                 \r
25                 private static void install(string fakeTargetDir, string targetDir)\r
26                 {\r
27                         string installSrc = fakeTargetDir;\r
28                         \r
29                         if (Directory.GetFiles(installSrc).Length == 0 &&\r
30                             Directory.GetDirectories(installSrc).Length == 1) {\r
31                                 installSrc = Directory.GetDirectories(installSrc)[0];\r
32                         }\r
33                         \r
34                         // ハッシュ比較\r
35                         if (Directory.Exists(targetDir)) {\r
36                                 InstalledFileList list = null;\r
37                                 try {\r
38                                         list = NaGet.Utils.GetDeserializedObject<InstalledFileList>(Path.Combine(targetDir, InstalledFileListName));\r
39                                 } catch {\r
40                                 }\r
41                                 if (list != null) {\r
42                                         foreach (InstalledFile changedFile in list.Verify(targetDir)) { // 変更されたファイルたちを。。。\r
43                                                 string changedFilePath = Path.Combine(targetDir, changedFile.Path);\r
44                                                 string toBeChangedFilePath = Path.Combine(installSrc, changedFile.Path);\r
45                                                 \r
46                                                 if (File.Exists(toBeChangedFilePath)) {\r
47                                                         File.Move(toBeChangedFilePath, toBeChangedFilePath + ".newfile"); // 新規を退避させて\r
48                                                 }\r
49                                                 File.Copy(changedFilePath, toBeChangedFilePath); // installSrcの方に反映させておく\r
50                                         }\r
51                                 }\r
52                         } else {\r
53                                 Directory.CreateDirectory(targetDir);\r
54                         }\r
55                         \r
56                         // まずはフォルダツリーを作成\r
57                         foreach (string dir in Directory.GetDirectories(installSrc, "*", SearchOption.AllDirectories)) {\r
58                                 string dirPath = NaGet.Utils.GetRelativePath(installSrc, dir);\r
59                                 string targetDirPath = Path.Combine(targetDir, dirPath);\r
60                                 if (! Directory.Exists(targetDirPath)) {\r
61                                         Directory.CreateDirectory(targetDirPath);\r
62                                 }\r
63                         }\r
64                         \r
65                         // ファイルをインストール(高速化のため移動)\r
66                         foreach (string file in Directory.GetFiles(installSrc, "*", SearchOption.AllDirectories)) {\r
67                                 string filePath = NaGet.Utils.GetRelativePath(installSrc, file);\r
68                                 string targetFilePath = Path.Combine(targetDir, filePath);\r
69                                 if (File.Exists(targetFilePath)) {\r
70                                         File.Delete(targetFilePath);\r
71                                 }\r
72                                 File.Move(file, targetFilePath);\r
73                         }\r
74                 }\r
75                 \r
76                 private static void postInstall(string targetDir, Package package)\r
77                 {\r
78                         // SYSTEM32へのコピーの実行\r
79                         if (!string.IsNullOrEmpty(package.System32CopyFiles)) {\r
80                                 if (! Directory.Exists(NaGet.Env.ArchiveSystem32)) {\r
81                                         Directory.CreateDirectory(NaGet.Env.ArchiveSystem32);\r
82                                 }\r
83                                 \r
84                                 string logfile = Path.Combine(NaGet.Env.ArchiveSystem32, ".applistation.install."+package.Name+".log");\r
85                                 if (File.Exists(logfile)) {\r
86                                         File.SetAttributes(logfile, FileAttributes.Normal);\r
87                                 }\r
88                                 using (FileStream fs = new FileStream(logfile, FileMode.Create))\r
89                                 using (StreamWriter sw = new StreamWriter(fs)){\r
90                                         foreach (string pathpat in package.System32CopyFiles.Split(';')) {\r
91                                                 foreach (string path in NaGet.Utils.ExtendWildcardFile(targetDir, pathpat)) {\r
92                                                         if ((File.GetAttributes(path) & FileAttributes.Directory) == 0) { // もしファイルならば\r
93                                                                 string destPath = Path.Combine(NaGet.Env.ArchiveSystem32, Path.GetFileName(path));\r
94                                                                 File.Copy(path, destPath, true);\r
95                                                                 \r
96                                                                 sw.WriteLine(Path.GetFileName(destPath));\r
97                                                         }\r
98                                                 }\r
99                                         }\r
100                                 }\r
101                                 File.SetAttributes(logfile, FileAttributes.Hidden);\r
102                         }\r
103                         \r
104                         // インストールスクリプトの実行\r
105                         if (! string.IsNullOrEmpty(package.InstallScript) ) {\r
106                                 Engine engine = MSBuild.Engine;\r
107                                 Project proj = new Project(engine);\r
108                                 try {\r
109                                         proj.LoadXml(package.InstallScript);\r
110                                 } catch (InvalidProjectFileException e) {\r
111                                         throw new ApplicationException("InstallScript is invalid", e);\r
112                                 }\r
113                                 \r
114                                 engine.BuildProject(proj, "Install");\r
115                         }\r
116                         \r
117                         // 直下のファイルで*.exeがGUIプログラムならプログラムフォルダに登録\r
118                         foreach (string exeFile in Directory.GetFiles(targetDir, "*.exe")) {\r
119                                 if (NaGet.InteropServices.PEFileInfoUtils.GetPEFileType(exeFile) == NaGet.InteropServices.PEFileInfoUtils.PEFileType.WinGUI) {\r
120                                         string progGrpPath = Path.Combine(NaGet.Env.ArchiveProgramGroup, package.Name);\r
121                                         if (! Directory.Exists(progGrpPath)) Directory.CreateDirectory(progGrpPath);\r
122                                         \r
123                                         using (NaGet.InteropServices.ShellLink lnk = new NaGet.InteropServices.ShellLink() ) {\r
124                                                 //string path = NaGet.Utils.GetRelativePath(progGrpPath, exeFile);// lnkファイルに相対パス指定不能\r
125                                                 string path = exeFile;\r
126                                                 \r
127                                                 lnk.Path = path;\r
128                                                 //lnk.SetIconLocation(path, 0);\r
129                                                 \r
130                                                 // .lnk ファイル名\r
131                                                 string lnkFileName;\r
132                                                 System.Diagnostics.FileVersionInfo vInfo = System.Diagnostics.FileVersionInfo.GetVersionInfo(exeFile);\r
133                                                 if (vInfo.ProductName != null && vInfo.ProductName != string.Empty\r
134                                                     && (!File.Exists(Path.Combine(progGrpPath, vInfo.ProductName+".lnk")))) {\r
135                                                         // 原則、lnkファイル名に製品名を採用\r
136                                                         lnkFileName = vInfo.ProductName;\r
137                                                 } else {\r
138                                                         // そのほかの場合は、*.exeファイルの名前をそのまま使用\r
139                                                         lnkFileName = Path.GetFileNameWithoutExtension(exeFile);\r
140                                                 }\r
141                                                 \r
142                                                 // 保存\r
143                                                 lnk.ToPersistFile().Save(Path.Combine(progGrpPath, lnkFileName+".lnk"), true);\r
144                                         }\r
145                                 }\r
146                         }\r
147                 }\r
148                 \r
149                 private static void storeInstalledFileList(string targetDir)\r
150                 {\r
151                         string installedFileListPath = Path.Combine(targetDir, InstalledFileListName);\r
152                         if (File.Exists(installedFileListPath)) {\r
153                                 File.SetAttributes(installedFileListPath, FileAttributes.Normal);\r
154                         }\r
155                         InstalledFileList installedFileList = InstalledFileList.CreateFromFiles(targetDir);\r
156                         NaGet.Utils.PutSerializeObject(installedFileListPath, installedFileList);\r
157                         \r
158                         File.SetAttributes(installedFileListPath, FileAttributes.Hidden | FileAttributes.ReadOnly);\r
159                 }\r
160                 \r
161                 private static void storePackageXml(Package package, string destDir)\r
162                 {\r
163                         if (package == null) {\r
164                                 return;\r
165                         }\r
166                         \r
167                         InstalledPackage pkg = InstalledPackage.PackageConverter(package);\r
168                         UninstallInformation uninfo = pkg.UninstallInfo;\r
169                         uninfo.InstallLocation = destDir;\r
170                         uninfo.UninstallString = string.Format("archive-inst -x \"{0}\"", package.Name);\r
171                         uninfo.EstimatedSize = (int) (NaGet.Utils.GetFileSize(destDir) >> 10);\r
172                         uninfo.InstallDateString = DateTime.Now.ToString("yyyyMMdd");\r
173                         pkg.UninstallInfo = uninfo;\r
174                         \r
175                         string packageXmlFilePath = Path.Combine(destDir, InstalledPackageFileName);\r
176                         if (File.Exists(packageXmlFilePath)) {\r
177                                 File.SetAttributes(packageXmlFilePath, FileAttributes.Normal);\r
178                         }\r
179                         NaGet.Utils.PutSerializeObject(packageXmlFilePath, pkg);\r
180                         File.SetAttributes(packageXmlFilePath, FileAttributes.Hidden | FileAttributes.ReadOnly);\r
181                 }\r
182                 \r
183                 private static void removePackage(InstalledPackage package, string targetDir)\r
184                 {\r
185                         // アンインストールスクリプトの実行\r
186                         if (! string.IsNullOrEmpty(package.InstallScript)) {\r
187                                 Engine engine = MSBuild.Engine;\r
188                                 Project proj = new Project(engine);\r
189                                 try {\r
190                                         proj.LoadXml(package.InstallScript);\r
191                                 } catch (InvalidProjectFileException e) {\r
192                                         throw new ApplicationException("InstallScript is invalid", e);\r
193                                 }\r
194                                 \r
195                                 engine.BuildProject(proj, "Uninstall");\r
196                         }\r
197                         \r
198                         // GUIプログラムでプログラムフォルダに登録しているのを解除\r
199                         string progGrpPath = Path.Combine(NaGet.Env.ArchiveProgramGroup, package.Name);\r
200                         if (Directory.Exists(progGrpPath)) {\r
201                                 NaGet.Utils.SetAttributeRecursive(progGrpPath, FileAttributes.Normal);\r
202                                 Directory.Delete(progGrpPath, true);\r
203                         }\r
204                         \r
205                         // SYSTEM32からの削除の実行\r
206                         if (! string.IsNullOrEmpty(package.System32CopyFiles) ) {\r
207                                 string logfile = Path.Combine(NaGet.Env.ArchiveSystem32, ".applistation.install."+package.Name+".log");\r
208                                 \r
209                                 if (File.Exists(logfile)) {\r
210                                         using (FileStream fs = new FileStream(logfile, FileMode.Open))\r
211                                         using (StreamReader sr = new StreamReader(fs)){\r
212                                                 string fileName = sr.ReadLine().Trim();\r
213                                                 string filePath = Path.Combine(NaGet.Env.ArchiveSystem32, fileName);\r
214                                                 \r
215                                                 if (File.Exists(filePath)) {\r
216                                                         File.SetAttributes(filePath, FileAttributes.Normal);\r
217                                                         File.Delete(filePath);\r
218                                                 }\r
219                                         }\r
220                                         File.SetAttributes(logfile, FileAttributes.Normal);\r
221                                         File.Delete(logfile);\r
222                                 }\r
223                         }\r
224                         \r
225                         NaGet.Utils.SetAttributeRecursive(targetDir, FileAttributes.Normal);\r
226                         Directory.Delete(targetDir, true);\r
227                 }\r
228                 \r
229                 private static void parseMainArguments(string[] args, out string arcFile, out string targetDir, out Package package)\r
230                 {\r
231                         if (args.Length < 1) {\r
232                                 throw new ArgumentException();\r
233                         }\r
234                         \r
235                         switch (args[0].ToLower()) {\r
236                                 case "-t":\r
237                                         if (args.Length != 3) {\r
238                                                 throw new ArgumentException();\r
239                                         }\r
240                                         \r
241                                         arcFile = args[1];\r
242                                         targetDir = args[2];\r
243                                         package = null;\r
244                                         break;\r
245                                 case "-i":\r
246                                         if (args.Length != 3) {\r
247                                                 throw new ArgumentException();\r
248                                         }\r
249                                         \r
250                                         arcFile = args[1];\r
251                                         PackageList<Package> pkgList = NaGet.Utils.GetDeserializedObject<PackageList<Package>>(NaGet.Env.PackageListFile);\r
252                                         package = pkgList.GetPackageForName(args[2]);\r
253                                         targetDir = Path.Combine(NaGet.Env.ArchiveProgramFiles, package.Name);\r
254                                         break;\r
255                                 case "-x":\r
256                                         if (args.Length != 2) {\r
257                                                 throw new ArgumentException();\r
258                                         }\r
259                                         \r
260                                         arcFile = null;\r
261                                         targetDir = Path.Combine(NaGet.Env.ArchiveProgramFiles, args[1]);\r
262                                         package = null;\r
263                                         \r
264                                         string filepath = Path.Combine(targetDir, InstalledPackageFileName);\r
265                                         if (File.Exists(filepath)) {\r
266                                                 package = NaGet.Utils.GetDeserializedObject<InstalledPackage>(filepath);\r
267                                         } else {\r
268                                                 Console.Error.WriteLine("Not found or already removed package : {0}", args[1]);\r
269                                                 Environment.Exit(100);\r
270                                         }\r
271                                         break;\r
272                                 default:\r
273                                         arcFile = null;\r
274                                         targetDir = null;\r
275                                         package = null;\r
276                                         Console.Error.WriteLine("Unreconized command \"{0}\".", args[0]);\r
277                                         Environment.Exit(100);\r
278                                         break;\r
279                         }\r
280                 }\r
281                 \r
282                 [STAThread]\r
283                 public static void Main(string[] args)\r
284                 {\r
285                         // アーカイブSYSTEM32をパスに足す\r
286                         NaGet.Utils.AddDirectoryToPath(NaGet.Env.ArchiveSystem32);\r
287                         \r
288                         string arcFile = null;\r
289                         string targetDir = null;\r
290                         Package package = null;\r
291                         \r
292                         try {\r
293                                 parseMainArguments(args, out arcFile, out targetDir, out package);\r
294                         } catch (ArgumentException) {\r
295                                 string executeFileName = System.AppDomain.CurrentDomain.FriendlyName;\r
296                                 Console.Write("Usage:");\r
297                                 Console.WriteLine("\t{0} -t archive.zip target_dir\tExtraction", executeFileName);\r
298                                 Console.WriteLine("\t{0} -i archive.zip PackageName\tInstall", executeFileName);\r
299                                 Console.WriteLine("\t{0} -x PackageName\t\tUninstall", executeFileName);\r
300                                 Console.WriteLine();\r
301                         }\r
302                                                 \r
303                         if (arcFile != null) { // install or extract    \r
304                                 string tempExtractDir = targetDir + "___temp___"; // HACK \r
305                                 Directory.CreateDirectory(tempExtractDir);\r
306                                 \r
307                                 try {\r
308                                         extract(arcFile, tempExtractDir);\r
309                                         \r
310                                         install(tempExtractDir, targetDir);\r
311                                         \r
312                                         if (package != null) {\r
313                                                 postInstall(targetDir, package);\r
314                                                 \r
315                                                 storeInstalledFileList(targetDir);\r
316                                                 storePackageXml(package, targetDir);\r
317                                         }\r
318                                 } catch (DllNotFoundException) {\r
319                                         Console.Error.WriteLine("E: Does not exist archive dll for {0}", arcFile); // TODO\r
320                                         Environment.Exit(10);\r
321                                 } finally {\r
322                                         Directory.Delete(tempExtractDir, true);\r
323                                 }\r
324                         } else if (package is InstalledPackage) {\r
325                                 removePackage((InstalledPackage) package, targetDir);\r
326                         }\r
327                 }\r
328         }\r
329 }\r