Merge branch 'timestamp-restorer' into 'master'
chore: Speed up compilation in CI See merge request mythic-insight/legendary!51
This commit is contained in:
		
						commit
						ef1728815b
					
				
					 5 changed files with 98 additions and 4 deletions
				
			
		| 
						 | 
					@ -1,5 +1,3 @@
 | 
				
			||||||
_build
 | 
					 | 
				
			||||||
deps
 | 
					 | 
				
			||||||
cover
 | 
					cover
 | 
				
			||||||
.elixir_ls
 | 
					.elixir_ls
 | 
				
			||||||
*.dump
 | 
					*.dump
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,10 @@ variables:
 | 
				
			||||||
test:
 | 
					test:
 | 
				
			||||||
  stage: test
 | 
					  stage: test
 | 
				
			||||||
  image: "elixir:1.10"
 | 
					  image: "elixir:1.10"
 | 
				
			||||||
 | 
					  cache:
 | 
				
			||||||
 | 
					    paths:
 | 
				
			||||||
 | 
					      - _build/
 | 
				
			||||||
 | 
					      - deps/
 | 
				
			||||||
  services:
 | 
					  services:
 | 
				
			||||||
  - name: postgres:12
 | 
					  - name: postgres:12
 | 
				
			||||||
  script: script/cibuild
 | 
					  script: script/cibuild
 | 
				
			||||||
| 
						 | 
					@ -27,9 +31,14 @@ build_image_for_commit:
 | 
				
			||||||
  image: "docker:20.10"
 | 
					  image: "docker:20.10"
 | 
				
			||||||
  only:
 | 
					  only:
 | 
				
			||||||
    - master
 | 
					    - master
 | 
				
			||||||
 | 
					  cache:
 | 
				
			||||||
 | 
					    paths:
 | 
				
			||||||
 | 
					      - _build/
 | 
				
			||||||
 | 
					      - deps/
 | 
				
			||||||
  services:
 | 
					  services:
 | 
				
			||||||
    - name: docker:20.10-dind
 | 
					    - name: docker:20.10-dind
 | 
				
			||||||
  script:
 | 
					  script:
 | 
				
			||||||
 | 
					    - script/ci/restore-timestamps
 | 
				
			||||||
    - docker login "https://${CI_REGISTRY}" -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD
 | 
					    - docker login "https://${CI_REGISTRY}" -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD
 | 
				
			||||||
    - docker pull $CI_REGISTRY_IMAGE:latest || true
 | 
					    - docker pull $CI_REGISTRY_IMAGE:latest || true
 | 
				
			||||||
    # This enables fast parallel builds
 | 
					    # This enables fast parallel builds
 | 
				
			||||||
| 
						 | 
					@ -38,6 +47,9 @@ build_image_for_commit:
 | 
				
			||||||
    # Push the commit SHA tagged version to registry. We will later choose to tag that as stable
 | 
					    # Push the commit SHA tagged version to registry. We will later choose to tag that as stable
 | 
				
			||||||
    #   if everything passes.
 | 
					    #   if everything passes.
 | 
				
			||||||
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
 | 
					    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
 | 
				
			||||||
 | 
					    # Pull out the built _build/prod directory so we can cache it!
 | 
				
			||||||
 | 
					    - docker cp `docker create $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA`:/root/app/_build/prod _build
 | 
				
			||||||
 | 
					    - script/ci/restore-timestamps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# If tests pass, tag the commit and update package versions
 | 
					# If tests pass, tag the commit and update package versions
 | 
				
			||||||
deploy_to_tags:
 | 
					deploy_to_tags:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,16 +26,18 @@ ADD ./apps/admin/mix.exs /root/app/apps/admin/
 | 
				
			||||||
ADD ./apps/app/mix.exs /root/app/apps/app/
 | 
					ADD ./apps/app/mix.exs /root/app/apps/app/
 | 
				
			||||||
ADD ./apps/content/mix.exs /root/app/apps/content/
 | 
					ADD ./apps/content/mix.exs /root/app/apps/content/
 | 
				
			||||||
ADD ./apps/core/mix.exs /root/app/apps/core/
 | 
					ADD ./apps/core/mix.exs /root/app/apps/core/
 | 
				
			||||||
 | 
					ADD ./_build/ /root/app/_build/
 | 
				
			||||||
 | 
					ADD ./deps/ /root/app/deps/
 | 
				
			||||||
RUN mix deps.get
 | 
					RUN mix deps.get
 | 
				
			||||||
RUN mix deps.compile
 | 
					RUN mix deps.compile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ADD ./apps /root/app/apps
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Leave off here so that we can built assets and compile the elixir app in parallel
 | 
					# Leave off here so that we can built assets and compile the elixir app in parallel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM node:15.0
 | 
					FROM node:15.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Build assets in a node container
 | 
					# Build assets in a node container
 | 
				
			||||||
 | 
					ADD ./apps/app/assets/ /root/app/apps/app/assets/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
WORKDIR /root/app/apps/app/assets/
 | 
					WORKDIR /root/app/apps/app/assets/
 | 
				
			||||||
COPY --from=0 /root/app/ /root/app/
 | 
					COPY --from=0 /root/app/ /root/app/
 | 
				
			||||||
RUN npm install
 | 
					RUN npm install
 | 
				
			||||||
| 
						 | 
					@ -43,6 +45,8 @@ RUN npm run deploy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FROM elixir1
 | 
					FROM elixir1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ADD ./apps /root/app/apps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Resume compilation of the elixir app
 | 
					# Resume compilation of the elixir app
 | 
				
			||||||
ADD ./script /root/app/script
 | 
					ADD ./script /root/app/script
 | 
				
			||||||
RUN MAKE=cmake mix compile
 | 
					RUN MAKE=cmake mix compile
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										76
									
								
								script/ci/restore-timestamps
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										76
									
								
								script/ci/restore-timestamps
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,76 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env elixir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					defmodule TimestampRestorer do
 | 
				
			||||||
 | 
					  @environment System.get_env("MIX_ENV", "dev")
 | 
				
			||||||
 | 
					  @db_path "_build/#{@environment}/timestamp-database"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def sha_all do
 | 
				
			||||||
 | 
					    timestamp_database = load_timestamp_database()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    "**/*.{ex,exs,beam}"
 | 
				
			||||||
 | 
					    |> Path.wildcard()
 | 
				
			||||||
 | 
					    |> Enum.reduce(%{}, fn filename, acc ->
 | 
				
			||||||
 | 
					      {sha, timestamp} = process(filename, timestamp_database)
 | 
				
			||||||
 | 
					      Map.put(acc, sha, timestamp)
 | 
				
			||||||
 | 
					    end)
 | 
				
			||||||
 | 
					    |> write_timestamp_database()
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp load_timestamp_database() do
 | 
				
			||||||
 | 
					    if File.exists?(@db_path) do
 | 
				
			||||||
 | 
					      @db_path
 | 
				
			||||||
 | 
					      |> File.read!()
 | 
				
			||||||
 | 
					      |> String.split("\n")
 | 
				
			||||||
 | 
					      |> Enum.reduce(%{}, fn line, acc ->
 | 
				
			||||||
 | 
					        [sha, timestamp_string] = String.split(line, ":")
 | 
				
			||||||
 | 
					        {timestamp, ""} = Integer.parse(timestamp_string)
 | 
				
			||||||
 | 
					        Map.put(acc, sha, timestamp)
 | 
				
			||||||
 | 
					      end)
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      %{}
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp write_timestamp_database(database) do
 | 
				
			||||||
 | 
					    File.mkdir_p!(Path.dirname(@db_path))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    database
 | 
				
			||||||
 | 
					    |> Enum.map(fn {key, value} -> "#{key}:#{value}" end)
 | 
				
			||||||
 | 
					    |> Enum.join("\n")
 | 
				
			||||||
 | 
					    |> (& File.write!(@db_path, &1)).()
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp process(filename, timestamp_database) do
 | 
				
			||||||
 | 
					    sha = sha(filename)
 | 
				
			||||||
 | 
					    {:ok, %{mtime: new_timestamp}} = File.lstat(filename, time: :posix)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    case Map.get(timestamp_database, sha) do
 | 
				
			||||||
 | 
					      nil ->
 | 
				
			||||||
 | 
					        :logger.debug("[NEW SHA  ] #{filename}: #{new_timestamp}")
 | 
				
			||||||
 | 
					      timestamp when timestamp < new_timestamp ->
 | 
				
			||||||
 | 
					        :logger.debug("[RESTORED ] #{filename}: #{timestamp}")
 | 
				
			||||||
 | 
					        File.touch(filename, timestamp)
 | 
				
			||||||
 | 
					      timestamp when timestamp >= new_timestamp ->
 | 
				
			||||||
 | 
					        :logger.debug("[UNCHANGED] #{filename}: #{timestamp}")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {sha, new_timestamp}
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  defp sha(filename) do
 | 
				
			||||||
 | 
					    hash_ref = :crypto.hash_init(:sha)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    File.stream!(filename)
 | 
				
			||||||
 | 
					    |> Enum.reduce(hash_ref, fn chunk, prev_ref->
 | 
				
			||||||
 | 
					      new_ref = :crypto.hash_update(prev_ref, chunk)
 | 
				
			||||||
 | 
					      new_ref
 | 
				
			||||||
 | 
					    end)
 | 
				
			||||||
 | 
					    |> :crypto.hash_final()
 | 
				
			||||||
 | 
					    |> Base.encode16()
 | 
				
			||||||
 | 
					    |> String.downcase()
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					{time, _result} = :timer.tc(TimestampRestorer, :sha_all, [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:logger.info("Restored timestamps in #{time / 1_000_000}s")
 | 
				
			||||||
| 
						 | 
					@ -6,8 +6,12 @@ set -e
 | 
				
			||||||
mix local.hex --force
 | 
					mix local.hex --force
 | 
				
			||||||
mix local.rebar --force
 | 
					mix local.rebar --force
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					script/ci/restore-timestamps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mix deps.get
 | 
					mix deps.get
 | 
				
			||||||
mix ecto.create
 | 
					mix ecto.create
 | 
				
			||||||
mix ecto.migrate
 | 
					mix ecto.migrate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mix test
 | 
					mix test
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					script/ci/restore-timestamps
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue