Skip to content

Commit 5ead722

Browse files
Merge branch 'master' into order_resource
2 parents a52cb43 + 8cb5a8d commit 5ead722

File tree

5 files changed

+136
-2
lines changed

5 files changed

+136
-2
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
[![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/JohnstonCode/svn-scm.svg)](https://isitmaintained.com/project/JohnstonCode/svn-scm "Average time to resolve an issue")
2121
[![Percentage of issues still open](https://isitmaintained.com/badge/open/JohnstonCode/svn-scm.svg)](https://isitmaintained.com/project/JohnstonCode/svn-scm "Percentage of issues still open")
2222

23+
[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/svn-scm/Lobby)
24+
2325
# Prerequisites
2426

2527
> **Note**: This extension leverages your machine's SVN installation,\
@@ -110,6 +112,8 @@ Example:
110112
|`svn.showOutput`|Show the output window when the extension starts|`false`|
111113
|`svn.conflicts.autoResolve`|Set file to status resolved after fix conflictss|`false`|
112114
|`svn.update.ignoreExternals`|Set to ignore externals definitions on update (add --ignore-externals)|`true`|
115+
|`svn.delete.actionForDeletedFiles`|When a file is deleted, what SVN should do? `none` - Do nothing, `prompt` - Ask the action, `remove` - automatically remove from SVN|`"prompt"`|
116+
|`svn.delete.ignoredRulesForDeletedFiles`|Ignored files/rules for `svn.delete.actionForDeletedFiles`(Ex.: file.txt or \*\*/\*.txt)|`[]`|
113117
|`svn.default.encoding`|Encoding of svn output if the output is not utf-8. When this parameter is null, the encoding is automatically detected. Example: 'windows-1252'.|`null`|
114118
|`svn.showUpdateMessage`|Show the update message when update is run|`true`|
115119
|`svn.remoteChanges.checkFrequency`|Set the interval in seconds to check changed files on remote repository and show in statusbar. 0 to disable|`300`|

package.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,24 @@
726726
"description": "Set to ignore externals definitions on update (add --ignore-externals)",
727727
"default": true
728728
},
729+
"svn.delete.actionForDeletedFiles": {
730+
"type": "string",
731+
"enum": [
732+
"none",
733+
"prompt",
734+
"remove"
735+
],
736+
"description": "When a file is deleted, what SVN should do? `none` - Do nothing, `prompt` - Ask the action, `remove` - automatically remove from SVN",
737+
"default": "prompt"
738+
},
739+
"svn.delete.ignoredRulesForDeletedFiles": {
740+
"type": "array",
741+
"items": {
742+
"type": "string"
743+
},
744+
"description": "Ignored files/rules for `svn.delete.actionForDeletedFiles`(Ex.: file.txt or **/*.txt)",
745+
"default": []
746+
},
729747
"svn.default.encoding": {
730748
"type": [
731749
"string",

src/commands.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1319,6 +1319,42 @@ export class SvnCommands implements IDisposable {
13191319
return;
13201320
}
13211321

1322+
@command("svn.promptRemove", { repository: true })
1323+
public async promptRemove(repository: Repository, ...uris: Uri[]) {
1324+
const files = uris.map(uri => uri.fsPath);
1325+
1326+
const relativeList = files
1327+
.map(file => repository.repository.removeAbsolutePath(file))
1328+
.sort();
1329+
1330+
const ignoreText = "Add to ignored list";
1331+
1332+
const resp = await window.showInformationMessage(
1333+
`The file(s) "${relativeList.join(
1334+
", "
1335+
)}" are removed from disk.\nWould you like remove from SVN?`,
1336+
{ modal: true },
1337+
"Yes",
1338+
ignoreText,
1339+
"No"
1340+
);
1341+
1342+
if (resp === "Yes") {
1343+
await repository.removeFiles(files, false);
1344+
} else if (resp === ignoreText) {
1345+
let ignoreList = configuration.get<string[]>(
1346+
"delete.ignoredRulesForDeletedFiles",
1347+
[]
1348+
);
1349+
1350+
ignoreList.push(...relativeList);
1351+
1352+
ignoreList = [...new Set(ignoreList)]; // Remove duplicates
1353+
1354+
configuration.update("delete.ignoredRulesForDeletedFiles", ignoreList);
1355+
}
1356+
}
1357+
13221358
private getSCMResource(uri?: Uri): Resource | undefined {
13231359
uri = uri
13241360
? uri

src/repository.ts

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export class Repository {
6969
public isIncomplete: boolean = false;
7070
public needCleanUp: boolean = false;
7171
private remoteChangedUpdateInterval?: NodeJS.Timer;
72+
private deletedUris: Uri[] = [];
7273

7374
private lastPromptAuth?: Thenable<boolean | undefined>;
7475

@@ -247,6 +248,17 @@ export class Repository {
247248
})
248249
);
249250

251+
// For each deleted file, append to list
252+
const onFsDelete = filterEvent(
253+
fsWatcher.onDidDelete,
254+
uri => !/[\\\/]\.svn[\\\/]/.test(uri.path)
255+
);
256+
257+
onFsDelete(uri => this.deletedUris.push(uri), this, this.disposables);
258+
259+
// Only check deleted files after the status list is fully updated
260+
this.onDidChangeStatus(this.actionForDeletedFiles, this, this.disposables);
261+
250262
this.createRemoteChangedInterval();
251263

252264
this.updateRemoteChangedFiles();
@@ -288,6 +300,70 @@ export class Repository {
288300
}, 1000 * updateFreq);
289301
}
290302

303+
/**
304+
* Check all recently deleted files and compare with svn status "missing"
305+
*/
306+
@debounce(1000)
307+
private async actionForDeletedFiles() {
308+
if (!this.deletedUris.length) {
309+
return;
310+
}
311+
312+
const allUris = this.deletedUris;
313+
this.deletedUris = [];
314+
315+
const actionForDeletedFiles = configuration.get<string>(
316+
"delete.actionForDeletedFiles",
317+
"prompt"
318+
);
319+
320+
if (actionForDeletedFiles === "none") {
321+
return;
322+
}
323+
324+
const resources = allUris
325+
.map(uri => this.getResourceFromFile(uri))
326+
.filter(
327+
resource => resource && resource.type === Status.MISSING
328+
) as Resource[];
329+
330+
let uris = resources.map(resource => resource.resourceUri);
331+
332+
if (!uris.length) {
333+
return;
334+
}
335+
336+
const ignoredRulesForDeletedFiles = configuration.get<string[]>(
337+
"delete.ignoredRulesForDeletedFiles",
338+
[]
339+
);
340+
const rules = ignoredRulesForDeletedFiles.map(
341+
ignored => new Minimatch(ignored)
342+
);
343+
344+
if (rules.length) {
345+
uris = uris.filter(uri => {
346+
// Check first for relative URL (Better for workspace configuration)
347+
const relativePath = this.repository.removeAbsolutePath(uri.fsPath);
348+
349+
// If some match, remove from list
350+
return !rules.some(
351+
rule => rule.match(relativePath) || rule.match(uri.fsPath)
352+
);
353+
});
354+
}
355+
356+
if (!uris.length) {
357+
return;
358+
}
359+
360+
if (actionForDeletedFiles === "remove") {
361+
return await this.removeFiles(uris.map(uri => uri.fsPath), false);
362+
} else if (actionForDeletedFiles === "prompt") {
363+
return await commands.executeCommand("svn.promptRemove", ...uris);
364+
}
365+
}
366+
291367
@debounce(1000)
292368
public async updateRemoteChangedFiles() {
293369
const updateFreq = configuration.get<number>(
@@ -752,7 +828,7 @@ export class Repository {
752828
);
753829
}
754830

755-
public async removeFiles(files: any[], keepLocal: boolean) {
831+
public async removeFiles(files: string[], keepLocal: boolean) {
756832
return this.run(Operation.Remove, () =>
757833
this.repository.removeFiles(files, keepLocal)
758834
);

src/svnRepository.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ export class Repository {
432432
return message;
433433
}
434434

435-
public async removeFiles(files: any[], keepLocal: boolean) {
435+
public async removeFiles(files: string[], keepLocal: boolean) {
436436
files = files.map(file => this.removeAbsolutePath(file));
437437
const args = ["remove"];
438438

0 commit comments

Comments
 (0)