/// <summary> /// Deletes the log file, if it exists. /// </summary> private static void DeleteLogIfExists() { // write the name of the current class and method we are now entering, into the log Console.WriteLine("In LogFileManager.DeleteLogIfExists"); Console.WriteLine( "LogFileManager.DeleteLogIfExists: Checking whether the folder '{0}' is writable...", LogFileDirectoryName); if (!FileAndFolderHelper.IsFolderWritable(LogFileDirectoryName)) { // If we cannot write to the folder where the log file to be deleted sits in, then Heaven help us! However the software // should try to work at all costs, so this method should just silently fail in this case. Console.WriteLine( "LogFileManager.DeleteLogIfExists: The folder '{0}' is not writable, so we can't delete the log file '{1}' as requested. Nothing to do.", LogFileDirectoryName, LogFilePath); Console.WriteLine( "LogFileManager.DeleteLogIfExists: Done."); return; } Console.WriteLine( "LogFileManager.DeleteLogIfExists: The folder '{0}' is writable, so therefore we can delete the log file '{1}'.", LogFileDirectoryName, LogFilePath); try { Console.WriteLine( "LogFileManager.DeleteLogIfExists: Deleting the log file folder '{0}' and all files and folders within it, and then re-creating the folder...", LogFileDirectoryName); if (Directory.Exists(LogFileDirectoryName)) { Directory.Delete(LogFileDirectoryName, true); } if (!Directory.Exists(LogFileDirectoryName)) { Directory.CreateDirectory(LogFileDirectoryName); } if (Directory.Exists(LogFileDirectoryName)) { Console.WriteLine( "LogFileManager:DeleteLogIfExists: Successfully deleted and re-created the folder '{0}'.", LogFileDirectoryName); } } catch (Exception e) { // dump all the exception info to the log/console DebugUtils.LogException(e); } Console.WriteLine("LogFileManager.DeleteLogIfExists: Done."); }
/// <summary> /// Compresses a directory full of files into a ZIP file with the same name as the directory. Does not add the /// directory itself to the ZIP file. /// </summary> /// <param name="directoryPath">Path to the directory containing the files to be ZIPped.</param> /// <param name="zipFilePath">Path to the output ZIP file. Must not be the same as the directory that is being ZIPped.</param> /// <returns></returns> public static bool CompressDirectory(string directoryPath, string zipFilePath) { // write the name of the current class and method we are now entering, into the log DebugUtils.WriteLine(DebugLevel.Debug, "In ZipperUpper.CompressDirectory"); // Dump the variable directoryPath to the log DebugUtils.WriteLine(DebugLevel.Debug, "ZipperUpper.CompressDirectory: directoryPath = '{0}'", directoryPath); // Dump the variable zipFilePath to the log DebugUtils.WriteLine(DebugLevel.Debug, "ZipperUpper.CompressDirectory: zipFilePath = '{0}'", zipFilePath); if (!Directory.Exists(directoryPath)) { // assume the directoryPath parameter specifies the release asset directory Console.WriteLine(Resources.ReleaseAssetDirNotFound, directoryPath); return(false); } if (string.IsNullOrWhiteSpace(zipFilePath)) { // Oops! There is nowhere to deposit the zip file when we're done! Console.WriteLine(Resources.OutputZipFilePathBlank); return(false); } // Check whether the zipFilePath contains characters that the operating // system does not allow to appear in a valid file name if (Path.GetFileName(zipFilePath).IndexOfAny(Path.GetInvalidFileNameChars()) >= 0) { Console.WriteLine(Resources.ReleaseZipFileNameContainsInvalidChars, zipFilePath); return(false); } var zipOutputFolder = Path.GetDirectoryName(zipFilePath); if (string.IsNullOrWhiteSpace(zipOutputFolder)) { // Oops! There is nowhere to deposit the zip file when we're done! Console.WriteLine(Resources.ZipOutputFolderBlank); return(false); } if (directoryPath.ToLower().Equals(zipOutputFolder.ToLower())) { // the output zip file is not allowed to live in the same directory as the files // that are being ZIPped. Console.WriteLine(Resources.ZipFolderMustBeDifferentFromAssetFolder); return(false); } /* Check whether the current user has access privileges to write to the input directory and the * directory where the output zip is going to live. If the current user does not, then fail */ if (!FileAndFolderHelper.IsFolderWritable(directoryPath)) { // Current user does not have write access privileges to the input folder. Console.WriteLine(Resources.UserNotHasPermissionsToFolder, directoryPath); return(false); } /* Create the folder where the outputted ZIP file is going to live, if that folder * does not already exist. */ FileAndFolderHelper.CreateDirectoryIfNotExists( zipOutputFolder ); if (!FileAndFolderHelper.IsFolderWritable(zipOutputFolder)) { // Current user does not have write access privileges to the output folder. Console.WriteLine(Resources.UserNotHasPermissionsToFolder, zipOutputFolder); return(false); } // Delete the output file if it already exists. if (File.Exists(zipFilePath)) { File.Delete(zipFilePath); } try { var events = new FastZipEvents(); // try to keep going even if a particular file or folder fails events.FileFailure += (s1, a1) => a1.ContinueRunning = true; events.DirectoryFailure += (s2, a2) => a2.ContinueRunning = true; //events.CompletedFile += (s3, a3) => Console.WriteLine($"Finished file '{a3.Name}."); //events.ProcessFile += (s4, a4) => Console.WriteLine($"Zipping file {a4.Name}..."); new FastZip(events) .CreateZip( zipFilePath, directoryPath, true, string.Empty); } catch (Exception e) { // dump all the exception info to the log DebugUtils.LogException(e); if (File.Exists(zipFilePath)) { File.Delete(zipFilePath); } return(false); } return(File.Exists(zipFilePath)); // operation succeeded if the zip file exists at the path the user wants it at. }
/// <summary> /// Initializes the application's logging subsystem. /// </summary> /// <param name="muteDebugLevelIfReleaseMode">Set to true if we should not write out "DEBUG" messages to the log file when in the NewRelease mode. Set to false if all messages should always be logged.</param> /// <param name="overwrite">Overwrites any existing logs for the application with the latest logging sent out by this instance.</param> /// <param name="configurationFilePathname">Specifies the path to the configuration file to be utilized for initializing log4net. If blank, the system attempts to utilize the default App.config file.</param> /// <remarks>Upon completion, this method sets the <see cref="IsLoggingInitialized"/> property. Applications should check the value of this /// property to determine whether logging succeeded.</remarks> public static void InitializeLogging(bool muteDebugLevelIfReleaseMode = true, bool overwrite = true, string configurationFilePathname = "") { // write the name of the current class and method we are now entering, into the log Console.WriteLine("In LogFileManager.InitializeLogging"); // Check whether the path to the configuration file is blank; or, if it's not blank, whether the specified file actually exists at the path indicated. // If the configuration file pathname is blank and/or it does not exist at the path indicated, then call the version of XmlConfigurator.Configure that does // not take any arguments. On the other hand, if the configurationFilePathname parameter is not blank, and it specifies a file that actually does exist // at the specified path, then pass that path to the XmlConfigurator.Configure method. if (string.IsNullOrWhiteSpace(configurationFilePathname) || !File.Exists(configurationFilePathname)) { // If the file specified by the configurationFilePathname does not actually exist, the author of this software // needs to know about it, so throw a FileNotFoundException if (!string.IsNullOrWhiteSpace(configurationFilePathname) && // only do this check for a non-blank file name. !File.Exists(configurationFilePathname)) { Console.WriteLine( $"The file '{configurationFilePathname}' was not found.\n\nThe application needs this file in order to continue."); IsLoggingInitialized = false; return; } XmlConfigurator.Configure(); } else { XmlConfigurator.Configure(new FileInfo(configurationFilePathname)); } // Check to see if the required property, LogFilePath, is blank, whitespace, or null. If it is any of these, send an // error to the log file and quit. if (string.IsNullOrWhiteSpace(LogFilePath)) { // if we are here, then the call above did not work, try to load the configuration from the // .exe.config file which may have been included as an embedded resource. if (!ConfigureLogFileFromEmbeddedResource()) { Console.WriteLine("LogFileManager.InitializeLogging: Failed to initialize logging from embedded configuration file."); return; } } // If we are here, then the required string property, LogFilePath, has a value. Check to ensure that the // LogFileDirectoryName read-only property also has a value, which should be the path to the folder in which // the log file lives. if (string.IsNullOrWhiteSpace(LogFileDirectoryName)) { return; } // Check whether the parent folder of the folder in which the log file will live, is also writable by the // currently-logged-in user var directoryInfo = new DirectoryInfo(LogFileDirectoryName).Parent; if (directoryInfo != null) { // Check whether the user has write permissions on the directory tree that will // contain the log files. Stop if the user does not. var logFileDirectoryParent = directoryInfo .FullName; // Dump the variable logFileDirectoryParent to the log Console.WriteLine("LogFileManager.InitializeLogging: logFileDirectoryParent = '{0}'", logFileDirectoryParent); Console.WriteLine( "LogFileManager.InitializeLogging: Checking whether the user has write-level access to the folder '{0}'...", logFileDirectoryParent); // Check if the user has write access to the parent directory of the log file. if (!FileAndFolderHelper.IsFolderWritable(logFileDirectoryParent)) { Console.WriteLine( @"LogFileManager.InitializeLogging: The user '{0}\{1}' does not have write-level access to the folder '{2}'.", Environment.UserDomainName, Environment.UserName, logFileDirectoryParent); // Mark the IsLoggingInitialized property to false IsLoggingInitialized = false; return; } } // Check whether the log file directory already exists. If not, then try to create it. FileAndFolderHelper.CreateDirectoryIfNotExists(LogFileDirectoryName); // We have to insist that the directory that the log file is in is writable. If we can't // get write access to the log file directory, then throw an exception. if (!FileAndFolderHelper.IsFolderWritable(LogFileDirectoryName)) { Console.WriteLine( $"The current user does not have write permissions to the directory '{LogFileDirectoryName}'."); IsLoggingInitialized = false; } // Set options on the file appender of the logging system to minimize locking issues FileAppenderConfigurator.SetMinimalLock(FileAppenderManager.GetFirstFileAppender()); // If the overwrite parameter's value is set to true, then overwrite the log -- that is, // delete any existing log file that may already exist. if (overwrite) { DeleteLogIfExists(); } // initialization succeeded IsLoggingInitialized = true; // Set up the Event Log and the DebugUtils objects. // Attempt to get a name for the executing application. DebugUtils.ApplicationName = GetDebugApplicationName(); // If we found a value for the ApplicationName, then initialize the EventLogManager. The EventLogManager // is a companion component to DebugUtils which also spits out logging to the System Event Log. This is handy // in the case where the user does not have write access to the C:\ProgramData directory, for example. if (!string.IsNullOrWhiteSpace(DebugUtils.ApplicationName)) { EventLogManager.Instance.Initialize(DebugUtils.ApplicationName, EventLogType.Application); } // Set up the DebugUtils object with values that specify how we want logging done. Be sure to specify that // we should not write log messages to the console under any circumstances, since this is a console application // that may be interactive to the user or have its stdout results parsed by another program. SetUpDebugUtils(muteDebugLevelIfReleaseMode, true, false, 1, true); // done }
/// <summary> /// Uploads the assets in the release asset directory individually to the newly-created release. Flattens any directory structure that might exist in the /// folder referred to by <see cref="releaseAssetDir"/>. /// </summary> /// <param name="releaseAssetDir">String containing the fully-qualified path to the directory containing release assets to be uploaded.</param> /// <param name="newRelease">Reference to an instance of a dynamic object which has been deserialized from the response JSON /// of the call to create the new release.</param> /// <param name="userAccessToken">String containing the user's API access token.</param> public static void UploadAssetsIndividually(string releaseAssetDir, dynamic newRelease, string userAccessToken) { if (string.IsNullOrWhiteSpace(releaseAssetDir)) { throw new ArgumentNullException(nameof(releaseAssetDir)); } if (!Directory.Exists(releaseAssetDir)) { throw new DirectoryNotFoundException(string.Format(Resources.DirectoryNotFound, releaseAssetDir)); } if (newRelease == null) { throw new ArgumentNullException(nameof(newRelease)); } if (string.IsNullOrWhiteSpace(userAccessToken)) { throw new ArgumentNullException(nameof(userAccessToken)); } // Iterate over all the files in the release asset directory and its subdirectories, // one by one. Flatten the directory tree into just a big ol' list of files. To preserve // the directory tree, distribute the release assets in ZIP format and then have your // Setup program un zip the assets into their directory structure. foreach (var assetFile in FileSearcher.GetAllFilesInFolder( releaseAssetDir).Where(fsi => (fsi.Attributes & FileAttributes.Directory) != FileAttributes.Directory)) { /* Make a new request each iteration of the loop over asset files */ var request = GitHubRequestFactory.PrepareGitHubRequest(Method.POST, userAccessToken); // Get just the name and extension of the asset for use in the // upload url later. If blank is returned, then something went wrong. // In that case, just skip the current file. var assetFileName = Path.GetFileName(assetFile.FullName); if (string.IsNullOrWhiteSpace(assetFileName)) { continue; } // If the file has zero bytes of length, do not upload it if (FileAndFolderHelper.FileHasZeroLength((FileInfo)assetFile)) { Console.WriteLine( $"ERROR: File '{assetFileName}' has zero bytes of length. Not uploading it."); // Just skip files that have zero length continue; } /* From Tavis.UriTemplates NuGet package -- works like Ruby uri_template gem */ var uploadUrl = new UriTemplate(newRelease.upload_url.Value) .AddParameters(new { name = assetFileName, label = assetFileName }) .Resolve(); if (string.IsNullOrWhiteSpace(uploadUrl)) { Console.WriteLine(Resources.UploadUrlNotObtainable); Environment.Exit(Resources.ERROR_NOT_OBTAINED_RELEASE_UPLOAD_URL); } // Prepare a REST request with the upload url from the create release API response // above var client = new RestClient( uploadUrl ); var assetMimeMapping = MimeMapping.GetMimeMapping(assetFile.FullName); request.AddHeader(Resources.ContentTypeHeaderName, assetMimeMapping ); var bytes = File.ReadAllBytes(assetFile.FullName); if (!bytes.Any()) { continue; // zero-length file } request.AddHeader("Content-Length", bytes.Length.ToString()); Console.WriteLine($"{bytes.Length} bytes read from file '{assetFile.FullName}'. Uploading..."); request.AddParameter( assetMimeMapping, bytes, ParameterType.RequestBody ); var response = client.Execute(request); if (response == null || response.StatusCode != HttpStatusCode.Created) { Console.WriteLine(Resources.FailedToUploadAsset, assetFileName); Environment.Exit(Resources.ERROR_ASSET_NOT_ACCEPTED); } else { Console.WriteLine(Resources.AssetAccepted, assetFileName); } } }