• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / edge-runtime / 15722458782

18 Jun 2025 02:29AM UTC coverage: 51.857% (-0.009%) from 51.866%
15722458782

push

github

web-flow
fix(cli): ip address parsing to support both ipv4 and ipv6 (#547)

0 of 4 new or added lines in 1 file covered. (0.0%)

3 existing lines in 3 files now uncovered.

18151 of 35002 relevant lines covered (51.86%)

5564.01 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/cli/src/main.rs
1
use std::fs::File;
2
use std::io::Write;
3
use std::net::IpAddr;
4
use std::net::SocketAddr;
5
use std::path::PathBuf;
6
use std::process::ExitCode;
7
use std::str::FromStr;
8
use std::sync::Arc;
9

10
use anyhow::bail;
11
use anyhow::Context;
12
use anyhow::Error;
13
use base::server::Builder;
14
use base::server::ServerFlags;
15
use base::server::Tls;
16
use base::utils::units::percentage_value;
17
use base::worker::pool::SupervisorPolicy;
18
use base::worker::pool::WorkerPoolPolicy;
19
use base::CacheSetting;
20
use base::InspectorOption;
21
use base::WorkerKind;
22
use deno::ConfigMode;
23
use deno::DenoOptionsBuilder;
24
use deno_facade::extract_from_file;
25
use deno_facade::generate_binary_eszip;
26
use deno_facade::EmitterFactory;
27
use deno_facade::Metadata;
28
use env::resolve_deno_runtime_env;
29
use flags::get_cli;
30
use flags::EszipV2ChecksumKind;
31
use log::warn;
32

33
mod env;
34
mod flags;
35

36
#[cfg(not(feature = "tracing"))]
37
mod logger;
38

39
fn main() -> Result<ExitCode, anyhow::Error> {
×
40
  resolve_deno_runtime_env();
×
41

×
42
  let runtime = tokio::runtime::Builder::new_current_thread()
×
43
    .enable_all()
×
44
    .thread_name("sb-main")
×
45
    .build()
×
46
    .unwrap();
×
47

×
48
  // TODO: Tokio runtime shouldn't be needed here (Address later)
×
49
  let local = tokio::task::LocalSet::new();
×
50
  let res: Result<ExitCode, Error> = local.block_on(&runtime, async {
×
51
    let matches = get_cli().get_matches();
×
52
    let verbose = matches.get_flag("verbose");
×
53

×
54
    if !matches.get_flag("quiet") {
×
55
      #[cfg(feature = "tracing")]
56
      {
57
        use tracing_subscriber::fmt::format::FmtSpan;
58
        use tracing_subscriber::EnvFilter;
59

60
        tracing_subscriber::fmt()
61
          .with_env_filter(EnvFilter::from_default_env())
62
          .with_thread_names(true)
63
          .with_span_events(if verbose {
64
            FmtSpan::FULL
65
          } else {
66
            FmtSpan::NONE
67
          })
68
          .init()
69
      }
70

71
      #[cfg(not(feature = "tracing"))]
72
      {
×
73
        let include_source = matches.get_flag("log-source");
×
74
        logger::init(verbose, include_source);
×
75
      }
×
76
    }
×
77

78
    #[allow(clippy::single_match)]
79
    #[allow(clippy::arc_with_non_send_sync)]
80
    let exit_code = match matches.subcommand() {
×
81
      Some(("start", sub_matches)) => {
×
82
        let ip = sub_matches.get_one::<String>("ip").cloned().unwrap();
×
NEW
83
        let ip = IpAddr::from_str(&ip)
×
NEW
84
          .context("failed to parse the IP address to bind the server")?;
×
85

86
        let port = sub_matches.get_one::<u16>("port").copied().unwrap();
×
NEW
87

×
NEW
88
        let addr = SocketAddr::new(ip, port);
×
89

90
        let maybe_tls =
×
91
          if let Some(port) = sub_matches.get_one::<u16>("tls").copied() {
×
92
            let Some((key_slice, cert_slice)) = sub_matches
×
93
              .get_one::<PathBuf>("key")
×
94
              .and_then(|it| std::fs::read(it).ok())
×
95
              .zip(
×
96
                sub_matches
×
97
                  .get_one::<PathBuf>("cert")
×
98
                  .and_then(|it| std::fs::read(it).ok()),
×
99
              )
×
100
            else {
101
              bail!("unable to load the key file or cert file");
×
102
            };
103

104
            Some(Tls::new(port, &key_slice, &cert_slice)?)
×
105
          } else {
106
            None
×
107
          };
108

109
        let main_service_path = sub_matches
×
110
          .get_one::<String>("main-service")
×
111
          .cloned()
×
112
          .unwrap();
×
113

×
114
        let no_module_cache = sub_matches
×
115
          .get_one::<bool>("disable-module-cache")
×
116
          .cloned()
×
117
          .unwrap();
×
118

×
119
        let allow_main_inspector = sub_matches
×
120
          .get_one::<bool>("inspect-main")
×
121
          .cloned()
×
122
          .unwrap();
×
123

×
124
        let event_service_manager_path =
×
125
          sub_matches.get_one::<String>("event-worker").cloned();
×
126
        let maybe_main_entrypoint =
×
127
          sub_matches.get_one::<String>("main-entrypoint").cloned();
×
128
        let maybe_events_entrypoint =
×
129
          sub_matches.get_one::<String>("events-entrypoint").cloned();
×
130

×
131
        let maybe_supervisor_policy = sub_matches
×
132
          .get_one::<String>("policy")
×
133
          .map(|it| it.parse::<SupervisorPolicy>().unwrap());
×
134

×
135
        let graceful_exit_deadline_sec = sub_matches
×
136
          .get_one::<u64>("graceful-exit-timeout")
×
137
          .cloned()
×
138
          .unwrap_or(0);
×
139

×
140
        let graceful_exit_keepalive_deadline_ms = sub_matches
×
141
          .get_one::<u64>("experimental-graceful-exit-keepalive-deadline-ratio")
×
142
          .cloned()
×
143
          .and_then(|it| {
×
144
            if it == 0 {
×
145
              return None;
×
146
            }
×
147

×
148
            percentage_value(graceful_exit_deadline_sec * 1000, it)
×
149
          });
×
150

×
151
        let event_worker_exit_deadline_sec = sub_matches
×
152
          .get_one::<u64>("event-worker-exit-timeout")
×
153
          .cloned()
×
154
          .unwrap_or(0);
×
155

×
156
        let maybe_max_parallelism =
×
157
          sub_matches.get_one::<usize>("max-parallelism").cloned();
×
158
        let maybe_request_wait_timeout =
×
159
          sub_matches.get_one::<u64>("request-wait-timeout").cloned();
×
160
        let maybe_request_idle_timeout =
×
161
          sub_matches.get_one::<u64>("request-idle-timeout").cloned();
×
162
        let maybe_request_read_timeout =
×
163
          sub_matches.get_one::<u64>("request-read-timeout").cloned();
×
164

×
165
        let maybe_beforeunload_wall_clock_pct = sub_matches
×
166
          .get_one::<u8>("dispatch-beforeunload-wall-clock-ratio")
×
167
          .cloned();
×
168
        let maybe_beforeunload_cpu_pct = sub_matches
×
169
          .get_one::<u8>("dispatch-beforeunload-cpu-ratio")
×
170
          .cloned();
×
171
        let maybe_beforeunload_memory_pct = sub_matches
×
172
          .get_one::<u8>("dispatch-beforeunload-memory-ratio")
×
173
          .cloned();
×
174

175
        let static_patterns =
×
176
          if let Some(val_ref) = sub_matches.get_many::<String>("static") {
×
177
            val_ref.map(|s| s.as_str()).collect::<Vec<&str>>()
×
178
          } else {
179
            vec![]
×
180
          };
181

182
        let static_patterns: Vec<String> =
×
183
          static_patterns.into_iter().map(|s| s.to_string()).collect();
×
184

×
185
        let inspector = sub_matches.get_one::<clap::Id>("inspector").zip(
×
186
          sub_matches
×
187
            .get_one("inspect")
×
188
            .or(sub_matches.get_one("inspect-brk"))
×
189
            .or(sub_matches.get_one::<SocketAddr>("inspect-wait")),
×
190
        );
×
191

192
        let maybe_inspector_option = if let Some((key, addr)) = inspector {
×
193
          Some(get_inspector_option(key.as_str(), addr).unwrap())
×
194
        } else {
195
          None
×
196
        };
197

198
        let tcp_nodelay =
×
199
          sub_matches.get_one::<bool>("tcp-nodelay").copied().unwrap();
×
200
        let request_buffer_size = sub_matches
×
201
          .get_one::<u64>("request-buffer-size")
×
202
          .copied()
×
203
          .unwrap();
×
204

×
205
        let flags = ServerFlags {
×
206
          no_module_cache,
×
207
          allow_main_inspector,
×
208
          tcp_nodelay,
×
209

×
210
          graceful_exit_deadline_sec,
×
211
          graceful_exit_keepalive_deadline_ms,
×
212
          event_worker_exit_deadline_sec,
×
213
          request_wait_timeout_ms: maybe_request_wait_timeout,
×
214
          request_idle_timeout_ms: maybe_request_idle_timeout,
×
215
          request_read_timeout_ms: maybe_request_read_timeout,
×
216
          request_buffer_size: Some(request_buffer_size),
×
217

×
218
          beforeunload_wall_clock_pct: maybe_beforeunload_wall_clock_pct,
×
219
          beforeunload_cpu_pct: maybe_beforeunload_cpu_pct,
×
220
          beforeunload_memory_pct: maybe_beforeunload_memory_pct,
×
221
        };
×
222

×
223
        let mut builder = Builder::new(addr, &main_service_path);
×
224

×
225
        builder.user_worker_policy(WorkerPoolPolicy::new(
×
226
          maybe_supervisor_policy,
×
227
          if let Some(true) = maybe_supervisor_policy
×
228
            .as_ref()
×
229
            .map(SupervisorPolicy::is_oneshot)
×
230
          {
231
            if let Some(parallelism) = maybe_max_parallelism {
×
232
              if parallelism == 0 || parallelism > 1 {
×
233
                warn!(
×
234
                  "{}",
×
235
                  concat!(
236
                    "if `oneshot` policy is enabled, the maximum ",
237
                    "parallelism is fixed to `1` as forcibly"
238
                  )
239
                );
240
              }
×
241
            }
×
242

243
            Some(1)
×
244
          } else {
245
            maybe_max_parallelism
×
246
          },
247
          flags,
×
248
        ));
249

250
        if let Some(tls) = maybe_tls {
×
251
          builder.tls(tls);
×
252
        }
×
253
        if let Some(worker_path) = event_service_manager_path {
×
254
          builder.event_worker_path(&worker_path);
×
255
        }
×
256
        if let Some(inspector_option) = maybe_inspector_option {
×
257
          builder.inspector(inspector_option);
×
258
        }
×
259

260
        builder.extend_static_patterns(static_patterns);
×
261
        builder.entrypoints_mut().main = maybe_main_entrypoint;
×
262
        builder.entrypoints_mut().events = maybe_events_entrypoint;
×
263

×
264
        *builder.flags_mut() = flags;
×
265

266
        let maybe_received_signum_or_exit_code =
×
267
          builder.build().await?.listen().await?;
×
268

269
        maybe_received_signum_or_exit_code
×
270
          .map(|it| it.map_left(|it| ExitCode::from(it as u8)).into_inner())
×
271
          .unwrap_or_default()
×
272
      }
273

274
      Some(("bundle", sub_matches)) => {
×
275
        let output_path =
×
276
          sub_matches.get_one::<String>("output").cloned().unwrap();
×
277
        let import_map_path =
×
278
          sub_matches.get_one::<String>("import-map").cloned();
×
279
        let decorator = sub_matches.get_one::<String>("decorator").cloned();
×
280
        let static_patterns =
×
281
          if let Some(val_ref) = sub_matches.get_many::<String>("static") {
×
282
            val_ref.map(|s| s.as_str()).collect::<Vec<&str>>()
×
283
          } else {
284
            vec![]
×
285
          };
286

287
        if import_map_path.is_some() {
×
288
          warn!(concat!(
×
289
            "Specifying import_map through flags is no longer supported. ",
×
290
            "Please use deno.json instead."
×
291
          ))
×
292
        }
×
293
        if decorator.is_some() {
×
294
          warn!(concat!(
×
295
            "Specifying decorator through flags is no longer supported. ",
×
296
            "Please use deno.json instead."
×
297
          ))
×
298
        }
×
299

300
        let entrypoint_script_path = sub_matches
×
301
          .get_one::<String>("entrypoint")
×
302
          .cloned()
×
303
          .unwrap();
×
304

×
305
        let entrypoint_script_path =
×
306
          PathBuf::from(entrypoint_script_path.as_str());
×
307
        if !entrypoint_script_path.is_file() {
×
308
          bail!(
×
309
            "entrypoint path does not exist ({})",
×
310
            entrypoint_script_path.display()
×
311
          );
×
312
        }
×
313

×
314
        let entrypoint_script_path =
×
315
          entrypoint_script_path.canonicalize().unwrap();
×
316

×
317
        let mut emitter_factory = EmitterFactory::new();
×
318

×
319
        if sub_matches
×
320
          .get_one::<bool>("disable-module-cache")
×
321
          .cloned()
×
322
          .unwrap()
×
323
        {
×
324
          emitter_factory.set_cache_strategy(Some(CacheSetting::ReloadAll));
×
325
        }
×
326

327
        let maybe_checksum_kind = sub_matches
×
328
          .get_one::<EszipV2ChecksumKind>("checksum")
×
329
          .copied()
×
330
          .and_then(EszipV2ChecksumKind::into);
×
331

×
332
        emitter_factory.set_permissions_options(Some(
×
333
          base::get_default_permissions(WorkerKind::MainWorker),
×
334
        ));
×
335

×
336
        let mut builder =
×
337
          DenoOptionsBuilder::new().entrypoint(entrypoint_script_path.clone());
×
338

339
        if let Some(path) = import_map_path {
×
340
          let path = PathBuf::from(path);
×
341
          if !path.exists() || !path.is_file() {
×
342
            bail!("import map path is incorrect");
×
343
          }
×
344
          builder.set_config(Some(ConfigMode::Path(path)));
×
345
        }
×
346
        emitter_factory.set_deno_options(builder.build()?);
×
347

348
        let mut metadata = Metadata::default();
×
349
        let eszip = generate_binary_eszip(
×
350
          &mut metadata,
×
351
          Arc::new(emitter_factory),
×
352
          None,
×
353
          maybe_checksum_kind,
×
354
          Some(static_patterns),
×
355
        )
×
356
        .await?;
×
357

358
        let bin = eszip.into_bytes();
×
359

×
360
        if output_path == "-" {
×
361
          let stdout = std::io::stdout();
×
362
          let mut handle = stdout.lock();
×
363

×
364
          handle.write_all(&bin)?
×
365
        } else {
366
          let mut file = File::create(output_path.as_str())?;
×
367
          file.write_all(&bin)?
×
368
        }
369

370
        ExitCode::SUCCESS
×
371
      }
372

373
      Some(("unbundle", sub_matches)) => {
×
374
        let output_path =
×
375
          sub_matches.get_one::<String>("output").cloned().unwrap();
×
376
        let eszip_path =
×
377
          sub_matches.get_one::<String>("eszip").cloned().unwrap();
×
378

×
379
        let output_path = PathBuf::from(output_path.as_str());
×
380
        let eszip_path = PathBuf::from(eszip_path.as_str());
×
381

×
382
        if extract_from_file(eszip_path, output_path.clone()).await {
×
383
          println!(
×
384
            "Eszip extracted successfully inside path {}",
×
385
            output_path.to_str().unwrap()
×
386
          );
×
387
        }
×
388

389
        ExitCode::SUCCESS
×
390
      }
391

392
      _ => {
393
        // unrecognized command
394
        ExitCode::FAILURE
×
395
      }
396
    };
397

398
    Ok(exit_code)
×
399
  });
×
400

×
401
  res
×
402
}
×
403

404
fn get_inspector_option(
×
405
  key: &str,
×
406
  addr: &SocketAddr,
×
407
) -> Result<InspectorOption, anyhow::Error> {
×
408
  match key {
×
409
    "inspect" => Ok(InspectorOption::Inspect(*addr)),
×
410
    "inspect-brk" => Ok(InspectorOption::WithBreak(*addr)),
×
411
    "inspect-wait" => Ok(InspectorOption::WithWait(*addr)),
×
412
    key => bail!("invalid inspector key: {}", key),
×
413
  }
414
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc