1
+ #!/usr/bin/env python
2
+
3
+ import os
4
+ import kinto_http
5
+ import hashlib
6
+ import pathlib
7
+ import uuid
8
+
9
+ from settings import config
10
+
11
+ from constants import WEBKIT_LISTS_DIR
12
+
13
+ def get_config_if_env (env_var , config_section , config_option , fallback = "" ):
14
+ """
15
+ Return the config value if the environment variable exists; otherwise, return the fallback.
16
+ """
17
+ if env_var in os .environ :
18
+ return os .environ [env_var ]
19
+ return config .get (config_section , config_option , fallback = fallback )
20
+
21
+ def get_file_hash (list_path ):
22
+ with open (list_path , "rb" ) as f :
23
+ return hashlib .sha256 (f .read ()).hexdigest ()
24
+
25
+ SERVER = get_config_if_env ("SERVER" , "main" , "remote_settings_url" )
26
+ BUCKET = "main-workspace"
27
+ COLLECTION = "tracking-protection-lists-ios"
28
+ AUTHORIZATION = get_config_if_env ("AUTHORIZATION" , "main" , "remote_settings_authorization" )
29
+ ENVIRONMENT = os .getenv ("ENVIRONMENT" , "local" ).lower ()
30
+ DRY_RUN = os .getenv ("DRY_RUN" , "0" ) in "1yY"
31
+
32
+ def publish2rs ():
33
+ client = kinto_http .Client (
34
+ server_url = SERVER ,
35
+ auth = AUTHORIZATION ,
36
+ bucket = BUCKET ,
37
+ collection = COLLECTION ,
38
+ dry_mode = DRY_RUN
39
+ )
40
+
41
+ remote_attachments = {
42
+ r ["name" ]: {"id" : r ["id" ], "hash" : r ["attachment" ]["hash" ]}
43
+ for r in client .get_records ()
44
+ }
45
+
46
+ local_attachments = {
47
+ file .stem : get_file_hash (file )
48
+ for file in pathlib .Path (WEBKIT_LISTS_DIR ).iterdir ()
49
+ }
50
+
51
+ # Determine records to create, update, or delete
52
+ # by comparing the attachment sha256 hashes.
53
+ to_create = []
54
+ to_update = []
55
+ for name , hash in local_attachments .items ():
56
+ remote_attachment = remote_attachments .pop (name , None )
57
+ if remote_attachment is None :
58
+ to_create .append ({"name" : name })
59
+ elif remote_attachment ["hash" ] != hash :
60
+ to_update .append ({"id" : remote_attachment ["id" ], "name" : name })
61
+ # Remaining records in `remote_attachments` are to be deleted.
62
+ to_delete = [{"id" : record ["id" ]} for _ , record in remote_attachments .items ()]
63
+
64
+ # Print changes
65
+ print ("Changes to apply:" )
66
+ print (f"To create: { to_create } " )
67
+ print (f"To update: { to_update } " )
68
+ print (f"To delete: { to_delete } " )
69
+
70
+ has_pending_changes = (len (to_create ) + len (to_update ) + len (to_delete )) > 0
71
+ if not has_pending_changes :
72
+ print ("Records are in sync. Nothing to do ✅." )
73
+ return os .EX_OK
74
+
75
+ # Batch delete operations.
76
+ # NOTE: Attachment deletion is implicit when deleting a record.
77
+ with client .batch () as batch :
78
+ for record in to_delete :
79
+ batch .delete_record (id = record ["id" ])
80
+
81
+ # Adding, updating attachments on client
82
+ # since batch operations are not supported.
83
+ for record in to_create :
84
+ id = str (uuid .uuid4 ())
85
+ filepath = f"{ WEBKIT_LISTS_DIR } /{ record ['name' ]} .json"
86
+ client .add_attachment (id = id , data = {"name" : record ["name" ]}, filepath = filepath )
87
+ for record in to_update :
88
+ filepath = f"{ WEBKIT_LISTS_DIR } /{ record ['name' ]} .json"
89
+ client .add_attachment (id = record ["id" ], filepath = filepath )
90
+
91
+
92
+ if ENVIRONMENT == "dev" :
93
+ # Self approve changes on DEV.
94
+ # message arg is not supported as of now.
95
+ client .approve_changes ()
96
+ print ("Changes applied to dev server ✅" )
97
+ else :
98
+ # Request review.
99
+ print ("Request review..." , end = "" )
100
+ client .request_review (message = "r?" )
101
+ print ("✅" )
0 commit comments