csharp: Download SVN source

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Text.RegularExpressions;
using System.IO;
using System.Threading;
using System.Xml;

namespace DownloadSVN
{

    /// <summary>
    /// SVN 2016-05-13
    /// Geovin Du edit
    /// </summary>
    public partial class MainForm : Form
    {
        ManualResetEvent _waitingForStop;
        ManualResetEvent _finishedReadingTree;
        List<FileDownloadData> _filesToDownload;
        Thread _readingThread;
        String _selectedSourceType;

        public MainForm()
        {
            InitializeComponent();

            this.comboBoxSourceType.SelectedIndex = 0;
        }

        private void buttonBrowseTargetFolder_Click(object sender, EventArgs e)
        {
            using (FolderBrowserDialog fbd = new FolderBrowserDialog())
            {
                if (fbd.ShowDialog() == DialogResult.OK)
                    this.textBoxTargetFolder.Text = fbd.SelectedPath;
            }
        }

        private void buttonGo_Click(object sender, EventArgs e)
        {
            if (_readingThread == null)
            {
                _selectedSourceType = this.comboBoxSourceType.Text;

                Thread t = new Thread(new ThreadStart(Run));
                t.Start();
                _readingThread = t;
                SetButtonGoText("Stop");
            }
            else
            {
                Stop();
            }
        }

        void Run()
        {
            // Start downloading threads
            _finishedReadingTree = new ManualResetEvent(false);
            _waitingForStop = new ManualResetEvent(false);
            _filesToDownload = new List<FileDownloadData>();

            List<Thread> downloadThreads = new List<Thread>();
            for (int i = 0; i < 5; i++)
            {
                Thread t = new Thread(new ThreadStart(DownloadFilesThread));
                t.Start();
                downloadThreads.Add(t);
            }

            try
            {
                if ((this.textBoxTargetFolder.Text != "") && (this.textBoxSourceSvnUrl.Text != ""))
                {
                    string url = this.textBoxSourceSvnUrl.Text;

                    if (_selectedSourceType == "GIT")
                        RunSvn(this.textBoxTargetFolder.Text, this.textBoxSourceSvnUrl.Text, RepositoryType.GIT);
                    else // "SVN"
                        RunSvn(this.textBoxTargetFolder.Text, this.textBoxSourceSvnUrl.Text, RepositoryType.SVN);
                }
                else
                    WriteToScreen("Parameters not set.");
            }
            catch (Exception ex)
            {
                WriteToScreen("Failed: " + ex);
                lock (_filesToDownload)
                {
                    _filesToDownload.Clear();
                }
            }
            finally
            {
                _finishedReadingTree.Set();
            }

            // Wait for downloading threads
            WriteToScreen("Waiting for file downloading threads to finish");
            for (int i = 0; i < downloadThreads.Count; i++)
                downloadThreads[i].Join();

            WriteToScreen("Done.");
            MessageBox.Show("Done", "Done");
            _readingThread = null;

            SetButtonGoText("Start");
        }

        delegate void SetButtonGoTextDelegate(string text);
        /// <summary>
        ///
        /// </summary>
        /// <param name="text"></param>
        void SetButtonGoText(string text)
        {
            if (InvokeRequired == true)
            {
                this.Invoke(new SetButtonGoTextDelegate(SetButtonGoText), text);
                return;
            }

            buttonGo.Text = text;
        }
        /// <summary>
        ///
        /// </summary>
        void DownloadFilesThread()
        {
            while (true)
            {
                FileDownloadData fileDownloadData  = null;
                lock (_filesToDownload)
                {
                    if (_filesToDownload.Count > 0)
                    {
                        fileDownloadData = _filesToDownload[0];
                        _filesToDownload.RemoveAt(0);
                    }
                }

                if ((fileDownloadData == null) && (_finishedReadingTree.WaitOne(0, false) == true))
                    return;

                if (fileDownloadData != null)
                {
                    bool retry = true;
                    while (retry == true)
                    {
                        if (_waitingForStop.WaitOne(0, false) == true)
                            return;

                        try
                        {
                            DownloadFile(fileDownloadData.Url, fileDownloadData.FileName);
                            retry = false;
                        }
                        catch (Exception ex)
                        {
                            WriteToScreen("Failed to download: " + ex.Message);
                        }
                    }
                }
                else
                {
                    Thread.Sleep(100);
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        public enum RepositoryType
        {
            SVN,
            GIT
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="baseFolder"></param>
        /// <param name="baseUrl"></param>
        /// <param name="repositoryType"></param>
        void RunSvn(string baseFolder, string baseUrl, RepositoryType repositoryType)
        {
            if (repositoryType == RepositoryType.SVN)
            {
                if (baseUrl.EndsWith("/") == false)
                    baseUrl += "/";
            }

            if (baseFolder.EndsWith("\\") == false)
                baseFolder += "\\";

            List<FolderLinkData> urls = new List<FolderLinkData>();
            urls.Add(new FolderLinkData(baseUrl, ""));

            while (urls.Count > 0)
            {
                if (_waitingForStop.WaitOne(0, false) == true)
                {
                    WriteToScreen("Stopping...");
                    lock (_filesToDownload)
                    {
                        _filesToDownload.Clear();
                    }
                    break;
                }

                FolderLinkData targetUrlData = urls[0];
                string targetUrl = targetUrlData.Url;
                urls.RemoveAt(0);

                // Create the folder
                string relative;
                if (targetUrlData.RelativePath == null)
                    relative = targetUrl.Substring(baseUrl.Length);
                else
                    relative = targetUrlData.RelativePath;

                relative = relative.Replace("/", "\\");
                string targetFolder = Path.Combine(baseFolder, relative);
                if (Directory.Exists(targetFolder) == false)
                    Directory.CreateDirectory(targetFolder);

                // Download target page
                string page = null;
                bool retry = true;
                while (retry == true)
                {
                    if (_waitingForStop.WaitOne(0, false) == true)
                        return;

                    try
                    {
                        page = DownloadUrl(targetUrl);
                        retry = false;
                    }
                    catch (Exception ex)
                    {
                        WriteToScreen("Failed to download: " + ex.Message);
                    }
                }

                if (repositoryType == RepositoryType.SVN)
                {
                    List<string> links = ParseLinks(page);

                    foreach (string link in links)
                    {
                        string linkFullUrl = targetUrl + link;
                        if (linkFullUrl.EndsWith("/") == true)
                        {
                            urls.Add(new FolderLinkData(linkFullUrl, null));
                        }
                        else // file - download
                        {
                            string fileName = targetFolder + link;
                            lock (_filesToDownload)
                            {
                                _filesToDownload.Add(new FileDownloadData(linkFullUrl, fileName));
                            }
                        }
                    }
                }
                else if (repositoryType == RepositoryType.GIT)
                {
                    List<PageLink> links = ParseGitLinks(page);
                    int pos = targetUrl.IndexOf("/?");
                    string serverUrl = targetUrl.Substring(0, pos);

                    foreach (PageLink link in links)
                    {
                        string linkFullUrl = serverUrl + link.Url;
                        if (link.IsFolder == true)
                            urls.Add(new FolderLinkData(linkFullUrl, targetUrlData.RelativePath + link.Name + "\\"));
                        else
                        {
                            string fileName = targetFolder + link.Name;

                            lock (_filesToDownload)
                            {
                                _filesToDownload.Add(new FileDownloadData(linkFullUrl, fileName));
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="page"></param>
        /// <returns></returns>
        List<string> ParseLinks(string page)
        {
            try
            {
                return ParseLinksFromXml(page);
            }
            catch
            {
                return ParseLinksFromHtml(page);
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="page"></param>
        /// <returns></returns>
        List<string> ParseLinksFromXml(string page)
        {
            List<string> list = new List<string>();

            XmlDocument doc = new XmlDocument();
            doc.LoadXml(page);

            XmlNode svnNode = doc.SelectSingleNode("/svn");
            if (svnNode == null)
                throw new Exception("Not a valid SVN xml");

            foreach (XmlNode node in doc.SelectNodes("/svn/index/dir"))
            {
                string dir = node.Attributes["href"].Value;
                list.Add(dir);
            }

            foreach (XmlNode node in doc.SelectNodes("/svn/index/file"))
            {
                string file = node.Attributes["href"].Value;
                list.Add(file);
            }

            return list;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="page"></param>
        /// <returns></returns>
        List<string> ParseLinksFromHtml(string page)
        {
            List<string> links = new List<string>();
            string listArea = null;

            // Find list area: <ul> ... </ul>
            int pos = page.IndexOf("<ul>");
            if (pos >= 0)
            {
                int lastPos = page.IndexOf("</ul>", pos);
                if (lastPos >= 0)
                    listArea = page.Substring(pos + 4, lastPos - (pos + 4));
            }

            if (listArea != null)
            {
                string[] lines = listArea.Split(‘\n‘);
                string linePattern = "<a [^>]*>([^<]*)<";
                for (int i = 0; i < lines.Length; i++)
                {
                    Match match = Regex.Match(lines[i], linePattern);
                    if (match.Success == true)
                    {
                        string linkRelUrl = match.Groups[1].Value;
                        if (linkRelUrl != "..")
                            links.Add(linkRelUrl);
                    }
                }
            }

            return links;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="page"></param>
        /// <returns></returns>
        List<PageLink> ParseGitLinks(string page)
        {
            List<PageLink> links = new List<PageLink>();

            string dataStartMarker = "<td class=\"mode\">";
            string nameMarker = "hb=HEAD\">";

            using (StringReader sr = new StringReader(page))
            {
                string line;
                while ((line = sr.ReadLine()) != null)
                {
                    if (line.StartsWith(dataStartMarker) == false)
                        continue;

                    bool isFolder = false;
                    if (line[dataStartMarker.Length] == ‘d‘)
                        isFolder = true;

                    line = sr.ReadLine();

                    // Get name
                    int pos = line.IndexOf(nameMarker);
                    int endPos = line.IndexOf("<", pos);
                    pos += nameMarker.Length;

                    string name = line.Substring(pos, endPos - pos);

                    if ((name == "..") || (name == "."))
                        continue;

                    // Get URL
                    pos = line.IndexOf("href=\"");
                    endPos = line.IndexOf("\">", pos);
                    pos += "href=\"".Length;
                    string url = line.Substring(pos, endPos - pos);
                    if (isFolder == false)
                    {
                        url = url.Replace(";a=blob;", ";a=blob_plain;");

                        pos = url.IndexOf(";h=");
                        url = url.Substring(0, pos);
                        url = url + ";hb=HEAD";
                    }

                    if (url.Contains(";a=tree;"))
                        isFolder = true;

                    links.Add(new PageLink(name, url, isFolder));
                }
            }

            return links;
        }

        #region Download helper functions
        /// <summary>
        ///
        /// </summary>
        /// <param name="url"></param>
        /// <param name="fileName"></param>
        void DownloadFile(string url, string fileName)
        {
            WriteToScreen("Downloading File: " + url);

            WebRequest webRequest = WebRequest.Create(url);
            webRequest.ContentType = "text/html; charset=utf-8"; //考虑乱码问题
            webRequest.Timeout = 50000;
            WebResponse webResponse = null;
            Stream responseStream = null;
            try
            {
                webResponse = webRequest.GetResponse();
                responseStream = webResponse.GetResponseStream();
                //  string  page = new StreamReader(responseStream, Encoding.UTF8, true).ReadToEnd();
                using (FileStream fs = new FileStream(fileName, FileMode.Create))
                {
                    byte[] buffer = new byte[1024];
                    int readSize;
                    while ((readSize = responseStream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        fs.Write(buffer, 0, readSize);
                    }
                }
            }
            finally
            {
                if (responseStream != null)
                    responseStream.Close();

                if (webResponse != null)
                    webResponse.Close();
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        string DownloadUrl(string url)
        {
            WriteToScreen("Downloading: " + url);
            using (WebClient client = new WebClient())
            {
                client.Encoding = System.Text.Encoding.UTF8; //GetEncoding("utf-8"); //考虑乱码问题
                string data = client.DownloadString(url);

                return data;
            }
        }
        #endregion

        delegate void WriteToScreenDelegate(string str);
        /// <summary>
        ///
        /// </summary>
        /// <param name="str"></param>
        void WriteToScreen(string str)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new WriteToScreenDelegate(WriteToScreen), str);
                return;
            }

            this.richTextBox1.AppendText(str + "\n");
            this.richTextBox1.ScrollToCaret();
        }

        private void buttonClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void Stop()
        {
            _waitingForStop.Set();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (_readingThread != null)
            {
                Stop();
                e.Cancel = true;
            }
        }
    }

    public class PageLink
    {
        string _name;
        string _url;
        bool _isFolder;

        public string Name { get { return _name; } }
        public string Url { get { return _url; } }
        public bool IsFolder { get { return _isFolder; } }

        public PageLink(string name, string url, bool isFolder)
        {
            _name = name;
            _url = url;
            _isFolder = isFolder;
        }
    }
    /// <summary>
    ///
    /// </summary>
    public class FolderLinkData
    {
        string _url;
        string _relativePath;

        public string Url { get { return _url; } }
        public string RelativePath { get { return _relativePath; } }

        public FolderLinkData(string url, string relativePath)
        {
            _url = url;
            _relativePath = relativePath;
        }
    }
    /// <summary>
    ///
    /// </summary>
    public class FileDownloadData
    {
        string _url;
        string _fileName;

        public string Url
        {
            get { return _url; }
        }

        public string FileName
        {
            get { return _fileName; }
        }

        public FileDownloadData(string url, string fileName)
        {
            _url = url;
            _fileName = fileName;
        }
    }
}

  

时间: 2024-11-05 12:19:42

csharp: Download SVN source的相关文章

Sitcore Download MediaLibrary Source

public partial class Download : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { try { if (!String.IsNullOrEmpty(Request["mid"])) { MediaItem mi = Sitecore.Context.Database.GetItem(new ID(Request["mid"])); St

SVN服务之VisualSVN-Server和TortoiseSVN

SVN客户端程序:TortoiseSVN SVN服务器程序:VisualSVN-Server 目前有个项目,需要版本服务器,由于习惯了svn的使用,让这边搭建一台svn服务器,做了一下整理,只满足部署,具体使用还需要看相关文档. SVN 是 Apache Subversion 的缩写,是一个开放源代码的版本控制系.这些数据放置在一个中央资料档案库(repository) 中. 这个档案库很像一个普通的文件服务器,不过它会记住每一次文件的变动. svn相关概念: repository(版本库):文

源代码管理工具Svn和Git

一.源代码管理工具诞生的原因: 1.无法后悔:做错了一个操作后,没有后悔药可以吃: 注解:在用Xcode编程的时候,我们做了一个代码修改,忽然Xcode崩了,或者是不小心关掉了.那么刚才所写的好代码就丢失了,即使Command+Z也无法后退 2.版本备份:费空间.费时间: 如果我们为了防止写完一个模块或者一个功能的代码后Xcode因不小心关闭而丢失代码,就去做版本备份,那写完一个项目,岂不是备份了成百上千份?耗时耗空间! 3.版本混乱:因版本备份过多造成混乱,难于找回正确的想要的版本: 备份过多

Downloading the Source

Downloading the Source IN THIS DOCUMENT Installing Repo Initializing a Repo client Downloading the Android Source Tree Using Authentication Troubleshooting network issues Using a local mirror Verifying Git Tags The Android source tree is located in a

Installing Python 3.5.2 from source

Here are the procedures we are to follow, Download the source code of an official Python release. Configure the build appropriately for our machine. Compile the software. Test the software to make sure it works properly. Install the software. Configu

Browse W3C&#39;s Open Source Software

https://www.w3.org/Status.html Browse W3C's Open Source Software Amaya - a Web browser/editor First released Feb '97, Amaya is not just a browser, but a hypertext editor. It's a test-bed for the design of embedded objects, stylesheets, math, structur

使用VisualSVN Server搭建SVN服务器 (Windows环境为例)

使用 VisualSVN Server来实现主要的 SVN功能则要比使用原始的 SVN和 Apache相配合来实现源代码的 SVN管理简单的多,下面就看看详细的说明. VisualSVN Server的下载地址如下,是免费的,随意不必有顾虑 http://www.visualsvn.com/server/download/ SVN 的下载地址如下 http://tortoisesvn.net/downloads.html [1]使用SVN,首先要安装TortoiseSVN,就是上面的SVN下载地

Thinking in Java 4th Edition Source Code

Thinking in Java 4th Edition Source Code Instructions for downloading, installing and testing the source code Download the source code zip file from this link. Create a directory in which to install the code. For these instructions, we'll refer to th

SVN服务器搭建与使用

使用 VisualSVN Server来实现主要的 SVN功能则要比使用原始的 SVN和 Apache相配合来实现源代码的 SVN管理简单的多,下面就看看详细的说明. VisualSVN Server的下载地址如下,是免费的,随意不必有顾虑 http://www.visualsvn.com/server/download/ SVN 的下载地址如下 http://tortoisesvn.net/downloads.html [1]使用SVN,首先要安装TortoiseSVN,就是上面的SVN下载地