├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
└── src
├── DPB.Tests
├── BuildProject.cs
├── DPB.Tests.csproj
├── ManifestTests.cs
├── Properties
│ └── AssemblyInfo.cs
├── SourceDir
│ ├── ChildrenDirectoriesWillBeRemoved
│ │ ├── NotRemove
│ │ │ ├── TextFile1.txt
│ │ │ └── TextFile2.txt
│ │ ├── Remove1
│ │ │ ├── TextFile1.txt
│ │ │ └── TextFile2.txt
│ │ └── Remove2
│ │ │ ├── TextFile1.txt
│ │ │ └── TextFile2.txt
│ ├── CustomFunctionFiles
│ │ ├── CustomFunctionFile1.txt
│ │ └── CustomFunctionFile2-net45-csproj.xml
│ ├── EmptyDirectoryToBeRemoved
│ │ ├── FileRemove1.txt
│ │ └── FileRemove2.txt
│ ├── JsonFiles
│ │ └── jsconfig1.json
│ ├── KeepPartsOfContent
│ │ └── KeepPartsOfContent.txt
│ ├── RemoveFiles
│ │ ├── KeepFile.txt
│ │ ├── NormalFile.txt
│ │ ├── RemoveFile1.txt
│ │ └── RemoveFile2.txt
│ ├── Startup.cs.txt
│ ├── StringFiles
│ │ ├── RegexReplaceFile.txt
│ │ └── StringReplaceFile.txt
│ ├── TestManifest-Keep.cs
│ ├── TestManifest.cs
│ ├── ThisDirectoryIsNotEmpty
│ │ ├── FileRemove.txt
│ │ └── FileRemoveOmit.txt
│ └── XmlFiles
│ │ ├── XMLFile1.xml
│ │ └── XMLFile2.xml
└── packages.config
└── DPB
├── DPB.csproj
├── DPB.sln
├── LetsGo.cs
├── LetsGoAsync.cs
├── Models
├── FileWrap.cs
└── Manifest.cs
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | *.nupkg
156 | # The packages folder can be ignored because of Package Restore
157 | **/packages/*
158 | # except build/, which is used as an MSBuild target.
159 | !**/packages/build/
160 | # Uncomment if necessary however generally it will be regenerated when needed
161 | #!**/packages/repositories.config
162 | # NuGet v3's project.json files produces more ignoreable files
163 | *.nuget.props
164 | *.nuget.targets
165 |
166 | # Microsoft Azure Build Output
167 | csx/
168 | *.build.csdef
169 |
170 | # Microsoft Azure Emulator
171 | ecf/
172 | rcf/
173 |
174 | # Windows Store app package directories and files
175 | AppPackages/
176 | BundleArtifacts/
177 | Package.StoreAssociation.xml
178 | _pkginfo.txt
179 |
180 | # Visual Studio cache files
181 | # files ending in .cache can be ignored
182 | *.[Cc]ache
183 | # but keep track of directories ending in .cache
184 | !*.[Cc]ache/
185 |
186 | # Others
187 | ClientBin/
188 | ~$*
189 | *~
190 | *.dbmdl
191 | *.dbproj.schemaview
192 | *.jfm
193 | *.pfx
194 | *.publishsettings
195 | node_modules/
196 | orleans.codegen.cs
197 |
198 | # Since there are multiple workflows, uncomment next line to ignore bower_components
199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
200 | #bower_components/
201 |
202 | # RIA/Silverlight projects
203 | Generated_Code/
204 |
205 | # Backup & report files from converting an old project file
206 | # to a newer Visual Studio version. Backup files are not needed,
207 | # because we have git ;-)
208 | _UpgradeReport_Files/
209 | Backup*/
210 | UpgradeLog*.XML
211 | UpgradeLog*.htm
212 |
213 | # SQL Server files
214 | *.mdf
215 | *.ldf
216 |
217 | # Business Intelligence projects
218 | *.rdl.data
219 | *.bim.layout
220 | *.bim_*.settings
221 |
222 | # Microsoft Fakes
223 | FakesAssemblies/
224 |
225 | # GhostDoc plugin setting file
226 | *.GhostDoc.xml
227 |
228 | # Node.js Tools for Visual Studio
229 | .ntvs_analysis.dat
230 |
231 | # Visual Studio 6 build log
232 | *.plg
233 |
234 | # Visual Studio 6 workspace options file
235 | *.opt
236 |
237 | # Visual Studio LightSwitch build output
238 | **/*.HTMLClient/GeneratedArtifacts
239 | **/*.DesktopClient/GeneratedArtifacts
240 | **/*.DesktopClient/ModelManifest.xml
241 | **/*.Server/GeneratedArtifacts
242 | **/*.Server/ModelManifest.xml
243 | _Pvt_Extensions
244 |
245 | # Paket dependency manager
246 | .paket/paket.exe
247 | paket-files/
248 |
249 | # FAKE - F# Make
250 | .fake/
251 |
252 | # JetBrains Rider
253 | .idea/
254 | *.sln.iml
255 |
256 | # CodeRush
257 | .cr/
258 |
259 | # Python Tools for Visual Studio (PTVS)
260 | __pycache__/
261 | *.pyc
262 | /src/DPB.Tests/OutputDir
263 | /BuildOutPut
264 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DPB: Dynamic Project Builder
2 |
3 | DPB is a tool that allows developers to automatically generate project code.
4 |
5 | You can add annotations to the code templates, and use DPB to automatically filter or generate code to build a complete new project.
6 |
7 | DPB support for all files and all languages.
8 |
9 | ## Why I need DPB
10 |
11 | We always build new customized projects and template projects. When new project requirements come, we have to copy the whole project files and do a lot of washing jobs: remove the files, change the key contents, modify configuration values and so on.
12 |
13 | Also when we published an open source project, we always support Demo / Sample and Documents. But it's really not every developer wants to read all of the code and sample project and documents.
14 |
15 | With DPB, you just need to put same marks into your code, such as `DPBMARK Keep` and 'DPBMARK_END', or configure a profile, then run DPB, it will build a new clearn-project into the Output Directory, just keep the code and files you want.
16 |
17 | ## How to use
18 |
19 | ### Method 1: Build App by your own
20 |
21 | 1. Install the DPB from Nuget into your project(or compile the source code): https://www.nuget.org/packages/DPB/
22 |
23 | > Both your working prject or a new project are OK.
24 |
25 | 2. Create a new class, such as BuildProject.cs
26 |
27 | 3. Create a method such as Build() in to BuildBProject
28 |
29 | 4. Create a manifest entity, and set the SourceDir(your template peojrct_ and OutputDir:
30 |
31 | ``` C#
32 |
33 | using DPB.Models;
34 |
35 | namespace DPB.Tests
36 | {
37 | public class BuildProject
38 | {
39 | public void Build()
40 | {
41 | Manifest manifest = new Manifest();
42 | manifest.SourceDir = "..\\..\\SourceDir";//or absolute address: e:\ThisProject\src
43 | manifest.OutputDir = "..\\..\\OutputDir";//or absolute address: e:\ThisProject\Output
44 | }
45 | }
46 | }
47 |
48 | ```
49 |
50 | 5. set the rules, such as :
51 |
52 | #### Remove content block
53 |
54 | ``` C#
55 | //keep content Condition - while all the code blocks in *.cs files with keywrod mark: DPBMARK MP
56 | manifest.ConfigGroup.Add(new GroupConfig()
57 | {
58 | Files = new List() { "*.cs" },
59 | KeepContentConiditions = new List() { "MP" }
60 | });
61 |
62 | ```
63 |
64 | it will keep the code in your source project with the certain code block:
65 |
66 | ``` C#
67 | //DPBMARK MP
68 | var tip = "this line will stay here in OutputDir while Conditions have MP keyword.";
69 | //DPBMARK_END
70 | ```
71 | When another code block with `DPBMARK OTHER` instead of `DPBMARK MP` in the file region, the block will be removed.
72 |
73 | You can also set multiple `KeepContentConiditions` keywords to keep the code stay in new project.
74 |
75 | The code (or any text file content) with out `DPBMARK` mark bolck will always keep in new project.
76 |
77 | #### Delete whole file
78 |
79 | If you want to remove a file, just Add the following code into the file in any where:
80 |
81 | > DPBMARK_FILE RemoveFile
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/src/DPB.Tests/BuildProject.cs:
--------------------------------------------------------------------------------
1 | using DPB.Models;
2 |
3 | namespace DPB.Tests
4 | {
5 | public class BuildProject
6 | {
7 | public void Build()
8 | {
9 | var sourceDir = "..\\..\\SourceDir";//or absolute address: e:\ThisProject\src
10 | var outputDir = "..\\..\\OutputDir";//or absolute address: e:\ThisProject\Output
11 | Manifest manifest = new Manifest(sourceDir,outputDir);
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/DPB.Tests/DPB.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Debug
7 | AnyCPU
8 | {4F412537-ACFE-40BC-A613-0DE0EC24FE9D}
9 | Library
10 | Properties
11 | DPB.Tests
12 | DPB.Tests
13 | v4.8
14 | 512
15 | {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
16 | 15.0
17 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
18 | $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages
19 | False
20 | UnitTest
21 |
22 |
23 |
24 |
25 |
26 | true
27 | full
28 | false
29 | bin\Debug\
30 | DEBUG;TRACE
31 | prompt
32 | 4
33 |
34 |
35 | pdbonly
36 | true
37 | bin\Release\
38 | TRACE
39 | prompt
40 | 4
41 |
42 |
43 |
44 | ..\DPB\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll
45 |
46 |
47 | ..\DPB\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll
48 |
49 |
50 | ..\DPB\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll
51 |
52 |
53 | ..\DPB\packages\Senparc.CO2NET.0.5.2\lib\net45\Senparc.CO2NET.dll
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | Designer
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | {2469ed76-cb41-4117-8dd9-447398fbff92}
105 | DPB
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | 这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/src/DPB.Tests/ManifestTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text.RegularExpressions;
5 | using System.Xml.Linq;
6 | using DPB.Models;
7 | using Microsoft.VisualStudio.TestTools.UnitTesting;
8 | using Senparc.CO2NET.Extensions;
9 | using Senparc.CO2NET.Helpers;
10 |
11 | namespace DPB.Tests
12 | {
13 | [TestClass]
14 | public class ManifestTests
15 | {
16 | [TestMethod]
17 | public void JsonTest()
18 | {
19 | var json = @"{
20 | ""SourceDir"":"""",
21 | ""OutputDir"":"""",
22 | ""Paths"":[{
23 | ""Files"":[],
24 | ""KeepFileConiditions"":[],
25 | ""KeepContentConiditions"":[],
26 | ""ReplaceContents"":[
27 | {""XmlContent"":{""TagName"":"""",""ReplaceContent"":""this is the new content""}}
28 | ]
29 | }]
30 | }";
31 |
32 | //测试配置JSON读取
33 | var dpbManifest = SerializerHelper.GetObject(json);
34 | Console.WriteLine(dpbManifest.ToJson());
35 | }
36 |
37 | [TestMethod]
38 | public void BuildTest()
39 | {
40 | var sourceDir = "..\\..\\SourceDir";//or absolute address: e:\ThisProject\src
41 | var outputDir = "..\\..\\OutputDir";//or absolute address: e:\ThisProject\Output
42 | Manifest manifest = new Manifest(sourceDir, outputDir);
43 |
44 | //keep content Condition - while all the code blocks in *.cs files with keywrod mark: DPBMARK MP
45 | manifest.ConfigGroup.Add(new GroupConfig()
46 | {
47 | Files = new List() { "*.cs" },
48 | OmitChangeFiles = new List() { "*-Keep.cs" },
49 | KeepContentConiditions = new List() { "MP" }
50 | });
51 |
52 | //keep files Condition - Keep
53 | manifest.ConfigGroup.Add(new GroupConfig()
54 | {
55 | Files = new List() { "*.txt" },
56 | KeepFileConiditions = new List() { "Keep" },
57 | //KeepContentConiditions= new List() { "o","k"}
58 | });
59 |
60 | //change certain string content
61 |
62 | manifest.ConfigGroup.Add(new GroupConfig()
63 | {
64 | Files = new List() { "StringReplaceFile.txt", "RegexReplaceFile.txt" },
65 | ReplaceContents = new List() {
66 | new ReplaceContent(){
67 | StringContent=new StringContent(){
68 | String="",
69 | ReplaceContent="[This is new content, replaced by StringContent]"
70 | }
71 | },
72 | new ReplaceContent(){
73 | RegexContent = new RegexContent(){
74 | Pattern = @"\<[^\>]*\>",
75 | ReplaceContent="[This is new content, replaced by ReplaceContent]",
76 | RegexOptions = RegexOptions.IgnoreCase
77 | }
78 | }
79 | }
80 | });
81 |
82 | //change xml nodes' value
83 | var pathConfigXml = new GroupConfig()
84 | {
85 | Files = new List() { "*.xml" }
86 | };
87 | pathConfigXml.ReplaceContents.Add(new ReplaceContent()
88 | {
89 | XmlContent = new XmlContent()
90 | {
91 | TagName = "ProjectName",
92 | ReplaceContent = "This is the new value"
93 | }
94 | });
95 | pathConfigXml.ReplaceContents.Add(new ReplaceContent()
96 | {
97 | XmlContent = new XmlContent()
98 | {
99 | TagName = "Count",
100 | ReplaceContent = "666"
101 | }
102 | });
103 | manifest.ConfigGroup.Add(pathConfigXml);
104 |
105 |
106 | //change jaon nodes' value
107 | var pathConfigJson = new GroupConfig()
108 | {
109 | Files = new List() { "*.json" }
110 | };
111 |
112 | pathConfigJson.ReplaceContents.Add(new ReplaceContent()
113 | {
114 | JsonContent = new JsonContent()
115 | {
116 | KeyName = "version",
117 | ReplaceContent = "6.6.6.6"
118 | }
119 | });
120 | manifest.ConfigGroup.Add(pathConfigJson);
121 |
122 | //remove file
123 | manifest.ConfigGroup.Add(new GroupConfig()
124 | {
125 | Files = new List() { "FileRemove*.txt" },
126 | OmitChangeFiles = new List() { "FileRemoveOmit.txt" },
127 | RemoveFiles = true
128 | });
129 |
130 | //remove directories
131 | manifest.ConfigGroup.Add(new GroupConfig()
132 | {
133 | RemoveDictionaries = new List() {
134 | "ChildrenDirectoriesWillBeRemoved\\Remove1",
135 | "ChildrenDirectoriesWillBeRemoved\\Remove2"
136 | }
137 | });
138 |
139 | //.net core file test
140 | manifest.ConfigGroup.Add(new GroupConfig()
141 | {
142 | Files = new List() { "Startup.cs.txt" },
143 | KeepContentConiditions = new List() { "MP", "Redis" }
144 | });
145 |
146 | //custom functions
147 | manifest.ConfigGroup.Add(new GroupConfig()
148 | {
149 | Files = new List() { "CustomFunctionFile1.txt" },
150 | CustomFunc = (fileName, fileContent) => fileContent.ToUpper() + $"{Environment.NewLine}FileName:{fileName} - {DateTime.Now}"// all letters ToUpper(), or do anythiny you like
151 | });
152 |
153 | manifest.ConfigGroup.Add(new GroupConfig()
154 | {
155 | Files = new List() { "CustomFunctionFile2-net45-csproj.xml" },
156 | KeepContentConiditions = new List() { "MP", "Redis" },
157 | CustomFunc = (fileName, fileContent) =>
158 | {
159 | XDocument d = XDocument.Parse(fileContent);
160 | XNamespace dc = d.Root.Name.Namespace;
161 | var xmlNamespace = dc.ToString();
162 |
163 | d.Root.Elements(dc + "ItemGroup").ToList()
164 | .ForEach(z => z.Elements(dc + "ProjectReference")
165 | .Where(el => !el.ToString().Contains("CommonService"))
166 | .Remove());
167 |
168 | //add each nuget packages
169 | var newItemGroup = new XElement(dc + "ItemGroup");
170 | d.Root.Add(newItemGroup);
171 |
172 | var newElement = new XElement(dc + "PackageReference");
173 | newElement.Add(new XAttribute("Include", "NEW_PACKAGE"));
174 | newElement.Add(new XAttribute("Version", "NEW_PACKAGE_VERSION"));
175 | newItemGroup.Add(newElement);
176 | return d.ToString();
177 | }
178 | });
179 |
180 | manifest.ConfigGroup.Add(new GroupConfig()
181 | {
182 | Files = new List() { "KeepPartsOfContent.txt" },
183 | KeepFileConiditions = new List() { "KeepPartsOfContent" },
184 | KeepContentConiditions = new List() { "KeepPartsOfContent" },
185 | });
186 |
187 | LetsGo letsGo = new LetsGo(manifest);
188 | letsGo.Build();
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/src/DPB.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyTitle("DPB.Tests")]
6 | [assembly: AssemblyDescription("")]
7 | [assembly: AssemblyConfiguration("")]
8 | [assembly: AssemblyCompany("")]
9 | [assembly: AssemblyProduct("DPB.Tests")]
10 | [assembly: AssemblyCopyright("Copyright © 2018")]
11 | [assembly: AssemblyTrademark("")]
12 | [assembly: AssemblyCulture("")]
13 |
14 | [assembly: ComVisible(false)]
15 |
16 | [assembly: Guid("4f412537-acfe-40bc-a613-0de0ec24fe9d")]
17 |
18 | // [assembly: AssemblyVersion("1.0.*")]
19 | [assembly: AssemblyVersion("1.0.0.0")]
20 | [assembly: AssemblyFileVersion("1.0.0.0")]
21 |
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/ChildrenDirectoriesWillBeRemoved/NotRemove/TextFile1.txt:
--------------------------------------------------------------------------------
1 | normal file, not remove
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/ChildrenDirectoriesWillBeRemoved/NotRemove/TextFile2.txt:
--------------------------------------------------------------------------------
1 | normal file, not remove
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/ChildrenDirectoriesWillBeRemoved/Remove1/TextFile1.txt:
--------------------------------------------------------------------------------
1 | whatever this file is , it will be deleted when parent directory removed.
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/ChildrenDirectoriesWillBeRemoved/Remove1/TextFile2.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/ChildrenDirectoriesWillBeRemoved/Remove2/TextFile1.txt:
--------------------------------------------------------------------------------
1 | whatever this file is , it will be deleted when parent directory removed.
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/ChildrenDirectoriesWillBeRemoved/Remove2/TextFile2.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/CustomFunctionFiles/CustomFunctionFile1.txt:
--------------------------------------------------------------------------------
1 | This is the Custom Function test file. All the mosquitoes here will be capitalized.
2 |
3 | Even there are multiple lines.
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/CustomFunctionFiles/CustomFunctionFile2-net45-csproj.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 |
8 |
9 | 2.0
10 | {9A4E286B-FE2C-4985-AFBC-FA1A598F97C1}
11 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
12 | Library
13 | Properties
14 | Senparc.Weixin.MP.Sample
15 | Senparc.Weixin.MP.Sample
16 | v4.5
17 | false
18 | true
19 | 65335
20 | enabled
21 | disabled
22 | false
23 | true
24 |
25 |
26 |
27 |
28 | 4.0
29 |
30 |
31 | ..\packages\WebGrease.1.5.2\lib
32 |
33 |
34 |
35 | true
36 | full
37 | false
38 | bin\
39 | TRACE;DEBUG;NET45
40 | prompt
41 | 4
42 | false
43 |
44 |
45 | pdbonly
46 | true
47 | bin\
48 | TRACE;NET45
49 | prompt
50 | 4
51 | false
52 |
53 |
54 |
55 | ..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll
56 |
57 |
58 | ..\packages\BinaryFormatter.2.1.4\lib\netstandard1.1\BinaryFormatter.dll
59 |
60 |
61 | ..\packages\elmah.corelibrary.1.2.2\lib\Elmah.dll
62 |
63 |
64 | ..\packages\Membase.2.14\lib\net35\Enyim.Caching.dll
65 |
66 |
67 | ..\packages\Enyim.Caching.Web.1.0.0.1\lib\net40\Enyim.Caching.Web.dll
68 |
69 |
70 | ..\packages\Membase.2.14\lib\net35\Membase.dll
71 |
72 |
73 |
74 | ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll
75 | True
76 |
77 |
78 | ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll
79 |
80 |
81 | ..\packages\Owin.1.0\lib\net40\Owin.dll
82 | True
83 |
84 |
85 | ..\packages\Senparc.CO2NET.0.3.0.2\lib\net45\Senparc.CO2NET.dll
86 |
87 |
88 | ..\packages\Senparc.CO2NET.APM.0.1.3.2\lib\net45\Senparc.CO2NET.APM.dll
89 |
90 |
91 | ..\packages\Senparc.CO2NET.Cache.Memcached.3.1.4.2\lib\net45\Senparc.CO2NET.Cache.Memcached.dll
92 |
93 |
94 | ..\packages\Senparc.CO2NET.Cache.Redis.3.2.1.2\lib\net45\Senparc.CO2NET.Cache.Redis.dll
95 |
96 |
97 | ..\packages\Senparc.CO2NET.Cache.Redis.RedLock.1.1.0.2\lib\net45\Senparc.CO2NET.Cache.Redis.RedLock.dll
98 |
99 |
100 | ..\packages\Senparc.NeuChar.0.4.4.3\lib\net45\Senparc.NeuChar.dll
101 |
102 |
103 | ..\packages\StackExchange.Redis.1.2.6\lib\net45\StackExchange.Redis.dll
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.6\lib\net45\System.Net.Http.Formatting.dll
114 |
115 |
116 |
117 | ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | ..\packages\Microsoft.AspNet.WebPages.3.2.6\lib\net45\System.Web.Helpers.dll
129 |
130 |
131 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.6\lib\net45\System.Web.Http.dll
132 |
133 |
134 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.6\lib\net45\System.Web.Http.WebHost.dll
135 |
136 |
137 | ..\packages\Microsoft.AspNet.Mvc.5.2.6\lib\net45\System.Web.Mvc.dll
138 |
139 |
140 | ..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll
141 |
142 |
143 | ..\packages\Microsoft.AspNet.Razor.3.2.6\lib\net45\System.Web.Razor.dll
144 |
145 |
146 |
147 |
148 | ..\packages\Microsoft.AspNet.WebPages.3.2.6\lib\net45\System.Web.WebPages.dll
149 |
150 |
151 | ..\packages\Microsoft.AspNet.WebPages.3.2.6\lib\net45\System.Web.WebPages.Deployment.dll
152 |
153 |
154 | ..\packages\Microsoft.AspNet.WebPages.3.2.6\lib\net45\System.Web.WebPages.Razor.dll
155 |
156 |
157 |
158 |
159 | ..\packages\EntityFramework.5.0.0\lib\net40\EntityFramework.dll
160 |
161 |
162 | True
163 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll
164 |
165 |
166 | True
167 | ..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.dll
168 |
169 |
170 | True
171 | ..\packages\Microsoft.Net.Http.2.0.20710.0\lib\net40\System.Net.Http.WebRequest.dll
172 |
173 |
174 | ..\packages\Microsoft.AspNet.Providers.Core.1.1\lib\net40\System.Web.Providers.dll
175 |
176 |
177 |
178 | ..\packages\WebGrease.1.5.2\lib\WebGrease.dll
179 |
180 |
181 | ..\packages\ZXing.Net.0.16.2\lib\net45\zxing.dll
182 |
183 |
184 | ..\packages\ZXing.Net.0.16.2\lib\net45\zxing.presentation.dll
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 | Code
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 | Global.asax
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 | Designer
337 |
338 |
339 | Web.config
340 |
341 |
342 | Web.config
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 | Designer
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 | Designer
411 |
412 |
413 |
414 |
415 | {b745f5f5-9120-4d56-a86d-ed34eadb703c}
416 | Senparc.WebSocket
417 |
418 |
419 | {5b729497-5323-41d7-a104-0632119bedde}
420 | Senparc.Weixin.Cache.Memcached
421 |
422 |
423 | {51ac27b4-11ae-4f59-b82a-0bb3afa5f62b}
424 | Senparc.Weixin.Cache.Redis
425 |
426 |
427 | {ee8630bc-6191-4c40-9061-12c76342562d}
428 | Senparc.Weixin.MP.MvcExtension
429 |
430 |
431 | {1d815fbf-451c-4e23-939c-cb80172f445c}
432 | Senparc.Weixin.MP
433 |
434 |
435 | {54732c3d-b673-4bbf-b0c3-6432e3d6f522}
436 | Senparc.Weixin.Open
437 |
438 |
439 | {defc9e7a-f6f0-4e97-ac11-30cf0e6a875c}
440 | Senparc.Weixin.TenPay
441 |
442 |
443 | {cc0ebec4-7120-4627-a596-c1f2958f3d5e}
444 | Senparc.Weixin.Work
445 |
446 |
447 | {379d8c97-4f96-45af-9f91-6bd160514495}
448 | Senparc.Weixin.WxOpen
449 |
450 |
451 | {814092cd-9cd0-4fb7-91e8-d147f476f1fb}
452 | Senparc.Weixin
453 |
454 |
455 | {ccd291e9-16fa-4b53-b032-ebd3f659567b}
456 | Senparc.Weixin.MP.Sample.CommonService
457 |
458 |
459 |
460 |
461 |
462 |
463 | 10.0
464 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
465 |
466 |
467 | true
468 | bin\
469 | DEBUG;TRACE
470 | full
471 | x86
472 | prompt
473 | MinimumRecommendedRules.ruleset
474 |
475 |
476 | bin\
477 | TRACE
478 | true
479 | pdbonly
480 | x86
481 | prompt
482 | MinimumRecommendedRules.ruleset
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 | True
495 | True
496 | 61637
497 | /
498 | http://localhost:65395/
499 | False
500 | False
501 |
502 |
503 | False
504 |
505 |
506 |
507 |
508 |
514 |
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/EmptyDirectoryToBeRemoved/FileRemove1.txt:
--------------------------------------------------------------------------------
1 | This file will be removed and the parent directory will be removed when it's empty.
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/EmptyDirectoryToBeRemoved/FileRemove2.txt:
--------------------------------------------------------------------------------
1 | This file will be removed and the parent directory will be removed when it's empty.
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/JsonFiles/jsconfig1.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "not change",
3 | "otherkey": "stay",
4 | "inner": {
5 | "inner2": {
6 | "version": "not change",
7 | "anotherkey": "still stay"
8 | }
9 | }
10 | }
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/KeepPartsOfContent/KeepPartsOfContent.txt:
--------------------------------------------------------------------------------
1 | // DPBMARK_FILE KeepPartsOfContent
2 |
3 | //DPBMARK KeepPartsOfContent
4 | This line will be kept.
5 | //DPBMARK_END
6 |
7 | This line will be kept because has a right Mark. // DPBMARK KeepPartsOfContent DPBMARK_END
8 |
9 | This line will not be kept even content contains the KEYWORK of 'KeepPartsOfContent'. // DPBMARK AnyOther DPBMARK_END
10 |
11 |
12 | //DPBMARK AnyOther
13 | This line will be removed.
14 | //DPBMARK_END
15 |
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/RemoveFiles/KeepFile.txt:
--------------------------------------------------------------------------------
1 | DPBMARK_FILE Keep
2 | Even above line is not existing, this file will keep.
3 |
4 | This line will be kept.
5 |
6 | //DPBMARK AnyOther
7 | This line will not be removed while KeepContentConiditions doesn't defined.
8 | //DPBMARK_END
9 |
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/RemoveFiles/NormalFile.txt:
--------------------------------------------------------------------------------
1 | This is a normal file without any DPB mark.
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/RemoveFiles/RemoveFile1.txt:
--------------------------------------------------------------------------------
1 | /*DPBMARK_FILE RemoveFile1*/
2 | this is the content
3 | line3
4 | line4
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/RemoveFiles/RemoveFile2.txt:
--------------------------------------------------------------------------------
1 | DPBMARK_FILE RemoveFile2
2 | this is the content
3 | line3
4 | line4
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/Startup.cs.txt:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.AspNetCore.Http;
4 | using Microsoft.Extensions.Configuration;
5 | using Microsoft.Extensions.DependencyInjection;
6 | using Microsoft.Extensions.Options;
7 | using Senparc.CO2NET;
8 | using Senparc.CO2NET.Cache;
9 | using Senparc.CO2NET.Cache.Memcached;
10 | using Senparc.CO2NET.Cache.Redis;
11 | using Senparc.CO2NET.RegisterServices;
12 | using Senparc.Weixin.Cache.Memcached;
13 | using Senparc.Weixin.Cache.Redis;
14 | using Senparc.Weixin.Entities;
15 | using Senparc.Weixin.MP.Sample.CommonService.Utilities;
16 | using Senparc.Weixin.Open;
17 | using Senparc.Weixin.Open.ComponentAPIs;
18 | using Senparc.Weixin.RegisterServices;
19 | using Senparc.Weixin.TenPay;
20 | using Senparc.Weixin.Work;
21 | using Senparc.Weixin.WxOpen;
22 | using System.IO;
23 |
24 | namespace Senparc.Weixin.MP.CoreSample
25 | {
26 | public class Startup
27 | {
28 | public Startup(IConfiguration configuration)
29 | {
30 | Configuration = configuration;
31 | }
32 |
33 | public IConfiguration Configuration { get; }
34 |
35 | // This method gets called by the runtime. Use this method to add services to the container.
36 | public void ConfigureServices(IServiceCollection services)
37 | {
38 | services.AddMvc();
39 |
40 | services.AddSingleton();
41 | services.AddMemoryCache();//使用本地缓存必须添加
42 | services.AddSession();//使用Session
43 |
44 | /*
45 | * CO2NET 是从 Senparc.Weixin 分离的底层公共基础模块,经过了长达 6 年的迭代优化,稳定可靠。
46 | * 关于 CO2NET 在所有项目中的通用设置可参考 CO2NET 的 Sample:
47 | * https://github.com/Senparc/Senparc.CO2NET/blob/master/Sample/Senparc.CO2NET.Sample.netcore/Startup.cs
48 | */
49 |
50 | services.AddSenparcGlobalServices(Configuration)//Senparc.CO2NET 全局注册
51 | .AddSenparcWeixinServices(Configuration);//Senparc.Weixin 注册
52 | }
53 |
54 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
55 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, IOptions senparcSetting, IOptions senparcWeixinSetting)
56 | {
57 | //引入EnableRequestRewind中间件
58 | app.UseEnableRequestRewind();
59 | app.UseSession();
60 |
61 | if (env.IsDevelopment())
62 | {
63 | app.UseDeveloperExceptionPage();
64 | app.UseBrowserLink();
65 | }
66 | else
67 | {
68 | app.UseExceptionHandler("/Home/Error");
69 | }
70 |
71 | app.UseStaticFiles();
72 |
73 | app.UseMvc(routes =>
74 | {
75 | routes.MapRoute(
76 | name: "default",
77 | template: "{controller=Home}/{action=Index}/{id?}");
78 | });
79 |
80 |
81 | #region 提供网站根目录(当前 Sample 用到,和 SDK 无关)
82 | if (env.ContentRootPath != null)
83 | {
84 | Senparc.Weixin.MP.Sample.CommonService.Utilities.Server.AppDomainAppPath = env.ContentRootPath;// env.ContentRootPath;
85 | }
86 | Senparc.Weixin.MP.Sample.CommonService.Utilities.Server.WebRootPath = env.WebRootPath;// env.ContentRootPath;
87 | #endregion
88 |
89 | // 启动 CO2NET 全局注册,必须!
90 | IRegisterService register = RegisterService.Start(env, senparcSetting.Value)
91 | //关于 UseSenparcGlobal() 的更多用法见 CO2NET Demo:https://github.com/Senparc/Senparc.CO2NET/blob/master/Sample/Senparc.CO2NET.Sample.netcore/Startup.cs
92 | .UseSenparcGlobal();
93 |
94 | //如果需要自动扫描自定义扩展缓存,可以这样使用:
95 | //register.UseSenparcGlobal(true);
96 | //如果需要指定自定义扩展缓存,可以这样用:
97 | //register.UseSenparcGlobal(false, GetExCacheStrategies);
98 |
99 | #region CO2NET 全局配置
100 |
101 | #region 全局缓存配置(按需)
102 |
103 | //当同一个分布式缓存同时服务于多个网站(应用程序池)时,可以使用命名空间将其隔离(非必须)
104 | register.ChangeDefaultCacheNamespace("DefaultCO2NETCache");
105 |
106 | #region 配置和使用 Redis -- DPBMARK Redis
107 |
108 | //配置全局使用Redis缓存(按需,独立)
109 | var redisConfigurationStr = senparcSetting.Value.Cache_Redis_Configuration;
110 | var useRedis = !string.IsNullOrEmpty(redisConfigurationStr) && redisConfigurationStr != "Redis配置";
111 | if (useRedis)//这里为了方便不同环境的开发者进行配置,做成了判断的方式,实际开发环境一般是确定的,这里的if条件可以忽略
112 | {
113 | /* 说明:
114 | * 1、Redis 的连接字符串信息会从 Config.SenparcSetting.Cache_Redis_Configuration 自动获取并注册,如不需要修改,下方方法可以忽略
115 | /* 2、如需手动修改,可以通过下方 SetConfigurationOption 方法手动设置 Redis 链接信息(仅修改配置,不立即启用)
116 | */
117 | Senparc.CO2NET.Cache.Redis.Register.SetConfigurationOption(redisConfigurationStr);
118 |
119 | //以下会立即将全局缓存设置为 Redis
120 | Senparc.CO2NET.Cache.Redis.Register.UseKeyValueRedisNow();//键值对缓存策略(推荐)
121 | //Senparc.CO2NET.Cache.Redis.Register.UseHashRedisNow();//HashSet储存格式的缓存策略
122 |
123 | //也可以通过以下方式自定义当前需要启用的缓存策略
124 | //CacheStrategyFactory.RegisterObjectCacheStrategy(() => RedisObjectCacheStrategy.Instance);//键值对
125 | //CacheStrategyFactory.RegisterObjectCacheStrategy(() => RedisHashSetObjectCacheStrategy.Instance);//HashSet
126 | }
127 | //如果这里不进行Redis缓存启用,则目前还是默认使用内存缓存
128 |
129 | #endregion // DPBMARK_END
130 |
131 | #region 配置和使用 Memcached -- DPBMARK Memcached
132 |
133 | //配置Memcached缓存(按需,独立)
134 | var memcachedConfigurationStr = senparcSetting.Value.Cache_Memcached_Configuration;
135 | var useMemcached = !string.IsNullOrEmpty(memcachedConfigurationStr) && memcachedConfigurationStr != "Memcached配置";
136 |
137 | if (useMemcached) //这里为了方便不同环境的开发者进行配置,做成了判断的方式,实际开发环境一般是确定的,这里的if条件可以忽略
138 | {
139 | app.UseEnyimMemcached();
140 |
141 | /* 说明:
142 | * 1、Memcached 的连接字符串信息会从 Config.SenparcSetting.Cache_Memcached_Configuration 自动获取并注册,如不需要修改,下方方法可以忽略
143 | /* 2、如需手动修改,可以通过下方 SetConfigurationOption 方法手动设置 Memcached 链接信息(仅修改配置,不立即启用)
144 | */
145 | Senparc.CO2NET.Cache.Memcached.Register.SetConfigurationOption(memcachedConfigurationStr);
146 |
147 | //以下会立即将全局缓存设置为 Memcached
148 | Senparc.CO2NET.Cache.Memcached.Register.UseMemcachedNow();
149 |
150 | //也可以通过以下方式自定义当前需要启用的缓存策略
151 | CacheStrategyFactory.RegisterObjectCacheStrategy(() => MemcachedObjectCacheStrategy.Instance);
152 | }
153 |
154 | #endregion // DPBMARK_END
155 |
156 | #endregion
157 |
158 | #region 注册日志(按需,建议)
159 |
160 | register.RegisterTraceLog(ConfigTraceLog);//配置TraceLog
161 |
162 | #endregion
163 |
164 | #endregion
165 |
166 | #region 微信相关配置
167 |
168 |
169 | /* 微信配置开始
170 | *
171 | * 建议按照以下顺序进行注册,尤其须将缓存放在第一位!
172 | */
173 |
174 | //注册开始
175 |
176 | #region 微信缓存(按需,必须在 register.UseSenparcWeixin() 之前)
177 |
178 | //微信的 Redis 缓存,如果不使用则注释掉(开启前必须保证配置有效,否则会抛错) -- DPBMARK Redis
179 | if (useRedis)
180 | {
181 | app.UseSenparcWeixinCacheRedis();
182 | } // DPBMARK_END
183 |
184 |
185 | // 微信的 Memcached 缓存,如果不使用则注释掉(开启前必须保证配置有效,否则会抛错) -- DPBMARK Memcached
186 | if (useMemcached)
187 | {
188 | app.UseSenparcWeixinCacheMemcached();
189 | } // DPBMARK_END
190 |
191 |
192 | #endregion
193 |
194 |
195 | //开始注册微信信息,必须!
196 | register.UseSenparcWeixin(senparcWeixinSetting.Value, senparcSetting.Value)
197 | //注意:上一行没有 ; 下面可接着写 .RegisterXX()
198 |
199 | #region 注册公众号或小程序(按需)
200 |
201 | //注册公众号(可注册多个) -- DPBMARK MP
202 | .RegisterMpAccount(senparcWeixinSetting.Value, "【盛派网络小助手】公众号")// DPBMARK_END
203 |
204 |
205 | //注册多个公众号或小程序(可注册多个) -- DPBMARK MiniProgram
206 | .RegisterWxOpenAccount(senparcWeixinSetting.Value, "【盛派网络小助手】小程序")// DPBMARK_END
207 |
208 | //除此以外,仍然可以在程序任意地方注册公众号或小程序:
209 | //AccessTokenContainer.Register(appId, appSecret, name);//命名空间:Senparc.Weixin.MP.Containers
210 | #endregion
211 |
212 | #region 注册企业号(按需) -- DPBMARK Work
213 |
214 | //注册企业微信(可注册多个)
215 | .RegisterWorkAccount(senparcWeixinSetting.Value, "【盛派网络】企业微信")
216 |
217 | //除此以外,仍然可以在程序任意地方注册企业微信:
218 | //AccessTokenContainer.Register(corpId, corpSecret, name);//命名空间:Senparc.Weixin.Work.Containers
219 | #endregion // DPBMARK_END
220 |
221 | #region 注册微信支付(按需) -- DPBMARK TenPay
222 |
223 | //注册旧微信支付版本(V2)(可注册多个)
224 | .RegisterTenpayOld(senparcWeixinSetting.Value, "【盛派网络小助手】公众号")//这里的 name 和第一个 RegisterMpAccount() 中的一致,会被记录到同一个 SenparcWeixinSettingItem 对象中
225 |
226 | //注册最新微信支付版本(V3)(可注册多个)
227 | .RegisterTenpayV3(senparcWeixinSetting.Value, "【盛派网络小助手】公众号")//记录到同一个 SenparcWeixinSettingItem 对象中
228 |
229 | #endregion // DPBMARK_END
230 |
231 | #region 注册微信第三方平台(按需) -- DPBMARK Open
232 |
233 | //注册第三方平台(可注册多个)
234 | .RegisterOpenComponent(senparcWeixinSetting.Value,
235 | //getComponentVerifyTicketFunc
236 | componentAppId =>
237 | {
238 | var dir = Path.Combine(Server.GetMapPath("~/App_Data/OpenTicket"));
239 | if (!Directory.Exists(dir))
240 | {
241 | Directory.CreateDirectory(dir);
242 | }
243 |
244 | var file = Path.Combine(dir, string.Format("{0}.txt", componentAppId));
245 | using (var fs = new FileStream(file, FileMode.Open))
246 | {
247 | using (var sr = new StreamReader(fs))
248 | {
249 | var ticket = sr.ReadToEnd();
250 | return ticket;
251 | }
252 | }
253 | },
254 |
255 | //getAuthorizerRefreshTokenFunc
256 | (componentAppId, auhtorizerId) =>
257 | {
258 | var dir = Path.Combine(Server.GetMapPath("~/App_Data/AuthorizerInfo/" + componentAppId));
259 | if (!Directory.Exists(dir))
260 | {
261 | Directory.CreateDirectory(dir);
262 | }
263 |
264 | var file = Path.Combine(dir, string.Format("{0}.bin", auhtorizerId));
265 | if (!File.Exists(file))
266 | {
267 | return null;
268 | }
269 |
270 | using (Stream fs = new FileStream(file, FileMode.Open))
271 | {
272 | var binFormat = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
273 | var result = (RefreshAuthorizerTokenResult)binFormat.Deserialize(fs);
274 | return result.authorizer_refresh_token;
275 | }
276 | },
277 |
278 | //authorizerTokenRefreshedFunc
279 | (componentAppId, auhtorizerId, refreshResult) =>
280 | {
281 | var dir = Path.Combine(Server.GetMapPath("~/App_Data/AuthorizerInfo/" + componentAppId));
282 | if (!Directory.Exists(dir))
283 | {
284 | Directory.CreateDirectory(dir);
285 | }
286 |
287 | var file = Path.Combine(dir, string.Format("{0}.bin", auhtorizerId));
288 | using (Stream fs = new FileStream(file, FileMode.Create))
289 | {
290 | //这里存了整个对象,实际上只存RefreshToken也可以,有了RefreshToken就能刷新到最新的AccessToken
291 | var binFormat = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
292 | binFormat.Serialize(fs, refreshResult);
293 | fs.Flush();
294 | }
295 | }, "【盛派网络】开放平台")
296 |
297 | //除此以外,仍然可以在程序任意地方注册开放平台:
298 | //ComponentContainer.Register();//命名空间:Senparc.Weixin.Open.Containers
299 | #endregion // DPBMARK_END
300 |
301 | ;
302 |
303 | /* 微信配置结束 */
304 |
305 | #endregion
306 | }
307 |
308 |
309 | ///
310 | /// 配置微信跟踪日志
311 | ///
312 | private void ConfigTraceLog()
313 | {
314 | //这里设为Debug状态时,/App_Data/WeixinTraceLog/目录下会生成日志文件记录所有的API请求日志,正式发布版本建议关闭
315 |
316 | //如果全局的IsDebug(Senparc.CO2NET.Config.IsDebug)为false,此处可以单独设置true,否则自动为true
317 | CO2NET.Trace.SenparcTrace.SendCustomLog("系统日志", "系统启动");//只在Senparc.Weixin.Config.IsDebug = true的情况下生效
318 |
319 | //全局自定义日志记录回调
320 | CO2NET.Trace.SenparcTrace.OnLogFunc = () =>
321 | {
322 | //加入每次触发Log后需要执行的代码
323 | };
324 |
325 | //当发生基于WeixinException的异常时触发
326 | WeixinTrace.OnWeixinExceptionFunc = ex =>
327 | {
328 | //加入每次触发WeixinExceptionLog后需要执行的代码
329 |
330 | //发送模板消息给管理员 -- DPBMARK Redis
331 | var eventService = new Senparc.Weixin.MP.Sample.CommonService.EventService();
332 | eventService.ConfigOnWeixinExceptionFunc(ex); // DPBMARK_END
333 | };
334 | }
335 | }
336 | }
337 |
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/StringFiles/RegexReplaceFile.txt:
--------------------------------------------------------------------------------
1 | This file is test for string replace. . This content will be kept.
2 | This file is test for string replace. . This content will be kept.
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/StringFiles/StringReplaceFile.txt:
--------------------------------------------------------------------------------
1 | This file is test for string replace. . This content will be kept.
2 | This file is test for string replace. . This content will be kept.
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/TestManifest-Keep.cs:
--------------------------------------------------------------------------------
1 | //this whole file will be kept (will not change anything)
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DPB.Tests.SourceDir
9 | {
10 | public class TestManifestKeep
11 | {
12 | public TestManifestKeep()
13 | {
14 | //DPBMARK MP
15 | var tip = "this line will stay here in OutputDir while Conditions have MP keyword.";
16 | //DPBMARK_END
17 |
18 | //DPBMARK NotStay
19 | var tip2 = "this line will not stay here in OutputDir while Conditions don't have NotStay keyword.";
20 | //DPBMARK_END
21 |
22 | #region 配置和使用 Memcached -- DPBMARK NotStay
23 | var tip3 = "this line will not stay here in OutputDir while Conditions don't have NotStay keyword.";
24 | #endregion -- DPBMARK_END
25 |
26 | var tip4 = "this line will not stay here in OutputDir while Conditions don't have NotStay keyword.";//DPBMARK NotStay DPBMARK_END
27 |
28 | var tip_stay = "this line will be always stay here.";
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/TestManifest.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DPB.Tests.SourceDir
9 | {
10 | public class TestManifest
11 | {
12 | public TestManifest()
13 | {
14 | //DPBMARK MP
15 | var tip = "this line will stay here in OutputDir while Conditions have MP keyword.";
16 | //DPBMARK_END
17 |
18 | //DPBMARK NotStay
19 | var tip2 = "this line will not stay here in OutputDir while Conditions don't have NotStay keyword.";
20 | //DPBMARK_END
21 |
22 | #region 配置和使用 Memcached -- DPBMARK NotStay
23 | var tip3 = "this line will not stay here in OutputDir while Conditions don't have NotStay keyword.";
24 | #endregion -- DPBMARK_END
25 |
26 | var tip4 = "this line will not stay here in OutputDir while Conditions don't have NotStay keyword.";//DPBMARK NotStay DPBMARK_END
27 |
28 | var tip_stay = "this line will be always stay here.";
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/ThisDirectoryIsNotEmpty/FileRemove.txt:
--------------------------------------------------------------------------------
1 | This file will be removed and the parent directory will not be removed because it's not empty.
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/ThisDirectoryIsNotEmpty/FileRemoveOmit.txt:
--------------------------------------------------------------------------------
1 | This file will not be removed and the parent directory will not be removed because it's not empty.
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/XmlFiles/XMLFile1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Name1
4 | 10
5 |
--------------------------------------------------------------------------------
/src/DPB.Tests/SourceDir/XmlFiles/XMLFile2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Name1
4 | 10
5 |
6 |
7 | Name2
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/DPB.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/DPB/DPB.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net462;netstandard2.0;
5 | 0.6.7
6 | DPB
7 | DPB
8 | true
9 |
10 |
11 | DPB is a tool that allows developers to automatically generate project code.
12 |
13 | You can add annotations to the code templates, and use DPB to automatically filter or generate code to build a complete new project.
14 |
15 | Senparc Copyright © 2004~2019
16 | dynamic,builder,project,build,C#,automation
17 |
18 |
19 | Senparc
20 | Senparc
21 | https://github.com/Senparc/DPB/blob/master/LICENSE
22 | https://github.com/JeffreySu/WeiXinMPSDK
23 | DPB: Dynamic Project Builder
24 |
25 | DPB is a tool that allows developers to automatically generate project code.
26 |
27 | You can add annotations to the code templates, and use DPB to automatically filter or generate code to build a complete new project.
28 | https://github.com/JeffreySu/WeiXinMPSDK
29 | http://sdk.weixin.senparc.com/Images/Logo.jpg
30 |
31 | How to use: https://github.com/Senparc/DPB
32 |
33 | v0.6.0 update memory-cache model
34 | v0.6.6 update for mark filter rules
35 | v0.6.7 fix bug: a line is kept when it contains any DPBMARK keyword in content instead of after DPBMARK.
36 |
37 | https://github.com/JeffreySu/WeiXinMPSDK
38 |
39 |
40 |
41 | ..\..\BuildOutPut
42 | TRACE
43 |
44 |
45 |
46 | ..\..\BuildOutPut\
47 | ..\..\BuildOutPut\net462\DPB.xml
48 |
49 |
50 |
51 | ..\..\BuildOutPut\
52 | ..\..\BuildOutPut\netstandard2.0\DPB.xml
53 |
54 |
55 |
56 |
57 | ..\..\BuildOutPut\
58 | ..\..\BuildOutPut\netcoreapp2.1\DPB.xml
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/src/DPB/DPB.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28010.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DPB", "DPB.csproj", "{2469ED76-CB41-4117-8DD9-447398FBFF92}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DPB.Tests", "..\DPB.Tests\DPB.Tests.csproj", "{4F412537-ACFE-40BC-A613-0DE0EC24FE9D}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {2469ED76-CB41-4117-8DD9-447398FBFF92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {2469ED76-CB41-4117-8DD9-447398FBFF92}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {2469ED76-CB41-4117-8DD9-447398FBFF92}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {2469ED76-CB41-4117-8DD9-447398FBFF92}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {4F412537-ACFE-40BC-A613-0DE0EC24FE9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {4F412537-ACFE-40BC-A613-0DE0EC24FE9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {4F412537-ACFE-40BC-A613-0DE0EC24FE9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {4F412537-ACFE-40BC-A613-0DE0EC24FE9D}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {33309871-BFA8-4060-A083-2BB2DE66C1A2}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/src/DPB/LetsGo.cs:
--------------------------------------------------------------------------------
1 | using DPB.Models;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.IO;
8 | using System.Text.RegularExpressions;
9 | using Senparc.CO2NET.Trace;
10 | using Senparc.CO2NET.Helpers;
11 | using Newtonsoft.Json;
12 | using Senparc.CO2NET.Extensions;
13 | using System.Xml.Linq;
14 | using Newtonsoft.Json.Linq;
15 |
16 | namespace DPB
17 | {
18 | public partial class LetsGo
19 | {
20 | public Manifest Manifest { get; set; }
21 |
22 | const string BEGIN_MARK_PERFIX = "DPBMARK ";
23 | const string END_MARK = "DPBMARK_END";
24 | const string FILE_MARK_PREFIX = "DPBMARK_FILE ";
25 |
26 | private Regex _fileMarkRegex = new Regex($@"{FILE_MARK_PREFIX}(\s)*(?[^\r\n \*,]*)");
27 | private Regex _contentMarkStart = new Regex($@"{BEGIN_MARK_PERFIX}(\s)*(?[^\r\n \*,]*)");
28 |
29 | public List Records { get; set; } = new List();
30 |
31 | private Action _recordAction = null;
32 |
33 | ///
34 | /// files memory Cache
35 | ///
36 | private Dictionary FilesCache = new Dictionary();
37 |
38 | public int AllFilesCount { get; set; }
39 | private int finishedFilesCount;
40 | public int FinishedFilesCount
41 | {
42 | get => finishedFilesCount;
43 | set
44 | {
45 | finishedFilesCount++;
46 | FinishPercentAction?.Invoke(Task.Factory.StartNew(() => AllFilesCount == 0 ? 0 : ((finishedFilesCount / AllFilesCount)) * 100));
47 | }
48 | }
49 |
50 |
51 | ///
52 | /// Find nodes from xml by tag name and relpace with specified value
53 | ///
54 | ///
55 | ///
56 | private void ReplaceXmlElements(XElement parentNode, XmlContent xmlContent)
57 | {
58 | if (parentNode == null)
59 | {
60 | return;
61 | }
62 |
63 | foreach (var item in parentNode.Elements())
64 | {
65 | if (item.Name == xmlContent.TagName)
66 | {
67 | Record($"xml node <{xmlContent.TagName}> changed vale from [{item.Value}] to [{xmlContent.ReplaceContent}]");
68 | item.Value = xmlContent.ReplaceContent;
69 | }
70 | else
71 | {
72 | ReplaceXmlElements(item, xmlContent);
73 | }
74 | }
75 | }
76 |
77 | ///
78 | /// Find nodes from json by key name and relpace with specified value
79 | ///
80 | ///
81 | ///
82 | private void ReplaceJsonNodes(JToken node, JsonContent jsonContent)
83 | {
84 | if (node is JProperty)
85 | {
86 | var key = ((JProperty)node).Name;
87 | if (key == jsonContent.KeyName)
88 | {
89 | Record($"json node <{jsonContent.KeyName}> changed vale from [{((JProperty)node).Value}] to [{jsonContent.ReplaceContent}]");
90 | ((JProperty)node).Value = jsonContent.ReplaceContent;
91 | }
92 |
93 | }
94 |
95 | if (node.Children().Count() > 0)
96 | {
97 | for (int i = 0; i < node.Children().Count(); i++)
98 | {
99 | ReplaceJsonNodes(node.Children().Skip(i).Take(1).First(), jsonContent);
100 | }
101 | }
102 | }
103 |
104 |
105 | /////
106 | ///// Copy all files in the sourceDir to outputDir
107 | /////
108 | /////
109 | /////
110 | //public void CopyDirectory(string sourceDir, string outputDir)
111 | //{
112 | // try
113 | // {
114 | // DirectoryInfo dir = new DirectoryInfo(sourceDir);
115 | // FileSystemInfo[] fileinfoArr = dir.GetFileSystemInfos();
116 |
117 | // Parallel.ForEach(fileinfoArr, /*new ParallelOptions() { MaxDegreeOfParallelism = 30 },*/ fileInfo =>
118 | // {
119 | // try
120 | // {
121 | // if (fileInfo is DirectoryInfo)
122 | // {
123 | // if (!Directory.Exists(Path.Combine(outputDir, fileInfo.Name)))
124 | // {
125 | // Directory.CreateDirectory(Path.Combine(outputDir, fileInfo.Name));
126 | // }
127 | // CopyDirectory(fileInfo.FullName, Path.Combine(outputDir, fileInfo.Name));
128 | // }
129 | // else
130 | // {
131 | // var newFile = Path.Combine(outputDir, fileInfo.Name);
132 | // File.Copy(fileInfo.FullName, newFile, true);
133 | // Record($"file copy from {fileInfo.FullName} to {newFile}");
134 | // }
135 | // }
136 | // catch (Exception)
137 | // {
138 |
139 | // }
140 |
141 |
142 | // });
143 |
144 | // //foreach (FileSystemInfo fileInfo in fileinfoArr)
145 | // //{
146 |
147 | // //}
148 | // }
149 | // catch (Exception ex)
150 | // {
151 | // Record($"file copy error: {ex}");
152 | // }
153 | //}
154 |
155 |
156 | ///
157 | /// Copy all files in the sourceDir to outputDir to memory
158 | ///
159 | ///
160 | ///
161 | public void ScanFile(string sourceDir, string outputDir)
162 | {
163 | try
164 | {
165 | DirectoryInfo dir = new DirectoryInfo(sourceDir);
166 | FileSystemInfo[] fileinfoArr = dir.GetFileSystemInfos();
167 |
168 | foreach (var fileInfo in fileinfoArr)
169 | {
170 | try
171 | {
172 | //Record($"[in memory] scan file {fileInfo.FullName}");
173 | if (fileInfo is DirectoryInfo)
174 | {
175 | ScanFile(fileInfo.FullName, Path.Combine(outputDir, fileInfo.Name));
176 | }
177 | else
178 | {
179 | var newFile = Path.Combine(outputDir, fileInfo.Name);
180 | FilesCache[fileInfo.FullName] = new FileWrap()
181 | {
182 | SourceFilePath = fileInfo.FullName,
183 | DestFilePath = newFile,
184 | };
185 |
186 | Record($"[in memory] file add from {fileInfo.FullName}");
187 | }
188 | }
189 | catch (Exception ex)
190 | {
191 | Record($@"[in memory] file add error {ex.Message}
192 | {ex.StackTrace}");
193 | }
194 | };
195 |
196 | //foreach (FileSystemInfo fileInfo in fileinfoArr)
197 | //{
198 |
199 | //}
200 | }
201 | catch (Exception ex)
202 | {
203 | Record($"file copy error: {ex}");
204 | }
205 | }
206 |
207 | ///
208 | /// Record logs
209 | ///
210 | ///
211 | private void Record(string message)
212 | {
213 | Records.Add($"{DateTime.Now.ToString()}\t{message}");
214 | _recordAction?.Invoke(message);
215 | Console.WriteLine(message);
216 | }
217 |
218 | ///
219 | /// LetsGo
220 | ///
221 | /// manifest entity
222 | /// run after each record
223 | public LetsGo(Manifest manifest, Action recordAction = null)
224 | {
225 | Manifest = manifest;
226 | _recordAction = recordAction;
227 | }
228 |
229 | ///
230 | /// LetsGo
231 | ///
232 | /// manifest json file
233 | public LetsGo(string manifestJson)
234 | {
235 | Manifest = SerializerHelper.GetObject(manifestJson);
236 | }
237 |
238 | ///
239 | /// How much percent finished
240 | ///
241 | public Action> FinishPercentAction = null;
242 |
243 |
244 | ///
245 | /// Build a new project from source
246 | ///
247 | ///
248 | public void Build(bool cleanOutputDir = true)
249 | {
250 | var startTime = DateTime.Now;
251 | try
252 | {
253 |
254 | Records.Clear();
255 | Record($"---- DBP Build begin at {startTime.ToString()} ----");
256 |
257 | //var fullSourceRoot = Path.Combine(Directory.GetCurrentDirectory(), Manifest.SourceDir);
258 | //var fullOutputRoot = Path.Combine(Directory.GetCurrentDirectory(), Manifest.OutputDir);
259 |
260 | if (cleanOutputDir)
261 | {
262 | try
263 | {
264 | if (Directory.Exists(Manifest.AbsoluteOutputDir))
265 | {
266 | Directory.Delete(Manifest.AbsoluteOutputDir, true);
267 | }
268 | }
269 | catch (Exception ex)
270 | {
271 | SenparcTrace.BaseExceptionLog(ex);
272 | }
273 | }
274 |
275 | if (!Directory.Exists(Manifest.AbsoluteOutputDir))
276 | {
277 | Directory.CreateDirectory(Manifest.AbsoluteOutputDir);
278 | }
279 |
280 | //Scan and save all file path to memory
281 | Record($"===== start scan all files =====");
282 | ScanFile(Manifest.AbsoluteSourceDir, Manifest.AbsoluteOutputDir);
283 | Record($"---- end sacn all files ----");
284 | Record($"---- {(DateTime.Now - startTime).TotalSeconds} seconds ----");
285 |
286 | int groupIndex = 0;
287 |
288 | //var filesGroup = new List>();
289 | //foreach (var configGroup in Manifest.ConfigGroup)
290 | //{
291 | // var omitFiles = configGroup.OmitFiles.SelectMany(f => Directory.GetFiles(Manifest.AbsoluteOutputDir, f, SearchOption.AllDirectories)).ToList();
292 | // var files = configGroup.Files.SelectMany(f => Directory.GetFiles(Manifest.AbsoluteOutputDir, f, SearchOption.AllDirectories))
293 | // .Where(f => !omitFiles.Contains(f)).ToList();
294 | // filesGroup.Add(files);
295 | // AllFilesCount += files.Count;
296 | //}
297 |
298 | AllFilesCount = Manifest.ConfigGroup.Sum(z => z.Files.Count());
299 |
300 | foreach (var configGroup in Manifest.ConfigGroup)
301 | {
302 | groupIndex++;
303 |
304 | Record($"config group: {groupIndex}");
305 |
306 | //select files my file condition (or search pattern)
307 | Func> searchFileFunc = (fileCondition) =>
308 | {
309 | string fileNamePattern = null;
310 | var exactMatchFileName = false;
311 | if (fileCondition != null)
312 | {
313 | if (fileCondition.Contains("*"))
314 | {
315 | fileNamePattern = $"({fileCondition.Replace("*", ".*")})";
316 |
317 | if (fileCondition.Last() != '*')
318 | {
319 | fileNamePattern += "$";//the file name ends by fileCondition
320 | }
321 |
322 | if (fileCondition.First() != '*')
323 | {
324 | fileNamePattern = "^" + fileNamePattern;//the file name starts by fileCondition
325 | }
326 | }
327 | else
328 | {
329 | fileNamePattern = fileCondition;
330 | exactMatchFileName = true;//not wildcard character, exact match file name
331 | }
332 | }
333 |
334 | var result = FilesCache.Keys.Where(z =>
335 | exactMatchFileName
336 | ? ((fileCondition.Contains("/") || fileCondition.Contains("\\"))
337 | ? z.EndsWith(fileCondition) // contains path charter
338 | : z.Split(new[] { '/', '\\' }).Last() == fileCondition) // whole file name without path charter
339 | : (fileNamePattern == null
340 | ? true // no fileNamePattern supported, all files allow
341 | : Regex.IsMatch(z.Split(new[] { '/', '\\' }).Last(), fileNamePattern, RegexOptions.IgnoreCase))); // fileNamePattern supported );
342 | return result;
343 | };
344 |
345 | var omitFiles = configGroup.OmitChangeFiles.SelectMany(searchFileFunc).ToList();
346 | //var files = configGroup.Files.SelectMany(searchFileFunc).Where(f => !omitFiles.Contains(f)).ToList();
347 | var files = configGroup.Files.SelectMany(searchFileFunc).ToList();
348 | //files.AddRange(omitFiles);//add omit change files
349 | //files = files.Distinct().ToList();// distinct
350 |
351 | #region Remove Files
352 |
353 | if (configGroup.RemoveFiles)
354 | {
355 | Record($"[in memory] remove files:");
356 | foreach (var file in files.ToList())
357 | {
358 | Record($"[in memory] try to remove file: {file}");
359 | FilesCache.Remove(file);
360 | files.Remove(file);
361 | FinishedFilesCount++;
362 | }
363 | continue;
364 | }
365 |
366 | #endregion
367 |
368 | #region Remove Directories
369 |
370 | foreach (var dir in configGroup.RemoveDictionaries)
371 | {
372 | var dirPath = Path.Combine(Manifest.AbsoluteOutputDir, dir);
373 | Record($"[in memory] tobe remove directory: {dirPath}");
374 |
375 | var removeDirFiles = FilesCache.Keys
376 | .Where(z => z.Contains($"\\{dir}\\") || z.Contains($"/{dir}/")).ToList();
377 |
378 | foreach (var file in removeDirFiles)
379 | {
380 | Record($"[in memory] remove directory: {dirPath}");
381 | FilesCache.Remove(file);
382 | files.Remove(file);
383 | }
384 | }
385 |
386 | #endregion
387 |
388 | foreach (var file in files)
389 | {
390 | try
391 | {
392 | Record($"[in memory] dynamic file: {file}");
393 |
394 | //string fileContent = null;
395 |
396 | var fileWrap = FilesCache[file];
397 |
398 | if (!omitFiles.Contains(file))
399 | {
400 | #region File Mark
401 |
402 | if (fileWrap.FileContent.Contains(FILE_MARK_PREFIX))
403 | {
404 | //judgement whether this file can keep
405 | var match = _fileMarkRegex.Match(fileWrap.FileContent);
406 | var fileKeyword = match.Groups["kw"].Value;
407 | //if (match.Success && !configGroup.KeepFileConiditions.Any(z => z == fileKeyword))
408 | if (match.Success && !Manifest.ConfigGroup.Exists(g => g.KeepFileConiditions.Any(z => z == fileKeyword)))
409 | {
410 | //remove this file
411 | Record($"[in memory] remove this file");
412 | try
413 | {
414 | FilesCache.Remove(file);
415 | Record($"[in memory] removed file: {file}");
416 | }
417 | catch (Exception ex)
418 | {
419 | Record($"[in memory] delete file error:{ex}");
420 | }
421 | continue;
422 | }
423 | }
424 |
425 | #endregion
426 |
427 | #region ReplaceContents
428 |
429 | XDocument xml = null;
430 | dynamic json = null;
431 | foreach (var replaceContent in configGroup.ReplaceContents)
432 | {
433 | #region String
434 |
435 | if (replaceContent.StringContent != null)
436 | {
437 | Record($"Replace String \"{replaceContent.StringContent.String}\" by \"{replaceContent.StringContent.ReplaceContent}\"");
438 | fileWrap.FileContent = fileWrap.FileContent.Replace(replaceContent.StringContent.String, replaceContent.StringContent.ReplaceContent);
439 | }
440 |
441 | #endregion
442 |
443 | #region Regex
444 |
445 | else if (replaceContent.RegexContent != null)
446 | {
447 | Record($"Regex Replace String \"{replaceContent.RegexContent.Pattern}\" by \"{replaceContent.RegexContent.ReplaceContent}\"");
448 | fileWrap.FileContent = Regex.Replace(fileWrap.FileContent, replaceContent.RegexContent.Pattern, replaceContent.RegexContent.ReplaceContent, replaceContent.RegexContent.RegexOptions);
449 | }
450 |
451 | #endregion
452 |
453 | #region Xml
454 |
455 | else if (replaceContent.XmlContent != null)
456 | {
457 | try
458 | {
459 | xml = xml ?? XDocument.Parse(fileWrap.FileContent);
460 | ReplaceXmlElements(xml.Root, replaceContent.XmlContent);
461 | }
462 | catch (Exception ex)
463 | {
464 | Record($"Xml file format wrong");
465 | SenparcTrace.SendCustomLog("Xml file format wrong", ex.Message);
466 | }
467 | }
468 | #endregion
469 |
470 | #region Json
471 | else if (replaceContent.JsonContent != null)
472 | {
473 | try
474 | {
475 | //var serializer = new JavaScriptSerializer();
476 | json = fileWrap.FileContent.GetObject(); //serializer.Deserialize(fileContent, typeof(object));
477 | ReplaceJsonNodes(json, replaceContent.JsonContent);
478 | }
479 | catch (Exception ex)
480 | {
481 | Record($"Json file format wrong");
482 | SenparcTrace.SendCustomLog("Json file format wrong", ex.Message);
483 | }
484 | }
485 |
486 | #endregion
487 | }
488 |
489 | if (xml != null)
490 | {
491 | fileWrap.FileContent = xml.ToString();
492 | Record($"Xml file changed.");
493 | }
494 | else if (json != null)
495 | {
496 | fileWrap.FileContent = JsonConvert.SerializeObject(json, Formatting.Indented);
497 | Record($"Json file changed.");
498 | }
499 |
500 |
501 | #endregion
502 |
503 | #region Custom Functions
504 |
505 | if (configGroup.CustomFunc != null)
506 | {
507 | fileWrap.FileContent = configGroup.CustomFunc(file, fileWrap.FileContent);
508 | Record($"Custom Function");
509 | }
510 |
511 |
512 | #region Content Mark
513 |
514 | if (configGroup.KeepContentConiditions.Count > 0 && fileWrap.FileContent.Contains(BEGIN_MARK_PERFIX))
515 | {
516 | var newContent = new StringBuilder();
517 |
518 | var lines = fileWrap.FileContent.Split(new string[] { Environment.NewLine, "\r", "\n" }, StringSplitOptions.None);
519 | var keep = true;
520 | var removeBlockCount = 0;
521 | var i = 0;
522 | foreach (var line in lines)
523 | {
524 | i++;
525 | if (keep)
526 | {
527 | if (line.Contains(BEGIN_MARK_PERFIX))
528 | {
529 | //begin to check Conditions
530 | var matchKeepLine = configGroup.KeepContentConiditions.Any(kw =>
531 | {
532 | var lineMatch = _contentMarkStart.Match(line);
533 | return lineMatch.Success && lineMatch.Groups["kw"].Value == kw;
534 | });
535 |
536 | if (!matchKeepLine)
537 | {
538 | //drop content
539 | removeBlockCount++;
540 |
541 | if (line.Contains(END_MARK))
542 | {
543 | //just remove this line
544 | keep = true;
545 | }
546 | else
547 | {
548 | keep = false;
549 | }
550 |
551 | continue;
552 | }
553 | }
554 |
555 | //keep
556 | newContent.Append(line);
557 | if (i != lines.Count())
558 | {
559 | newContent.Append(Environment.NewLine); //not last Item
560 | }
561 | }
562 | else
563 | {
564 | //not keep, waiting the end mark
565 | if (line.Contains(END_MARK))
566 | {
567 | keep = true;
568 | }
569 | }
570 | fileWrap.FileContent = newContent.ToString();
571 | }
572 | }
573 | else
574 | {
575 | //newContent.Append(fileWrap.FileContent);
576 | }
577 |
578 | Record("[in memory] File Size:" + fileWrap.FileContent.Length);
579 |
580 | #endregion
581 |
582 |
583 | #endregion
584 | }
585 | else
586 | {
587 | //newContent.Append(fileWrap.FileContent);// not change anything
588 | }
589 |
590 | Record($"[in memory] complete file processing: {file}");
591 |
592 | FinishedFilesCount++;
593 | }
594 | catch (Exception ex)
595 | {
596 | Record($@"error[{file}]: {ex.Message}
597 | {ex.StackTrace}");
598 | }
599 | };
600 | }
601 | }
602 | catch (Exception ex)
603 | {
604 | Record($@"build error: {ex.Message}
605 | {ex.StackTrace}");
606 | }
607 | finally
608 | {
609 |
610 |
611 | }
612 |
613 | try
614 | {
615 | #region save new files
616 | foreach (var fileWrap in FilesCache.Values.ToList())
617 | {
618 | try
619 | {
620 | var dir = fileWrap.DestFilePath.Substring(0, fileWrap.DestFilePath.LastIndexOf(Path.DirectorySeparatorChar));
621 | if (!Directory.Exists(dir))
622 | {
623 | Directory.CreateDirectory(dir);
624 | }
625 |
626 | //save the file to OutputDir
627 | var openMode = File.Exists(fileWrap.DestFilePath) ? FileMode.Truncate : FileMode.Create;
628 | using (var fs = new FileStream(fileWrap.DestFilePath, openMode))
629 | {
630 | fileWrap.TryLoadStream();//try load content stream
631 | fileWrap.FileContentStream.CopyTo(fs);
632 | fs.Flush(true);
633 | fileWrap.FileContentStream.Dispose();//close the stream
634 | Record($"modified and saved a new file: {fileWrap.DestFilePath}");
635 | }
636 | }
637 | catch (Exception ex)
638 | {
639 | Record($@"saved a file error: {fileWrap.DestFilePath}
640 | {ex.Message}
641 | {ex.StackTrace}");
642 | }
643 |
644 | }
645 | #endregion
646 |
647 | #region save manifest and log files
648 |
649 | var manifestFileName = Path.Combine(Manifest.AbsoluteOutputDir, "manifest.config");
650 | using (var logFs = new FileStream(manifestFileName, FileMode.Create))
651 | {
652 | var sw = new StreamWriter(logFs, Encoding.UTF8);
653 | sw.Write(Manifest.ToJson());
654 | sw.Flush();
655 | logFs.Flush(true);
656 | }
657 | Record($"saved manifest file: {manifestFileName}");
658 |
659 |
660 | var logFileName = Path.Combine(Manifest.AbsoluteOutputDir, "DPB.log");
661 | Record($"saved log file: {logFileName}");
662 | Record($"===== DPB Build Finished =====");
663 | Record($"---- Total time: {(DateTime.Now - startTime).TotalSeconds} seconds ----");
664 |
665 | using (var logFs = new FileStream(logFileName, FileMode.Create))
666 | {
667 | var sw = new StreamWriter(logFs, Encoding.UTF8);
668 | var logs = new StringBuilder();
669 | Records.ForEach(z => logs.AppendLine(z));
670 | sw.Write(logs.ToString());
671 | sw.Flush();
672 | logFs.Flush(true);
673 | }
674 |
675 | #endregion
676 | }
677 | catch (Exception ex)
678 | {
679 | Console.WriteLine(ex);
680 | //TODO:recore out side
681 | }
682 | }
683 |
684 | }
685 | }
686 |
--------------------------------------------------------------------------------
/src/DPB/LetsGoAsync.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DPB
9 | {
10 | public partial class LetsGo
11 | {
12 |
13 | #region Asynchronous Method
14 |
15 |
16 | #endregion
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/DPB/Models/FileWrap.cs:
--------------------------------------------------------------------------------
1 | using Senparc.CO2NET.Extensions;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace DPB.Models
10 | {
11 | internal class FileWrap
12 | {
13 | public string SourceFilePath { get; set; }
14 | public string DestFilePath { get; set; }
15 | public string FileContent
16 | {
17 | get
18 | {
19 | TryLoadStream();
20 | FileContentStream.Seek(0, SeekOrigin.Begin);
21 | var sr = new StreamReader(FileContentStream);
22 | var str = sr.ReadToEnd();//save file content to memory cache (option)
23 | FileContentStream.Seek(0, SeekOrigin.Begin);
24 | return str;
25 | }
26 | set
27 | {
28 | FileContentStream?.Dispose();
29 | FileContentStream = new MemoryStream();
30 | var sw = new StreamWriter(FileContentStream);
31 | sw.Write(value);
32 | sw.Flush();
33 | FileContentStream.Flush();
34 | FileContentStream.Seek(0, SeekOrigin.Begin);
35 | }
36 | }
37 |
38 | public Stream FileContentStream { get; private set; }
39 |
40 |
41 | ///
42 | /// try to load FileContentStream while FileContentStream is null or empty
43 | ///
44 | public void TryLoadStream()
45 | {
46 | if (FileContentStream == null)
47 | {
48 | FileContentStream = new MemoryStream();
49 | using (var fs = new FileStream(SourceFilePath, FileMode.Open))
50 | {
51 | fs.CopyTo(FileContentStream);
52 | fs.Flush();
53 | FileContentStream.Flush();
54 | FileContentStream.Seek(0, SeekOrigin.Begin);
55 | }
56 | }
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/DPB/Models/Manifest.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Text.RegularExpressions;
8 | using System.Threading.Tasks;
9 |
10 | namespace DPB.Models
11 | {
12 | ///
13 | /// Manifest module
14 | ///
15 | public class Manifest
16 | {
17 | private string _sourceDir;
18 | private string _outputDir;
19 |
20 | ///
21 | /// Source directory
22 | ///
23 | public string SourceDir
24 | {
25 | get => _sourceDir;
26 | set
27 | {
28 | _sourceDir = value;
29 | if (Directory.GetLogicalDrives().ToList().Any(z => _sourceDir.ToUpper().StartsWith(z.ToUpper())))
30 | {
31 | AbsoluteSourceDir = _sourceDir;
32 | }
33 | else
34 | {
35 | AbsoluteSourceDir = Path.Combine(Directory.GetCurrentDirectory(), _sourceDir);
36 | }
37 | }
38 | }
39 | ///
40 | /// Absolute source directory
41 | ///
42 | public string AbsoluteSourceDir { get; private set; }
43 |
44 | ///
45 | /// Output target directory
46 | ///
47 | public string OutputDir
48 | {
49 | get => _outputDir; set
50 | {
51 | _outputDir = value;
52 | if (Directory.GetLogicalDrives().ToList().Any(z => _outputDir.ToUpper().StartsWith(z.ToUpper())))
53 | {
54 | AbsoluteOutputDir = _outputDir;
55 | }
56 | else
57 | {
58 | AbsoluteOutputDir = Path.Combine(Directory.GetCurrentDirectory(), _outputDir);
59 | }
60 | }
61 | }
62 | ///
63 | /// Absolute output target directory
64 | ///
65 | public string AbsoluteOutputDir { get; private set; }
66 | ///
67 | /// find the paths in this config group
68 | ///
69 | public List ConfigGroup { get; set; } = new List();
70 |
71 | ///
72 | /// Manifest
73 | ///
74 | /// Source directory
75 | /// Output target directory
76 | public Manifest(string sourceDir, string outputDir)
77 | {
78 | SourceDir = sourceDir;
79 | OutputDir = outputDir;
80 | }
81 | }
82 |
83 | public class GroupConfig
84 | {
85 |
86 | ///
87 | /// partten to find the files in this config group, ex. *.cs
88 | ///
89 | public List Files { get; set; } = new List();
90 | ///
91 | /// omit files, do not change anything
92 | ///
93 | public List OmitChangeFiles { get; set; } = new List();
94 | ///
95 | /// remove all files in Files but OmitFiles
96 | ///
97 | public bool RemoveFiles { get; set; }
98 | ///
99 | /// remove dictionaries(relative address)
100 | ///
101 | public List RemoveDictionaries { get; set; } = new List();
102 |
103 | ///
104 | /// while meet one of the conditions, the files will not be deleted
105 | ///
106 | public List KeepFileConiditions { get; set; } = new List();
107 | ///
108 | /// while meet one of the conditions, the code block in file will be retained (kept). Otherwise the code block will be removed.
109 | /// //DPB Keep,this,BLOCK
110 | /// this is the block
111 | /// for any condition: 'Keep', 'this' or 'BLOCK' (case insensitive) can be retained
112 | /// until the following line
113 | /// //DPB END
114 | /// PS: DPB at the begin and DPB END at the and must be use UPPERCASE, // is not optional, just for many languages to support the annotations
115 | ///
116 | public List KeepContentConiditions { get; set; } = new List();
117 | ///
118 | /// The content to replace
119 | ///
120 | public List ReplaceContents { get; set; } = new List();
121 |
122 | ///
123 | /// Custom functions for file content, input is (fileName,fileContent) ,outpit is new file content
124 | ///
125 | [JsonIgnore]
126 | public Func CustomFunc { get; set; }
127 | }
128 |
129 | ///
130 | /// Replace content config
131 | ///
132 | public class ReplaceContent
133 | {
134 | ///
135 | /// String config
136 | ///
137 | public StringContent StringContent { get; set; }
138 | ///
139 | /// Regex config
140 | ///
141 | public RegexContent RegexContent { get; set; }
142 | ///
143 | /// Xml node config (only for xml format file)
144 | ///
145 | public XmlContent XmlContent { get; set; }
146 | ///
147 | /// Json node config (only for json file)
148 | ///
149 | public JsonContent JsonContent { get; set; }
150 | }
151 |
152 |
153 | ///
154 | /// String config
155 | ///
156 | public class StringContent
157 | {
158 | ///
159 | /// String
160 | ///
161 | public string String { get; set; }
162 | /////
163 | ///// Is CaseSensitive, default: false
164 | /////
165 | //public bool CaseSensitive { get; set; } = false;
166 | ///
167 | /// While condition string meets, this node's content will be replaced with new value
168 | ///
169 | public string ReplaceContent { get; set; }
170 | }
171 |
172 | ///
173 | /// Regex config
174 | ///
175 | public class RegexContent
176 | {
177 | ///
178 | /// Regex pattern
179 | ///
180 | public string Pattern { get; set; }
181 | ///
182 | /// RegexOptions
183 | ///
184 | public RegexOptions RegexOptions { get; set; }
185 | ///
186 | /// While condition string meets, this node's content will be replaced with new value
187 | ///
188 | public string ReplaceContent { get; set; }
189 | }
190 |
191 | ///
192 | /// Xml node config (only for xml format file)
193 | ///
194 | public class XmlContent
195 | {
196 | ///
197 | /// Tag name for xml
198 | ///
199 | public string TagName { get; set; }
200 | ///
201 | /// While condition string meets, this node's content will be replaced with new value
202 | ///
203 | public string ReplaceContent { get; set; }
204 | }
205 |
206 | ///
207 | /// Json node config (only for json file)
208 | ///
209 | public class JsonContent
210 | {
211 | ///
212 | /// Json key name
213 | ///
214 | public string KeyName { get; set; }
215 | ///
216 | /// While condition string meets, this node's content will be replaced with new value
217 | ///
218 | public string ReplaceContent { get; set; }
219 | }
220 |
221 |
222 |
223 | //public class TextContent
224 | //{
225 | // ///
226 | // /// Json key name
227 | // ///
228 | // public string KeyName { get; set; }
229 | // ///
230 | // /// While condition string meets, this node's content will be replaced with new value
231 | // ///
232 | // public string ReplaceContent { get; set; }
233 | //}
234 | }
235 |
--------------------------------------------------------------------------------
/src/DPB/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------