blob: a994e2187f71afab0f8b521e4e63fba2eca39f21 [file] [log] [blame]
#region Apache License, Version 2.0
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
#endregion
using System.Globalization;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Xml;
using VSLangProj;
using NPanday.Artifact;
using NPanday.Model.Pom;
using NPanday.Model.Settings;
using NPanday.Utils;
namespace NPanday.VisualStudio.Addin
{
public partial class AddArtifactsForm : Form
{
private List<NPanday.Artifact.Artifact> localArtifacts = new List<NPanday.Artifact.Artifact>();
private ArtifactContext artifactContext;
private Project project;
private FileInfo pom;
private WebClient webClient = new WebClient();
public bool fileProtocol = false;
private string settingsPath;
private Settings settings;
private string selectedRepoUrl;
private string prevSelectedRepoUrl = string.Empty;
/// <summary>
/// For Testing
/// </summary>
public AddArtifactsForm()
{
//InitializeForm();
InitializeComponent();
addArtifact.Show();
}
public string settings_Path
{
get { return settingsPath; }
}
public AddArtifactsForm(Project project, ArtifactContext container, FileInfo pom)
{
this.project = project;
InitializeForm();
InitializeComponent();
addArtifact.Visible = true;
localListView.View = View.Details;
artifactContext = container;
this.pom = pom;
}
public static void SetUnsafeHttpHeaderParsing()
{
Assembly assembly = Assembly.GetAssembly(typeof(System.Net.Configuration.SettingsSection));
Type settingsSectionType = assembly.GetType("System.Net.Configuration.SettingsSectionInternal");
object settingsSection = settingsSectionType.InvokeMember("Section",
BindingFlags.Static | BindingFlags.GetProperty | BindingFlags.NonPublic,
null, null, new object[] { });
FieldInfo fieldInfo = settingsSectionType.GetField("useUnsafeHeaderParsing",
BindingFlags.NonPublic | BindingFlags.Instance);
fieldInfo.SetValue(settingsSection, true);
}
private void InitializeForm()
{
this.SuspendLayout();
//
// AddArtifactsForm
//
this.ClientSize = new System.Drawing.Size(292, 260);
this.Name = "AddArtifactsForm";
this.Load += new System.EventHandler(this.AddArtifactsForm_Load);
this.ResumeLayout(false);
}
private void AddArtifactsForm_Load(object sender, EventArgs e)
{
localListView_Refresh();
loadSettings();
if (settings == null)
{
this.Close();
return;
}
selectedRepoUrl = getDefaultRepositoryUrl();
remoteTreeView_Refresh();
repoCombo_Refresh(selectedRepoUrl);
}
private void localListView_Refresh()
{
localListView.Items.Clear();
localArtifacts = artifactContext.GetArtifactRepository().GetArtifacts();
foreach (NPanday.Artifact.Artifact artifact in localArtifacts)
{
LocalArtifactItem item = new LocalArtifactItem(new string[] {
artifact.ArtifactId, artifact.Version}, -1);
item.Artifact = artifact;
localListView.Items.Add(item);
}
}
private void remoteTreeView_Refresh()
{
SetUnsafeHttpHeaderParsing();
treeView1.Nodes.Clear();
List<TreeNode> treeNodes = getNodesFor(selectedRepoUrl);
treeView1.Nodes.AddRange(treeNodes.ToArray());
prevSelectedRepoUrl = selectedRepoUrl;
}
private bool isSelectedRepoModified(NPanday.Model.Settings.Repository selectedRepo)
{
if (selectedRepo == null)
{
return false;
}
if (selectedRepo.snapshots == null || selectedRepo.releases == null ||
checkBoxSnapshot.Checked != selectedRepo.snapshots.enabled || checkBoxRelease.Checked != selectedRepo.releases.enabled)
{
return true;
}
// check if URL is already in NPanday.id profile
NPanday.Model.Settings.Profile defaultProfile = getDefaultProfile();
if (defaultProfile != null)
{
foreach (NPanday.Model.Settings.Repository repo in defaultProfile.repositories)
{
if (repo.url == RepoCombo.Text)
{
return false;
}
}
}
return true;
}
private bool isIncluded(string name, string uri)
{
if (name.StartsWith(".") || name.Equals("Parent Directory") || name.Equals("Terms of Use"))
{
return false;
}
if (uri.StartsWith(".."))
{
return false;
}
if (uri.Contains("."))
{
string[] tokens = name.Split(".".ToCharArray());
string extension = tokens[tokens.Length - 1];
if (extension.Equals("txt") || extension.Equals("pom") ||
extension.Equals("md5") || extension.Equals("sha1") ||
extension.Equals("xml") || extension.Equals("tar") ||
extension.Equals("gz") || extension.Equals("rb") ||
extension.Equals("htm") || extension.Equals("html") ||
extension.Equals("jsp"))
{
return false;
}
}
if (uri.ToLower().StartsWith("http") || uri.ToLower().StartsWith("mailto", true, CultureInfo.InvariantCulture))
{
return false;
}
return true;
}
private bool isDirectory(string name)
{
if (name.Contains("."))
{
string[] tokens = name.Split(".".ToCharArray());
string extension = tokens[tokens.Length - 1];
if (extension.Equals("dll") || extension.Equals("jar") ||
extension.Equals("exe"))
{
return false;
}
}
return true;
}
private void verifyRemoteAccess(string url)
{
while (true)
{
try
{
webClient.DownloadData(url);
break;
}
catch (WebException ex)
{
// ask for user credentials then try again
if (ex.Response != null && (ex.Response as HttpWebResponse).StatusCode == HttpStatusCode.Unauthorized)
{
LoginForm dialog = new LoginForm("Enter repository credentials:");
if (dialog.ShowDialog(this) == DialogResult.OK)
{
CredentialCache cache = new CredentialCache();
cache.Add(new Uri(url), "Basic", new NetworkCredential(dialog.Username, dialog.Password));
webClient.Credentials = cache;
continue;
}
throw new Exception("Sorry, but you are not authorized to access the specified URL.");
}
else
{
throw new Exception("Sorry, but you have entered an invalid URL for the Remote Repository.");
}
}
catch (Exception)
{
throw new Exception("Sorry, but you have entered an invalid URL for the Remote Repository.");
}
}
}
private void verifyFileProtocol(string url)
{
string chkDir = url.Replace("file:///", "");
if (!Directory.Exists(chkDir))
{
throw new Exception("Sorry, but you have entered an invalid URL for the Remote Repository.");
}
}
List<TreeNode> getNodesFromRemote(string url)
{
List<TreeNode> treeNodes = new List<TreeNode>();
byte[] page = null;
if (!url.EndsWith("/"))
{
url += "/";
}
//prevent VS crash
try
{
page = webClient.DownloadData(url);
}
catch (Exception)
{
//MessageBox.Show("Cannot read remote repository: " + url + " " + ex.Message + ex.StackTrace);
MessageBox.Show("Cannot read remote repository: " + url, "Configure Repository", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return treeNodes;
}
string pattern = (@"<a[^>]*href\s*=\s*[\""\']?(?<URI>[^""'>\s]*)[\""\']?[^>]*>(?<Name>[^<]+|.*?)?<");
MatchCollection matches = Regex.Matches(Encoding.ASCII.GetString(page), pattern, RegexOptions.IgnoreCase);
// treeView1.ImageList = imageList1;
foreach (Match match in matches)
{
string name = match.Groups["Name"].Value;
string uri = match.Groups["URI"].Value;
// this will convert absolute URI to relative
if (uri.ToLower().StartsWith("http"))
{
uri = Regex.Replace(uri, url, "", RegexOptions.IgnoreCase);
}
if (isIncluded(name, uri))
{
RemoteArtifactNode node = new RemoteArtifactNode(name); // new TreeNode(name);
if (!isDirectory(name))
{
node.ImageIndex = 1;
}
node.IsFileSystem = false;
string ext = Path.GetExtension(name).ToLower();
if (ext == ".dll" || ext == ".exe" || ext == ".netmodule" || ext == ".ocx")
{
node.IsAssembly = true;
}
else
{
node.IsAssembly = false;
}
String newUrl = url;
newUrl += uri.TrimEnd("/".ToCharArray()); ;
node.ArtifactUrl = newUrl;
treeNodes.Add(node);
}
}
return treeNodes;
}
private bool isValidRemoteRepositoryUrl(string repoUrl)
{
byte[] page = null;
try
{
page = webClient.DownloadData(repoUrl);
}
catch (Exception ex)
{
MessageBox.Show("Cannot read remote repository: " + repoUrl + " " + ex.Message + ex.StackTrace);
return false;
}
return true;
}
private string normalizePath(string path)
{
//
// e.g.: Castle/./Castle.Core/./2.0-rc2/./Castle.Core-2.0-rc2.dll
// transform it to: Castle/Castle.Core/2.0-rc2/Castle.Core-2.0-rc2.dll
//
//
return path.Replace("/./", "/");
}
void addArtifactToPom(Artifact.Artifact artifact)
{
try
{
if (pom != null)
{
PomHelperUtility pomUtil = new PomHelperUtility(pom);
pomUtil.AddPomDependency(artifact.GroupId, artifact.ArtifactId, artifact.Version);
}
}
catch (Exception err)
{
MessageBox.Show(this, err.Message, "NPanday Add Dependency Warning:", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
}
bool addVSProjectReference(Artifact.Artifact artifact, string name)
{
VSProject vsProject = (VSProject)project.Object;
if (vsProject.References.Find(name) != null)
{
MessageBox.Show(this, "A version of artifact is already added to the project, please remove it first before adding this version.", this.Text);
return false;
}
try
{
Assembly a = Assembly.LoadFile(artifact.FileInfo.FullName);
//if (a.ToString().Split(",".ToCharArray())[0].ToLower().StartsWith("interop."))
//{
// MessageBox.Show("Cannot add COM Interop reference from a Maven Artifact, just use Add Reference if you wish to add a COM reference.", "Add Maven Artifact", MessageBoxButtons.OK, MessageBoxIcon.Information);
// return false;
//}
addArtifactToPom(artifact);
vsProject.References.Add(artifact.FileInfo.FullName);
return true;
}
catch
{
MessageBox.Show("Cannot add COM reference from a Maven Artifact.", "Add Maven Artifact", MessageBoxButtons.OK, MessageBoxIcon.Information);
return false;
}
}
bool addVSWebProjectReference(Artifact.Artifact artifact, string name)
{
try
{
VsWebSite.VSWebSite website = (VsWebSite.VSWebSite)project.Object;
Assembly a = Assembly.LoadFile(artifact.FileInfo.FullName);
if (a.ToString().Split(",".ToCharArray())[0].ToLower().StartsWith("interop.", true, CultureInfo.InvariantCulture))
{
MessageBox.Show("Cannot add COM Interop reference from a Maven Artifact, just use Add Reference if you wish to add a COM reference.", "Add Maven Artifact", MessageBoxButtons.OK, MessageBoxIcon.Information);
return false;
}
bool referenced = false;
try
{
referenced = (website.References.Item(name) != null);
}
catch
{
referenced = false;
}
if (referenced)
{
MessageBox.Show(this, "A version of artifact is already added to the project, please remove it first before adding this version.", this.Text);
return false;
}
// not need to written in pom anymore
//addArtifactToPom(artifact);
website.References.AddFromFile(artifact.FileInfo.FullName);
return true;
}
catch
{
MessageBox.Show("Cannot add COM reference from a Maven Artifact.", "Add Maven Artifact", MessageBoxButtons.OK, MessageBoxIcon.Information);
return false;
}
}
void addLocalArtifact(LocalArtifactItem item)
{
NPanday.Artifact.Artifact artifact = item.Artifact;
addReferenceToProject(ref artifact, item.Text);
}
private void addReferenceToProject(ref NPanday.Artifact.Artifact artifact, string text)
{
if (project.Object is VSProject)
{
IReferenceManager refMgr = new ReferenceManager();
refMgr.Initialize((VSLangProj80.VSProject2)project.Object);
artifact = refMgr.Add(new ReferenceInfo(artifact));
if (!addVSProjectReference(artifact, text))
return;
}
else if (Connect.IsWebSite(project))
{
if (!addVSWebProjectReference(artifact, text))
return;
}
else
{
MessageBox.Show(this, "Cannot add artifact to none VS projects.", this.Text);
return;
}
}
void addRemoteArtifact(RemoteArtifactNode node)
{
string uri = node.ArtifactUrl;
string paths;
string repoUrl = selectedRepoUrl;
if (node.IsFileSystem)
{
//Uri repoUri = new Uri(repoUrl);
//paths = uri.Substring(repoUri.LocalPath.Length).Replace(@"\",@"/");
paths = uri;
}
else
{
paths = normalizePath(uri.Substring(repoUrl.Length));
}
NPanday.Artifact.Artifact artifact =
artifactContext.GetArtifactRepository().GetArtifactFor(paths);
//Download
artifact.FileInfo.Directory.Create();
if (node.IsFileSystem)
{
if (!File.Exists(artifact.FileInfo.FullName))
{
File.Copy(node.ArtifactUrl, artifact.FileInfo.FullName);
}
}
else
{
if (!File.Exists(artifact.FileInfo.FullName))
{
byte[] assembly = webClient.DownloadData(uri);
FileStream stream = new FileStream(artifact.FileInfo.FullName, FileMode.Create);
stream.Write(assembly, 0, assembly.Length);
stream.Flush();
stream.Close();
stream.Dispose();
webClient.Dispose();
}
//make sure that file is properly closed before adding it to the reference
System.Threading.Thread.Sleep(1000);
}
addReferenceToProject(ref artifact, artifact.ArtifactId);
//if (project.Object is VSProject)
//{
// if (!addVSProjectReference(artifact, artifact.ArtifactId))
// return;
//}
//else if (Connect.IsWebProject(project))
//{
// if (!addVSWebProjectReference(artifact, artifact.ArtifactId))
// return;
//}
//else
//{
// MessageBox.Show(this, "Cannot add artifact to none VS projects.", this.Text);
// return;
//}
}
private void executeRepoUpdate()
{
if (string.IsNullOrEmpty(RepoCombo.Text))
{
MessageBox.Show("Sorry, Repository cannot be blank.", "Repository Configuration", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
string selectedUrl = RepoCombo.Text;
// verify if URL is accessible
try
{
if (selectedUrl.Contains("file:///"))
{
verifyFileProtocol(selectedUrl);
}
else
{
verifyRemoteAccess(selectedUrl);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Repository Configuration", MessageBoxButtons.OK, MessageBoxIcon.Warning);
artifactTabControl.SelectedIndex = 2;
RepoCombo.Text = string.Empty;
return;
}
// add repository to profile
NPanday.Model.Settings.Repository repo = SettingsUtil.SetProfileRepository(getDefaultProfile(), selectedUrl, checkBoxRelease.Checked, checkBoxSnapshot.Checked);
selectedRepoUrl = selectedUrl;
// set the mirror too
SettingsUtil.SetMirrorUrl(settings, selectedUrl);
// make NPanday.id profile active
SettingsUtil.AddActiveProfile(settings, SettingsUtil.defaultProfileID);
// write to Settings.xml
SettingsUtil.MergeSettings(settings, settingsPath);
// do not specify SelectedUrl to suppress SelectedIndexChanged event
repoCombo_Refresh(null);
MessageBox.Show(this, "Successfully Changed Remote Repository.", "Repository Configuration");
//localListView_Refresh();
}
}
private void repoCombo_Refresh(string selectedUrl)
{
RepoCombo.Items.Clear();
if (settings.profiles != null)
{
List<NPanday.Model.Settings.Repository> repositories = SettingsUtil.GetAllRepositories(settings);
foreach (NPanday.Model.Settings.Repository repo in repositories)
{
if (!RepoCombo.Items.Contains(repo.url))
{
RepoCombo.Items.Add(repo.url);
}
}
if (RepoCombo.Items.Count > 0 && !string.IsNullOrEmpty(selectedUrl))
{
RepoCombo.SelectedIndex = RepoCombo.Items.IndexOf(selectedUrl);
}
}
}
private void repoCheckboxes_Refresh(NPanday.Model.Settings.Repository selectedRepo)
{
checkBoxRelease.Checked = (selectedRepo != null && selectedRepo.releases != null) ? selectedRepo.releases.enabled : true;
checkBoxSnapshot.Checked = (selectedRepo != null && selectedRepo.snapshots != null) ? selectedRepo.snapshots.enabled : false;
}
#region GUI Events
private void localListView_DoubleClick(object sender, EventArgs e)
{
try
{
LocalArtifactItem item = localListView.SelectedItems[0] as LocalArtifactItem;
addLocalArtifact(item);
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "NPanday Add Dependency Warning:", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
{
try
{
RemoteArtifactNode node = e.Node as RemoteArtifactNode;
if (node.IsAssembly)
{
addRemoteArtifact(node);
}
}
catch (Exception ex)
{
MessageBox.Show(this, ex.Message, "NPanday Add Dependency Warning:", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
private void addArtifact_Click(object sender, EventArgs e)
{
try
{
ListView.SelectedListViewItemCollection selectedItems = localListView.SelectedItems;
if (selectedItems != null)
{
foreach (ListViewItem item in selectedItems)
{
addLocalArtifact(item as LocalArtifactItem);
}
}
if (treeView1.SelectedNode != null)
{
RemoteArtifactNode treeNode = treeView1.SelectedNode as RemoteArtifactNode;
if (treeNode.IsAssembly)
{
addRemoteArtifact(treeNode);
}
else
{
MessageBox.Show(this, string.Format("Cannot add {0} not an artifact assembly.", treeNode.FullPath), this.Text);
return;
}
}
}
catch (Exception err)
{
MessageBox.Show(this, err.Message, "NPanday Add Dependency Warning:", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
this.Close();
}
private void update_Click(object sender, EventArgs e)
{
executeRepoUpdate();
}
private void RepoListBox_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void ConfigureTab_Click(object sender, EventArgs e)
{
addArtifact.Hide();
}
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
RemoteArtifactNode node = e.Node as RemoteArtifactNode;
if (node.IsAssembly)
return;
List<TreeNode> treeNodes = getNodesFor(node.ArtifactUrl);
node.Nodes.Clear();
node.Nodes.AddRange(treeNodes.ToArray());
addArtifact.Show();
}
private void remoteTabPage_Click(object sender, EventArgs e)
{
addArtifact.Show();
}
private void localTabPage_Click(object sender, EventArgs e)
{
addArtifact.Show();
}
private void localListView_SelectedIndexChanged(object sender, EventArgs e)
{
addArtifact.Show();
}
private void RepoCombo_SelectedIndexChanged(object sender, EventArgs e)
{
NPanday.Model.Settings.Repository selectedRepo = getRepository(RepoCombo.Text);
selectedRepoUrl = RepoCombo.Text;
repoCheckboxes_Refresh(selectedRepo);
}
private void artifactTabControl_SelectedIndexChanged(object sender, EventArgs e)
{
if (artifactTabControl.SelectedIndex == 2)
{
RepoCombo.Focus();
addArtifact.Hide();
}
else if (artifactTabControl.SelectedIndex == 1)
{
//check if there is an existing settings.xml file
if (settings == null)
{
loadSettings();
}
NPanday.Model.Settings.Repository selectedRepo;
if (selectedRepoUrl == null)
{
selectedRepo = getRepositoryFromDefaultProfile();
selectedRepoUrl = selectedRepo.url;
}
else
{
selectedRepo = getRepository(selectedRepoUrl);
}
if (isSelectedRepoModified(selectedRepo))
{
executeRepoUpdate();
}
if (prevSelectedRepoUrl != selectedRepoUrl)
{
remoteTreeView_Refresh();
}
treeView1.Focus();
addArtifact.Show();
}
else
{
localListView.Focus();
addArtifact.Show();
}
}
#endregion
#region GUI Operations
List<TreeNode> getNodesFor(string url)
{
try
{
Uri repoUri = new Uri(url);
if (repoUri.IsFile)
{
return getNodesFromLocal(repoUri.LocalPath);
}
else
{
return getNodesFromRemote(url);
}
}
catch (Exception e)
{
MessageBox.Show("There was a problem with the provided URL. \nStack Trace:" + e.Message, "Get Artifacts from Remote Repository Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return null;
}
List<TreeNode> getNodesFromLocal(string repoFolder)
{
List<TreeNode> nodes = new List<TreeNode>();
if (!Directory.Exists(repoFolder))
{
MessageBox.Show(this, "Local repository path not found.", "Local Repository");
return nodes;
}
foreach (FileSystemInfo fsi in (new DirectoryInfo(repoFolder).GetFileSystemInfos()))
{
if (fsi is FileInfo)
{
string ext = Path.GetExtension(fsi.FullName).ToLower();
if (ext != ".dll" && ext != ".exe" && ext != ".netmodule" && ext != ".ocx")
continue;
}
RemoteArtifactNode node = new RemoteArtifactNode(fsi.Name);
node.IsFileSystem = true;
node.ArtifactUrl = Path.Combine(repoFolder, fsi.Name);
node.IsAssembly = (fsi is FileInfo);
nodes.Add(node);
}
return nodes;
}
#endregion
#region Settings.xml Operations
private void loadSettings()
{
settingsPath = SettingsUtil.GetUserSettingsPath();
try
{
if (File.Exists(settingsPath))
{
settings = SettingsUtil.ReadSettings(new FileInfo(settingsPath));
}
else
{
throw new Exception("Sorry, but no settings.xml file was found in your Local Repository.");
}
}
catch (Exception ex)
{
MessageBox.Show("Invalid settings.xml File:" + " " + ex.Message, "Configuration Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
}
private NPanday.Model.Settings.Profile getDefaultProfile()
{
if (settings == null)
{
loadSettings();
}
return SettingsUtil.GetDefaultProfile(settings, true);
}
private NPanday.Model.Settings.Repository getRepository(string url)
{
if (string.IsNullOrEmpty(url))
{
return null;
}
// extract from NPanday repositories first
NPanday.Model.Settings.Repository repo;
NPanday.Model.Settings.Profile defaultProfile = getDefaultProfile();
if (defaultProfile != null)
{
repo = SettingsUtil.GetRepositoryFromProfile(defaultProfile, url);
if (repo != null)
{
return repo;
}
}
// extract from NON-NPanday repositories
return SettingsUtil.GetRepositoryByUrl(settings, url);
}
private NPanday.Model.Settings.Repository getRepositoryFromDefaultProfile()
{
NPanday.Model.Settings.Profile defaultProfile = getDefaultProfile();
if (defaultProfile != null && defaultProfile.repositories != null && defaultProfile.repositories.Length > 0)
{
return defaultProfile.repositories[0];
}
return null;
}
private string getDefaultRepositoryUrl()
{
NPanday.Model.Settings.Repository repo = getRepositoryFromDefaultProfile();
return repo != null ? repo.url : SettingsUtil.GetSettingsRepositories()["central"];
}
#endregion
}
}