public NewProjectWizard() { InitializeComponent(); // Init new project _project = new DeploymentProject(); _project.InitNewProject(); }
/// <summary> /// Deploys files to an FTP site. /// </summary> internal void Deploy(DeploymentProject project, DeploymentStructure structure) { // Init FTP client // FtpServerSettings settings = project.FtpServer; // _ftp = new FTPClient(settings.Address, settings.Port); // _ftp.CommandSent += new FTPMessageHandler(Ftp_CommandSent); // _ftp.ReplyReceived += new FTPMessageHandler(Ftp_ReplyReceived); // _ftp.BytesTransferred += new BytesTransferredHandler(Ftp_BytesTransferred); // _ftp.Login(settings.Login, settings.Password); // _ftp.TransferType = FTPTransferType.BINARY; // // // Deploy the structure // DeployStructure(structure, settings.Path); // // _ftp.Quit(); }
/// <summary> /// Scans a directory and all subdirectory and returns all the files found that match the scan filter. /// If we are to use project filter, files are read from project instead of directory. /// </summary> /// <param name="project">The current project settings.</param> /// <param name="modifiedSince">Only return files modified after this date.</param> /// <returns>A structure with the files that were found.</returns> internal DeploymentStructure FindFiles(DeploymentProject project, DateTime modifiedSince) { // These members are used for easy access during scanning _project = project; _config = project.ActiveDeployConfig; if (_config == null) throw new ApplicationException("The project has no active deploy configuration."); // Build structure of matching files _structure = new DeploymentStructure(); if (_config.UseProjectFilter) { string projectFilename = project.GetVisualStudioProjectFileName(); if (projectFilename == null) throw new ApplicationException("Could not find a Visual Studio project file in the root directory."); ScanProjectFile(projectFilename, project.LocalPathAbsolute, modifiedSince); } else ScanDirectoryRecurse(project.LocalPathAbsolute, string.Empty, modifiedSince); return _structure; }
/// <summary> /// Retrieves the local cached timestamp or null if not found. /// </summary> /// <param name="project"></param> /// <returns></returns> public TimestampFile GetLocalTimestampFile(DeploymentProject project) { string fname = GetTimestampFilename(project, false); if (!File.Exists(fname)) return null; return TimestampFile.Load(fname); }
/// <summary> /// Updates the remote timestamp. /// </summary> private static void UpdateTimestamp(DeploymentProject project) { try { // Get timestamp plugin if available ITimestampControl tsplugin = GetTimestampPlugin(project); if (tsplugin == null) return; // Create timestamp with current time and cache it locally before uploading it to remote server TimestampFile timestamp = new TimestampFile(); timestamp.DeployedBy = Environment.UserName; timestamp.LastDeployment = DateTime.Now; string fname = GetTimestampFilename(project, false); timestamp.Save(fname); tsplugin.Connect(); tsplugin.UploadTimestampFile(fname, project.RemoteTimestampFilename); tsplugin.Disconnect(); } catch (DirectoryNotFoundException ex) { EventManager.OnNotificationMessage("*** WARNING: Unable to update timestamp: " + ex.Message); } catch(IOException ex) { throw new ApplicationException(ex.Message); } }
/// <summary> /// Determines if a plugin has timestamp support. /// </summary> /// <param name="pluginIdentifier"></param> //public bool HasTimestampSupport(string pluginIdentifier) { // ITimestampControl ts = PluginManager.Plugins.Get(pluginIdentifier) as ITimestampControl; // if (ts == null) // return false; // return true; //} /// <summary> /// Deploys files. /// </summary> /// <param name="project">Contains information about what and where to deploy.</param> /// <param name="files">The files to deploy.</param> public void DeployFiles(DeploymentProject project, IList<DeploymentFile> files) { // Nothing to deploy? if(files.Count == 0) return; EventManager.OnNotificationMessage("Updating timestamp..."); UpdateTimestamp(project); EventManager.OnNotificationMessage("Starting deployment..."); try { // Initiate all deployment hooks foreach (var hook in project.ActiveDeployConfig.HookSettings) { IDeployerHook hookPlugin = PluginManager.GetPluginForHook(hook); hookPlugin.BeforeDeploy(this); } // Signal to all plugins in the project that deployment is starting foreach (DeployDestination dest in project.ActiveDeployConfig.Destinations) { var plugin = PluginManager.GetPluginForDestination(dest) as IFileDeployer; if(plugin != null) plugin.DeployStart(this); } // Deploy files foreach(DeploymentFile file in files) { if(file.IncludeInDeployment) { EventManager.OnNotificationMessage(string.Format("Deploying \"{0}\"...", file.Name)); // Signal that transfer started TransferEventArgs args = new TransferEventArgs(file.LocalPath); EventManager.OnTransferBegin(args); // Start transferring string destid = file.DeployDestinationIdentifier; IDeployerPlugin plugin = PluginManager.GetPlugin(destid); if(plugin == null) throw new ApplicationException(string.Format("Unable to deploy to destination '{0}'. The destination has not been configured.", destid)); var fileDeployer = plugin as IFileDeployer; if(fileDeployer == null) throw new InvalidOperationException(string.Format("Plugin '{0}' does not support file deployment.", plugin.Name)); // Transfer retry loop bool retry; do { retry = false; // Assume we won't retry operation try { string remotename = string.IsNullOrEmpty(file.RemoteName) ? file.Name : file.RemoteName; // Deploy file using plugin fileDeployer.DeployFile(file.LocalPath, file.RemotePath, remotename); // All ok, update event args args.BytesSent = args.TotalBytes; } catch (DeployCancelException) { throw; // Rethrow exception to cancel deployment loop } catch(DeploySkipException) { EventManager.OnNotificationMessage("Skipped file " + file.LocalPath); } catch(Exception ex) { DeployErrorForm dlg = new DeployErrorForm(); dlg.ErrorMessage = ex.Message; dlg.SetLocalInfo("Local File:", file.LocalPath); dlg.SetRemoteInfo("Remote Path:", file.RemotePath); dlg.Plugin = fileDeployer.Name; DialogResult result = dlg.ShowDialog(); switch(result) { case DialogResult.Retry: retry = true; break; case DialogResult.Ignore: break; // Skip to next file case DialogResult.Cancel: throw new DeployCancelException("User cancelled."); } } } while (retry); // Signal that transfer is complete EventManager.OnTransferComplete(args); } } // Signal to all plugins in the project that deployment is complete foreach (DeployDestination dest in project.ActiveDeployConfig.Destinations) { var plugin = PluginManager.GetPluginForDestination(dest) as IFileDeployer; if(plugin != null) plugin.DeployEnd(); } // Signal all deployment hooks foreach (var hook in project.ActiveDeployConfig.HookSettings) { IDeployerHook hookPlugin = PluginManager.GetPluginForHook(hook); hookPlugin.AfterDeploy(this); } EventManager.OnNotificationMessage("Deployment completed."); } catch (DeployCancelException ex) { // Deployment has been cancelled EventManager.OnNotificationMessage("*** Deployment stopped! " + ex.Message); } finally { // Signal to all plugins in the project that deployment is complete foreach (DeployDestination dest in project.ActiveDeployConfig.Destinations) { var plugin = PluginManager.GetPluginForDestination(dest) as IFileDeployer; if (plugin != null) plugin.DeployEnd(); } } }
/// <summary> /// Returns the path to the local timestamp file containing info about when the user last deployed the project. /// </summary> /// <param name="project">The current project file.</param> /// <param name="remote">If true it is the remote timestamp file, if false it is the local one.</param> private static string GetTimestampFilename(DeploymentProject project, bool remote) { string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Deployer"); if (!Directory.Exists(path)) Directory.CreateDirectory(path); // Use the filename to get a unique filename for the timestamp file, or the project name if not yet saved string fileName = !string.IsNullOrEmpty(project.FileName) ? project.FileName : project.Name; string filepath = Path.Combine(path, string.Format("{0}_{1}", fileName.GetHashCode().ToString("x"), project.ActiveDeployConfigName)); if (remote) return filepath + ".remote"; else return filepath + ".local"; }
/// <summary> /// Gets the plugin that has been configured to handle timestamping for the project. /// Returns null if no timestamping is configured. /// </summary> /// <param name="project">The current project settings.</param> private static ITimestampControl GetTimestampPlugin(DeploymentProject project) { // Verify timestamp plugin for the project string destid = project.ActiveDeployConfig.TimestampDestinationIdentifier; if (string.IsNullOrEmpty(destid)) return null; // Lookup destination DeployDestination dest = project.ActiveDeployConfig.Destinations.Get(destid); if(dest == null) throw new ApplicationException(string.Format("Destination '{0}' not found.", destid)); ITimestampControl plugin = PluginManager.GetPluginForDestination(dest) as ITimestampControl; if (plugin == null) throw new ApplicationException(string.Format("Plugin for destination '{0}' does not support timestamp control", dest.Name)); return plugin; }
/// <summary> /// Scans a database for objects to deploy. /// </summary> public DatabaseDeploymentStructure ScanDatabase(DeploymentProject project, DatabasePair databases) { DatabaseDeployer ds = new DatabaseDeployer(); return ds.ScanDatabase(project, databases); }
/// <summary> /// Scans the files in the project and returns a structure that can be used when deploying. /// </summary> public DeploymentStructure ScanFiles(DeploymentProject project, DateTime modifiedSince) { // Find all files to deploy FileScanner fs = new FileScanner(); return fs.FindFiles(project, modifiedSince); }
/// <summary> /// Saves the settings for the currently active deployment target. /// (Only those plugins are loaded at the same time). /// </summary> public static void SavePluginSettings(DeploymentProject project) { DeployConfig config = project.ActiveDeployConfig; if (config == null) return; foreach(DeployDestination dest in config.Destinations) { IDeployerPlugin plugin; if (_plugins.TryGetValue(dest.Identifier, out plugin)) { string settings = plugin.SaveSettings(); // TODO This is a hack to replace the settings (need to implement a better way to handle plugin settings) int TODO; XmlDocument xd = new XmlDocument(); xd.LoadXml(settings); XmlElement oldsettings = dest.PluginSettings.Settings; XmlElement newsettings = (XmlElement)oldsettings.OwnerDocument.ImportNode(xd.DocumentElement, true); //oldsettings.ParentNode.ReplaceChild(newsettings, oldsettings); dest.PluginSettings.Settings = newsettings; //dest.PluginSettings.OldSettings = null; } } }
/// <summary> /// Loads the plugin settings for the currently active deploy target. /// </summary> public static void LoadPluginSettings(DeploymentProject project) { DeployConfig config = project.ActiveDeployConfig; if (config == null) return; // Load settings for plugins foreach (DeployDestination dest in config.Destinations) { IDeployerPlugin plugin; if (_plugins.TryGetValue(dest.Identifier, out plugin)) { plugin.LoadSettings(dest.PluginSettings.Settings.OuterXml); } } }
/// <summary> /// Scans a database for objects to deploy. /// </summary> internal DatabaseDeploymentStructure ScanDatabase(DeploymentProject project, DatabasePair databases) { InitializeServices(databases); DatabaseDeploymentStructure structure = new DatabaseDeploymentStructure(databases); ScanProcedures(project.ActiveDeployConfig.DatabaseSettings.ExcludeProcedures, structure); ScanViews(structure); ShutdownServices(); return structure; }
/// <summary> /// Initializes a new empty project. /// </summary> private void NewProject() { try { if (!CheckSave()) return; // *** Wizard test NewProjectWizard wizard = new NewProjectWizard(); DialogResult result = wizard.ShowDialog(this); if (result == DialogResult.Cancel) return; // Get new project _currentProject = wizard.Project; ResetProjectState(); RefreshUI(false); SetStatusText("New project created."); UpdateMainFormTitle(); } catch (Exception ex) { ShowNonFatalException(ex); } }
/// <summary> /// Loads the project with the specified filename. /// </summary> private void LoadProject(string filename) { try { ResetProjectState(); SetStatusText(string.Format("Loading project \"{0}\".", filename)); UpdateProgressPercent(5); LockUI(); // Load project file _currentProject = DeploymentProject.Load(filename); //_isDirty = false; // Must be set after loading since the loading itself fires the modification event // Load cached timestamp file UpdateLastUploadTime(); AddRecentFile(filename); UpdateMainFormTitle(); RefreshUI(false); SetStatusText(string.Format("Loaded project \"{0}\".", filename)); } catch (FileLoadException ex) { ShowError(ex.Message); } catch (FileNotFoundException) { ShowError(string.Format("The file '{0}' could not be found.", filename)); } catch (UnauthorizedAccessException ex) { MessageBox.Show(this, ex.Message, "Unable to load project", MessageBoxButtons.OK, MessageBoxIcon.Error); } catch (Exception ex) { ShowNonFatalException(ex); } UnlockUI(); }
/// <summary> /// Closes the current project. /// </summary> private void CloseProject() { try { if (!CheckSave()) return; // Close all ResetProjectState(); _currentProject = null; //_isDirty = false; SetStatusText("Project closed."); UpdateMainFormTitle(); UpdateUI(); } catch (Exception ex) { ShowNonFatalException(ex); } }
/// <summary> /// Edits the settings for the server to deploy to. /// </summary> private void ShowProjectSettingsDialog() { try { // Save project state byte[] state = _currentProject.SaveState(); // Show dialog ProjectSettingsForm frm = new ProjectSettingsForm(); frm.Project = _currentProject; if (frm.ShowDialog(this) == DialogResult.Cancel) { // Recall old project state _currentProject = DeploymentProject.LoadState(state); return; } RefreshUI(false); } catch (Exception ex) { ShowNonFatalException(ex); } }
/// <summary> /// Retrieves the remote timestamp information. Returns null if no timestamp was found. /// </summary> /// <param name="project">The current deployment project.</param> /// <returns></returns> public TimestampFile GetRemoteTimestampFile(DeploymentProject project) { try { ITimestampControl plugin = GetTimestampPlugin(project); if (plugin == null) return null; // Download timestamp file EventManager.OnNotificationMessage("Checking timestamp..."); string fname = GetTimestampFilename(project, true); plugin.Connect(); bool retval = plugin.DownloadTimestampFile(fname, project.RemoteTimestampFilename); plugin.Disconnect(); if (!retval) { EventManager.OnNotificationMessage("No timestamp found."); return null; } EventManager.OnNotificationMessage("Timestamp retrieved."); return TimestampFile.Load(fname); } catch (FileLoadException ex) { EventManager.OnNotificationMessage("Timestamp not found. " + ex.Message); return null; } }
/// <summary> /// Loads all plugins for the currently active deploy target. /// Previously loaded plugins are unloaded first. /// </summary> public static void LoadPlugins(DeploymentProject project) { UnloadPlugins(); DeployConfig config = project.ActiveDeployConfig; if (config == null) return; // Load settings for plugins foreach(DeployDestination dest in config.Destinations) { LoadPlugin(dest); } }