@@ -31,25 +31,74 @@ def prompt_shared_data_path() -> str:
3131 return expand_path (chosen )
3232
3333
34+ def _required_env_values ():
35+ return {
36+ "SECRET_KEY" : _get_random_secret_key (),
37+ "AUTH_JWT_SIGNING_KEY" : _get_random_secret_key (),
38+ "AGENT_JWT_SIGNING_KEY" : _get_random_secret_key (),
39+ "FIELD_ENCRYPTION_KEY" : _get_encryption_key (),
40+ "SHARED_DATA_PATH" : prompt_shared_data_path (),
41+ "POSTGRES_USER" : POSTGRES_USER ,
42+ "POSTGRES_PASSWORD" : POSTGRES_PASSWORD ,
43+ "POSTGRES_DB" : POSTGRES_DB ,
44+ }
45+
46+
47+ def _parse_env_keys (lines ):
48+ keys = set ()
49+ for line in lines :
50+ stripped = line .strip ()
51+ if not stripped or stripped .startswith ("#" ) or "=" not in stripped :
52+ continue
53+ key , _ = stripped .split ("=" , 1 )
54+ keys .add (key .strip ())
55+ return keys
56+
57+
58+ def _format_env_line (key , value ):
59+ if key == "SHARED_DATA_PATH" :
60+ return f'{ key } ="{ value } "'
61+ return f"{ key } ={ value } "
62+
63+
3464def write_env_file ():
35- secret_key = _get_random_secret_key ()
36- field_encryption_key = _get_encryption_key ()
37- shared_data_path = prompt_shared_data_path ()
65+ env_path = Path .cwd () / ENV_FILENAME
66+ required_values = _required_env_values ()
67+ ordered_required_keys = [
68+ "SECRET_KEY" ,
69+ "AUTH_JWT_SIGNING_KEY" ,
70+ "AGENT_JWT_SIGNING_KEY" ,
71+ "FIELD_ENCRYPTION_KEY" ,
72+ "SHARED_DATA_PATH" ,
73+ "POSTGRES_USER" ,
74+ "POSTGRES_PASSWORD" ,
75+ "POSTGRES_DB" ,
76+ ]
77+
78+ if env_path .exists ():
79+ existing_lines = env_path .read_text (encoding = "utf-8" ).splitlines ()
80+ existing_keys = _parse_env_keys (existing_lines )
81+ missing_keys = [key for key in ordered_required_keys if key not in existing_keys ]
82+
83+ if not missing_keys :
84+ print (f"{ ENV_FILENAME } already contains all required keys." )
85+ return
86+
87+ if existing_lines and existing_lines [- 1 ].strip ():
88+ existing_lines .append ("" )
89+ for key in missing_keys :
90+ existing_lines .append (_format_env_line (key , required_values [key ]))
91+
92+ env_path .write_text ("\n " .join (existing_lines ) + "\n " , encoding = "utf-8" )
93+ print (
94+ f"Updated { ENV_FILENAME } at: { env_path } (added keys: { ', ' .join (missing_keys )} )"
95+ )
96+ return
3897
3998 env_contents = "\n " .join (
40- [
41- f"SECRET_KEY={ secret_key } " ,
42- f"FIELD_ENCRYPTION_KEY={ field_encryption_key } " ,
43- f'SHARED_DATA_PATH="{ shared_data_path } "' ,
44- f"POSTGRES_USER={ POSTGRES_USER } " ,
45- f"POSTGRES_PASSWORD={ POSTGRES_PASSWORD } " ,
46- f"POSTGRES_DB={ POSTGRES_DB } " ,
47- "" ,
48- ]
99+ [_format_env_line (key , required_values [key ]) for key in ordered_required_keys ]
49100 )
50-
51- env_path = Path .cwd () / ENV_FILENAME
52- env_path .write_text (env_contents , encoding = "utf-8" )
101+ env_path .write_text (env_contents + "\n " , encoding = "utf-8" )
53102 print (f"Wrote { ENV_FILENAME } to: { env_path } " )
54103
55104
@@ -63,9 +112,25 @@ def write_docker_compose_file() -> Path:
63112 # arcsecond/hosting/docker/docker-compose.yml
64113 compose = resources .files ("arcsecond.hosting.docker" ).joinpath ("docker-compose.yml" )
65114
66- with compose .open ("rb" ) as src , dest .open ("wb" ) as dst :
67- dst .write (src .read ())
115+ with compose .open ("rb" ) as src :
116+ expected_content = src .read ()
117+
118+ if not dest .exists ():
119+ dest .write_bytes (expected_content )
120+ print (f"Wrote docker-compose.yml to: { dest } " )
121+ return dest
68122
123+ current_content = dest .read_bytes ()
124+ if current_content == expected_content :
125+ print ("docker-compose.yml is already up to date." )
126+ return dest
127+
128+ latest_dest = Path .cwd () / "docker-compose.latest.yml"
129+ latest_dest .write_bytes (expected_content )
130+ print (
131+ "docker-compose.yml differs from the latest packaged version. "
132+ f"Wrote new template to: { latest_dest } "
133+ )
69134 return dest
70135
71136
0 commit comments