summaryrefslogtreecommitdiff
path: root/src/luarocks/fs.lua
blob: a8156a21fc93f78facba4a3fb2c6fe884ae21059 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148

--- Proxy module for filesystem and platform abstractions.
-- All code using "fs" code should require "luarocks.fs",
-- and not the various platform-specific implementations.
-- However, see the documentation of the implementation
-- for the API reference.

local pairs = pairs

local fs = {}
-- To avoid a loop when loading the other fs modules.
package.loaded["luarocks.fs"] = fs

local cfg = require("luarocks.core.cfg")

local pack = table.pack or function(...) return { n = select("#", ...), ... } end

math.randomseed(os.time())

local fs_is_verbose = false

do
   local old_popen, old_execute

   -- patch io.popen and os.execute to display commands in verbose mode
   function fs.verbose()
      fs_is_verbose = true

      if old_popen or old_execute then return end
      old_popen = io.popen
      -- luacheck: push globals io os
      io.popen = function(one, two)
         if two == nil then
            print("\nio.popen: ", one)
         else
            print("\nio.popen: ", one, "Mode:", two)
         end
         return old_popen(one, two)
      end

      old_execute = os.execute
      os.execute = function(cmd)
         -- redact api keys if present
         print("\nos.execute: ", (cmd:gsub("(/api/[^/]+/)([^/]+)/", function(cap, key) return cap.."<redacted>/" end)) )
         local a, b, c = old_execute(cmd)
         if type(a) == "boolean" then
            print((a and ".........." or "##########") .. ": " .. tostring(c) .. (b == "exit" and "" or " (" .. tostring(b) .. ")"))
         elseif type(a) == "number" then
            print(((a == 0) and ".........." or "##########") .. ": " .. tostring(a))
         end
         return a, b, c
      end
      -- luacheck: pop
   end
end

do
   local skip_verbose_wrap = {
      ["current_dir"] = true,
   }

   local function load_fns(fs_table, inits)
      for name, fn in pairs(fs_table) do
         if name ~= "init" and not fs[name] then
            if skip_verbose_wrap[name] then
               fs[name] = fn
            else
               fs[name] = function(...)
                  if fs_is_verbose then
                     local args = pack(...)
                     for i=1, args.n do
                        local arg = args[i]
                        local pok, v = pcall(string.format, "%q", arg)
                        args[i] = pok and v or tostring(arg)
                     end
                     print("fs." .. name .. "(" .. table.concat(args, ", ") .. ")")
                  end
                  return fn(...)
               end
            end
         end
      end
      if fs_table.init then
         table.insert(inits, fs_table.init)
      end
   end

   local function load_platform_fns(patt, inits)
      local each_platform = cfg.each_platform

      -- FIXME A quick hack for the experimental Windows build
      if os.getenv("LUAROCKS_CROSS_COMPILING") then
         each_platform = function()
            local i = 0
            local plats = { "linux", "unix" }
            return function()
               i = i + 1
               return plats[i]
            end
         end
      end

      for platform in each_platform("most-specific-first") do
         local ok, fs_plat = pcall(require, patt:format(platform))
         if ok and fs_plat then
            load_fns(fs_plat, inits)
         end
      end
   end

   function fs.init()
      local inits = {}

      if fs.current_dir then
         -- unload luarocks fs so it can be reloaded using all modules
         -- providing extra functionality in the current package paths
         for k, _ in pairs(fs) do
            if k ~= "init" and k ~= "verbose" then
               fs[k] = nil
            end
         end
         for m, _ in pairs(package.loaded) do
            if m:match("luarocks%.fs%.") then
               package.loaded[m] = nil
            end
         end
      end

      -- Load platform-specific functions
      load_platform_fns("luarocks.fs.%s", inits)

      -- Load platform-independent pure-Lua functionality
      load_fns(require("luarocks.fs.lua"), inits)

      -- Load platform-specific fallbacks for missing Lua modules
      load_platform_fns("luarocks.fs.%s.tools", inits)

      -- Load platform-independent external tool functionality
      load_fns(require("luarocks.fs.tools"), inits)

      -- Run platform-specific initializations after everything is loaded
      for _, init in ipairs(inits) do
         init()
      end
   end
end

return fs