Add Wox.UpdateFeedGenerator

This commit is contained in:
qianlifeng 2015-01-22 22:57:54 +08:00
parent bda67afd4f
commit 21edfdb62e
22 changed files with 685 additions and 73 deletions

View File

@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Settings>
<BaseURL>http://127.0.0.1:8888</BaseURL>
<IgnoreVsHosting>True</IgnoreVsHosting>
<CompareSize>False</CompareSize>
<CleanUp>True</CleanUp>
<IgnoreDebugSymbols>False</IgnoreDebugSymbols>
<IgnoreFiles>&lt;?xml version="1.0" encoding="utf-16"?&gt;
&lt;ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" /&gt;</IgnoreFiles>
<CopyFiles>True</CopyFiles>
<CompareVersion>False</CompareVersion>
<OutputFolder>..\..\Output\Release</OutputFolder>
<CompareHash>True</CompareHash>
<CompareDate>False</CompareDate>
<FeedXML>..\..\Output\Update\Update.xml</FeedXML>
</Settings>

Binary file not shown.

View File

@ -1,54 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
<section name="FeedBuilder.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
</sectionGroup>
</configSections>
<userSettings>
<FeedBuilder.Properties.Settings>
<setting name="BaseURL" serializeAs="String">
<value />
</setting>
<setting name="CleanUp" serializeAs="String">
<value>True</value>
</setting>
<setting name="CompareDate" serializeAs="String">
<value>False</value>
</setting>
<setting name="CompareHash" serializeAs="String">
<value>True</value>
</setting>
<setting name="CompareSize" serializeAs="String">
<value>False</value>
</setting>
<setting name="CompareVersion" serializeAs="String">
<value>True</value>
</setting>
<setting name="CopyFiles" serializeAs="String">
<value>True</value>
</setting>
<setting name="FeedXML" serializeAs="String">
<value />
</setting>
<setting name="IgnoreDebugSymbols" serializeAs="String">
<value>True</value>
</setting>
<setting name="IgnoreFiles" serializeAs="Xml">
<value>
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>*.pdb</string>
<string>*.config</string>
</ArrayOfString>
</value>
</setting>
<setting name="IgnoreVsHosting" serializeAs="String">
<value>True</value>
</setting>
<setting name="OutputFolder" serializeAs="String">
<value />
</setting>
</FeedBuilder.Properties.Settings>
</userSettings>
</configuration>

View File

@ -1,2 +0,0 @@
cd /d %~dp0
%~dp0FeedBuilder.exe "%~dp0FeedBuilder.config" -Build

View File

@ -1 +0,0 @@
FeedBuilder.exe "FeedBuilder.config" -ShowGUI

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,2 @@
cd /d %~dp0
%~dp0Wox.UpdateFeedGenerator.exe

View File

@ -0,0 +1,10 @@
{
"OutputDirectory": "..\\..\\Output\\Update",
"SourceDirectory": "..\\..\\Output\\Release",
"BaseURL": "http://127.0.0.1:8888",
"FeedXMLName": "update.xml",
"CheckVersion": false,
"CheckSize": false,
"CheckDate": false,
"CheckHash": true
}

View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using Newtonsoft.Json;
using Wox.Infrastructure.Storage;
namespace Wox.UpdateFeedGenerator
{
public class ConfigStorage : JsonStrorage<ConfigStorage>
{
[JsonProperty]
public string OutputDirectory { get; set; }
[JsonProperty]
public string SourceDirectory { get; set; }
[JsonProperty]
public string BaseURL { get; set; }
[JsonProperty]
public string FeedXMLName { get; set; }
[JsonProperty]
public bool CheckVersion { get; set; }
[JsonProperty]
public bool CheckSize { get; set; }
[JsonProperty]
public bool CheckDate { get; set; }
[JsonProperty]
public bool CheckHash { get; set; }
protected override void OnAfterLoad(ConfigStorage config)
{
if (string.IsNullOrEmpty(config.OutputDirectory))
{
config.OutputDirectory = @"Update";
ConfigStorage.Instance.Save();
}
}
protected override string ConfigFolder
{
get { return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); }
}
protected override string ConfigName
{
get { return "config"; }
}
}
}

View File

@ -0,0 +1,38 @@
using System.Diagnostics;
using System.IO;
namespace Wox.UpdateFeedGenerator
{
public class FileInfoEx
{
private readonly FileInfo myFileInfo;
private readonly string myFileVersion;
private readonly string myHash;
public FileInfo FileInfo
{
get { return myFileInfo; }
}
public string FileVersion
{
get { return myFileVersion; }
}
public string Hash
{
get { return myHash; }
}
public string RelativeName { get; private set; }
public FileInfoEx(string fileName,int rootDirectoryLength)
{
myFileInfo = new FileInfo(fileName);
myFileVersion = FileVersionInfo.GetVersionInfo(fileName).FileVersion;
if (myFileVersion != null) myFileVersion = myFileVersion.Replace(", ", ".");
myHash = NAppUpdate.Framework.Utils.FileChecksum.GetSHA256Checksum(fileName);
RelativeName = fileName.Substring(rootDirectoryLength + 1);
}
}
}

View File

@ -0,0 +1,248 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using Microsoft.Win32.SafeHandles;
using Wox.UpdateFeedGenerator.Win32;
namespace Wox.UpdateFeedGenerator
{
namespace Win32
{
/// <summary>
/// Structure that maps to WIN32_FIND_DATA
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
internal sealed class FindData
{
public int fileAttributes;
public int creationTime_lowDateTime;
public int creationTime_highDateTime;
public int lastAccessTime_lowDateTime;
public int lastAccessTime_highDateTime;
public int lastWriteTime_lowDateTime;
public int lastWriteTime_highDateTime;
public int nFileSizeHigh;
public int nFileSizeLow;
public int dwReserved0;
public int dwReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public String fileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public String alternateFileName;
}
/// <summary>
/// SafeHandle class for holding find handles
/// </summary>
internal sealed class SafeFindHandle : SafeHandleMinusOneIsInvalid
{
/// <summary>
/// Constructor
/// </summary>
public SafeFindHandle() : base(true) {}
/// <summary>
/// Release the find handle
/// </summary>
/// <returns> true if the handle was released </returns>
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
protected override bool ReleaseHandle()
{
return SafeNativeMethods.FindClose(handle);
}
}
/// <summary>
/// Wrapper for P/Invoke methods used by FileSystemEnumerator
/// </summary>
[SecurityPermission(SecurityAction.Assert, UnmanagedCode = true)]
internal static class SafeNativeMethods
{
[DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
public static extern SafeFindHandle FindFirstFile(String fileName, [In, Out] FindData findFileData);
[DllImport("kernel32", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FindNextFile(SafeFindHandle hFindFile, [In, Out] FindData lpFindFileData);
[DllImport("kernel32", CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FindClose(IntPtr hFindFile);
}
}
/// <summary>
/// File system enumerator. This class provides an easy to use, efficient mechanism for searching a list of
/// directories for files matching a list of file specifications. The search is done incrementally as matches
/// are consumed, so the overhead before processing the first match is always kept to a minimum.
/// </summary>
public sealed class FileSystemEnumerator : IDisposable
{
/// <summary>
/// Information that's kept in our stack for simulated recursion
/// </summary>
private struct SearchInfo
{
/// <summary>
/// Find handle returned by FindFirstFile
/// </summary>
public readonly SafeFindHandle Handle;
/// <summary>
/// Path that was searched to yield the find handle.
/// </summary>
public readonly string Path;
/// <summary>
/// Constructor
/// </summary>
/// <param name="h"> Find handle returned by FindFirstFile. </param>
/// <param name="p"> Path corresponding to find handle. </param>
public SearchInfo(SafeFindHandle h, string p)
{
Handle = h;
Path = p;
}
}
/// <summary>
/// Stack of open scopes. This is a member (instead of a local variable)
/// to allow Dispose to close any open find handles if the object is disposed
/// before the enumeration is completed.
/// </summary>
private readonly Stack<SearchInfo> m_scopes;
/// <summary>
/// Array of paths to be searched.
/// </summary>
private readonly string[] m_paths;
/// <summary>
/// Array of regular expressions that will detect matching files.
/// </summary>
private readonly List<Regex> m_fileSpecs;
/// <summary>
/// If true, sub-directories are searched.
/// </summary>
private readonly bool m_includeSubDirs;
#region IDisposable implementation
/// <summary>
/// IDisposable.Dispose
/// </summary>
public void Dispose()
{
while (m_scopes.Count > 0) {
SearchInfo si = m_scopes.Pop();
si.Handle.Close();
}
}
#endregion
/// <summary>
/// Constructor.
/// </summary>
/// <param name="pathsToSearch"> Semicolon- or comma-delimitted list of paths to search. </param>
/// <param name="fileTypesToMatch"> Semicolon- or comma-delimitted list of wildcard filespecs to match. </param>
/// <param name="includeSubDirs"> If true, subdirectories are searched. </param>
public FileSystemEnumerator(string pathsToSearch, string fileTypesToMatch, bool includeSubDirs)
{
m_scopes = new Stack<SearchInfo>();
// check for nulls
if (null == pathsToSearch) throw new ArgumentNullException("pathsToSearch");
if (null == fileTypesToMatch) throw new ArgumentNullException("fileTypesToMatch");
// make sure spec doesn't contain invalid characters
if (fileTypesToMatch.IndexOfAny(new[] { ':', '<', '>', '/', '\\' }) >= 0) throw new ArgumentException("invalid cahracters in wildcard pattern", "fileTypesToMatch");
m_includeSubDirs = includeSubDirs;
m_paths = pathsToSearch.Split(new[] { ';', ',' });
string[] specs = fileTypesToMatch.Split(new[] { ';', ',' });
m_fileSpecs = new List<Regex>(specs.Length);
foreach (string spec in specs) {
// trim whitespace off file spec and convert Win32 wildcards to regular expressions
string pattern = spec.Trim().Replace(".", @"\.").Replace("*", @".*").Replace("?", @".?");
m_fileSpecs.Add(new Regex("^" + pattern + "$", RegexOptions.IgnoreCase));
}
}
/// <summary>
/// Get an enumerator that returns all of the files that match the wildcards that
/// are in any of the directories to be searched.
/// </summary>
/// <returns> An IEnumerable that returns all matching files one by one. </returns>
/// <remarks>
/// The enumerator that is returned finds files using a lazy algorithm that
/// searches directories incrementally as matches are consumed.
/// </remarks>
public IEnumerable<FileInfo> Matches()
{
foreach (string rootPath in m_paths) {
string path = rootPath.Trim();
// we "recurse" into a new directory by jumping to this spot
top:
// check security - ensure that caller has rights to read this directory
new FileIOPermission(FileIOPermissionAccess.PathDiscovery, Path.Combine(path, ".")).Demand();
// now that security is checked, go read the directory
FindData findData = new FindData();
SafeFindHandle handle = SafeNativeMethods.FindFirstFile(Path.Combine(path, "*"), findData);
m_scopes.Push(new SearchInfo(handle, path));
bool restart = false;
// we "return" from a sub-directory by jumping to this spot
restart:
// ReSharper disable InvertIf
if (!handle.IsInvalid) {
// ReSharper restore InvertIf
do {
// if we restarted the loop (unwound a recursion), fetch the next match
if (restart) {
restart = false;
continue;
}
// don't match . or ..
if (findData.fileName.Equals(@".") || findData.fileName.Equals(@"..")) continue;
if ((findData.fileAttributes & (int)FileAttributes.Directory) != 0) {
if (m_includeSubDirs) {
// it's a directory - recurse into it
path = Path.Combine(path, findData.fileName);
goto top;
}
} else {
// it's a file, see if any of the filespecs matches it
foreach (Regex fileSpec in m_fileSpecs) {
// if this spec matches, return this file's info
if (fileSpec.IsMatch(findData.fileName)) yield return new FileInfo(Path.Combine(path, findData.fileName));
}
}
} while (SafeNativeMethods.FindNextFile(handle, findData));
// close this find handle
handle.Close();
// unwind the stack - are we still in a recursion?
m_scopes.Pop();
if (m_scopes.Count > 0) {
SearchInfo si = m_scopes.Peek();
handle = si.Handle;
path = si.Path;
restart = true;
goto restart;
}
}
}
}
}
}

View File

@ -0,0 +1,179 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Xml;
namespace Wox.UpdateFeedGenerator
{
public class Generator
{
private string OutputDirectory;
private string SourceDirectory;
private string BaseURL = ConfigStorage.Instance.BaseURL;
private string feedXMLPath;
private bool checkVersion = ConfigStorage.Instance.CheckVersion;
private bool checkSize = ConfigStorage.Instance.CheckSize;
private bool checkDate = ConfigStorage.Instance.CheckDate;
private bool checkHash = ConfigStorage.Instance.CheckHash;
public Generator()
{
OutputDirectory = Path.GetFullPath(ConfigStorage.Instance.OutputDirectory);
SourceDirectory = Path.GetFullPath(ConfigStorage.Instance.SourceDirectory);
feedXMLPath = Path.Combine(ConfigStorage.Instance.OutputDirectory, ConfigStorage.Instance.FeedXMLName);
}
private List<FileInfoEx> ReadSourceFiles()
{
List<FileInfoEx> files = new List<FileInfoEx>();
FileSystemEnumerator enumerator = new FileSystemEnumerator(SourceDirectory, "*.*", true);
foreach (FileInfo fi in enumerator.Matches())
{
string file = fi.FullName;
if ((IsIgnorable(file))) continue;
FileInfoEx thisInfo = new FileInfoEx(file, SourceDirectory.Length);
files.Add(thisInfo);
}
return files;
}
private bool IsIgnorable(string thisFile)
{
return false;
}
public void Build()
{
Console.WriteLine("Building Wox update feed");
if (!Directory.Exists(OutputDirectory))
{
Directory.CreateDirectory(OutputDirectory);
}
XmlDocument doc = new XmlDocument();
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(dec);
XmlElement feed = doc.CreateElement("Feed");
feed.SetAttribute("BaseUrl", BaseURL.Trim());
doc.AppendChild(feed);
XmlElement tasks = doc.CreateElement("Tasks");
foreach (FileInfoEx file in ReadSourceFiles())
{
Console.WriteLine("adding {0} to feed xml.", file.FileInfo.FullName);
XmlElement task = doc.CreateElement("FileUpdateTask");
task.SetAttribute("localPath", file.RelativeName);
// generate FileUpdateTask metadata items
task.SetAttribute("lastModified", file.FileInfo.LastWriteTime.ToFileTime().ToString(CultureInfo.InvariantCulture));
task.SetAttribute("fileSize", file.FileInfo.Length.ToString(CultureInfo.InvariantCulture));
if (!string.IsNullOrEmpty(file.FileVersion)) task.SetAttribute("version", file.FileVersion);
XmlElement conds = doc.CreateElement("Conditions");
XmlElement cond;
bool hasFirstCondition = false;
//File Exists
cond = doc.CreateElement("FileExistsCondition");
cond.SetAttribute("type", "or");
conds.AppendChild(cond);
//Version
if (checkVersion && !string.IsNullOrEmpty(file.FileVersion))
{
cond = doc.CreateElement("FileVersionCondition");
cond.SetAttribute("what", "below");
cond.SetAttribute("version", file.FileVersion);
conds.AppendChild(cond);
hasFirstCondition = true;
}
//Size
if (checkSize)
{
cond = doc.CreateElement("FileSizeCondition");
cond.SetAttribute("type", hasFirstCondition ? "or-not" : "not");
cond.SetAttribute("what", "is");
cond.SetAttribute("size", file.FileInfo.Length.ToString(CultureInfo.InvariantCulture));
conds.AppendChild(cond);
}
//Date
if (checkDate)
{
cond = doc.CreateElement("FileDateCondition");
if (hasFirstCondition) cond.SetAttribute("type", "or");
cond.SetAttribute("what", "older");
// local timestamp, not UTC
cond.SetAttribute("timestamp", file.FileInfo.LastWriteTime.ToFileTime().ToString(CultureInfo.InvariantCulture));
conds.AppendChild(cond);
}
//Hash
if (checkHash)
{
cond = doc.CreateElement("FileChecksumCondition");
cond.SetAttribute("type", hasFirstCondition ? "or-not" : "not");
cond.SetAttribute("checksumType", "sha256");
cond.SetAttribute("checksum", file.Hash);
conds.AppendChild(cond);
}
task.AppendChild(conds);
tasks.AppendChild(task);
string destFile = Path.Combine(OutputDirectory, file.RelativeName);
CopyFile(file.FileInfo.FullName, destFile);
}
feed.AppendChild(tasks);
doc.Save(feedXMLPath);
}
private bool CopyFile(string sourceFile, string destFile)
{
// If the target folder doesn't exist, create the path to it
var fi = new FileInfo(destFile);
var d = Directory.GetParent(fi.FullName);
if (!Directory.Exists(d.FullName)) CreateDirectoryPath(d.FullName);
// Copy with delayed retry
int retries = 3;
while (retries > 0)
{
try
{
if (File.Exists(destFile)) File.Delete(destFile);
File.Copy(sourceFile, destFile);
retries = 0; // success
return true;
}
catch (IOException)
{
// Failed... let's try sleeping a bit (slow disk maybe)
if (retries-- > 0) Thread.Sleep(200);
}
catch (UnauthorizedAccessException)
{
// same handling as IOException
if (retries-- > 0) Thread.Sleep(200);
}
}
return false;
}
private void CreateDirectoryPath(string directoryPath)
{
// Create the folder/path if it doesn't exist, with delayed retry
int retries = 3;
while (retries > 0 && !Directory.Exists(directoryPath))
{
Directory.CreateDirectory(directoryPath);
if (retries-- < 3) Thread.Sleep(200);
}
}
}
}

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Xml;
namespace Wox.UpdateFeedGenerator
{
class Program
{
static void Main(string[] args)
{
new Generator().Build();
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// 有关程序集的常规信息通过以下
// 特性集控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Wox.UpdateFeedGenerator")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Wox.UpdateFeedGenerator")]
[assembly: AssemblyCopyright("Copyright © 2015")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 使此程序集中的类型
// 对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型,
// 则将该类型上的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
[assembly: Guid("2f3420c0-2c21-4f71-a45d-a47b5305fe20")]
// 程序集的版本信息由下面四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值,
// 方法是按如下所示使用“*”:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1 @@
NAppUpdate feed generator for Wox. It's something like [FeedBuilder](https://github.com/synhershko/NAppUpdate/tree/master/FeedBuilder)

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D120E62B-EC59-4FB4-8129-EFDD4C446A5F}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Wox.UpdateFeedGenerator</RootNamespace>
<AssemblyName>Wox.UpdateFeedGenerator</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="NAppUpdate.Framework">
<HintPath>..\References\NAppUpdate.Framework.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Newtonsoft.Json.6.0.8\lib\net35\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="ConfigStorage.cs" />
<Compile Include="FileInfoEx.cs" />
<Compile Include="FileSystemEnumerator.cs" />
<Compile Include="Generator.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
<None Include="README.md" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Wox.Infrastructure\Wox.Infrastructure.csproj">
<Project>{4fd29318-a8ab-4d8f-aa47-60bc241b8da3}</Project>
<Name>Wox.Infrastructure</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。启用“NuGet 程序包还原”可下载这些程序包。有关详细信息,请参阅 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('$(SolutionDir)\.nuget\NuGet.targets')" Text="$([System.String]::Format('$(ErrorText)', '$(SolutionDir)\.nuget\NuGet.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net35" />
</packages>

View File

@ -41,6 +41,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.CrashReporter", "Wox.Cr
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Plugin.QueryHistory", "Plugins\Wox.Plugin.QueryHistory\Wox.Plugin.QueryHistory.csproj", "{B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Plugin.QueryHistory", "Plugins\Wox.Plugin.QueryHistory\Wox.Plugin.QueryHistory.csproj", "{B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.UpdateFeedGenerator", "Wox.UpdateFeedGenerator\Wox.UpdateFeedGenerator.csproj", "{D120E62B-EC59-4FB4-8129-EFDD4C446A5F}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -119,6 +121,10 @@ Global
{B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}.Debug|Any CPU.Build.0 = Debug|Any CPU {B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}.Release|Any CPU.ActiveCfg = Release|Any CPU {B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}.Release|Any CPU.Build.0 = Release|Any CPU {B552DCB6-692E-4B1D-9E0B-9096A2A7E6B0}.Release|Any CPU.Build.0 = Release|Any CPU
{D120E62B-EC59-4FB4-8129-EFDD4C446A5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D120E62B-EC59-4FB4-8129-EFDD4C446A5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D120E62B-EC59-4FB4-8129-EFDD4C446A5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D120E62B-EC59-4FB4-8129-EFDD4C446A5F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE