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

yast / yast-packager / 15441808734

04 Jun 2025 12:05PM UTC coverage: 37.221% (-0.2%) from 37.407%
15441808734

push

github

web-flow
Merge pull request #659 from yast/huha-no-baseurl-crash

Prevent a crash if a repo doesn't have a baseurl

1 of 1 new or added line in 1 file covered. (100.0%)

123 existing lines in 11 files now uncovered.

4366 of 11730 relevant lines covered (37.22%)

23.4 hits per line

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

26.89
/src/modules/SourceManager.rb
1
require "yast"
1✔
2

3
require "shellwords"
1✔
4
require "y2packager/resolvable"
1✔
5

6
# Yast namespace
7
module Yast
1✔
8
  # Representation of the configuration of source-manager.
9
  # Input and output routines.
10
  class SourceManagerClass < Module
1✔
11
    def main
1✔
12
      Yast.import "UI"
1✔
13
      Yast.import "Pkg"
1✔
14

15
      textdomain "packager"
1✔
16

17
      Yast.import "Progress"
1✔
18
      Yast.import "Report"
1✔
19
      Yast.import "Popup"
1✔
20
      Yast.import "Label"
1✔
21
      Yast.import "Summary"
1✔
22
      Yast.import "HTML"
1✔
23
      Yast.import "Mode"
1✔
24
      Yast.import "URL"
1✔
25
      Yast.import "Linuxrc"
1✔
26
      Yast.import "Installation"
1✔
27
      Yast.import "String"
1✔
28

29
      @newSources = []
1✔
30

31
      @numSources = 0
1✔
32

33
      @sourceStates = []
1✔
34

35
      @sourceStatesIn = []
1✔
36

37
      @sourceStatesOut = []
1✔
38

39
      @url_tokens = {}
1✔
40

41
      @currentUrl = ""
1✔
42

43
      # Sources that are removed in memory but still not in libzypp
44
      # They will be removed in Write() at the end
45
      @just_removed_sources = []
1✔
46

47
      # Data was modified?
48
      @modified = false
1✔
49

50
      @proposal_valid = false
1✔
51
    end
52

53
    # Abort function
54
    # return boolean return true if abort
55
    def AbortFunction
1✔
56
      false
×
57
    end
58

59
    # Abort function
60
    # @return [Boolean] return true if abort
61
    def Abort
1✔
62
      return false if fun_ref(method(:AbortFunction), "boolean ()").nil?
×
63

64
      AbortFunction()
×
65
    end
66

67
    # Data was modified?
68
    # @return true if modified
69
    def Modified
1✔
70
      Builtins.y2debug("modified=%1", @modified)
×
71
      # return modified;
72
      @sourceStatesIn != @sourceStatesOut
×
73
    end
74

75
    def ReadSources
1✔
76
      success = Pkg.SourceStartManager(false)
×
77
      return success if !success
×
78

79
      @sourceStates = Pkg.SourceStartCache(false)
×
80
      @sourceStatesIn = Pkg.SourceEditGet
×
81
      @sourceStatesOut = deep_copy(@sourceStatesIn)
×
82
      true
×
83
    end
84

85
    # Read all source-manager settings
86
    # @return true on success
87
    def Read
1✔
88
      # SourceManager read dialog caption
89
      caption = _("Initializing Available Repositories")
×
90

91
      steps = 2
×
92

93
      # We do not set help text here, because it was set outside
94
      Progress.New(
×
95
        caption,
96
        " ",
97
        steps,
98
        [
99
          # Progress stage 1/3
100
          _("Read configured repositories"),
101
          # Progress stage 2/3
102
          _("Detect available repositories via SLP")
103
        ],
104
        [
105
          # Progress step 1/3
106
          _("Reading configured repositories..."),
107
          # Progress step 2/3
108
          _("Detecting available repositories..."),
109
          # Progress finished
110
          _("Finished")
111
        ],
112
        ""
113
      )
114

115
      # read database
116
      return false if Abort()
×
117

118
      Progress.NextStage
×
119

120
      # Error message
121
      Report.Error(_("Cannot read repositories.")) if !ReadSources()
×
122

123
      # read another database
124
      return false if Abort()
×
125

126
      Progress.NextStep
×
127

128
      return false if Abort()
×
129

130
      # Progress finished
131
      Progress.NextStage
×
132

133
      return false if Abort()
×
134

135
      @modified = false
×
136
      true
×
137
    end
138

139
    # Commit changed repositories
140
    def CommitSources
1✔
141
      Builtins.y2debug("In: %1  Out: %2", @sourceStatesIn, @sourceStatesOut)
×
142
      success = false
×
143
      loop do
×
144
        success = Pkg.SourceEditSet(@sourceStatesOut)
×
145
        break if success
×
146

147
        # popup message header
148
        message1 = _("Unable to save changes to the repository.\n")
×
149
        # popup message, after message header, header of details
150
        message2 = Ops.add(_("Details:") + "\n", Pkg.LastError)
×
151
        # end of popup message, question
152
        message2 = Ops.add(Ops.add(message2, "\n"), _("Try again?"))
×
153

154
        tryagain = Popup.YesNo(Ops.add(Ops.add(message1, "\n"), message2))
×
155
        break if !tryagain
×
156
      end
157
      success
×
158
    end
159

160
    # Write all repository-manager settings
161
    # @return true on success
162
    def Write
1✔
163
      # SourceManager read dialog caption
164
      caption = _("Saving Repository Configuration")
×
165

166
      steps = 1
×
167

168
      # We do not set help text here, because it was set outside
169
      Progress.New(
×
170
        caption,
171
        " ",
172
        steps,
173
        [
174
          # Progress stage 1/1
175
          _("Write repository settings")
176
        ],
177
        [
178
          # Progress step 1/1
179
          _("Writing the settings..."),
180
          # Progress finished
181
          _("Finished")
182
        ],
183
        ""
184
      )
185

186
      # write settings
187
      return false if Abort()
×
188

189
      Progress.NextStage
×
190
      # Error message
191

192
      exit = CommitSources()
×
193

194
      return false if Abort()
×
195

196
      # Progress finished
197
      Progress.NextStage
×
198

199
      return false if Abort()
×
200

201
      exit
×
202
    end
203

204
    # Get all repository-manager settings from the first parameter
205
    # (For use by autoinstallation.)
206
    # @param [Hash] _settings The YCP structure to be imported.
207
    # @return [Boolean] True on success
208
    def Import(_settings)
1✔
209
      true
×
210
    end
211

212
    # Dump the repository-manager settings to a single map
213
    # (For use by autoinstallation.)
214
    # @return [Hash] Dumped settings (later acceptable by Import ())
215
    def Export
1✔
216
      {}
×
217
    end
218

219
    # Get Repository ID by index
220
    def GetSrcIdByIndex(idx)
1✔
221
      Ops.get_integer(@sourceStatesOut, [idx, "SrcId"], -1)
×
222
    end
223

224
    # Set current used repository URL by index
225
    def SetUrlByIndex(idx)
1✔
226
      src_id = Ops.get_integer(@sourceStatesOut, [idx, "SrcId"], -1)
×
227
      @currentUrl = Ops.get_string(Pkg.SourceGeneralData(src_id), "url", "")
×
UNCOV
228
      nil
×
229
    end
230

231
    # Get Repository ID when only URL is known
232
    def getSourceId(url)
1✔
233
      @numSources = Builtins.size(@sourceStatesOut)
×
234
      i = 0
×
235
      id = -1
×
236
      while Ops.less_than(i, @numSources)
×
237
        generalData = Pkg.SourceGeneralData(
×
238
          Ops.get_integer(@sourceStatesOut, [i, "SrcId"], -1)
239
        )
240
        if Ops.get_string(generalData, "url", "") == url
×
241
          id = Ops.get_integer(@sourceStatesOut, [i, "SrcId"], -1)
×
242
          break
×
243
        end
244

245
        i = Ops.add(i, 1)
×
246
      end
247

248
      id
×
249
    end
250

251
    # Gather Repository Metadata
252
    def SourceData(source)
1✔
253
      g = Pkg.SourceGeneralData(source)
×
254
      Builtins.y2milestone("generalData: %1", g)
×
255
      p = Pkg.SourceProductData(source)
×
256
      p = {} if p.nil?
×
257

258
      Builtins.y2milestone("productData: %1", p)
×
259
      Builtins.union(g, p)
×
260
    end
261

262
    # Create a repository from an URL
263
    def createSource(url)
1✔
264
      return :cancel if url == ""
×
265

266
      if !Mode.commandline
×
267
        UI.OpenDialog(
×
268
          VBox(VSpacing(0.2), Label(_("Adding repository...")), VSpacing(0.2))
269
        )
270
      end
271
      @newSources = Pkg.SourceScan(url, "")
×
272

273
      UI.CloseDialog if !Mode.commandline
×
274

275
      # Pkg.SourceScan can return Array with repos or -1 if failed. So be more
276
      # paranoid here and accept only non empty list as success result.
277
      if !@newSources.is_a?(::Array) || @newSources.empty?
×
278
        message1 = Builtins.sformat(
×
279
          _("Unable to create repository\nfrom URL '%1'."),
280
          URL.HidePassword(url)
281
        )
282

283
        message2 = Ops.add(_("Details:") + "\n", Pkg.LastError)
×
284
        # end of popup message, question
285
        message2 = Ops.add(Ops.add(message2, "\n"), _("Try again?"))
×
286

287
        tryagain = Popup.YesNo(Ops.add(Ops.add(message1, "\n"), message2))
×
288
        if tryagain
×
289
          :again
×
290
        else
291
          :cancel
×
292
        end
293
      else
294
        ul_sources = Builtins.filter(@newSources) do |s|
×
295
          src_data = Pkg.SourceGeneralData(s)
×
296
          src_type = Ops.get_string(src_data, "type", "")
×
297
          src_type == "YaST"
×
298
        end
299
        if Builtins.size(ul_sources).zero? && !Popup.AnyQuestion(
×
300
          Popup.NoHeadline,
301
          # continue-back popup
302
          _(
303
            "There is no product information available at the given location.\n" \
304
            "If you expected to to point a product, go back and enter\n" \
305
            "the correct location.\n" \
306
            "To make rpm packages located at the specified location available\n" \
307
            "in the packages selection, continue.\n"
308
          ),
309
          Label.ContinueButton,
310
          Label.BackButton,
311
          :focus_yes
312
        )
313
          return :again
×
314
        end
315

316
        Builtins.foreach(@newSources) do |id|
×
317
          sourceState = { "SrcId" => id, "enabled" => true }
×
318
          @sourceStatesOut = Builtins.add(@sourceStatesOut, sourceState)
×
319
        end
320
        :ok
×
321
      end
322
    end
323

324
    # Delete repository by Repository ID
325
    def deleteSourceBySrcId(src_id)
1✔
326
      Builtins.y2debug("removing repository: %1 %2", src_id, @sourceStatesOut)
×
327
      @numSources = Builtins.size(@sourceStatesOut)
×
328
      i = 0
×
329

330
      while Ops.less_than(i, @numSources)
×
331
        if Ops.get_integer(@sourceStatesOut, [i, "SrcId"], -1) == src_id
×
332
          @sourceStatesOut = Builtins.remove(@sourceStatesOut, i)
×
333
          break
×
334
        end
335

336
        i = Ops.add(i, 1)
×
337
      end
UNCOV
338
      nil
×
339
    end
340

341
    # Delete Repository by the repository index
342
    def deleteSourceByIndex(idx)
1✔
343
      @sourceStatesOut = Builtins.remove(@sourceStatesOut, idx)
×
UNCOV
344
      nil
×
345
    end
346

347
    # Delete Repository by repository URL
348
    def deleteSourceByUrl(url)
1✔
349
      deleteSourceBySrcId(getSourceId(url))
×
UNCOV
350
      nil
×
351
    end
352

353
    # Create Summary Item
354
    def createItem(_index, source)
1✔
355
      source = deep_copy(source)
×
356
      id = Ops.get_integer(source, "SrcId", 0)
×
357
      generalData = Pkg.SourceGeneralData(id)
×
358
      productData = Pkg.SourceProductData(id)
×
359
      sitem = ""
×
360
      # status info, to be used inside summary
361
      status = Ops.get_boolean(source, "enabled", true) ? _("Enabled") : _("Disabled")
×
362
      color = Ops.get_boolean(source, "enabled", true) ? "#006600" : "#FF0000"
×
363
      sitem = Ops.add(
×
364
        sitem,
365
        HTML.Colorize(Ops.add(Ops.add("[", status), "] "), color)
366
      )
367
      # translators: name of a repository if no other idenfication found
368
      sitem = Ops.add(
×
369
        sitem,
370
        Ops.get_locale(
371
          productData,
372
          "label",
373
          Ops.get_locale(generalData, "type", _("unknown"))
374
        )
375
      )
376
      Ops.add(
×
377
        Ops.add(Ops.add(sitem, " ( "), Ops.get_string(generalData, "url", "")),
378
        ")"
379
      )
380
    end
381

382
    # Create Repository Item for Overview
383
    def createOverviewItem(index, source)
1✔
384
      source = deep_copy(source)
×
385
      id = Ops.get_integer(source, "SrcId", 0)
×
386
      generalData = Pkg.SourceGeneralData(id)
×
387
      productData = Pkg.SourceProductData(id)
×
388

389
      item = Item(
×
390
        Id(index),
391
        # corresponds to the "Enable/Disable" button
392
        Ops.get_boolean(source, "enabled", true) ? _("On") : _("Off"),
×
393
        Ops.get_locale(
394
          productData,
395
          "label",
396
          Ops.get_locale(generalData, "type", _("Unknown"))
397
        ),
398
        Ops.get_string(generalData, "url", "")
399
      )
400

401
      deep_copy(item)
×
402
    end
403

404
    # Handle Multiple repositories URLs (order/instorder)
405
    def HandleMultipleSources(url)
1✔
406
      Pkg.SourceStartManager(false)
×
407
      initial_source = Ops.get(Pkg.SourceScan(url, ""), 0)
×
408
      if initial_source.nil?
×
409
        Builtins.y2error("No repository in '%1'", url)
×
410
        return false
×
411
      end
412

413
      false
×
414
    end
415

416
    # Create a textual summary and a list of unconfigured cards
417
    # @return summary of the current configuration
418
    def Summary
1✔
419
      summary = ""
×
420
      # summary header
421
      summary = Summary.AddHeader(summary, _("Configured Repositories"))
×
422
      summary = Summary.OpenList(summary)
×
423
      @numSources = Builtins.size(@sourceStatesOut)
×
424
      i = 0
×
425
      while Ops.less_than(i, @numSources)
×
426
        summary = Summary.AddListItem(
×
427
          summary,
428
          createItem(i, Ops.get(@sourceStatesOut, i, {}))
429
        )
430
        i = Ops.add(i, 1)
×
431
      end
432
      summary = Summary.CloseList(summary)
×
433

434
      [summary, []]
×
435
    end
436

437
    # Create an overview table with all configured cards
438
    # @return table items
439
    def Overview
1✔
440
      @numSources = Builtins.size(@sourceStatesOut)
×
441
      i = 0
×
442
      source_overview = []
×
443
      while Ops.less_than(i, @numSources)
×
444
        source_overview = Builtins.add(
×
445
          source_overview,
446
          createOverviewItem(i, Ops.get(@sourceStatesOut, i, {}))
447
        )
448
        i = Ops.add(i, 1)
×
449
      end
450
      deep_copy(source_overview)
×
451
    end
452

453
    # Parse a URL query (already unescaped) to a map.
454
    # If no equal sign, the value will be nil.
455
    # @param [String] query foo=bar&baz=qux
456
    # @return [Hash] hash with "param" => "value" mapping,
457
    #    e.g. ["foo": "bar", "baz": "qux"]
458
    def ParseUrlQuery(query)
1✔
459
      q_items = Builtins.splitstring(query, "&")
×
460
      q_map = Builtins.listmap(q_items) do |q_item|
×
461
        eqpos = Builtins.search(q_item, "=")
×
462
        if eqpos.nil?
×
463
          { q_item => nil }
×
464
        else
465
          key = Builtins.substring(q_item, 0, eqpos)
×
466
          val = Builtins.substring(q_item, Ops.add(eqpos, 1))
×
467
          { key => val }
×
468
        end
469
      end
470
      deep_copy(q_map)
×
471
    end
472

473
    # @param [String] attr SourceGeneralData item
474
    # @return For existing repositories, get a mapping from an attribute to the id
475
    def get_attr_to_id(attr)
1✔
476
      src_ids = Pkg.SourceGetCurrent(
×
477
        false # enabled only?
478
      )
479
      a2i = Builtins.listmap(src_ids) do |src_id|
×
480
        gendata = Pkg.SourceGeneralData(src_id)
×
481
        alias_name = Ops.get_string(gendata, attr, "")
×
482
        { alias_name => src_id }
×
483
      end
484
      deep_copy(a2i)
×
485
    end
486

487
    # @return For existing repositories, get a mapping from the alias to the id
488
    def get_alias_to_id
1✔
489
      get_attr_to_id("alias")
×
490
    end
491

492
    # @return For existing repositories, get a mapping from the URL to the id
493
    def get_url_to_id
1✔
494
      get_attr_to_id("url")
×
495
    end
496

497
    # Extract an alias parameter from the URL and check whether we have
498
    # such a repository already.
499
    # @param [String] url a repository with an alias parameter (actually optional)
500
    # @param [Hash{String => Fixnum}] alias_to_id a premade mapping, @see get_alias_to_id
501
    # @return the repository id or -1
502
    def SourceByAliasOrUrl(url, alias_to_id, url_to_id)
1✔
503
      alias_to_id = deep_copy(alias_to_id)
×
504
      url_to_id = deep_copy(url_to_id)
×
505
      # parse the URL
506
      parsed_url = URL.Parse(url)
×
507
      Builtins.y2milestone("parsed: %1", parsed_url)
×
508
      # (reassemble and warn if it differs)
509
      reassembled = URL.Build(parsed_url)
×
510
      Builtins.y2warning("reassembled differs: %1", reassembled) if url != reassembled
×
511
      # get the alias
512
      q_map = ParseUrlQuery(Ops.get_string(parsed_url, "query", ""))
×
513
      Builtins.y2milestone("query: %1", q_map)
×
514
      alias_name = Ops.get(q_map, "alias", "")
×
515

516
      # (empty: box safeguard)
517
      if alias_name != "" && Builtins.haskey(alias_to_id, alias_name)
×
518
        return Ops.get(alias_to_id, alias_name, -1)
×
519
      end
520

521
      # #188572: if no match by alias, try url
522
      Ops.get(url_to_id, url, -1)
×
523
    end
524

525
    # Used by registration. ZMD sync has been disabled - ZLM7.3 on sle11 supports
526
    # only HTTP and FTP repositories, sync would fail for other types.
527
    # See bnc#480845 for more details.
528
    #
529
    # @param [Array<String>] urls URLs to add
530
    # @return a list of added URLs
531
    def AddUpdateSources(urls)
1✔
532
      urls = deep_copy(urls)
×
533
      ret = []
×
534

535
      # prepare for lookup of known aliases
536
      aliases = get_alias_to_id
×
537
      Builtins.y2milestone("alias mapping: %1", aliases)
×
538
      by_url = get_url_to_id
×
539
      Builtins.y2milestone("url mapping: %1", by_url)
×
540

541
      # add the repositories
542
      # but do not make duplicates (#168740)
543
      # we detect them based on alias that suse_register gives us (#158850#c17)
544
      # / (but only for SLE... :-/ )
545
      # / Need to test what happens when we get two different update
546
      # / servers for SL
547
      # / Anyway that means only that #168740 remains unfixed for SL
548
      Builtins.foreach(urls) do |url|
×
549
        Builtins.y2milestone("Should add an update repository: %1", url)
×
550
        # inst_addon_update_sources also calls Pkg::SourceCreate
551
        # but it already skips duplicates
552

553
        # check if alias already there
554
        # if yes, delete the old one
555
        todel = SourceByAliasOrUrl(url, aliases, by_url)
×
556
        if todel != -1
×
557
          Builtins.y2milestone("deleting the old copy, repository %1", todel)
×
558
          Pkg.SourceDelete(todel)
×
559
        end
560
        # then add the new one
561
        Builtins.y2milestone("Adding update repository...")
×
562
        toadd = Pkg.SourceCreate(url, "/")
×
563
        # adding failed, try http fallback for ftp repo (#227059)
564
        if toadd.nil? || Ops.less_than(toadd, 0)
×
565
          parsed_url = URL.Parse(url)
×
566
          scheme = Ops.get_string(parsed_url, "scheme", "")
×
567

568
          if Builtins.tolower(scheme) == "ftp"
×
569
            Builtins.y2milestone(
×
570
              "Cannot add FTP update repository, trying HTTP..."
571
            )
572

573
            Ops.set(parsed_url, "scheme", "http")
×
574
            fallback_url = URL.Build(parsed_url)
×
575

576
            toadd = Pkg.SourceCreate(fallback_url, "/")
×
577
            url = fallback_url
×
578
          end
579
        end
580
        if toadd != -1 && !toadd.nil?
×
581
          ret = Builtins.add(ret, url) # #180820#c26
×
582

583
          # is there any patch available?
584
          patches = Y2Packager::Resolvable.find(kind: :patch)
×
585

586
          if Ops.greater_than(Builtins.size(patches), 0)
×
587
            # loaded target is required to get list of applicable patches (#270919)
588
            Builtins.y2milestone(
×
589
              "Repository %1 provides %2 patches, loading target...",
590
              url,
591
              Builtins.size(patches)
592
            )
593
            # suppose that we are running in an installed system and use "/" directory
594
            Pkg.TargetInitialize("/")
×
595
            Pkg.TargetLoad
×
596
          end
597
        end
598
      end
599

600
      deep_copy(ret)
×
601
    end
602

603
    def AskForCD(message)
1✔
604
      cdroms = SCR.Read(path(".probe.cdrom"))
×
605
      multiple_drives = (cdroms.size > 1)
×
606
      drives_sel = Empty()
×
607
      if multiple_drives
×
608
        devices = cdroms.map do |d|
×
609
          Item(Id(d["dev_name"] || ""), "#{d["model"]} (#{d["dev_name"]})")
×
610
        end
611
        # To adjust the width of the dialog, look for the more lengthy device label
612
        # (and add some extra space for the frame)
613
        min_width = devices.map { |d| d[1].to_s.size }.max + 4
×
614
        drives_sel = MinSize(min_width, 5, SelectionBox(Id(:drives), _("&Drive to eject"), devices))
×
615
      end
616
      contents = HBox(
×
617
        HSpacing(1),
618
        VBox(
619
          VSpacing(0.5),
620
          Label(message),
621
          VSpacing(0.5),
622
          drives_sel,
623
          VSpacing(0.5),
624
          HBox(
625
            HStretch(),
626
            HWeight(1, PushButton(Id(:cont), Label.ContinueButton)),
627
            HWeight(1, PushButton(Id(:cancel), Label.CancelButton)),
628
            HWeight(1, PushButton(Id(:eject), _("&Eject"))),
629
            HStretch()
630
          ),
631
          VSpacing(0.5)
632
        ),
633
        HSpacing(1)
634
      )
635
      UI.OpenDialog(contents)
×
636
      if multiple_drives
×
637
        UI.ChangeWidget(
×
638
          Id(:drives),
639
          :CurrentItem,
640
          Ops.get_string(cdroms, [0, "dev_name"], "")
641
        )
642
      end
643
      UI.SetFocus(Id(:cont))
×
644
      ret = nil
×
645
      loop do
×
646
        ret = Convert.to_symbol(UI.UserInput)
×
647
        break if [:cont, :cancel].include?(ret)
×
648

649
        if ret == :eject
×
650
          if multiple_drives
×
651
            device = Convert.to_string(UI.QueryWidget(Id(:drives), :Value))
×
652
            SCR.Execute(
×
653
              path(".target.bash"),
654
              "/usr/bin/eject #{device.shellescape}"
655
            )
656
          else
657
            SCR.Execute(
×
658
              path(".target.bash"),
659
              Builtins.sformat(
660
                "/usr/bin/eject %1",
661
                Ops.get_string(cdroms, [0, "dev_name"], "").shellescape
662
              )
663
            )
664
          end
665
        end
666
        ret = nil
×
667
      end
668

669
      result = { "continue" => ret == :cont }
×
670

671
      if multiple_drives
×
672
        result = Builtins.add(
×
673
          result,
674
          "device",
675
          Convert.to_string(UI.QueryWidget(Id(:drives), :Value))
676
        )
677
      end
678

679
      UI.CloseDialog
×
680

681
      deep_copy(result)
×
682
    end
683

684
    # Function returns the partiton name which is used as a repository for the installation
685
    # (IF any partition is used as a repository for installation, of course).
686
    # Otherwise it returns an empty string "". See bugzilla #208222 for more information.
687
    #
688
    # @return [String] partition name
689
    def InstallationSourceOnPartition
1✔
690
      install_mode = Linuxrc.InstallInf("InstMode")
×
691

692
      # Hard Disk is used for the installation
693
      if install_mode == "hd"
×
694
        install_partition = Linuxrc.InstallInf("Partition")
×
695

696
        # No partiton is defined - error
697
        if install_partition == "" || install_partition.nil?
×
698
          Builtins.y2error(
×
699
            "Despite the fact that the install-mode is '%1', install-partition is '%2'",
700
            install_mode,
701
            install_partition
702
          )
703
          ""
×
704
        else
705
          install_partition
×
706
        end
707
      else
708
        ""
×
709
      end
710
    end
711

712
    # Finds the biggest temporary directory and uses it as
713
    # packager download area.
714
    def InstInitSourceMoveDownloadArea
1✔
715
      spaces = Pkg.TargetGetDU
×
716
      root_info = Ops.get_list(
×
717
        spaces,
718
        "/tmp",
719
        Ops.get_list(spaces, "/tmp/", Ops.get_list(spaces, "/", []))
720
      )
721
      total = Ops.get_integer(root_info, 0, 0)
×
722
      current = Ops.get_integer(root_info, 1, 0)
×
723
      future = Ops.get_integer(root_info, 2, 0)
×
724
      future = current if Ops.less_than(future, current)
×
725
      tmp_space = Ops.subtract(total, future)
×
726
      # no temp space left or read-only
727
      tmp_space = 0 if Ops.less_than(tmp_space, 0) || Ops.get_integer(root_info, 3, 1) == 1
×
728

729
      var_info = Ops.get_list(
×
730
        spaces,
731
        "/var/tmp",
732
        Ops.get_list(
733
          spaces,
734
          "/var/tmp/",
735
          Ops.get_list(
736
            spaces,
737
            "/var",
738
            Ops.get_list(spaces, "/var/", Ops.get_list(spaces, "/", []))
739
          )
740
        )
741
      )
742
      total = Ops.get_integer(var_info, 0, 0)
×
743
      current = Ops.get_integer(var_info, 1, 0)
×
744
      future = Ops.get_integer(var_info, 2, 0)
×
745
      future = current if Ops.less_than(future, current)
×
746
      var_tmp_space = Ops.subtract(total, future)
×
747
      # no temp space left or read-only
748
      var_tmp_space = 0 if Ops.less_than(var_tmp_space, 0) || Ops.get_integer(var_info, 3, 1) == 1
×
749

750
      #-------
751
      # /tmp or /var/tmp ?
752

753
      download_dir = Ops.greater_than(tmp_space, var_tmp_space) ? "/tmp" : "/var/tmp"
×
754
      download_dir = Ops.add(Installation.destdir, download_dir)
×
755
      # TODO: check the size of the largest package on CD1
756
      successful = SCR.Execute(
×
757
        path(".target.bash"),
758
        "/usr/bin/mkdir -p #{download_dir.shellescape}"
759
      )
760
      if successful.zero?
×
761
        Pkg.SourceMoveDownloadArea(download_dir)
×
762
      else
763
        Builtins.y2error("Unable to create %1 directory", download_dir)
×
764
      end
765

UNCOV
766
      nil
×
767
    end
768

769
    publish variable: :newSources, type: "list <integer>"
1✔
770
    publish variable: :numSources, type: "integer"
1✔
771
    publish variable: :sourceStates, type: "list <integer>"
1✔
772
    publish variable: :sourceStatesIn, type: "list <map <string, any>>"
1✔
773
    publish variable: :sourceStatesOut, type: "list <map <string, any>>"
1✔
774
    publish variable: :url_tokens, type: "map"
1✔
775
    publish variable: :currentUrl, type: "string"
1✔
776
    publish variable: :just_removed_sources, type: "list <integer>"
1✔
777
    publish function: :Modified, type: "boolean ()"
1✔
778
    publish function: :createSource, type: "symbol (string)"
1✔
779
    publish variable: :modified, type: "boolean"
1✔
780
    publish variable: :proposal_valid, type: "boolean"
1✔
781
    publish function: :AbortFunction, type: "boolean ()"
1✔
782
    publish function: :Abort, type: "boolean ()"
1✔
783
    publish function: :ReadSources, type: "boolean ()"
1✔
784
    publish function: :Read, type: "boolean ()"
1✔
785
    publish function: :CommitSources, type: "boolean ()"
1✔
786
    publish function: :Write, type: "boolean ()"
1✔
787
    publish function: :Import, type: "boolean (map)"
1✔
788
    publish function: :Export, type: "map ()"
1✔
789
    publish function: :GetSrcIdByIndex, type: "integer (integer)"
1✔
790
    publish function: :SetUrlByIndex, type: "void (integer)"
1✔
791
    publish function: :getSourceId, type: "integer (string)"
1✔
792
    publish function: :SourceData, type: "map (integer)"
1✔
793
    publish function: :deleteSourceBySrcId, type: "void (integer)"
1✔
794
    publish function: :deleteSourceByIndex, type: "void (integer)"
1✔
795
    publish function: :deleteSourceByUrl, type: "void (string)"
1✔
796
    publish function: :Summary, type: "list ()"
1✔
797
    publish function: :Overview, type: "list ()"
1✔
798
    publish function: :AddUpdateSources, type: "list <string> (list <string>)"
1✔
799
    publish function: :AskForCD, type: "map <string, any> (string)"
1✔
800
    publish function: :InstallationSourceOnPartition, type: "string ()"
1✔
801
    publish function: :InstInitSourceMoveDownloadArea, type: "void ()"
1✔
802
  end
803

804
  SourceManager = SourceManagerClass.new
1✔
805
  SourceManager.main
1✔
806
end
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

© 2025 Coveralls, Inc