@@ -3,6 +3,7 @@ import type Sync from "./lib/sync"
3
3
import pathModule from "path"
4
4
import fs from "fs-extra"
5
5
import writeFileAtomic from "write-file-atomic"
6
+ import { Semaphore } from "./semaphore"
6
7
7
8
export const IGNORER_VERSION = 1
8
9
@@ -11,47 +12,96 @@ export class Ignorer {
11
12
public instance = ignore ( )
12
13
public name : string = "ignorer"
13
14
public pattern : string [ ] = [ ]
15
+ private readonly mutex = new Semaphore ( 1 )
14
16
15
17
public constructor ( sync : Sync , name : string = "ignorer" ) {
16
18
this . sync = sync
17
19
this . name = name
18
20
}
19
21
20
22
public async fetch ( ) : Promise < string > {
21
- const filePath = pathModule . join ( this . sync . dbPath , this . name , `v${ IGNORER_VERSION } ` , this . sync . syncPair . uuid , "filenIgnore" )
23
+ await this . mutex . acquire ( )
24
+
25
+ try {
26
+ const filePath = pathModule . join ( this . sync . dbPath , this . name , `v${ IGNORER_VERSION } ` , this . sync . syncPair . uuid , "filenIgnore" )
27
+ const physicalFilePath = pathModule . join ( this . sync . syncPair . localPath , ".filenignore" )
28
+ let content : string = ""
29
+ const [ exists , physicalExists ] = await Promise . all ( [ fs . exists ( filePath ) , fs . exists ( physicalFilePath ) ] )
30
+
31
+ if ( exists ) {
32
+ const stats = await fs . stat ( filePath )
33
+
34
+ if ( stats . size > 0 ) {
35
+ content += await fs . readFile ( filePath , {
36
+ encoding : "utf-8"
37
+ } )
38
+ }
39
+ }
40
+
41
+ if ( physicalExists ) {
42
+ const stats = await fs . stat ( physicalFilePath )
43
+
44
+ if ( stats . size > 0 ) {
45
+ content += `${ content . length > 0 ? "\n" : "" } ${ await fs . readFile ( physicalFilePath , {
46
+ encoding : "utf-8"
47
+ } ) } `
48
+ }
49
+ }
50
+
51
+ return content
52
+ } finally {
53
+ this . mutex . release ( )
54
+ }
55
+ }
22
56
23
- await fs . ensureDir ( pathModule . dirname ( filePath ) )
57
+ public async write ( content : string ) : Promise < void > {
58
+ await this . mutex . acquire ( )
24
59
25
- const exists = await fs . exists ( filePath )
60
+ try {
61
+ const filePath = pathModule . join ( this . sync . syncPair . localPath , ".filenignore" )
26
62
27
- if ( ! exists ) {
28
- return ""
29
- }
63
+ await fs . ensureDir ( pathModule . dirname ( filePath ) )
30
64
31
- const stats = await fs . stat ( filePath )
32
-
33
- if ( stats . size === 0 ) {
34
- return ""
65
+ await writeFileAtomic ( filePath , content , {
66
+ encoding : "utf-8"
67
+ } )
68
+ } finally {
69
+ this . mutex . release ( )
35
70
}
71
+ }
36
72
37
- return await fs . readFile ( filePath , {
38
- encoding : "utf-8"
39
- } )
73
+ public async clearFile ( ) : Promise < void > {
74
+ await this . mutex . acquire ( )
75
+
76
+ try {
77
+ const filePath = pathModule . join ( this . sync . dbPath , this . name , `v${ IGNORER_VERSION } ` , this . sync . syncPair . uuid , "filenIgnore" )
78
+ const physicalFilePath = pathModule . join ( this . sync . syncPair . localPath , ".filenignore" )
79
+ const [ exists , physicalExists ] = await Promise . all ( [ fs . exists ( filePath ) , fs . exists ( physicalFilePath ) ] )
80
+
81
+ if ( exists ) {
82
+ await writeFileAtomic ( filePath , "" , {
83
+ encoding : "utf-8"
84
+ } )
85
+ }
86
+
87
+ if ( physicalExists ) {
88
+ await writeFileAtomic ( physicalFilePath , "" , {
89
+ encoding : "utf-8"
90
+ } )
91
+ }
92
+ } finally {
93
+ this . mutex . release ( )
94
+ }
40
95
}
41
96
42
97
public async initialize ( passedContent ?: string ) : Promise < void > {
43
98
this . sync . localFileSystem . ignoredCache . clear ( )
44
99
this . sync . remoteFileSystem . ignoredCache . clear ( )
45
100
46
101
let content : string [ ] = [ ]
47
- const filePath = pathModule . join ( this . sync . dbPath , this . name , `v${ IGNORER_VERSION } ` , this . sync . syncPair . uuid , "filenIgnore" )
48
-
49
- await fs . ensureDir ( pathModule . dirname ( filePath ) )
50
102
51
103
if ( typeof passedContent === "string" ) {
52
- await writeFileAtomic ( filePath , passedContent , {
53
- encoding : "utf-8"
54
- } )
104
+ await this . write ( passedContent )
55
105
56
106
content = passedContent
57
107
. split ( "\n" )
@@ -80,19 +130,6 @@ export class Ignorer {
80
130
this . instance = ignore ( )
81
131
}
82
132
83
- public async clearFile ( ) : Promise < void > {
84
- const filePath = pathModule . join ( this . sync . dbPath , this . name , `v${ IGNORER_VERSION } ` , this . sync . syncPair . uuid , "filenIgnore" )
85
-
86
- await fs . ensureDir ( pathModule . dirname ( filePath ) )
87
-
88
- await fs . rm ( filePath , {
89
- force : true ,
90
- maxRetries : 60 * 10 ,
91
- recursive : true ,
92
- retryDelay : 100
93
- } )
94
- }
95
-
96
133
public ignores ( path : string ) : boolean {
97
134
const normalizedPath = path . startsWith ( "\\" ) ? path . slice ( 1 ) : path . startsWith ( "/" ) ? path . slice ( 1 ) : path
98
135
0 commit comments