4 using Microsoft.Build.BuildEngine;
\r
5 using NaGet.Packages;
\r
6 using NaGet.Packages.Install;
\r
8 namespace ArchiveInstall
\r
12 public const string InstalledFileListName = ".applistation.installedfiles.xml";
\r
14 public const string InstalledPackageFileName = ".applistation.package.xml";
\r
16 private static void extract(string arcFile, string extractDestDir)
\r
18 StringBuilder output = new StringBuilder(1024);
\r
19 int res = NaGet.InteropServices.CommonArchiverExtracter.ExtractArchive(arcFile, extractDestDir, output, IntPtr.Zero);
\r
21 Environment.Exit(res);
\r
25 private static void install(string fakeTargetDir, string targetDir)
\r
28 if (Directory.Exists(targetDir)) {
\r
29 InstalledFileList list = null;
\r
31 list = NaGet.Utils.GetDeserializedObject<InstalledFileList>(Path.Combine(targetDir, InstalledFileListName));
\r
35 // 変更されたファイル(設定ファイル)をキープする処理
\r
36 foreach (InstalledFile changedFile in list.Verify(targetDir)) {
\r
37 string changedFilePath = Path.Combine(targetDir, changedFile.Path);
\r
38 string toBeChangedFilePath = Path.Combine(fakeTargetDir, changedFile.Path);
\r
41 if (File.Exists(toBeChangedFilePath)) {
\r
42 File.Move(toBeChangedFilePath, toBeChangedFilePath + ".newfile");
\r
45 // 変更済みファイルをinstallSrcの方に反映させる
\r
46 if (File.Exists(changedFilePath)) {
\r
47 if (! Directory.Exists(Path.GetDirectoryName(toBeChangedFilePath))) {
\r
49 Directory.CreateDirectory(Path.GetDirectoryName(toBeChangedFilePath));
\r
51 File.Copy(changedFilePath, toBeChangedFilePath);
\r
56 Directory.CreateDirectory(targetDir);
\r
60 foreach (string dir in Directory.GetDirectories(fakeTargetDir, "*", SearchOption.AllDirectories)) {
\r
61 string dirPath = NaGet.Utils.GetRelativePath(fakeTargetDir, dir);
\r
62 string targetDirPath = Path.Combine(targetDir, dirPath);
\r
63 if (! Directory.Exists(targetDirPath)) {
\r
64 Directory.CreateDirectory(targetDirPath);
\r
68 // ファイルをインストール(高速化のため移動)
\r
69 foreach (string file in Directory.GetFiles(fakeTargetDir, "*", SearchOption.AllDirectories)) {
\r
70 string filePath = NaGet.Utils.GetRelativePath(fakeTargetDir, file);
\r
71 string targetFilePath = Path.Combine(targetDir, filePath);
\r
72 if (File.Exists(targetFilePath)) {
\r
74 File.SetAttributes(targetFilePath, FileAttributes.Normal);
\r
75 File.Delete(targetFilePath);
\r
76 } catch (UnauthorizedAccessException e) {
\r
77 throw new IOException(string.Format("Access denied '{0}'", targetFilePath), e);
\r
80 File.Move(file, targetFilePath);
\r
84 private static void _installDllTo(string sys32path, string srcDir, Package package)
\r
86 if (!string.IsNullOrEmpty(package.System32CopyFiles)) {
\r
87 if (! Directory.Exists(sys32path)) {
\r
88 Directory.CreateDirectory(sys32path);
\r
91 string logfile = Path.Combine(sys32path, ".applistation.install."+package.Name+".log");
\r
92 if (File.Exists(logfile)) {
\r
93 File.SetAttributes(logfile, FileAttributes.Normal);
\r
95 using (FileStream fs = new FileStream(logfile, FileMode.Create))
\r
96 using (StreamWriter sw = new StreamWriter(fs)){
\r
97 foreach (string pathpat in package.System32CopyFiles.Split(';')) {
\r
98 foreach (string path in NaGet.Utils.ExtendWildcardFile(srcDir, pathpat)) {
\r
99 if ((File.GetAttributes(path) & FileAttributes.Directory) == 0) { // もしファイルならば
\r
100 string destPath = Path.Combine(sys32path, Path.GetFileName(path));
\r
101 File.Copy(path, destPath, true);
\r
103 sw.WriteLine(Path.GetFileName(destPath));
\r
108 File.SetAttributes(logfile, FileAttributes.Hidden);
\r
112 private static void postInstall(string targetDir, Package package)
\r
114 // SYSTEM32へのコピーの実行
\r
115 _installDllTo(NaGet.Env.ArchiveSystem32, targetDir, package);
\r
118 if (! string.IsNullOrEmpty(package.InstallScript) ) {
\r
119 Engine engine = MSBuild.Engine;
\r
120 Project proj = new Project(engine);
\r
122 proj.LoadXml(package.InstallScript);
\r
123 } catch (InvalidProjectFileException e) {
\r
124 throw new ApplicationException("InstallScript is invalid", e);
\r
127 engine.BuildProject(proj, "Install");
\r
130 // 直下のファイルで*.exeがGUIプログラムならプログラムフォルダーに登録
\r
131 foreach (string exeFile in Directory.GetFiles(targetDir, "*.exe")) {
\r
132 if (NaGet.InteropServices.PEFileInfoUtils.GetPEFileType(exeFile) == NaGet.InteropServices.PEFileType.WinGUI) {
\r
133 string progGrpPath = Path.Combine(NaGet.Env.ArchiveProgramGroup, package.Name);
\r
134 if (! Directory.Exists(progGrpPath)) Directory.CreateDirectory(progGrpPath);
\r
136 using (NaGet.InteropServices.ShellLink lnk = new NaGet.InteropServices.ShellLink() ) {
\r
137 //string path = NaGet.Utils.GetRelativePath(progGrpPath, exeFile);// lnkファイルに相対パス指定不能
\r
138 string path = exeFile;
\r
141 //lnk.SetIconLocation(path, 0);
\r
144 string lnkFilePath = Path.Combine(progGrpPath, lnk.GetSuitableShellLinkNameFor() + ".lnk");
\r
145 if (File.Exists(lnkFilePath)) { // ファイル名がかぶってしまったとき
\r
146 lnkFilePath = Path.Combine(progGrpPath, Path.GetFileNameWithoutExtension(exeFile) + ".lnk");
\r
150 lnk.ToPersistFile().Save(lnkFilePath, true);
\r
156 private static void storeInstalledFileList(string targetDir)
\r
158 string installedFileListPath = Path.Combine(targetDir, InstalledFileListName);
\r
159 if (File.Exists(installedFileListPath)) {
\r
160 File.SetAttributes(installedFileListPath, FileAttributes.Normal);
\r
162 InstalledFileList installedFileList = InstalledFileList.CreateFromFiles(targetDir);
\r
163 NaGet.Utils.PutSerializeObject(installedFileListPath, installedFileList);
\r
165 File.SetAttributes(installedFileListPath, FileAttributes.Hidden | FileAttributes.ReadOnly);
\r
168 private static void storePackageXml(Package package, string destDir)
\r
170 if (package == null) {
\r
174 InstalledPackage pkg = InstalledPackage.PackageConverter(package);
\r
175 UninstallInformation uninfo = pkg.UninstallInfo;
\r
176 uninfo.InstallLocation = destDir;
\r
177 uninfo.UninstallString = string.Format("archive-inst -x \"{0}\"", package.Name);
\r
178 uninfo.EstimatedSize = (int) (NaGet.Utils.GetFileSize(destDir) >> 10);
\r
179 uninfo.InstallDateString = DateTime.Now.ToString("yyyyMMdd");
\r
180 pkg.UninstallInfo = uninfo;
\r
182 string packageXmlFilePath = Path.Combine(destDir, InstalledPackageFileName);
\r
183 if (File.Exists(packageXmlFilePath)) {
\r
184 File.SetAttributes(packageXmlFilePath, FileAttributes.Normal);
\r
186 NaGet.Utils.PutSerializeObject(packageXmlFilePath, pkg);
\r
187 File.SetAttributes(packageXmlFilePath, FileAttributes.Hidden | FileAttributes.ReadOnly);
\r
190 private static void _removeDllFrom(string sys32path, InstalledPackage package)
\r
192 if (! string.IsNullOrEmpty(package.System32CopyFiles) ) {
\r
193 string logfile = Path.Combine(sys32path, ".applistation.install."+package.Name+".log");
\r
195 if (File.Exists(logfile)) {
\r
196 using (FileStream fs = new FileStream(logfile, FileMode.Open))
\r
197 using (StreamReader sr = new StreamReader(fs)){
\r
198 string fileName = sr.ReadLine().Trim();
\r
199 string filePath = Path.Combine(sys32path, fileName);
\r
201 if (File.Exists(filePath)) {
\r
202 File.SetAttributes(filePath, FileAttributes.Normal);
\r
203 File.Delete(filePath);
\r
206 File.SetAttributes(logfile, FileAttributes.Normal);
\r
207 File.Delete(logfile);
\r
212 private static void removePackage(InstalledPackage package, string targetDir)
\r
214 // アンインストールスクリプトの実行
\r
215 if (! string.IsNullOrEmpty(package.InstallScript)) {
\r
216 Engine engine = MSBuild.Engine;
\r
217 Project proj = new Project(engine);
\r
219 proj.LoadXml(package.InstallScript);
\r
220 } catch (InvalidProjectFileException e) {
\r
221 throw new ApplicationException("InstallScript is invalid", e);
\r
224 engine.BuildProject(proj, "Uninstall");
\r
227 // GUIプログラムでプログラムフォルダーに登録しているのを解除
\r
228 string progGrpPath = Path.Combine(NaGet.Env.ArchiveProgramGroup, package.Name);
\r
229 if (Directory.Exists(progGrpPath)) {
\r
230 NaGet.Utils.SetAttributeRecursive(progGrpPath, FileAttributes.Normal);
\r
231 Directory.Delete(progGrpPath, true);
\r
234 // SYSTEM32からの削除の実行
\r
235 _removeDllFrom(NaGet.Env.ArchiveSystem32, package);
\r
238 NaGet.Utils.SetAttributeRecursive(targetDir, FileAttributes.Normal);
\r
239 Directory.Delete(targetDir, true);
\r
240 } catch (UnauthorizedAccessException) {
\r
241 Console.Error.WriteLine("W: could not complete to delete '{0}': Permission denied", targetDir);
\r
242 Environment.Exit(1);
\r
246 private static void parseMainArguments(string[] args, out string arcFile, out string targetDir, out Package package)
\r
248 if (args.Length < 1) {
\r
249 throw new ArgumentException();
\r
252 switch (args[0].ToLower()) {
\r
254 if (args.Length != 3) {
\r
255 throw new ArgumentException();
\r
259 targetDir = args[2];
\r
263 if (args.Length != 3) {
\r
264 throw new ArgumentException();
\r
268 PackageList<Package> pkgList = NaGet.Utils.GetDeserializedObject<PackageList<Package>>(NaGet.Env.PackageListFile);
\r
269 package = pkgList.GetPackageForName(args[2]);
\r
270 targetDir = Path.Combine(NaGet.Env.ArchiveProgramFiles, package.Name);
\r
273 if (args.Length != 2) {
\r
274 throw new ArgumentException();
\r
278 targetDir = Path.Combine(NaGet.Env.ArchiveProgramFiles, args[1]);
\r
281 string filepath = Path.Combine(targetDir, InstalledPackageFileName);
\r
282 if (File.Exists(filepath)) {
\r
283 package = NaGet.Utils.GetDeserializedObject<InstalledPackage>(filepath);
\r
285 Console.Error.WriteLine("Not found or already removed package : {0}", args[1]);
\r
286 Environment.Exit(100);
\r
293 Console.Error.WriteLine("Unreconized command \"{0}\".", args[0]);
\r
294 Environment.Exit(100);
\r
300 public static void Main(string[] args)
\r
302 // アーカイブSYSTEM32をパスに足す
\r
303 NaGet.Utils.AddDirectoryToPath(NaGet.Env.ArchiveSystem32);
\r
305 string arcFile = null;
\r
306 string targetDir = null;
\r
307 Package package = null;
\r
311 parseMainArguments(args, out arcFile, out targetDir, out package);
\r
312 } catch (ArgumentException) {
\r
313 string executeFileName = System.AppDomain.CurrentDomain.FriendlyName;
\r
314 Console.Write("Usage:");
\r
315 Console.WriteLine("\t{0} -t archive.zip target_dir\tExtraction", executeFileName);
\r
316 Console.WriteLine("\t{0} -i archive.zip PackageName\tInstall", executeFileName);
\r
317 Console.WriteLine("\t{0} -x PackageName\t\tUninstall", executeFileName);
\r
318 Console.WriteLine();
\r
322 if (arcFile != null) {
\r
323 string tempExtractDir = targetDir + "___temp___"; // HACK
\r
324 Directory.CreateDirectory(tempExtractDir);
\r
328 if (package != null && package.Type == InstallerType.ITSELF) {
\r
329 // 書庫でない場合展開せずにそのままコピーする
\r
330 string destFile = Path.Combine(tempExtractDir, Path.GetFileName(arcFile));
\r
331 File.Copy(arcFile, destFile);
\r
333 extract(arcFile, tempExtractDir);
\r
336 // インストールの元となるフォルダを決定する
\r
337 string installSrc = tempExtractDir;
\r
338 // 展開先のトップに唯一のフォルダーしかないのであれば、そのフォルダー内を基準とする
\r
339 if (Directory.GetFiles(tempExtractDir).Length == 0 &&
\r
340 Directory.GetDirectories(tempExtractDir).Length == 1) {
\r
341 installSrc = Directory.GetDirectories(tempExtractDir)[0];
\r
344 // STEP2. インストール元フォルダでインストールファイルリストの作成
\r
345 storeInstalledFileList(installSrc);
\r
348 install(installSrc, targetDir);
\r
350 if (package != null) {
\r
351 // STEP4. カスタマイズ可能な後処理
\r
352 postInstall(targetDir, package);
\r
354 // STEP5. パッケージ情報をインストール先(targetDir)に置く
\r
355 storePackageXml(package, targetDir);
\r
357 } catch (DllNotFoundException) {
\r
358 Console.Error.WriteLine("E: Does not exist archive dll for {0}", arcFile); // TODO
\r
359 Environment.Exit(10);
\r
360 } catch (IOException e) {
\r
361 Console.Error.WriteLine("E: File I/O Error : {0}", e.Message);
\r
362 Environment.Exit(1);
\r
364 Directory.Delete(tempExtractDir, true);
\r
366 } else if (package is InstalledPackage) {
\r
367 removePackage((InstalledPackage) package, targetDir);
\r